UNPKG

@feathersjs/feathers

Version:

A framework for real-time applications and REST API with JavaScript and TypeScript

380 lines (379 loc) 15.6 kB
import { EventEmitter } from 'events'; import { NextFunction, HookContext as BaseHookContext } from '@feathersjs/hooks'; type SelfOrArray<S> = S | S[]; type OptionalPick<T, K extends PropertyKey> = Pick<T, Extract<keyof T, K>>; type Entries<T> = { [K in keyof T]: [K, T[K]]; }[keyof T][]; type GetKeyByValue<Obj, Value> = Extract<Entries<Obj>[number], [PropertyKey, Value]>[0]; export type { NextFunction }; /** * The object returned from `.find` call by standard database adapters */ export interface Paginated<T> { total: number; limit: number; skip: number; data: T[]; } /** * Options that can be passed when registering a service via `app.use(name, service, options)` */ export interface ServiceOptions<MethodTypes = string> { /** * A list of custom events that this service emits to clients */ events?: string[] | readonly string[]; /** * A list of service methods that should be available __externally__ to clients */ methods?: MethodTypes[] | readonly MethodTypes[]; /** * Provide a full list of events that this service should emit to clients. * Unlike the `events` option, this will not be merged with the default events. */ serviceEvents?: string[] | readonly string[]; /** * Initial data to always add as route params to this service. */ routeParams?: { [key: string]: any; }; } export interface ClientService<Result = any, Data = Partial<Result>, PatchData = Data, FindResult = Paginated<Result>, P = Params> { find(params?: P): Promise<FindResult>; get(id: Id, params?: P): Promise<Result>; create(data: Data[], params?: P): Promise<Result[]>; create(data: Data, params?: P): Promise<Result>; update(id: Id, data: Data, params?: P): Promise<Result>; update(id: NullableId, data: Data, params?: P): Promise<Result | Result[]>; update(id: null, data: Data, params?: P): Promise<Result[]>; patch(id: NullableId, data: PatchData, params?: P): Promise<Result | Result[]>; patch(id: Id, data: PatchData, params?: P): Promise<Result>; patch(id: null, data: PatchData, params?: P): Promise<Result[]>; remove(id: NullableId, params?: P): Promise<Result | Result[]>; remove(id: Id, params?: P): Promise<Result>; remove(id: null, params?: P): Promise<Result[]>; } export interface ServiceMethods<Result = any, Data = Partial<Result>, ServiceParams = Params, PatchData = Partial<Data>> { find(params?: ServiceParams & { paginate?: PaginationParams; }): Promise<Result | Result[]>; get(id: Id, params?: ServiceParams): Promise<Result>; create(data: Data, params?: ServiceParams): Promise<Result>; update(id: NullableId, data: Data, params?: ServiceParams): Promise<Result | Result[]>; patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>; remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]>; setup?(app: Application, path: string): Promise<void>; teardown?(app: Application, path: string): Promise<void>; } export interface ServiceOverloads<Result = any, Data = Partial<Result>, ServiceParams = Params, PatchData = Partial<Data>> { create?(data: Data[], params?: ServiceParams): Promise<Result[]>; update?(id: Id, data: Data, params?: ServiceParams): Promise<Result>; update?(id: null, data: Data, params?: ServiceParams): Promise<Result[]>; patch?(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>; patch?(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>; remove?(id: Id, params?: ServiceParams): Promise<Result>; remove?(id: null, params?: ServiceParams): Promise<Result[]>; } /** * A complete service interface. The `ServiceInterface` type should be preferred for customs service * implementations */ export type Service<Result = any, Data = Partial<Result>, ServiceParams = Params, PatchData = Partial<Data>> = ServiceMethods<Result, Data, ServiceParams> & ServiceOverloads<Result, Data, ServiceParams, PatchData>; /** * The `Service` service interface but with none of the methods required. */ export type ServiceInterface<Result = any, Data = Partial<Result>, ServiceParams = Params, PatchData = Partial<Data>> = Partial<ServiceMethods<Result, Data, ServiceParams, PatchData>>; export interface ServiceAddons<A = Application, S = Service> extends EventEmitter { id?: string; hooks(options: HookOptions<A, S>): this; } export interface ServiceHookOverloads<S, P = Params> { find(params: P & { paginate?: PaginationParams; }, context: HookContext): Promise<HookContext>; get(id: Id, params: P, context: HookContext): Promise<HookContext>; create(data: ServiceGenericData<S> | ServiceGenericData<S>[], params: P, context: HookContext): Promise<HookContext>; update(id: NullableId, data: ServiceGenericData<S>, params: P, context: HookContext): Promise<HookContext>; patch(id: NullableId, data: ServiceGenericData<S>, params: P, context: HookContext): Promise<HookContext>; remove(id: NullableId, params: P, context: HookContext): Promise<HookContext>; } export type FeathersService<A = FeathersApplication, S = Service> = S & ServiceAddons<A, S> & OptionalPick<ServiceHookOverloads<S>, keyof S>; export type CustomMethods<T extends { [key: string]: [any, any]; }> = { [K in keyof T]: (data: T[K][0], params?: Params) => Promise<T[K][1]>; }; /** * An interface usually use by transport clients that represents a e.g. HTTP or websocket * connection that can be configured on the application. */ export type TransportConnection<Services = any> = { (app: Application<Services>): void; Service: any; service: <L extends keyof Services & string>(name: L) => keyof any extends keyof Services ? ServiceInterface : Services[L]; }; /** * A real-time connection object */ export interface RealTimeConnection { [key: string]: any; } /** * The interface for a custom service method. Can e.g. be used to type client side services. */ export type CustomMethod<T = any, R = T, P extends Params = Params> = (data: T, params?: P) => Promise<R>; export type ServiceMixin<A> = (service: FeathersService<A>, path: string, options: ServiceOptions) => void; export type ServiceGenericType<S> = S extends ServiceInterface<infer T> ? T : any; export type ServiceGenericData<S> = S extends ServiceInterface<infer _T, infer D> ? D : any; export type ServiceGenericParams<S> = S extends ServiceInterface<infer _T, infer _D, infer P> ? P : any; export interface FeathersApplication<Services = any, Settings = any> { /** * The Feathers application version */ version: string; /** * A list of callbacks that run when a new service is registered */ mixins: ServiceMixin<Application<Services, Settings>>[]; /** * The index of all services keyed by their path. * * __Important:__ Services should always be retrieved via `app.service('name')` * not via `app.services`. */ services: Services; /** * The application settings that can be used via * `app.get` and `app.set` */ settings: Settings; /** * A private-ish indicator if `app.setup()` has been called already */ _isSetup: boolean; /** * Retrieve an application setting by name * * @param name The setting name */ get<L extends keyof Settings & string>(name: L): Settings[L]; /** * Set an application setting * * @param name The setting name * @param value The setting value */ set<L extends keyof Settings & string>(name: L, value: Settings[L]): this; /** * Runs a callback configure function with the current application instance. * * @param callback The callback `(app: Application) => {}` to run */ configure(callback: (this: this, app: this) => void): this; /** * Returns a fallback service instance that will be registered * when no service was found. Usually throws a `NotFound` error * but also used to instantiate client side services. * * @param location The path of the service */ defaultService(location: string): ServiceInterface; /** * Register a new service or a sub-app. When passed another * Feathers application, all its services will be re-registered * with the `path` prefix. * * @param path The path for the service to register * @param service The service object to register or another * Feathers application to use a sub-app under the `path` prefix. * @param options The options for this service */ use<L extends keyof Services & string>(path: L, service: keyof any extends keyof Services ? ServiceInterface | Application : Services[L], options?: ServiceOptions<keyof any extends keyof Services ? string : keyof Services[L]>): this; /** * Unregister an existing service. * * @param path The name of the service to unregister */ unuse<L extends keyof Services & string>(path: L): Promise<FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>>; /** * Get the Feathers service instance for a path. This will * be the service originally registered with Feathers functionality * like hooks and events added. * * @param path The name of the service. */ service<L extends keyof Services & string>(path: L): FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>; /** * Set up the application and call all services `.setup` method if available. * * @param server A server instance (optional) */ setup(server?: any): Promise<this>; /** * Tear down the application and call all services `.teardown` method if available. * * @param server A server instance (optional) */ teardown(server?: any): Promise<this>; /** * Register application level hooks. * * @param map The application hook settings. */ hooks(map: ApplicationHookOptions<this>): this; } export interface Application<Services = any, Settings = any> extends FeathersApplication<Services, Settings>, EventEmitter { } export type Id = number | string; export type NullableId = Id | null; export interface Query { [key: string]: any; } export interface Params<Q = Query> { query?: Q; provider?: string; route?: { [key: string]: any; }; headers?: { [key: string]: any; }; } export interface PaginationOptions { default?: number; max?: number; } export type PaginationParams = false | PaginationOptions; export interface Http { /** * A writeable, optional property with status code override. */ status?: number; /** * A writeable, optional property with headers. */ headers?: { [key: string]: string | string[]; }; /** * A writeable, optional property with `Location` header's value. */ location?: string; } export type HookType = 'before' | 'after' | 'error' | 'around'; type Serv<FA> = FA extends Application<infer S> ? S : never; export interface HookContext<A = Application, S = any> extends BaseHookContext<ServiceGenericType<S>> { /** * A read only property that contains the Feathers application object. This can be used to * retrieve other services (via context.app.service('name')) or configuration values. */ readonly app: A; /** * A read only property with the name of the service method (one of find, get, * create, update, patch, remove). */ readonly method: string; /** * A read only property and contains the service name (or path) without leading or * trailing slashes. */ path: 0 extends 1 & S ? keyof Serv<A> & string : GetKeyByValue<Serv<A>, S> & string; /** * A read only property and contains the service this hook currently runs on. */ readonly service: S; /** * A read only property with the hook type (one of 'around', 'before', 'after' or 'error'). */ readonly type: HookType; /** * The list of method arguments. Should not be modified, modify the * `params`, `data` and `id` properties instead. */ readonly arguments: any[]; /** * A writeable property containing the data of a create, update and patch service * method call. */ data?: ServiceGenericData<S>; /** * A writeable property with the error object that was thrown in a failed method call. * It is only available in error hooks. */ error?: any; /** * A writeable property and the id for a get, remove, update and patch service * method call. For remove, update and patch context.id can also be null when * modifying multiple entries. In all other cases it will be undefined. */ id?: Id; /** * A writeable property that contains the service method parameters (including * params.query). */ params: ServiceGenericParams<S>; /** * A writeable property containing the result of the successful service method call. * It is only available in after hooks. * * `context.result` can also be set in * * - A before hook to skip the actual service method (database) call * - An error hook to swallow the error and return a result instead */ result?: ServiceGenericType<S>; /** * A writeable, optional property and contains a 'safe' version of the data that * should be sent to any client. If context.dispatch has not been set context.result * will be sent to the client instead. */ dispatch?: ServiceGenericType<S>; /** * A writeable, optional property that allows to override the standard HTTP status * code that should be returned. * * @deprecated Use `http.status` instead. */ statusCode?: number; /** * A writeable, optional property with options specific to HTTP transports. */ http?: Http; /** * The event emitted by this method. Can be set to `null` to skip event emitting. */ event: string | null; } export type HookFunction<A = Application, S = Service> = (this: S, context: HookContext<A, S>) => Promise<HookContext<Application, S> | void> | HookContext<Application, S> | void; export type Hook<A = Application, S = Service> = HookFunction<A, S>; type HookMethodMap<A, S> = { [L in keyof S]?: SelfOrArray<HookFunction<A, S>>; } & { all?: SelfOrArray<HookFunction<A, S>>; }; type HookTypeMap<A, S> = SelfOrArray<HookFunction<A, S>> | HookMethodMap<A, S>; export type AroundHookFunction<A = Application, S = Service> = (context: HookContext<A, S>, next: NextFunction) => Promise<void>; export type AroundHookMap<A, S> = { [L in keyof S]?: AroundHookFunction<A, S>[]; } & { all?: AroundHookFunction<A, S>[]; }; export type HookMap<A, S> = { around?: AroundHookMap<A, S>; before?: HookTypeMap<A, S>; after?: HookTypeMap<A, S>; error?: HookTypeMap<A, S>; }; export type HookOptions<A, S> = AroundHookMap<A, S> | AroundHookFunction<A, S>[] | HookMap<A, S>; export interface ApplicationHookContext<A = Application> extends BaseHookContext { app: A; server: any; } export type ApplicationHookFunction<A> = (context: ApplicationHookContext<A>, next: NextFunction) => Promise<void>; export type ApplicationHookMap<A> = { setup?: ApplicationHookFunction<A>[]; teardown?: ApplicationHookFunction<A>[]; }; export type ApplicationHookOptions<A> = HookOptions<A, any> | ApplicationHookMap<A>;