UNPKG

@radatek/microserver

Version:
866 lines (864 loc) 32 kB
/** * MicroServer * @version 2.3.11 * @package @radatek/microserver * @copyright Darius Kisonas 2022 * @license MIT */ import http from 'http'; import net from 'net'; import { Readable } from 'stream'; import fs from 'fs'; import { EventEmitter } from 'events'; export declare class Warning extends Error { constructor(text: string); } export declare class ResponseError extends Error { static getStatusCode(text: string | number | undefined): number; static getStatusText(text: string | number | undefined): string; statusCode: number; constructor(text: string | number | undefined, statusCode?: number); } export declare class AccessDenied extends ResponseError { constructor(text?: string); } export declare class InvalidData extends ResponseError { constructor(text?: string, type?: string); } export declare class NotFound extends ResponseError { constructor(text?: string); } export declare class WebSocketError extends Error { statusCode: number; constructor(text?: string, code?: number); } export type Routes = () => Record<string, Array<any>> | Array<Array<any>>; export declare abstract class Plugin { name?: string; priority?: number; handler?(req: ServerRequest, res: ServerResponse, next: Function): Promise<string | object | void> | string | object | void; routes?(): Promise<Routes> | Routes; initialise?(): Promise<void> | void; constructor(router: Router, ...args: any); } interface PluginClass { new (router: Router, ...args: any): Plugin; } export type ServerRequestBody<T = any> = T extends Model<infer U extends ModelSchema> ? ModelDocument<U> : Record<string, any>; /** Extended http.IncomingMessage */ export declare class ServerRequest<T = any> extends http.IncomingMessage { /** Request protocol: http or https */ protocol: string; /** Request client IP */ ip?: string; /** Request from local network */ localip?: boolean; /** Request is secure (https) */ secure?: boolean; /** Request whole path */ path: string; /** Request pathname */ pathname: string; /** Base url */ baseUrl: string; /** Original url */ originalUrl?: string; /** Query parameters */ query: Record<string, string>; /** Router named parameters */ params: Record<string, string>; /** Router named parameters list */ paramsList: string[]; /** Router */ router: Router; /** Authentication object */ auth?: Auth; /** Authenticated user info */ user?: UserInfo; /** Model used for request */ model?: T; /** Authentication token id */ tokenId?: string; /** Request raw body */ rawBody: Buffer[]; /** Request raw body size */ rawBodySize: number; private constructor(); /** Update request url */ updateUrl(url: string): void; /** Rewrite request url */ rewrite(url: string): void; /** Request body: JSON or POST parameters */ get body(): ServerRequestBody<T>; /** Alias to body */ get post(): ServerRequestBody<T>; /** Get websocket */ get websocket(): WebSocket; /** get files list in request */ files(): Promise<any[] | undefined>; /** Decode request body */ bodyDecode(res: ServerResponse, options: any, next: () => void): void; } /** Extends http.ServerResponse */ export declare class ServerResponse<T = any> extends http.ServerResponse { req: ServerRequest<T>; router: Router; isJson: boolean; headersOnly: boolean; private constructor(); /** Send error reponse */ error(error: string | number | Error): void; /** Sets Content-Type acording to data and sends response */ send(data?: string | Buffer | Error | Readable | object): void; /** Send json response */ json(data: any): void; /** Send json response in form { success: false, error: err } */ jsonError(error: string | number | object | Error): void; /** Send json response in form { success: true, ... } */ jsonSuccess(data?: object | string): void; /** Send redirect response to specified URL with optional status code (default: 302) */ redirect(code: number | string, url?: string): void; /** Set status code */ status(code: number): this; file(path: string, filename?: string): void; } /** WebSocket options */ export interface WebSocketOptions { maxPayload?: number; autoPong?: boolean; permessageDeflate?: boolean; maxWindowBits?: number; timeout?: number; deflate?: boolean; } /** WebSocket class */ export declare class WebSocket extends EventEmitter { ready: boolean; constructor(req: ServerRequest, options?: WebSocketOptions); /** Close connection */ close(reason?: number, data?: Buffer): void; /** Generate WebSocket frame from data */ static getFrame(data: number | string | Buffer | undefined, options?: any): Buffer; /** Send data */ send(data: string | Buffer): void; /** Send ping frame */ ping(buffer?: Buffer): void; /** Send pong frame */ pong(buffer?: Buffer): void; protected _sendFrame(opcode: number, data: Buffer, cb?: () => void): void; } /** * Controller for dynamic routes * * @example * ```js * class MyController extends Controller { * static model = MyModel; * static acl = 'auth'; * * static 'acl:index' = ''; * static 'url:index' = 'GET /index'; * async index (req, res) { * res.send('Hello World') * } * * //function name prefixes translated to HTTP methods: * // all => GET, get => GET, insert => POST, post => POST, * // update => PUT, put => PUT, delete => DELETE, * // modify => PATCH, patch => PATCH, * // websocket => internal WebSocket * // automatic acl will be: class_name + '/' + function_name_prefix * // automatic url will be: method + ' /' + class_name + '/' + function_name_without_prefix * * //static 'acl:allUsers' = 'MyController/all'; * //static 'url:allUsers' = 'GET /MyController/Users'; * async allUsers () { * return ['usr1', 'usr2', 'usr3'] * } * * //static 'acl:getOrder' = 'MyController/get'; * //static 'url:getOrder' = 'GET /Users/:id/:id1'; * static 'group:getOrder' = 'orders'; * static 'model:getOrder' = OrderModel; * async getOrder (id: string, id1: string) { * return {id, extras: id1, type: 'order'} * } * * //static 'acl:insertOrder' = 'MyController/insert'; * //static 'url:insertOrder' = 'POST /Users/:id'; * static 'model:insertOrder' = OrderModel; * async insertOrder (id: string, id1: string) { * return {id, extras: id1, type: 'order'} * } * * static 'acl:POST /login' = ''; * async 'POST /login' () { * return {id, extras: id1, type: 'order'} * } * } * ``` */ export declare class Controller<T extends Model<any> = any> { req: ServerRequest<T>; res: ServerResponse<T>; get model(): T | undefined; constructor(req: ServerRequest<T>, res: ServerResponse<T>); /** Generate routes for this controller */ static routes(): any[]; } /** Middleware */ export interface Middleware { (req: ServerRequest, res: ServerResponse, next: Function): any; /** @default 0 */ priority?: number; plugin?: Plugin; } declare class Waiter { isBusy(id?: string): boolean; startJob(id?: string): void; endJob(id?: string): void; get nextId(): string; wait(id?: string): Promise<void>; } /** Router */ export declare class Router extends EventEmitter { server: MicroServer; auth?: Auth; plugins: Record<string, Plugin>; _waiter: Waiter; /** @param {MicroServer} server */ constructor(server: MicroServer); /** bind middleware or create one from string like: 'redirect:302,https://redirect.to', 'error:422', 'param:name=value', 'acl:users/get', 'model:User', 'group:Users', 'user:admin' */ bind(fn: string | Function | object): Function; /** Handler */ handler(req: ServerRequest, res: ServerResponse, next: Function, method?: string): void; /** Clear routes and middlewares */ clear(): this; /** * Add middleware route. * Middlewares may return promises for res.jsonSuccess(...), throw errors for res.error(...), return string or {} for res.send(...) * * @signature add(plugin: Plugin) * @param {Plugin} plugin plugin module instance * @return {Promise<>} * * @signature add(pluginid: string, ...args: any) * @param {string} pluginid pluginid module * @param {...any} args arguments passed to constructor * @return {Promise<>} * * @signature add(pluginClass: typeof Plugin, ...args: any) * @param {typeof Plugin} pluginClass plugin class * @param {...any} args arguments passed to constructor * @return {Promise<>} * * @signature add(middleware: Middleware) * @param {Middleware} middleware * @return {Promise<>} * * @signature add(methodUrl: string, ...middlewares: any) * @param {string} methodUrl 'METHOD /url' or '/url' * @param {...any} middlewares * @return {Promise<>} * * @signature add(methodUrl: string, controllerClass: typeof Controller) * @param {string} methodUrl 'METHOD /url' or '/url' * @param {typeof Controller} controllerClass * @return {Promise<>} * * @signature add(methodUrl: string, routes: Array<Array<any>>) * @param {string} methodUrl 'METHOD /url' or '/url' * @param {Array<Array<any>>} routes list with subroutes: ['METHOD /suburl', ...middlewares] * @return {Promise<>} * * @signature add(methodUrl: string, routes: Array<Array<any>>) * @param {string} methodUrl 'METHOD /url' or '/url' * @param {Array<Array<any>>} routes list with subroutes: ['METHOD /suburl', ...middlewares] * @return {Promise<>} * * @signature add(routes: { [key: string]: Array<any> }) * @param { {[key: string]: Array<any>} } routes list with subroutes: 'METHOD /suburl': [...middlewares] * @return {Promise<>} * * @signature add(methodUrl: string, routes: { [key: string]: Array<any> }) * @param {string} methodUrl 'METHOD /url' or '/url' * @param { {[key: string]: Array<any>} } routes list with subroutes: 'METHOD /suburl': [...middlewares] * @return {Promise<>} */ use(...args: any): Promise<void>; waitPlugin(id: string): Promise<Plugin>; /** Add hook */ hook(url: string, ...mid: Middleware[]): void; /** Check if middleware allready added */ has(mid: Middleware): boolean; } export interface HttpHandler { (req: ServerRequest, res: ServerResponse): void; } export interface TcpHandler { (socket: net.Socket): void; } export interface ListenConfig { /** listen port(s) with optional protocol and host (Ex. 8080 or '0.0.0.0:8080,8180' or 'https://0.0.0.0:8080' or 'tcp://0.0.0.0:8080' or 'tls://0.0.0.0:8080') */ listen?: string | number; /** tls options */ tls?: { cert: string; key: string; ca?: string; }; /** custom handler */ handler?: HttpHandler | TcpHandler; } export interface CorsOptions { /** allowed origins (default: '*') */ origin: string; /** allowed headers (default: '*') */ headers: string; /** allow credentials (default: false) */ credentials: boolean; /** Expose headers */ expose?: string; /** Max age */ maxAge?: number; } /** MicroServer configuration */ export interface MicroServerConfig extends ListenConfig { /** server instance root path */ root?: string; /** Auth options */ auth?: AuthOptions; /** routes to add */ routes?: any; /** Static file options */ static?: StaticOptions; /** max body size (default: 5MB) */ maxBodySize?: number; /** allowed HTTP methods */ methods?: string; /** trust proxy */ trustProxy?: string[]; /** cors options */ cors?: string | CorsOptions | boolean; /** upload dir (default: './upload') */ uploadDir?: string; /** allow websocket deflate compression (default: false) */ websocketCompress?: boolean; /** max websocket payload (default: 1MB) */ websocketMaxPayload?: number; /** websocket max window bits 8-15 for deflate (default: 10) */ websocketMaxWindowBits?: number; /** extra options for plugins */ [key: string]: any; } export declare class MicroServer extends EventEmitter { /** server configuration */ config: MicroServerConfig; /** main router */ router: Router; /** virtual host routers */ vhosts?: { [key: string]: Router; }; /** all sockets */ sockets: Set<net.Socket>; /** server instances */ servers: Set<net.Server>; _waiter: Waiter; static plugins: { [key: string]: PluginClass; }; constructor(config: MicroServerConfig); /** Add one time listener or call immediatelly for 'ready' */ once(name: string, cb: Function): this; /** Add listener and call immediatelly for 'ready' */ on(name: string, cb: Function): this; get isReady(): boolean; waitReady(): Promise<void>; waitPlugin(id: string): Promise<void>; /** Listen server, should be used only if config.listen is not set */ listen(config?: ListenConfig): Promise<void>; /** Add middleware, routes, etc.. see {router.use} */ use(...args: any): Promise<void>; /** Default server handler */ handler(req: ServerRequest, res: ServerResponse): void; protected requestInit(req: ServerRequest, res?: ServerResponse): void; /** Preprocess request, used by {MicroServer.handler} */ handlerInit(req: ServerRequest, res: ServerResponse, next: Function): void; /** Last request handler */ handlerLast(req: ServerRequest, res: ServerResponse, next?: Function): any; /** Default upgrade handler, used for WebSockets */ handlerUpgrade(req: ServerRequest, socket: net.Socket, head: any): void; /** Close server instance */ close(): Promise<void>; /** Add route, alias to `server.router.use(url, ...args)` */ all(url: string, ...args: any): MicroServer; /** Add route, alias to `server.router.use('GET ' + url, ...args)` */ get(url: string, ...args: any): MicroServer; /** Add route, alias to `server.router.use('POST ' + url, ...args)` */ post(url: string, ...args: any): MicroServer; /** Add route, alias to `server.router.use('PUT ' + url, ...args)` */ put(url: string, ...args: any): MicroServer; /** Add route, alias to `server.router.use('PATCH ' + url, ...args)` */ patch(url: string, ...args: any): MicroServer; /** Add route, alias to `server.router.use('DELETE ' + url, ...args)` */ delete(url: string, ...args: any): MicroServer; /** Add websocket handler, alias to `server.router.use('WEBSOCKET ' + url, ...args)` */ websocket(url: string, ...args: any): MicroServer; /** Add router hook, alias to `server.router.hook(url, ...args)` */ hook(url: string, ...args: any): MicroServer; } /** Static files options */ export interface StaticOptions { /** files root directory */ root?: string; /** url path */ path?: string; /** additional mime types */ mimeTypes?: { [key: string]: string; }; /** file extension handlers */ handlers?: { [key: string]: Middleware; }; /** ignore prefixes */ ignore?: string[]; /** index file. default: 'index.html' */ index?: string; /** Update Last-Modified header. default: true */ lastModified?: boolean; /** Update ETag header. default: true */ etag?: boolean; /** Max file age in seconds */ maxAge?: number; } export interface ServeFileOptions { /** path */ path: string; /** root */ root?: string; /** file name */ filename?: string; /** file mime type */ mimeType?: string; /** last modified date */ lastModified?: boolean; /** etag */ etag?: boolean; /** max age */ maxAge?: number; /** range */ range?: boolean; /** stat */ stats?: fs.Stats; } /** Proxy plugin options */ export interface ProxyPluginOptions { /** Base path */ path?: string; /** Remote url */ remote?: string; /** Match regex filter */ match?: string; /** Override/set headers for remote */ headers?: { [key: string]: string; }; /** Valid headers to forward */ validHeaders?: { [key: string]: boolean; }; } export declare class ProxyPlugin extends Plugin { /** Default valid headers */ static validHeaders: { [key: string]: boolean; }; /** Current valid headers */ validHeaders: { [key: string]: boolean; }; /** Override headers to forward to remote */ headers: { [key: string]: string; } | undefined; /** Remote url */ remoteUrl: URL; /** Match regex filter */ regex?: RegExp; constructor(router: Router, options?: ProxyPluginOptions | string); /** Default proxy handler */ proxyHandler(req: ServerRequest, res: ServerResponse, next: Function): any; /** Proxy plugin handler as middleware */ handler?(req: ServerRequest, res: ServerResponse, next: Function): void; } /** User info */ export interface UserInfo { /** User _id */ _id?: string; /** User id */ id?: string; /** User password plain or hash */ password?: string; /** ACL options */ acl?: { [key: string]: boolean; }; /** User group */ group?: string; /** Custom user data */ [key: string]: any; } /** Authentication options */ export interface AuthOptions { /** Authentication token */ token: string | Buffer; /** Users */ users?: { [key: string]: UserInfo; } | ((usr: string, psw?: string) => Promise<UserInfo | undefined>); /** Default ACL */ defaultAcl?: { [key: string]: boolean; }; /** Expire time in seconds */ expire?: number; /** Authentication mode */ mode?: 'cookie' | 'token'; /** Authentication realm for basic authentication */ realm?: string; /** Redirect URL */ redirect?: string; /** Authentication cache */ cache?: { [key: string]: { data: UserInfo; time: number; }; }; /** Interal next cache cleanup time */ cacheCleanup?: number; } export interface AuthOptionsInternal extends AuthOptions { /** Authentication token */ token: Buffer; /** Users */ users: (usr: string, psw?: string) => Promise<UserInfo | undefined>; /** Default ACL */ defaultAcl: { [key: string]: boolean; }; /** Expire time in seconds */ expire: number; /** Use object token instead of user id */ objectToken: boolean; /** Authentication mode */ mode: 'cookie' | 'token'; /** Authentication realm for basic authentication */ realm: string; /** Redirect URL */ redirect: string; /** Authentication cache */ cache: { [key: string]: { data: UserInfo; time: number; }; }; /** Interal next cache cleanup time */ cacheCleanup: number; } /** Authentication class */ export declare class Auth { /** Server request */ req: ServerRequest | undefined; /** Server response */ res: ServerResponse | undefined; /** Authentication options */ options: AuthOptionsInternal; constructor(options: AuthOptionsInternal, req?: ServerRequest, res?: ServerResponse); /** Decode token */ decode(data: string): { data: string; expire: number; }; /** Encode token */ encode(data: string, expire?: number): string; /** * Check acl over authenticated user with: `id`, `group/*`, `*` * @param {string} id - to authenticate: `id`, `group/id`, `model/action`, comma separated best: true => false => def * @param {boolean} [def=false] - default access */ acl(id: string, def?: boolean): boolean; /** * Authenticate user and setup cookie * @param {string|UserInfo} usr - user id used with options.users to retrieve user object. User object must contain `id` and `acl` object (Ex. usr = {id:'usr', acl:{'users/*':true}}) * @param {string} [psw] - user password (if used for user authentication with options.users) * @param {number} [expire] - expire time in seconds (default: options.expire) */ token(usr: string | UserInfo | undefined, psw: string | undefined, expire?: number): Promise<string | undefined>; /** * Authenticate user and setup cookie */ login(usr: string | UserInfo | undefined, psw?: string, options?: { expire?: number; salt?: string; }): Promise<UserInfo | undefined>; /** Logout logged in user */ logout(): void; /** Get hashed string from user and password */ password(usr: string, psw: string, salt?: string): string; /** Get hashed string from user and password */ static password(usr: string, psw: string, salt?: string): string; /** Validate user password */ checkPassword(usr: string, psw: string, storedPsw: string, salt?: string): boolean; /** Validate user password */ static checkPassword(usr: string, psw: string, storedPsw: string, salt?: string): boolean; /** Clear user cache if users setting where changed */ clearCache(): void; } /** Create microserver */ export declare function create(config: MicroServerConfig): MicroServer; export interface FileStoreOptions { /** Base directory */ dir?: string; /** Cache timeout in milliseconds */ cacheTimeout?: number; /** Max number of cached items */ cacheItems?: number; /** Debounce timeout in milliseconds for autosave */ debounceTimeout?: number; } /** JSON File store */ export declare class FileStore { constructor(options?: FileStoreOptions); /** cleanup cache */ cleanup(): void; close(): Promise<void>; sync(): Promise<void>; /** load json file data */ load(name: string, autosave?: boolean): Promise<any>; /** save data */ save(name: string, data: any): Promise<any>; /** load all files in directory */ all(name: string, autosave?: boolean): Promise<Record<string, any>>; /** delete data file */ delete(name: string): Promise<void>; /** Observe data object */ observe(data: object, cb: (data: object, key: string, value: any) => void): object; } /** Model validation options */ interface ModelContextOptions { /** User info */ user?: UserInfo; /** Request params */ params?: Object; /** is insert */ insert?: boolean; /** is read-only */ readOnly?: boolean; /** validate */ validate?: boolean; /** use default */ default?: boolean; /** use primary key only for filter */ primaryKey?: boolean; /** projection fields */ projection?: Record<string, 0 | 1 | true | false>; } /** Model field validation options */ interface ModelValidateFieldOptions extends ModelContextOptions { name: string; field: ResolvedFieldSchema; model: Model<any>; } export interface ModelCallbackFunc { (options: any): any; } type ModelBasicCtorType = typeof String | typeof Number | typeof Boolean | typeof Date; type ModelBasicNamedType = 'string' | 'String' | 'number' | 'Number' | 'int' | 'Int' | 'integer' | 'Integer' | 'boolean' | 'Boolean' | 'object' | 'Object' | 'objectid' | 'ObjectId' | 'date' | 'Date' | 'any' | 'Any'; type ModelBasicType = ModelBasicNamedType | ModelBasicCtorType | Model<any>; type ModelFieldSimpleType = ModelBasicType | [ModelBasicType] | [ModelBasicType, ...never[]]; /** Model field description */ export interface ModelFieldSchema { /** Field type */ type: ModelFieldSimpleType; /** Is array */ array?: true | false; /** Is primary key, used for filtering */ primaryKey?: true | false; /** Is required */ required?: boolean | string | ModelCallbackFunc; /** Can read */ canRead?: boolean | string | ModelCallbackFunc; /** Can write */ canWrite?: boolean | string | ModelCallbackFunc; /** Default value */ default?: number | string | ModelCallbackFunc; /** Validate function */ validate?: (value: any, options: ModelContextOptions) => string | number | object | null | Error | typeof Error; /** Valid values */ enum?: Array<string | number>; /** Minimum value for string and number */ minimum?: number | string; /** Maximum value for string and number */ maximum?: number | string; /** Regex validation or 'email', 'url', 'date', 'time', 'date-time' */ format?: string; } interface ResolvedFieldSchema { type: string; model?: Model<any>; primaryKey?: boolean; required?: ModelCallbackFunc; canRead: ModelCallbackFunc; canWrite: ModelCallbackFunc; default: ModelCallbackFunc; validate: (value: any, options: ModelValidateFieldOptions) => any; } export interface ModelSchema { [K: string]: ModelFieldSchema | ModelFieldSimpleType; } type ModelDocumentTypeByName<T> = T extends 'string' | 'String' ? string : T extends 'number' | 'Number' | 'int' | 'Int' ? number : T extends 'boolean' | 'Boolean' ? boolean : T extends 'date' | 'Date' ? Date : T extends 'objectid' | 'ObjectId' ? string : T extends 'object' | 'Object' ? Record<string, any> : T extends 'any' | 'Any' ? any : never; type ModelDocumentTypeByCtor<T> = T extends typeof String ? string : T extends typeof Number ? number : T extends typeof Boolean ? boolean : T extends typeof Date ? Date : T extends typeof Object ? Record<string, any> : never; type ModelFieldTypeExtract<T extends ModelFieldSchema> = T['type'] extends string ? ModelDocumentTypeByName<T['type']> : T['type'] extends Array<infer U> ? Array<ModelDocumentType<U>> : T['type'] extends Function ? ModelDocumentTypeByCtor<T['type']> : T['type'] extends Model<infer U> ? ModelDocument<U> : never; type ModelDocumentType<T> = T extends string ? ModelDocumentTypeByName<T> : T extends Array<infer U> ? Array<ModelDocumentType<U>> : T extends Function ? ModelDocumentTypeByCtor<T> : T extends ModelFieldSchema ? ModelFieldTypeExtract<T> : T extends Model<infer U> ? ModelDocument<U> : never; export interface ModelDocumentField<T extends ModelFieldSchema> { value: T['array'] extends true ? Array<ModelFieldTypeExtract<T>> : ModelFieldTypeExtract<T>; required?: T['required']; canRead?: T['canRead']; canWrite?: T['canWrite']; default?: T['default']; validate?: T['validate']; } export type ModelDocument<T extends ModelSchema> = { [K in keyof T]: ModelDocumentType<T[K]>; } & { _id?: string; }; export declare interface ModelCollections { collection(name: string): Promise<MicroCollection>; } export declare class Models { } export declare class Model<TSchema extends ModelSchema> { static collections: ModelCollections; static models: Models; static set db(db: any); static get db(): any; /** Dynamic model extension */ static dynamic<T extends Model<any>>(model: T, options: { controller?: Controller; collection?: MicroCollection<any>; req?: ServerRequest; } | Controller): T; static register<K extends string, T extends Model<any>>(name: K, model: T): typeof Model; /** Define model */ static define<K extends string, T extends ModelSchema>(name: K, schema: T, options?: { collection?: MicroCollection | Promise<MicroCollection>; class?: typeof Model; }): Model<T>; /** Model fields description */ model: Record<string, ResolvedFieldSchema>; /** Model collection for persistance */ collection?: MicroCollection | Promise<MicroCollection>; /** Custom options */ options: Record<string, any>; /** Create model acording to description */ constructor(schema: TSchema, options?: { collection?: MicroCollection | Promise<MicroCollection>; name?: string; }); /** Get model name */ get name(): any; /** Validate data over model */ document(data: Record<string, any>, options?: ModelContextOptions): ModelDocument<TSchema>; /** Generate filter for data queries */ getFilter(data: Record<string, any>, options?: ModelContextOptions): Record<string, any>; /** Find one document */ findOne(query: Query, options?: ModelContextOptions): Promise<ModelDocument<TSchema> | undefined>; /** Find many documents */ findMany(query: Query, options?: ModelContextOptions): Promise<ModelDocument<TSchema>[]>; /** Insert a new document */ insert(data: Record<string, any>, options?: ModelContextOptions): Promise<ModelDocument<TSchema>>; /** Update one matching document */ update(query: Record<string, any>, options?: ModelContextOptions): Promise<ModelDocument<TSchema>>; /** Update many matching documents */ updateMany(query: Record<string, any>, update: Record<string, any>, options?: ModelContextOptions): Promise<ModelDocument<TSchema>>; /** Delete one matching document */ delete(query: Query, options?: ModelContextOptions): Promise<number>; /** Delete many matching documents */ deleteMany(query: Query, options?: ModelContextOptions): Promise<number>; /** Microserver middleware */ handler(req: ServerRequest, res: ServerResponse): any; } export declare interface MicroCollectionOptions<T extends ModelSchema = any> { /** Collection name */ name?: string; /** Custom data saver */ save?: (id: string, doc: ModelDocument<T> | undefined, col: MicroCollection) => Promise<ModelDocument<T>>; /** Preloaded data object */ data?: Record<string, ModelDocument<T>>; } export declare interface Query { [key: string]: any; } /** Cursor */ export declare interface Cursor<T extends ModelSchema> { forEach(cb: Function, self?: any): Promise<number>; all(): Promise<ModelDocument<T>[]>; } /** Find options */ export declare interface FindOptions { /** Query */ query?: Query; /** is upsert */ upsert?: boolean; /** is upsert */ delete?: boolean; /** update object */ update?: Query; /** maximum number of hits */ limit?: number; } /** Collection factory */ export declare class MicroCollectionStore { constructor(dataPath?: string, storeTimeDelay?: number); /** Get collection */ collection(name: string): Promise<MicroCollection>; } /** minimalistic indexed mongo type collection with persistance for usage with Model */ export declare class MicroCollection<TSchema extends ModelSchema = any> { /** Collection name */ name: string; /** Collection data */ data: Record<string, ModelDocument<TSchema>>; constructor(options?: MicroCollectionOptions<TSchema>); /** Query document with query filter */ protected queryDocument(query?: Query, data?: ModelDocument<TSchema>): ModelDocument<TSchema>; /** Count all documents */ countDocuments(): Promise<number>; /** Find one matching document */ findOne(query: Query): Promise<ModelDocument<TSchema> | undefined>; /** Find all matching documents */ find(query: Query): Cursor<TSchema>; /** Find and modify one matching document */ findAndModify(options: FindOptions): Promise<ModelDocument<TSchema> | undefined>; /** Insert one document */ insertOne(doc: ModelDocument<TSchema>): Promise<ModelDocument<TSchema>>; /** Insert multiple documents */ insertMany(docs: ModelDocument<TSchema>[]): Promise<ModelDocument<TSchema>[]>; /** Delete one matching document */ deleteOne(query: Query): Promise<number>; /** Delete all matching documents */ deleteMany(query: Query): Promise<number>; updateOne(query: Query, update: Record<string, any>, options?: FindOptions): Promise<{ upsertedId: any; modifiedCount: number; }>; updateMany(query: Query, update: Record<string, any>, options?: FindOptions): Promise<{ upsertedId: any; modifiedCount: number; }>; }