import mongoose, { Schema } from 'mongoose'; import { Response, NextFunction, RequestHandler, Router } from 'express'; import { A as AccessRouterBaseRequest, aj as GuardHook, aI as ModelRequest, d8 as AccessRuntime, V as DataRouterOptions, T as DataRequest, d9 as DataService, a4 as ExtendedDataRouterOptions, a8 as Filter, b2 as Projection, c0 as Sort, a$ as Populate, aJ as ModelRouterOptions, da as Service, db as PublicService, aS as ModelVirtualRecordAccess, aO as ModelVirtualDescriptor, aQ as ModelVirtualGetter, aR as ModelVirtualLeaf, a6 as ExtendedModelRouterOptions, cL as Validation, bQ as RootRouterOptions, dc as OpenApiRouterOptions, dd as OpenApiRegistryOptions, de as OpenApiRouteDescriptor, df as OpenApiDocumentOptions, dg as OpenApiParameter, dh as OpenApiSchema, di as OpenApiResponses, ah as GlobalOptions, Z as DefaultModelRouterOptions, a5 as ExtendedDefaultModelRouterOptions } from './parsers-DhUuvj9B.mjs'; export { dj as AccessRouterPermissionMap, dk as AccessRouterPermissions, c as AccessRouterRequest, d as AccessRouterRequestExtensions, l as AjvErrorObjectLike, n as AjvValidatorLike, o as ArkTypeErrorsLike, p as ArkTypeLike, a7 as FieldOperationAccess, ai as GlobalPermissionValue, am as IoTsContextEntryLike, an as IoTsDecodeErrorLike, ao as IoTsDecoderLike, ap as JoiSchemaLike, aq as JoiValidationErrorDetailLike, aw as MaybePromise, ax as ModelBaseFilterHook, az as ModelDeleteHook, aA as ModelDocPermissionsHook, aC as ModelDocumentHook, aD as ModelHook, aF as ModelIdentifierHook, aG as ModelListHook, aH as ModelOverrideFilterHook, aK as ModelValidateHook, aL as ModelVirtualAccess, aM as ModelVirtualAccessRecord, aN as ModelVirtualContext, aP as ModelVirtualDoc, aT as ModelVirtuals, dl as OpenApiMethod, aU as OperationAccess, aX as PairedRouteAccess, a_ as PermissionSchema, dm as Permissions, bk as RequestSchemaAdapter, bl as RequestSchemaFailure, bm as RequestSchemaIssue, bn as RequestSchemaLike, bo as RequestSchemaOptions, bp as RequestSchemaResult, bq as RequestSchemaSuccess, br as RequestSchemaValidator, bT as RouteBaseAccess, bU as RouteGuardAccess, bV as RouteVariant, bW as RouteVariantAccess, c2 as StandardSchemaFailure, c3 as StandardSchemaInferOutput, c4 as StandardSchemaIssue, c5 as StandardSchemaPathSegment, c6 as StandardSchemaResult, c7 as StandardSchemaSuccess, c8 as StandardSchemaV1, cb as SubOperationAccess, cf as SubRouteGuardOptions, cr as SuperstructFailureLike, cs as SuperstructValidateLike, cF as ValibotIssueLike, cG as ValibotPathItemLike, cH as ValibotSafeParseLike, cI as ValibotSafeParseResult, cN as VineValidationErrorLike, cO as VineValidationMessageLike, cP as VineValidatorLike, cQ as VirtualSubModel, cR as WithVirtuals, cS as YupSchemaLike, cT as YupValidationErrorLike, dn as defaultRuntime, cU as defineRequestSchema, cV as fromAjv, cW as fromArkType, cX as fromIoTs, cY as fromJoi, cZ as fromStandardSchema, c_ as fromSuperstruct, c$ as fromValibot, d0 as fromVine, d1 as fromYup, d2 as fromZod } from './parsers-DhUuvj9B.mjs'; import JsonRouter from '@web-ts-toolkit/express-json-router'; import 'zod'; declare function macl(): (req: AccessRouterBaseRequest, res: Response, next: NextFunction) => Promise; interface GuardModelConditionID { type: 'param' | 'query'; key: string; } interface GuardModelCondition { modelName: string; id: string | GuardModelConditionID; condition: string | string[]; } declare function guard(condition: string): RequestHandler; declare function guard(conditions: string[]): RequestHandler; declare function guard(conditionFunc: GuardHook): RequestHandler; declare function guard(modelCondition: GuardModelCondition): RequestHandler; type SetTargetOption$1 = { (option: TOption): TRouter; (key: string, option: unknown): TRouter; }; declare class DataRouter { readonly runtime: AccessRuntime; readonly dataName: string; readonly router: JsonRouter; /** Frozen construction-time snapshot. Read current policy with runtime.getDataOptions(dataName). */ readonly options: DataRouterOptions; readonly fullBasePath: string; constructor(dataName: string, initialOptions: DataRouterOptions, runtime?: AccessRuntime); private getRequestSchema; getService(req: DataRequest): DataService; private assertAllowed; private registerOpenApiRoute; private setCollectionRoutes; private setDocumentRoutes; /** * Update live behavior with a typed key/path or an options object. Dotted paths * such as `operationAccess.basicRead` update one key; object assignment replaces * supplied top-level values shallowly. The construction-time options snapshot stays fixed. */ set>(key: K, value: ExtendedDataRouterOptions[K]): this; set(options: DataRouterOptions): this; /** Set one live option/path; `setOption('operationAccess.basicRead', undefined)` restores inheritance. */ setOption>(key: K, option: ExtendedDataRouterOptions[K]): this; /** Shallowly replace supplied top-level options; an operationAccess object replaces that entire rule object. */ setOptions(options: DataRouterOptions): this; data: SetTargetOption$1, DataRouterOptions['data']>; listHardLimit: SetTargetOption$1, DataRouterOptions['listHardLimit']>; /** Base-operation field grants; basic/advanced route guards belong to operationAccess. */ permissionSchema: SetTargetOption$1, DataRouterOptions['permissionSchema']>; /** * Live list/read guards plus basicList/advancedList/basicRead/advancedRead. * `operationAccess('basicRead', false)` updates one key and denies GET /:id * (and HEAD) with HTTP 401; registered POST reads still inherit `read`. * `operationAccess({ list: true, read: true })` replaces the whole rule object, * not a deep merge. Use setOption with undefined to restore variant inheritance. */ operationAccess: SetTargetOption$1, DataRouterOptions['operationAccess']>; baseFilter: SetTargetOption$1, DataRouterOptions['baseFilter']>; /** * Trusted filter replacements applied before base-filter composition. * They may replace ordinary filters, but cannot replace an existing `false` denial. * Returning `false` denies the transaction. */ overrideFilter: SetTargetOption$1, DataRouterOptions['overrideFilter']>; decorate: SetTargetOption$1, DataRouterOptions['decorate']>; decorateAll: SetTargetOption$1, DataRouterOptions['decorateAll']>; idField: SetTargetOption$1, DataRouterOptions['idField']>; resolveIdFilter: SetTargetOption$1, DataRouterOptions['resolveIdFilter']>; queryRouteSegment: SetTargetOption$1, DataRouterOptions['queryRouteSegment']>; get routes(): Router; } interface FindProps { filter: Filter; select?: Projection; sort?: Sort; populate?: Populate[] | string; limit?: string | number; hardLimit?: number; skip?: string | number; lean?: boolean; } interface FindOneProps { filter: Filter; select?: Projection; sort?: Sort; populate?: Populate[] | string; lean?: boolean; } declare class Model { modelName: string; mongooseModel: mongoose.Model; runtime: AccessRuntime | null; constructor(modelName: string, runtime?: AccessRuntime); new(): any; create(data: unknown): Promise; find({ filter, select, sort, populate, limit, hardLimit, skip, lean }: FindProps): mongoose.Query; findOne({ filter, select, sort, populate, lean }: FindOneProps): mongoose.Query; exists(filter: Filter): ReturnType | null; countDocuments(filter?: {}): mongoose.Query; /** Cast a copy using this model's query schema/setters, without executing query middleware or persistence. */ castFilter(filter: Record): Record; distinct(field: string, conditions?: {}): mongoose.Query; aggregate(pipeline: unknown[]): mongoose.Aggregate; } type SetTargetOption = { (option: TOption): TRouter; (key: string, option: unknown): TRouter; }; declare class ModelRouter> { readonly runtime: AccessRuntime; readonly modelName: string; readonly router: JsonRouter; readonly model: Model; /** Frozen construction-time snapshot. Read current policy with runtime.getModelOptions(modelName). */ readonly options: ModelRouterOptions; readonly fullBasePath: string; constructor(modelName: string, initialOptions: ModelRouterOptions, runtime?: AccessRuntime); static fromModel>(model: mongoose.Model, initialOptions: ModelRouterOptions, runtime?: AccessRuntime): ModelRouter; private getRequestSchema; getService(req: ModelRequest): Service; getPublicService(req: ModelRequest): PublicService; private assertAllowed; private registerOpenApiRoute; private setCollectionRoutes; private setDocumentRoutes; private setSubDocumentRoutes; private logEndpoints; /** * Update live behavior with a typed key/path or an options object. Dotted paths * such as `operationAccess.basicRead` update one key; object assignment replaces * supplied top-level values shallowly. The construction-time options snapshot stays fixed. */ set & string, A extends ModelVirtualRecordAccess>(key: `virtuals.${K}.${A}`, value: ModelVirtualDescriptor | ModelVirtualGetter): this; set & string>(key: `virtuals.${K}`, value: ModelVirtualLeaf): this; set>(key: K, value: ExtendedModelRouterOptions[K]): this; set(options: ModelRouterOptions): this; /** Set one live option/path; `setOption('operationAccess.basicRead', undefined)` restores inheritance. */ setOption>(key: K, option: ExtendedModelRouterOptions[K]): this; /** Shallowly replace supplied top-level options; an operationAccess object replaces that entire rule object. */ setOptions(options: ModelRouterOptions): this; /** * The maximum limit of the number of documents returned from the `list` operation. */ listHardLimit: SetTargetOption, ModelRouterOptions['listHardLimit']>; /** * The object schema to define the access control policy for each model field. * Virtual permission keys (`fullAddress`, etc.) are typed via `TVirtuals`. * Basic/advanced route guards belong to operationAccess, not field-rule objects. */ permissionSchema: SetTargetOption, ModelRouterOptions['permissionSchema']>; /** * Package-level computed fields (VIRT-01, VIRT-00A D1-D8). * Mutable post-construction (not a build-time key). Supports * `virtuals({...})`, `virtuals(name, descriptor)`, and dotted * `set('virtuals..', descriptor)` forms. Exact → * `.default` → bare resolution applies; inapplicable registered names stay * virtual. Configuration is validated before commit against the receiving * Mongoose schema + child scopes, protected permission-field overlaps, * `_id`/reserved paths, and dotted names; rejected mutations preserve the * previous valid configuration. * * Reachable from the root (`@web-ts-toolkit/access-router`) and the * existing `./advanced` interface barrel; no new subpaths. Selected * virtual outputs are optional (`Partial`) because authorization, absent * dependencies, `undefined`, and fail-closed errors can omit them. * * @example Shortest typed happy-path (persisted model lacks `fullAddress`): * ```ts * import acl from '@web-ts-toolkit/access-router'; * interface User { name: string; address: string; } * interface UserVirtuals { fullAddress: string; } * const router = acl.createRouter('User', { * permissionSchema: { * name: { read: true }, * address: { read: 'canViewAddress' }, * fullAddress: { read: 'canViewAddress' }, * }, * virtuals: { * fullAddress: { * dependsOn: ['address'], * read: async function (doc) { * if (doc.address === undefined) return undefined; * return `addr:${doc.address}`; * }, * }, * }, * }); * router.virtuals({ * fullAddress: { * dependsOn: ['address'], * read: async function (doc) { * if (doc.address === undefined) return undefined; * return `addr:${doc.address}`; * }, * }, * }); * router.set('virtuals.fullAddress.read', { * get: async function (doc) { * if (doc.address === undefined) return undefined; * return `addr:${doc.address}`; * }, * dependsOn: ['address'], * }); * void router; * ``` */ virtuals: SetTargetOption, ModelRouterOptions['virtuals']>; /** * The object field to store the document permissions. */ documentPermissionField: SetTargetOption, ModelRouterOptions['documentPermissionField']>; /** * The model fields always selected for ACL and response shaping. */ alwaysSelectFields: SetTargetOption, ModelRouterOptions['alwaysSelectFields']>; /** * The function called in the process of generating document permissions. */ docPermissions: SetTargetOption, ModelRouterOptions['docPermissions']>; /** * Configure live base and basic/advanced route guards. Only undefined inherits; * selected false denies with HTTP 401 without removing routes or OpenAPI entries. * `operationAccess('basicRead', false)` updates one key, and * `operationAccess('subs.comments.basicRead', false)` updates a field-specific key. * `operationAccess({ list: true, read: true })` replaces the whole rule object, * not a deep merge. Use setOption with undefined to restore variant inheritance. */ operationAccess: SetTargetOption, ModelRouterOptions['operationAccess']>; /** * The base filter definitions applied in every query transaction. * @operation `list`, `read`, `update`, `delete` */ baseFilter: SetTargetOption, ModelRouterOptions['baseFilter']>; /** * Trusted filter replacements applied before base-filter composition. * They may replace ordinary filters, but cannot replace an existing `false` denial. * Returning `false` denies the transaction. * @operation `list`, `read`, `update`, `delete` */ overrideFilter: SetTargetOption, ModelRouterOptions['overrideFilter']>; /** * Hook * * The function called before a new/update document data is processed in `prepare` hooks. This method is used to validate `write data` and throw an error if not valid. * @operation `create`, `update` */ validate: SetTargetOption, ModelRouterOptions['validate']>; /** * Hook * * The function called before a new document is created or an existing document is updated. This method is used to process raw data passed into the API endpoints. * @operation `create`, `update` */ prepare: SetTargetOption, ModelRouterOptions['prepare']>; /** * Hook * * The function called before an updated document is saved. * @operation `update` */ transform: SetTargetOption, ModelRouterOptions['transform']>; /** * Hook * * The function called after a new document is created or an updated document is saved. * @operation `create`, `update` */ afterPersist: SetTargetOption, ModelRouterOptions['afterPersist']>; /** * Hook * * The function called after an updated document changes have been finalized. * @operation `update` */ onChange: SetTargetOption, ModelRouterOptions['onChange']>; /** * Hook * * The function called before a document is deleted. * @operation `delete` */ beforeDelete: SetTargetOption, ModelRouterOptions['beforeDelete']>; /** * Hook * * The function called after a document is deleted. * @operation `delete` */ afterDelete: SetTargetOption, ModelRouterOptions['afterDelete']>; /** * Hook * * The function called before response data is sent. This method is used to process raw data to apply custom logic before sending the result. * @operation `list`, `read`, `create`, `update` */ decorate: SetTargetOption, ModelRouterOptions['decorate']>; /** * Hook * * The functions are called before response data is sent and after `decorate` hooks run. This method is used to process and filter multiple document objects before sending the result. * @operation `list` */ decorateAll: SetTargetOption, ModelRouterOptions['decorateAll']>; /** * The field matched against the `id` route param. * @operation `read`, `update`, `delete` */ idField: SetTargetOption, ModelRouterOptions['idField']>; /** * The function used to resolve the `id` route param into a document filter. * @operation `read`, `update`, `delete` */ resolveIdFilter: SetTargetOption, ModelRouterOptions['resolveIdFilter']>; /** * The route segment used for advanced query endpoints. */ queryRouteSegment: SetTargetOption, ModelRouterOptions['queryRouteSegment']>; /** * The route segment used for advanced mutation endpoints. */ mutationRouteSegment: SetTargetOption, ModelRouterOptions['mutationRouteSegment']>; /** * The default values used when missing in the operations. */ defaults: SetTargetOption, ModelRouterOptions['defaults']>; get routes(): Router; } declare class RootRouter { readonly runtime: AccessRuntime; router: JsonRouter; basename: string; operationAccess: Validation; maxBatchEntries: number; maxOrderGroups: number; maxConcurrentOperations: number; private readonly modelOperations; private readonly dataOperations; constructor(options?: RootRouterOptions, runtime?: AccessRuntime); private registerOpenApiRoute; private wrapResult; private hasTarget; private isAllowed; private processOp; private groupItemsByOrder; private normalizePositiveLimit; private validateBatch; private runGroup; private assertAllowed; private setRoutes; get routes(): Router; } declare function createOpenApiRouter(runtime: AccessRuntime, options?: OpenApiRouterOptions): Router; declare class OpenApiRegistry { private readonly routes; private options; constructor(options?: OpenApiRegistryOptions); register(route: OpenApiRouteDescriptor): void; private assertOperationIdAvailable; getRoutes(): OpenApiRouteDescriptor[]; clear(): void; setStrictMode(enabled: boolean): void; getSpec(info: OpenApiDocumentOptions): { openapi: string; info: Omit; servers?: OpenApiDocumentOptions["servers"]; paths: Record; }; responses: OpenApiResponses; }>>; }; snapshot(): { routes: OpenApiRouteDescriptor[]; options: Required; }; restore(snapshot: { routes: OpenApiRouteDescriptor[]; options: Required; }): void; } type AccessRouterInstance = ModelRouter | DataRouter | RootRouter; type CombinedRouteInput = Router | AccessRouterInstance; declare function combineRoutes(...inputs: CombinedRouteInput[]): Router; declare class OpenApiCollisionError extends Error { readonly collisionKind: 'path' | 'operationId'; readonly method?: string; readonly path?: string; readonly operationId?: string; readonly existing?: unknown; readonly incoming?: unknown; constructor(message: string, details: { collisionKind: 'path' | 'operationId'; method?: string; path?: string; operationId?: string; existing?: unknown; incoming?: unknown; }); } declare const setGlobalOptions: (options: GlobalOptions) => void; declare const setGlobalOption: (key: K, value: GlobalOptions[K]) => void; declare const getGlobalOptions: () => GlobalOptions; declare const getGlobalOption: (key: K, defaultValue?: GlobalOptions[K]) => GlobalOptions[K]; declare const setModelOptions: >(modelName: string, options: ModelRouterOptions) => void; declare const setModelOption: , TModel = unknown, TVirtuals extends object = Record>(modelName: string, key: K, value: ExtendedModelRouterOptions[K]) => void; declare const getModelOptions: >(modelName: string) => ModelRouterOptions; declare const getModelOption: , TModel = unknown, TVirtuals extends object = Record>(modelName: string, key: K | string, defaultValue?: ExtendedModelRouterOptions[K]) => ExtendedModelRouterOptions[K]; declare const getModelNames: () => string[]; declare const getModelJsonSchema: (modelName: string) => Record; declare const registerModelInstance: (modelName: string, model: mongoose.Model) => void; declare const hasModelInstance: (modelName: string) => boolean; declare const getModelInstance: (modelName: string) => mongoose.Model | null; declare const setDefaultModelOptions: (options: DefaultModelRouterOptions) => void; declare const setDefaultModelOption: (key: K, value: ExtendedDefaultModelRouterOptions[K]) => void; declare const getDefaultModelOptions: () => DefaultModelRouterOptions; declare const getDefaultModelOption: (key: K, defaultValue?: ExtendedDefaultModelRouterOptions[K]) => ExtendedDefaultModelRouterOptions[K]; interface Options { virtualPermissionField?: string; modelName: string; } declare function permissionsPlugin(schema: Schema, options: Options): void; type LogLevel = 'debug' | 'info' | 'warn' | 'error'; declare const redactFilter: (filter: T) => T; declare const redactPayload: (payload: T) => T; declare const safeStringify: (value: unknown) => string; declare const isLevelEnabled: (level: LogLevel) => boolean; interface OpLogContext { op: string; modelName?: string; dataName?: string; populateCount?: number; selectCount?: number; page?: number; pageSize?: number; skip?: number; limit?: number; sort?: unknown; filterKeyValueCount?: number; startedAt?: number; durationMs?: number; resultCode?: string | number; } type CreateRouter = { >(model: mongoose.Model, options: ModelRouterOptions): ModelRouter; >(modelName: string, options: ModelRouterOptions): ModelRouter; (options: RootRouterOptions): RootRouter; }; type CreateDataRouter = { (dataName: string, options: DataRouterOptions): DataRouter; }; type CreateRuntimeOpenApiRouter = (options?: OpenApiRouterOptions) => Router; type WttSet = { (key: K, value: GlobalOptions[K]): void; (options: { [K in keyof GlobalOptions]: GlobalOptions[K]; }): void; }; interface Wtt { runtime: AccessRuntime; createRouter: CreateRouter; createDataRouter: CreateDataRouter; createOpenApiRouter: CreateRuntimeOpenApiRouter; combineRoutes: typeof combineRoutes; set: WttSet; setGlobalOptions: typeof setGlobalOptions; setGlobalOption: typeof setGlobalOption; getGlobalOptions: typeof getGlobalOptions; getGlobalOption: typeof getGlobalOption; setModelOptions: typeof setModelOptions; setModelOption: typeof setModelOption; getModelOptions: typeof getModelOptions; getModelOption: typeof getModelOption; getModelNames: typeof getModelNames; getModelJsonSchema: typeof getModelJsonSchema; setDefaultModelOptions: typeof setDefaultModelOptions; setDefaultModelOption: typeof setDefaultModelOption; getDefaultModelOptions: typeof getDefaultModelOptions; getDefaultModelOption: typeof getDefaultModelOption; registerModelInstance: (modelName: string, model: mongoose.Model) => void; hasModelInstance: (modelName: string) => boolean; getModelInstance: (modelName: string) => mongoose.Model | null; RootRouter: typeof RootRouter; ModelRouter: typeof ModelRouter; DataRouter: typeof DataRouter; } type AccessRuntimeApi = typeof macl & Wtt; declare function createAccessRuntime(): AccessRuntimeApi; declare const acl: AccessRuntimeApi; export { AccessRuntime, type AccessRuntimeApi, type CombinedRouteInput, DataRouter, DataRouterOptions, DefaultModelRouterOptions, ExtendedDataRouterOptions, ExtendedDefaultModelRouterOptions, ExtendedModelRouterOptions, GlobalOptions, GuardHook, type GuardModelCondition, type GuardModelConditionID, ModelRouter, ModelRouterOptions, ModelVirtualDescriptor, ModelVirtualGetter, ModelVirtualLeaf, ModelVirtualRecordAccess, type OpLogContext, OpenApiCollisionError, OpenApiDocumentOptions, OpenApiRegistry, OpenApiRegistryOptions, OpenApiRouteDescriptor, OpenApiRouterOptions, RootRouter, RootRouterOptions, Validation, acl, combineRoutes, createAccessRuntime, createOpenApiRouter, acl as default, getDefaultModelOption, getDefaultModelOptions, getGlobalOption, getGlobalOptions, getModelInstance, getModelJsonSchema, getModelNames, getModelOption, getModelOptions, guard, hasModelInstance, isLevelEnabled, permissionsPlugin, redactFilter, redactPayload, registerModelInstance, safeStringify, setDefaultModelOption, setDefaultModelOptions, setGlobalOption, setGlobalOptions, setModelOption, setModelOptions };