UNPKG

14.9 kBPlain TextView Raw
1import { EventEmitter } from 'events'
2import { NextFunction, HookContext as BaseHookContext } from '@feathersjs/hooks'
3
4type SelfOrArray<S> = S | S[]
5type OptionalPick<T, K extends PropertyKey> = Pick<T, Extract<keyof T, K>>
6
7export type { NextFunction }
8
9/**
10 * The object returned from `.find` call by standard database adapters
11 */
12export interface Paginated<T> {
13 total: number
14 limit: number
15 skip: number
16 data: T[]
17}
18
19/**
20 * Options that can be passed when registering a service via `app.use(name, service, options)`
21 */
22export interface ServiceOptions<MethodTypes = string> {
23 /**
24 * A list of custom events that this service emits to clients
25 */
26 events?: string[] | readonly string[]
27 /**
28 * A list of service methods that should be available __externally__ to clients
29 */
30 methods?: MethodTypes[] | readonly MethodTypes[]
31 /**
32 * Provide a full list of events that this service should emit to clients.
33 * Unlike the `events` option, this will not be merged with the default events.
34 */
35 serviceEvents?: string[] | readonly string[]
36 /**
37 * Initial data to always add as route params to this service.
38 */
39 routeParams?: { [key: string]: any }
40}
41
42export interface ClientService<
43 Result = any,
44 Data = Partial<Result>,
45 PatchData = Data,
46 FindResult = Paginated<Result>,
47 P = Params
48> {
49 find(params?: P): Promise<FindResult>
50
51 get(id: Id, params?: P): Promise<Result>
52
53 create(data: Data[], params?: P): Promise<Result[]>
54 create(data: Data, params?: P): Promise<Result>
55
56 update(id: Id, data: Data, params?: P): Promise<Result>
57 update(id: NullableId, data: Data, params?: P): Promise<Result | Result[]>
58 update(id: null, data: Data, params?: P): Promise<Result[]>
59
60 patch(id: NullableId, data: PatchData, params?: P): Promise<Result | Result[]>
61 patch(id: Id, data: PatchData, params?: P): Promise<Result>
62 patch(id: null, data: PatchData, params?: P): Promise<Result[]>
63
64 remove(id: NullableId, params?: P): Promise<Result | Result[]>
65 remove(id: Id, params?: P): Promise<Result>
66 remove(id: null, params?: P): Promise<Result[]>
67}
68
69export interface ServiceMethods<
70 Result = any,
71 Data = Partial<Result>,
72 ServiceParams = Params,
73 PatchData = Partial<Data>
74> {
75 find(params?: ServiceParams & { paginate?: PaginationParams }): Promise<Result | Result[]>
76
77 get(id: Id, params?: ServiceParams): Promise<Result>
78
79 create(data: Data, params?: ServiceParams): Promise<Result>
80
81 update(id: NullableId, data: Data, params?: ServiceParams): Promise<Result | Result[]>
82
83 patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>
84
85 remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]>
86
87 setup?(app: Application, path: string): Promise<void>
88
89 teardown?(app: Application, path: string): Promise<void>
90}
91
92export interface ServiceOverloads<
93 Result = any,
94 Data = Partial<Result>,
95 ServiceParams = Params,
96 PatchData = Partial<Data>
97> {
98 create?(data: Data[], params?: ServiceParams): Promise<Result[]>
99
100 update?(id: Id, data: Data, params?: ServiceParams): Promise<Result>
101
102 update?(id: null, data: Data, params?: ServiceParams): Promise<Result[]>
103
104 patch?(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>
105
106 patch?(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>
107
108 remove?(id: Id, params?: ServiceParams): Promise<Result>
109
110 remove?(id: null, params?: ServiceParams): Promise<Result[]>
111}
112
113/**
114 * A complete service interface. The `ServiceInterface` type should be preferred for customs service
115 * implementations
116 */
117export type Service<
118 Result = any,
119 Data = Partial<Result>,
120 ServiceParams = Params,
121 PatchData = Partial<Data>
122> = ServiceMethods<Result, Data, ServiceParams> & ServiceOverloads<Result, Data, ServiceParams, PatchData>
123
124/**
125 * The `Service` service interface but with none of the methods required.
126 */
127export type ServiceInterface<
128 Result = any,
129 Data = Partial<Result>,
130 ServiceParams = Params,
131 PatchData = Partial<Data>
132> = Partial<ServiceMethods<Result, Data, ServiceParams, PatchData>>
133
134export interface ServiceAddons<A = Application, S = Service> extends EventEmitter {
135 id?: string
136 hooks(options: HookOptions<A, S>): this
137}
138
139export interface ServiceHookOverloads<S, P = Params> {
140 find(params: P & { paginate?: PaginationParams }, context: HookContext): Promise<HookContext>
141
142 get(id: Id, params: P, context: HookContext): Promise<HookContext>
143
144 create(
145 data: ServiceGenericData<S> | ServiceGenericData<S>[],
146 params: P,
147 context: HookContext
148 ): Promise<HookContext>
149
150 update(id: NullableId, data: ServiceGenericData<S>, params: P, context: HookContext): Promise<HookContext>
151
152 patch(id: NullableId, data: ServiceGenericData<S>, params: P, context: HookContext): Promise<HookContext>
153
154 remove(id: NullableId, params: P, context: HookContext): Promise<HookContext>
155}
156
157export type FeathersService<A = FeathersApplication, S = Service> = S &
158 ServiceAddons<A, S> &
159 OptionalPick<ServiceHookOverloads<S>, keyof S>
160
161export type CustomMethods<T extends { [key: string]: [any, any] }> = {
162 [K in keyof T]: (data: T[K][0], params?: Params) => Promise<T[K][1]>
163}
164
165/**
166 * An interface usually use by transport clients that represents a e.g. HTTP or websocket
167 * connection that can be configured on the application.
168 */
169export type TransportConnection<Services = any> = {
170 (app: Application<Services>): void
171 Service: any
172 service: <L extends keyof Services & string>(
173 name: L
174 ) => keyof any extends keyof Services ? ServiceInterface : Services[L]
175}
176
177/**
178 * A real-time connection object
179 */
180export interface RealTimeConnection {
181 [key: string]: any
182}
183
184/**
185 * The interface for a custom service method. Can e.g. be used to type client side services.
186 */
187export type CustomMethod<T = any, R = T, P extends Params = Params> = (data: T, params?: P) => Promise<R>
188
189export type ServiceMixin<A> = (service: FeathersService<A>, path: string, options: ServiceOptions) => void
190
191export type ServiceGenericType<S> = S extends ServiceInterface<infer T> ? T : any
192export type ServiceGenericData<S> = S extends ServiceInterface<infer _T, infer D> ? D : any
193export type ServiceGenericParams<S> = S extends ServiceInterface<infer _T, infer _D, infer P> ? P : any
194
195export interface FeathersApplication<Services = any, Settings = any> {
196 /**
197 * The Feathers application version
198 */
199 version: string
200
201 /**
202 * A list of callbacks that run when a new service is registered
203 */
204 mixins: ServiceMixin<Application<Services, Settings>>[]
205
206 /**
207 * The index of all services keyed by their path.
208 *
209 * __Important:__ Services should always be retrieved via `app.service('name')`
210 * not via `app.services`.
211 */
212 services: Services
213
214 /**
215 * The application settings that can be used via
216 * `app.get` and `app.set`
217 */
218 settings: Settings
219
220 /**
221 * A private-ish indicator if `app.setup()` has been called already
222 */
223 _isSetup: boolean
224
225 /**
226 * Retrieve an application setting by name
227 *
228 * @param name The setting name
229 */
230 get<L extends keyof Settings & string>(name: L): Settings[L]
231
232 /**
233 * Set an application setting
234 *
235 * @param name The setting name
236 * @param value The setting value
237 */
238 set<L extends keyof Settings & string>(name: L, value: Settings[L]): this
239
240 /**
241 * Runs a callback configure function with the current application instance.
242 *
243 * @param callback The callback `(app: Application) => {}` to run
244 */
245 configure(callback: (this: this, app: this) => void): this
246
247 /**
248 * Returns a fallback service instance that will be registered
249 * when no service was found. Usually throws a `NotFound` error
250 * but also used to instantiate client side services.
251 *
252 * @param location The path of the service
253 */
254 defaultService(location: string): ServiceInterface
255
256 /**
257 * Register a new service or a sub-app. When passed another
258 * Feathers application, all its services will be re-registered
259 * with the `path` prefix.
260 *
261 * @param path The path for the service to register
262 * @param service The service object to register or another
263 * Feathers application to use a sub-app under the `path` prefix.
264 * @param options The options for this service
265 */
266 use<L extends keyof Services & string>(
267 path: L,
268 service: keyof any extends keyof Services ? ServiceInterface | Application : Services[L],
269 options?: ServiceOptions<keyof any extends keyof Services ? string : keyof Services[L]>
270 ): this
271
272 /**
273 * Unregister an existing service.
274 *
275 * @param path The name of the service to unregister
276 */
277 unuse<L extends keyof Services & string>(
278 path: L
279 ): Promise<FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>>
280
281 /**
282 * Get the Feathers service instance for a path. This will
283 * be the service originally registered with Feathers functionality
284 * like hooks and events added.
285 *
286 * @param path The name of the service.
287 */
288 service<L extends keyof Services & string>(
289 path: L
290 ): FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>
291
292 /**
293 * Set up the application and call all services `.setup` method if available.
294 *
295 * @param server A server instance (optional)
296 */
297 setup(server?: any): Promise<this>
298
299 /**
300 * Tear down the application and call all services `.teardown` method if available.
301 *
302 * @param server A server instance (optional)
303 */
304 teardown(server?: any): Promise<this>
305
306 /**
307 * Register application level hooks.
308 *
309 * @param map The application hook settings.
310 */
311 hooks(map: ApplicationHookOptions<this>): this
312}
313
314// This needs to be an interface instead of a type
315// so that the declaration can be extended by other modules
316export interface Application<Services = any, Settings = any>
317 extends FeathersApplication<Services, Settings>,
318 EventEmitter {}
319
320export type Id = number | string
321export type NullableId = Id | null
322
323export interface Query {
324 [key: string]: any
325}
326
327export interface Params<Q = Query> {
328 query?: Q
329 provider?: string
330 route?: { [key: string]: any }
331 headers?: { [key: string]: any }
332}
333
334export interface PaginationOptions {
335 default?: number
336 max?: number
337}
338
339export type PaginationParams = false | PaginationOptions
340
341export interface Http {
342 /**
343 * A writeable, optional property with status code override.
344 */
345 status?: number
346 /**
347 * A writeable, optional property with headers.
348 */
349 headers?: { [key: string]: string | string[] }
350 /**
351 * A writeable, optional property with `Location` header's value.
352 */
353 location?: string
354}
355
356export type HookType = 'before' | 'after' | 'error' | 'around'
357
358export interface HookContext<A = Application, S = any> extends BaseHookContext<ServiceGenericType<S>> {
359 /**
360 * A read only property that contains the Feathers application object. This can be used to
361 * retrieve other services (via context.app.service('name')) or configuration values.
362 */
363 readonly app: A
364 /**
365 * A read only property with the name of the service method (one of find, get,
366 * create, update, patch, remove).
367 */
368 readonly method: string
369 /**
370 * A read only property and contains the service name (or path) without leading or
371 * trailing slashes.
372 */
373 readonly path: string
374 /**
375 * A read only property and contains the service this hook currently runs on.
376 */
377 readonly service: S
378 /**
379 * A read only property with the hook type (one of 'around', 'before', 'after' or 'error').
380 */
381 readonly type: HookType
382 /**
383 * The list of method arguments. Should not be modified, modify the
384 * `params`, `data` and `id` properties instead.
385 */
386 readonly arguments: any[]
387 /**
388 * A writeable property containing the data of a create, update and patch service
389 * method call.
390 */
391 data?: ServiceGenericData<S>
392 /**
393 * A writeable property with the error object that was thrown in a failed method call.
394 * It is only available in error hooks.
395 */
396 error?: any
397 /**
398 * A writeable property and the id for a get, remove, update and patch service
399 * method call. For remove, update and patch context.id can also be null when
400 * modifying multiple entries. In all other cases it will be undefined.
401 */
402 id?: Id
403 /**
404 * A writeable property that contains the service method parameters (including
405 * params.query).
406 */
407 params: ServiceGenericParams<S>
408 /**
409 * A writeable property containing the result of the successful service method call.
410 * It is only available in after hooks.
411 *
412 * `context.result` can also be set in
413 *
414 * - A before hook to skip the actual service method (database) call
415 * - An error hook to swallow the error and return a result instead
416 */
417 result?: ServiceGenericType<S>
418 /**
419 * A writeable, optional property and contains a 'safe' version of the data that
420 * should be sent to any client. If context.dispatch has not been set context.result
421 * will be sent to the client instead.
422 */
423 dispatch?: ServiceGenericType<S>
424 /**
425 * A writeable, optional property that allows to override the standard HTTP status
426 * code that should be returned.
427 *
428 * @deprecated Use `http.status` instead.
429 */
430 statusCode?: number
431 /**
432 * A writeable, optional property with options specific to HTTP transports.
433 */
434 http?: Http
435 /**
436 * The event emitted by this method. Can be set to `null` to skip event emitting.
437 */
438 event: string | null
439}
440
441// Regular hook typings
442export type HookFunction<A = Application, S = Service> = (
443 this: S,
444 context: HookContext<A, S>
445) => Promise<HookContext<Application, S> | void> | HookContext<Application, S> | void
446
447export type Hook<A = Application, S = Service> = HookFunction<A, S>
448
449type HookMethodMap<A, S> = {
450 [L in keyof S]?: SelfOrArray<HookFunction<A, S>>
451} & { all?: SelfOrArray<HookFunction<A, S>> }
452
453type HookTypeMap<A, S> = SelfOrArray<HookFunction<A, S>> | HookMethodMap<A, S>
454
455// New @feathersjs/hook typings
456export type AroundHookFunction<A = Application, S = Service> = (
457 context: HookContext<A, S>,
458 next: NextFunction
459) => Promise<void>
460
461export type AroundHookMap<A, S> = {
462 [L in keyof S]?: AroundHookFunction<A, S>[]
463} & { all?: AroundHookFunction<A, S>[] }
464
465export type HookMap<A, S> = {
466 around?: AroundHookMap<A, S>
467 before?: HookTypeMap<A, S>
468 after?: HookTypeMap<A, S>
469 error?: HookTypeMap<A, S>
470}
471
472export type HookOptions<A, S> = AroundHookMap<A, S> | AroundHookFunction<A, S>[] | HookMap<A, S>
473
474export interface ApplicationHookContext<A = Application> extends BaseHookContext {
475 app: A
476 server: any
477}
478
479export type ApplicationHookFunction<A> = (
480 context: ApplicationHookContext<A>,
481 next: NextFunction
482) => Promise<void>
483
484export type ApplicationHookMap<A> = {
485 setup?: ApplicationHookFunction<A>[]
486 teardown?: ApplicationHookFunction<A>[]
487}
488
489export type ApplicationHookOptions<A> = HookOptions<A, any> | ApplicationHookMap<A>