UNPKG

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