@web-ts-toolkit/access-router 0.45.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -110,6 +110,29 @@ filter before the base filter is applied, but it is not called for an existing `
110
110
  that denial. Returning `false` from `overrideFilter` also denies the query. Empty or absent filters retain their
111
111
  normal unrestricted meaning unless a base filter restricts them.
112
112
 
113
+ **Model service denial contract:** internal `findOne`/`find`/`updateOne`/`upsert`
114
+ `args.overrides.filter` and `findById`/`updateById` `args.overrides.idFilter` distinguish
115
+ `false` from omitted/`undefined`/`null`. False returns a `forbidden` ErrorResult without
116
+ fallback filter/identifier generation or persistence (including client subqueries).
117
+ Nullish overrides use normal generation. Trusted object filter overrides replace the
118
+ generated filter; object **idFilter** overrides replace identifier resolution but still
119
+ receive row policy. These service arguments are trusted application inputs.
120
+
121
+ `Service.exists(filter, { access: 'read', includeId: false })` returns a successful
122
+ boolean for allowed queries; `includeId: true` returns an `{ _id }` record or `null`.
123
+ Explicit/base/override terminal false now returns `forbidden` **before adapter dispatch**
124
+ in both modes, rather than a successful false/null. An allowed filter that matches no
125
+ visible row is still a successful miss. Check `result.success` before using `result.data`.
126
+
127
+ Public `_read` and `_readFilter` with `tryList: true` (the default) never retry Forbidden
128
+ or BadRequest. An authorized read miss can still fall back to list policy, subject to
129
+ list operation access. This deliberately removes list fallback for terminal read denial.
130
+ Public `_upsert` with an `_id` propagates denied update-policy existence as Forbidden
131
+ (previously Unauthorized); an allowed miss remains Unauthorized and neither case creates.
132
+ Generated direct routes map Forbidden to HTTP 403; root batches use per-entry 403 within
133
+ HTTP 200. **Custom Express routes own HTTP serialization:** returning an ErrorResult or
134
+ calling `res.json(result)` does not automatically set HTTP 403; map its code explicitly.
135
+
113
136
  Advanced mutation validators drive dispatch: nested `data` validators run first, then the whole-body (`default`)
114
137
  validator sees that transformed envelope, and the service persists only the final parsed `data`, `select`,
115
138
  `populate`, `tasks`, and allowed `options`. Missing body options fall back to `returning_all`/`include_permissions`
@@ -132,9 +155,62 @@ Root entrypoint (`@web-ts-toolkit/access-router`):
132
155
 
133
156
  Subpath entrypoints:
134
157
 
135
- - `@web-ts-toolkit/access-router/advanced` — low-level runtime context, symbols (`MIDDLEWARE`, `DATA_MIDDLEWARE`, `PERMISSIONS`, ...), enums (`Codes`, `StatusCodes`), internals (`parseBody`, `parseQuery`, `parseBodyWithSchema`, request schemas). Does NOT export `acl`, `defaultRuntime`, or router-creation helpers.
158
+ - `@web-ts-toolkit/access-router/advanced` — request/service/option interfaces and include wire types, symbols (`MIDDLEWARE`, `DATA_MIDDLEWARE`, `PERMISSIONS`, ...), enums (`Codes`, `StatusCodes`), and validation helpers (`parseBody`, `parseQuery`, `parseBodyWithSchema`, request schemas). Runtime-context functions are internal; use root exports such as `createAccessRuntime`, `AccessRuntime`, and `defaultRuntime` for runtime ownership. `/advanced` does not export runtime instances or router-creation helpers.
136
159
  - `@web-ts-toolkit/access-router/processors` — `copyAndDepopulate`, `copyPaths`, `movePaths`, `sliceArrays`, `countPaths`, `maskPaths` and processor option types (`ProcessCopy`, `CopyAndDepopulateOptions`, `CopyAndDepopulateOutput`, `ProcessorOptions`, `SliceProcessorOptions`, `ProcessSlice`, `ProcessCount`, `ProcessMask`, `ProcessorOutput`) for transforming populated documents.
137
160
 
161
+ ## AJV validation contract
162
+
163
+ Install `ajv` in your application when using `fromAjv`; it is not a mandatory
164
+ access-router runtime dependency. Import the helper and `AjvValidatorLike` type
165
+ from `@web-ts-toolkit/access-router`.
166
+
167
+ - Synchronous validators return boolean **verdicts**: true returns the input
168
+ (including any in-place AJV mutations), false returns normalized issues. Mutable
169
+ `validate.errors` are snapshotted before any suspension or next validation call.
170
+ - Validators tagged `$async: true` return promises/thenables of **validated data**.
171
+ Every fulfillment succeeds, including `false`, `true`, `null`, scalars and objects;
172
+ the fulfilled value is returned, not substituted with the input. Shared
173
+ `validate.errors` is never read on this path. Real AJV `ValidationError` rejections
174
+ (`ajv: true`, `validation: true`, an `errors` array) provide input-local diagnostics
175
+ under concurrency. Other exceptions propagate unchanged as operational failures.
176
+ - Untagged promises/thenables now reject with a configuration `TypeError`; their
177
+ rejections are observed to avoid unhandled rejection. Sync non-boolean results
178
+ also reject with `TypeError`.
179
+
180
+ <!-- doc-example: complete-runtime -->
181
+
182
+ ```ts
183
+ import { Ajv, type AsyncSchema } from 'ajv';
184
+ import { fromAjv } from '@web-ts-toolkit/access-router';
185
+
186
+ const ajv = new Ajv();
187
+ const sync = fromAjv<boolean>(ajv.compile<boolean>({ type: 'boolean' }));
188
+ const asyncSchema: AsyncSchema = { $async: true, type: 'boolean' };
189
+ const asyncData = fromAjv(ajv.compile<boolean>(asyncSchema));
190
+ const syncResult = await sync(false);
191
+ const asyncResult = await asyncData(false);
192
+ if (!syncResult.success || syncResult.data !== false || !asyncResult.success || asyncResult.data !== false) {
193
+ throw new Error('Both AJV validators must preserve valid false data');
194
+ }
195
+ ```
196
+
197
+ **Migration:** pass genuine compiled AJV sync/async validators directly, without
198
+ casts or wrappers that discard `$async`. `AjvValidatorLike<T>` now separates sync
199
+ boolean and tagged async data signatures; use a literal tag (`$async: true as const`)
200
+ for structural async adapters. An async boolean-verdict wrapper must instead return
201
+ the original validated data or reject with an AJV validation error; merely adding
202
+ the tag changes false/true into successful data. Alternatively implement a
203
+ `RequestSchemaValidator` returning `{ success, data }` / `{ success: false, issues }`.
204
+ Rejections with only an `errors` property are operational, not AJV validation errors.
205
+ AJV's overloaded `AsyncValidateFunction<T>` extends its sync `ValidateFunction<T>`;
206
+ TypeScript can erase the tag in that base type, so runtime checks remain necessary.
207
+ Genuine AJV sync/async output types are inferred via their type-guard overload;
208
+ structural async output is inferred from the promise. Use `fromAjv<T>(syncValidator)`
209
+ for a structural boolean validator without a type guard. An inline schema can select AJV's earlier
210
+ sync overload even with `$async: true`; an `AsyncSchema`-typed schema, as above,
211
+ selects its async overload without casts (also for `compileAsync`). Runtime
212
+ behavior follows the validator's actual tag in either case.
213
+
138
214
  ## Default runtime vs. isolated runtime
139
215
 
140
216
  The default export `acl` is bound to a single shared `AccessRuntime`, which is fine for most services.
@@ -202,6 +278,42 @@ Advanced read/list requests can attach related model data with `include` entries
202
278
  `op: 'count'` returns exact authorized counts and ignores include pagination fields such as `args.limit`.
203
279
  `op: 'list'` materializes authorized related rows through the target model's normal list path, so target `limit`, `page`, `pageSize`, and `listHardLimit` bounds still apply to included rows.
204
280
 
281
+ Legacy count joins use one grouped aggregate for all parents per include execution.
282
+ They count distinct target documents in the authorized count scope: duplicate local
283
+ keys, repeated foreign array entries, or one document matching multiple local keys
284
+ do not inflate a parent's count. No matches produce `0`.
285
+
286
+ The target Mongoose schema casts both the complete authorized filter (including
287
+ tenant filters) and foreign-key operands, including after array unwind. ObjectId/String
288
+ joins and query setters retain association to the original parent keys. Invalid
289
+ schema operands/filters produce controlled `BadRequest` (direct HTTP 400; root entry
290
+ `statusCode: 400`, `code: 'bad_request'`) rather than misleading zero counts. Count
291
+ operation denials still prevent target work; a terminal `false` count row policy
292
+ retains legacy omitted include output and a grouped-service Forbidden result.
293
+
294
+ This is query-schema/setter parity, not execution of `countDocuments` middleware or
295
+ plugins: casting is synchronous and performs no query. Aggregate middleware still
296
+ belongs to the aggregate operation. Express router count authorization through
297
+ `operationAccess` and row-filter hooks. Arbitrary pipelines passed to
298
+ `router.model.aggregate(...)` are not automatically cast.
299
+
300
+ ### Safe include output paths
301
+
302
+ Treat `path` as output only: put an invoice's related count at `lineItemCount`, for
303
+ example, rather than inside permission metadata. Legacy and correlated read/list/count
304
+ paths must not equal, descend from, or be an ancestor of the receiving model's
305
+ `documentPermissionField` (default `_permissions`). With `auth.policy.permissions`,
306
+ `auth`, `auth.policy`, and `auth.policy.permissions.canReadSecret` all reject;
307
+ `auth.policy.permissionsExtra` is an ordinary sibling. Equivalent legacy bracket
308
+ paths follow the same rule.
309
+
310
+ The include tree is preflighted before target persistence, including every supported
311
+ nested level using that receiving target's configuration. Overlaps return BadRequest
312
+ (direct HTTP 400; affected root entry 400/`bad_request` within its HTTP 200 batch
313
+ envelope), even if the relationship would be empty. Malformed reads do not retry
314
+ through list access. Ordinary output-field replacement remains supported; generated
315
+ include data cannot grant source-field permission.
316
+
205
317
  ## Correlated Includes
206
318
 
207
319
  Besides the legacy `localField`/`foreignField` joins, `include` entries accept
@@ -213,8 +325,17 @@ such as `$eq`/`$in`, `$in` array elements, `$and`/`$or`/`$nor` clauses,
213
325
  `$elemMatch` subtrees) and as the whole `id` of identifier reads. Plain
214
326
  strings are never references: `'$special'` keeps its literal query meaning.
215
327
  Match a literal `{ "$parent": "x" }` object with
216
- `{ "$escape": { "$parent": "x" } }` (use the `$eq`-wrapped form when the
217
- literal sits in a bare field position).
328
+ `{ "$escape": { "$parent": "x" } }`. In a bare field position,
329
+ `{ "note": { "$escape": { "$parent": "x" } } }` resolves to
330
+ `{ "note": { "$eq": { "$parent": "x" } } }`, just like bare substituted
331
+ parent objects. The explicit spelling
332
+ `{ "note": { "$eq": { "$escape": { "$parent": "x" } } } }` remains
333
+ equivalent. Operator operands and array elements receive the literal object
334
+ without another `$eq` wrapper. Escapes are resolved once and never read parent
335
+ data; missing, null or changed `parent.x` cannot change the literal. Malformed
336
+ escapes are rejected, and expanded operands still consume complexity budgets.
337
+ This bare-position correction requires an updated server; older servers with
338
+ the bare-escape defect still require the explicit `$eq` spelling.
218
339
 
219
340
  Wire shapes (the originating method fixes `op`; there is no override):
220
341
 
@@ -250,15 +371,16 @@ Semantics:
250
371
  become operators) and arrays are never flattened.
251
372
  - Each correlated entry counts toward `maxIncludeCount`; expanded filters
252
373
  are revalidated against `maxNodes`/`maxDepth`/`maxInValues`/
253
- `maxLogicalClauses`. Total inner executions per request are bounded by
374
+ `maxLogicalClauses`. Total inner executions per request/runtime are bounded by
254
375
  `maxCorrelatedQueries` (default `100`) and nesting by
255
376
  `maxCorrelatedDepth` (default `5`); exceeding any bound fails the whole
256
- request. Fan-out shares the request-scoped scheduler (no per-parent
257
- reset). Target authorization denials fail the whole request with zero
258
- target persistence queries; target runtime errors fail the whole request.
377
+ request/affected root entry. Fan-out shares request-and-runtime-owned
378
+ persistence admission (see below). Target authorization denials fail the
379
+ request/affected root entry with zero target persistence queries; target
380
+ runtime errors also fail that request/entry.
259
381
  `path` must be a non-empty valid field path (not `_id`, not `$`-prefixed);
260
382
  duplicates in one include array are `BadRequest`; collisions with parent
261
- fields overwrite (legacy `setDocValue` parity).
383
+ fields overwrite except for the permission-metadata overlaps described above.
262
384
  - Referenced parent fields are added to the parent DB select like legacy
263
385
  `localField`s, then trimmed unless allowed by field policy and selected.
264
386
  A policy-forbidden reference still resolves — only its query effects are
@@ -267,7 +389,7 @@ Semantics:
267
389
  attach to read/list parents only. Correlated entries are accepted in both
268
390
  direct (`model-router.ts`) and root (`root-router.ts`) validators with
269
391
  identical verdicts; malformed correlated input is a controlled
270
- `BadRequest`, never a silent drop. Legacy entries are unchanged, and
392
+ `BadRequest`, never a silent drop. Legacy entries also enforce safe output paths, and
271
393
  legacy-shaped entries carrying `$parent` markers are rejected.
272
394
 
273
395
  The TypeScript wire types (`ParentRef`, `CorrelatedInclude`, `Include`) are
@@ -275,6 +397,130 @@ reachable without deep imports via `@web-ts-toolkit/access-router/advanced`
275
397
  (which re-exports `./interfaces`). See the website `services`,
276
398
  `configuration`, `validation`, and `openapi` pages for the full contract.
277
399
 
400
+ ## Nested updates and trusted hooks
401
+
402
+ Partial updates follow **authorized policy paths**, not a generic deep merge. For a
403
+ customer profile editor, grant only the editable leaf and send nested JSON:
404
+
405
+ <!-- doc-example: partial -->
406
+
407
+ ```ts
408
+ import type { ModelRouterOptions } from '@web-ts-toolkit/access-router';
409
+
410
+ // Non-generic options accept dotted policy paths.
411
+ const options: ModelRouterOptions = {
412
+ operationAccess: { update: true },
413
+ permissionSchema: { 'profile.public': { update: true } },
414
+ };
415
+ const updateBody = { profile: { public: 'New display name' } };
416
+ // Pass options to acl.createRouter(CustomerModel, options); send updateBody to PATCH.
417
+ // Existing profile.secret and omitted siblings survive.
418
+ void [options, updateBody];
419
+ ```
420
+
421
+ This applies to `updateOne`, `updateById`, existing-row upsert, and single/bulk
422
+ subdocument updates, including Mongoose nested and single-nested schemas. Authorized
423
+ leaves can initialize missing/null containers. Authorizing `profile` itself instead
424
+ allows whole replacement and removes omitted children; whole grants take priority
425
+ over overlapping leaf grants. An authorized object leaf replaces just that leaf.
426
+ Arrays replace as a whole when authorized as a whole; an explicit `items.0.public`
427
+ grant patches that indexed leaf. Omitted fields remain unchanged, admitted `null`
428
+ clears the selected field, and authorized empty objects/arrays replace it (Mongoose
429
+ `minimize` may omit empty objects in storage). A null/empty/malformed client container
430
+ does not supply descendant leaves and cannot clear a protected parent. Casting and
431
+ validation still apply. Literal dotted/bracket client keys are ignored by field
432
+ selection; they are not `$set`/`$unset` instructions.
433
+
434
+ Model `prepare` and `transform` hooks are trusted application code. Validation sees
435
+ selected client data before prepare. Prepare output is not re-filtered: it can add
436
+ protected/server-only fields, including dotted Mongoose paths. At strict ancestors of
437
+ admitted paths, supplied children of plain-object/array prepare output are applied
438
+ while omitted siblings survive. Other prepare paths remain whole assignments.
439
+ An empty partial container or omitted parent does not delete siblings; explicit
440
+ `{ profile: null }` / `{ profile: undefined }` can clear/unset it. An entirely
441
+ null/undefined prepare result supplies no assignments.
442
+
443
+ For deliberate parent replacement, trusted `transform.update` can call
444
+ `doc.set('profile', replacement)`. Do not blindly reintroduce unfiltered
445
+ `context.originalData`. The update order remains validation → prepare →
446
+ assigned-document transform → save → afterPersist → changes; snapshots/diffs reflect
447
+ persisted changes. Subdocument operations retain their own lifecycle and do not gain
448
+ model prepare/transform hooks.
449
+
450
+ ## Subdocument writes with hidden responses
451
+
452
+ Appending an attachment or updating a line item can succeed without permission to
453
+ read it. After saving, mutation responses require the parent's read operation/row
454
+ access, checked against post-save state. Full-array **create** responses (including
455
+ POST `[]`) additionally require both `subs.<sub>.list` and `.read` operation guards
456
+ and row filters. **Single/bulk update** responses require subdocument read access
457
+ only and return readable mutation targets; they do not require list access.
458
+
459
+ All three use read-field projection plus `_id`. Counts reflect visible returned
460
+ rows, not stored/updated totals. Filtering preserves stored array order, including
461
+ service `addFirst` insertion order; bulk request order does not reorder the response.
462
+ `addFirst` remains a service option, not a new generated HTTP option.
463
+
464
+ When a response guard denies access, a row policy returns `false`, or no readable
465
+ parent/rows match, the committed write still succeeds:
466
+
467
+ | Operation | Service/root result fields | Direct HTTP body/status; root entry status |
468
+ | ------------- | ------------------------------------------------------------------ | ------------------------------------------ |
469
+ | Create | `success: true, kind: 'list', code: 'created', data: [], count: 0` | `[]`, 201; 201 |
470
+ | Bulk update | `success: true, kind: 'list', code: 'success', data: [], count: 0` | `[]`, 200; 200 |
471
+ | Single update | `success: true, kind: 'single', code: 'success', data: null` | JSON `null`, 200; 200 |
472
+
473
+ Root batches retain their HTTP 200 envelope. **Do not retry a successful write just
474
+ because its output is empty.** Actual write denials and validation/persistence failures
475
+ retain their errors. Response visibility needs at most one extra parent query and
476
+ resolves applicable row policies once per mutation, rather than once per returned row.
477
+
478
+ ## Persistence concurrency and resource limits
479
+
480
+ `requestComplexity.maxBulkConcurrency` (default `10`) bounds simultaneous awaited
481
+ **adapter/document persistence operations** for access-router model services sharing
482
+ one request and runtime. Direct service calls, root entries, subqueries, legacy
483
+ includes and nested correlated includes share admission. Different requests and
484
+ different runtimes have independent pools and correlated-query totals. Services
485
+ capture their owning runtime at construction; later ambient runtime changes do not
486
+ move their persistence to another pool.
487
+
488
+ Admission covers lazy adapter query settlement, document save/delete, and
489
+ service-triggered post-write populate. Bulk create submits one admitted singleton-array
490
+ adapter call per item, preserves result order, and still submits every item if one
491
+ rejects. Internal custom adapters must preserve array-in/array-out create semantics.
492
+ Their optional synchronous `castFilter` must cast a copy and preserve `$in` operand
493
+ order/cardinality; without it they retain identity casting.
494
+
495
+ Recursive orchestration holds no persistence permit while waiting for descendants,
496
+ so limit `1` supports nested includes. Internal map/run loops remain bounded per
497
+ invocation. `RootRouter.maxConcurrentOperations` separately bounds whole root
498
+ operations within each order group, with results in input-index order. Permits
499
+ release on success or error and pass FIFO to waiting work; release neither cancels
500
+ submitted siblings nor refunds the cumulative `maxCorrelatedQueries` budget (default
501
+ `100`). `maxCorrelatedDepth` (default `5`) separately bounds template nesting.
502
+
503
+ The ceiling is **not a MongoDB driver-command count**: one admitted operation can
504
+ run Mongoose middleware/populate that issues multiple commands. Router ACL, prepare,
505
+ afterPersist, decorate and recursive include orchestration are outside the permit;
506
+ Mongoose's own middleware runs inside the awaited operation. Direct database/network
507
+ calls from trusted hooks are not governed. This is neither a process-wide connection
508
+ pool limit nor a throughput guarantee. Controlled nested-query instrumentation reduced
509
+ peak active collection calls from 9 to 3 at limit 3 for the tested paths; it is not a
510
+ production benchmark or a guarantee about middleware/populate fan-out.
511
+
512
+ ### Compatibility notes
513
+
514
+ These boundary fixes preserve public entrypoints and require no new dependency or
515
+ option. Move computed include output away from permission metadata. Nested leaf edits
516
+ now preserve protected siblings; prepare hooks relying on omission to delete a parent
517
+ must replace it explicitly in transform. Handle successful null/empty subdocument
518
+ responses as completed writes. Legacy counts now cast schema values and report invalid
519
+ operands as BadRequest; they remain grouped and independent of list pagination.
520
+ Persistence admission is shared across nested work within each request/runtime, so
521
+ timing may change. It does not provide transactions, idempotency or optimistic
522
+ concurrency protection for competing edits.
523
+
278
524
  ## Import styles
279
525
 
280
526
  The package ships both a default export and named exports:
package/advanced.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AccessRouterBaseRequest, a as AccessRouterFieldKey, b as AccessRouterLogger, c as AccessRouterRequest, d as AccessRouterRequestExtensions, e as AdvancedCreateBody, f as AdvancedListBody, g as AdvancedReadBody, h as AdvancedReadFilterBody, i as AdvancedUpdateBody, j as AdvancedUpsertBody, k as AfterPersistAccess, l as AjvErrorObjectLike, m as AjvValidationErrorLike, n as AjvValidatorLike, o as ArkTypeErrorsLike, p as ArkTypeLike, q as ArkTypeProblemLike, B as BaseFilterAccess, C as Change, r as Codes, s as CorrelatedCountInclude, t as CorrelatedFilter, u as CorrelatedInclude, v as CorrelatedIncludeArgs, w as CorrelatedListInclude, x as CorrelatedReadByFilterInclude, y as CorrelatedReadByIdInclude, z as CountBody, D as CreateArgs, E as CreateOptions, F as CreateQueryInput, G as CustomHeaders, H as DATA_MIDDLEWARE, I as DataBaseFilterHook, J as DataFilter, K as DataFindArgs, L as DataFindOneArgs, M as DataFindOneOptions, N as DataFindOptions, O as DataHook, P as DataHookContext, Q as DataIdentifierHook, R as DataListHook, S as DataOverrideFilterHook, T as DataRequest, U as DataRequestSchemas, V as DataRouterOptions, W as DecorateAccess, X as DecorateAllAccess, Y as DeepFieldPath, Z as DefaultModelRouterOptions, _ as Defaults, $ as DistinctArgs, a0 as DistinctBody, a1 as DocPermissionsAccess, a2 as ErrorResult, a3 as ExistsOptions, a4 as ExtendedDataRouterOptions, a5 as ExtendedDefaultModelRouterOptions, a6 as ExtendedModelRouterOptions, a7 as Filter, a8 as FilterOperator, a9 as FindAccess, aa as FindArgs, ab as FindByIdArgs, ac as FindByIdOptions, ad as FindOneArgs, ae as FindOneOptions, af as FindOptions, ag as GlobalOptions, ah as GlobalPermissionValue, ai as GuardHook, aj as IdentifierHook, ak as Include, al as IoTsContextEntryLike, am as IoTsDecodeErrorLike, an as IoTsDecoderLike, ao as JoiSchemaLike, ap as JoiValidationErrorDetailLike, aq as KeyValueProjection, ar as LegacyInclude, as as ListQueryInput, at as ListResult, au as MIDDLEWARE, av as MaybePromise, aw as ModelBaseFilterHook, ax as ModelChangeHook, ay as ModelDeleteHook, az as ModelDocPermissionsHook, aA as ModelDocument, aB as ModelDocumentHook, aC as ModelHook, aD as ModelHookContext, aE as ModelIdentifierHook, aF as ModelListHook, aG as ModelOverrideFilterHook, aH as ModelRequest, aI as ModelRouterOptions, aJ as ModelValidateHook, aK as PERMISSIONS, aL as PERMISSION_KEYS, aM as ParentRef, aN as PathValue, aO as PermissionSchema, aP as Populate, aQ as PopulateAccess, aR as PrepareAccess, aS as Projection, aT as PublicCreateArgs, aU as PublicCreateOptions, aV as PublicErrorResult, aW as PublicListArgs, aX as PublicListOptions, aY as PublicListResult, aZ as PublicOutput, a_ as PublicReadArgs, a$ as PublicReadOptions, b0 as PublicServiceResult, b1 as PublicSingleResult, b2 as PublicUpdateArgs, b3 as PublicUpdateOptions, b4 as PublicUpsertArgs, b5 as PublicUpsertOptions, b6 as ReadQueryInput, b7 as Request, b8 as RequestSchemaAdapter, b9 as RequestSchemaFailure, ba as RequestSchemaIssue, bb as RequestSchemaLike, bc as RequestSchemaOptions, bd as RequestSchemaResult, be as RequestSchemaSuccess, bf as RequestSchemaValidator, bg as RequestSchemas, bh as RootDataListQueryEntry, bi as RootDataOperation, bj as RootDataReadByFilterQueryEntry, bk as RootDataReadByIdQueryEntry, bl as RootModelCountQueryEntry, bm as RootModelCreateQueryEntry, bn as RootModelDeleteQueryEntry, bo as RootModelDistinctQueryEntry, bp as RootModelListQueryEntry, bq as RootModelNewQueryEntry, br as RootModelOperation, bs as RootModelReadByFilterQueryEntry, bt as RootModelReadByIdQueryEntry, bu as RootModelSubBulkUpdateQueryEntry, bv as RootModelSubCreateQueryEntry, bw as RootModelSubDeleteQueryEntry, bx as RootModelSubListQueryEntry, by as RootModelSubReadQueryEntry, bz as RootModelSubUpdateQueryEntry, bA as RootModelUpdateQueryEntry, bB as RootModelUpsertQueryEntry, bC as RootOperationResult, bD as RootQueryEntry, bE as RootRouterOptions, bF as RootSubOperation, bG as RootTarget, bH as RouteGuardAccess, bI as SelectAccess, bJ as SelectedPopulatedPublicOutput, bK as SelectedPublicOutput, bL as ServiceResult, bM as SingleResult, bN as Sort, bO as SortOrder, bP as StandardSchemaFailure, bQ as StandardSchemaInferOutput, bR as StandardSchemaIssue, bS as StandardSchemaPathSegment, bT as StandardSchemaResult, bU as StandardSchemaSuccess, bV as StandardSchemaV1, bW as StatusCodes, bX as SubListBody, bY as SubPopulate, bZ as SubQueryEntry, b_ as SubReadBody, b$ as SubdocumentBulkRecord, c0 as SubdocumentBulkUpdateInput, c1 as SubdocumentCreateInput, c2 as SubdocumentCreateOptions, c3 as SubdocumentId, c4 as SubdocumentListOptions, c5 as SubdocumentName, c6 as SubdocumentParentArgs, c7 as SubdocumentParentOptions, c8 as SubdocumentReadOptions, c9 as SubdocumentRecord, ca as SuperstructFailureLike, cb as SuperstructValidateLike, cc as Task, cd as TaskType, ce as TransformAccess, cf as TypedFilter, cg as UpdateByIdArgs, ch as UpdateByIdOptions, ci as UpdateOneArgs, cj as UpdateOneOptions, ck as UpdateQueryInput, cl as UpsertArgs, cm as UpsertOptions, cn as UpsertQueryInput, co as ValibotIssueLike, cp as ValibotPathItemLike, cq as ValibotSafeParseLike, cr as ValibotSafeParseResult, cs as ValidateAccess, ct as ValidateRule, cu as Validation, cv as ValidationError, cw as VineValidationErrorLike, cx as VineValidationMessageLike, cy as VineValidatorLike, cz as YupSchemaLike, cA as YupValidationErrorLike, cB as defineRequestSchema, cC as fromAjv, cD as fromArkType, cE as fromIoTs, cF as fromJoi, cG as fromStandardSchema, cH as fromSuperstruct, cI as fromValibot, cJ as fromVine, cK as fromYup, cL as fromZod, cM as parseBody, cN as parseBodyWithSchema, cO as parseNestedBodyWithSchema, cP as parsePathParam, cQ as parseQuery } from './parsers-DppKW-Fd.mjs';
1
+ export { A as AccessRouterBaseRequest, a as AccessRouterFieldKey, b as AccessRouterLogger, c as AccessRouterRequest, d as AccessRouterRequestExtensions, e as AdvancedCreateBody, f as AdvancedListBody, g as AdvancedReadBody, h as AdvancedReadFilterBody, i as AdvancedUpdateBody, j as AdvancedUpsertBody, k as AfterPersistAccess, l as AjvErrorObjectLike, m as AjvValidationErrorLike, n as AjvValidatorLike, o as ArkTypeErrorsLike, p as ArkTypeLike, q as ArkTypeProblemLike, B as BaseFilterAccess, C as Change, r as Codes, s as CorrelatedCountInclude, t as CorrelatedFilter, u as CorrelatedInclude, v as CorrelatedIncludeArgs, w as CorrelatedListInclude, x as CorrelatedReadByFilterInclude, y as CorrelatedReadByIdInclude, z as CountBody, D as CreateArgs, E as CreateOptions, F as CreateQueryInput, G as CustomHeaders, H as DATA_MIDDLEWARE, I as DataBaseFilterHook, J as DataFilter, K as DataFindArgs, L as DataFindOneArgs, M as DataFindOneOptions, N as DataFindOptions, O as DataHook, P as DataHookContext, Q as DataIdentifierHook, R as DataListHook, S as DataOverrideFilterHook, T as DataRequest, U as DataRequestSchemas, V as DataRouterOptions, W as DecorateAccess, X as DecorateAllAccess, Y as DeepFieldPath, Z as DefaultModelRouterOptions, _ as Defaults, $ as DistinctArgs, a0 as DistinctBody, a1 as DocPermissionsAccess, a2 as ErrorResult, a3 as ExistsOptions, a4 as ExtendedDataRouterOptions, a5 as ExtendedDefaultModelRouterOptions, a6 as ExtendedModelRouterOptions, a7 as Filter, a8 as FilterOperator, a9 as FindAccess, aa as FindArgs, ab as FindByIdArgs, ac as FindByIdOptions, ad as FindOneArgs, ae as FindOneOptions, af as FindOptions, ag as GlobalOptions, ah as GlobalPermissionValue, ai as GuardHook, aj as IdentifierHook, ak as Include, al as IoTsContextEntryLike, am as IoTsDecodeErrorLike, an as IoTsDecoderLike, ao as JoiSchemaLike, ap as JoiValidationErrorDetailLike, aq as KeyValueProjection, ar as LegacyInclude, as as ListQueryInput, at as ListResult, au as MIDDLEWARE, av as MaybePromise, aw as ModelBaseFilterHook, ax as ModelChangeHook, ay as ModelDeleteHook, az as ModelDocPermissionsHook, aA as ModelDocument, aB as ModelDocumentHook, aC as ModelHook, aD as ModelHookContext, aE as ModelIdentifierHook, aF as ModelListHook, aG as ModelOverrideFilterHook, aH as ModelRequest, aI as ModelRouterOptions, aJ as ModelValidateHook, aK as PERMISSIONS, aL as PERMISSION_KEYS, aM as ParentRef, aN as PathValue, aO as PermissionSchema, aP as Populate, aQ as PopulateAccess, aR as PrepareAccess, aS as Projection, aT as PublicCreateArgs, aU as PublicCreateOptions, aV as PublicErrorResult, aW as PublicListArgs, aX as PublicListOptions, aY as PublicListResult, aZ as PublicOutput, a_ as PublicReadArgs, a$ as PublicReadOptions, b0 as PublicServiceResult, b1 as PublicSingleResult, b2 as PublicUpdateArgs, b3 as PublicUpdateOptions, b4 as PublicUpsertArgs, b5 as PublicUpsertOptions, b6 as ReadQueryInput, b7 as Request, b8 as RequestSchemaAdapter, b9 as RequestSchemaFailure, ba as RequestSchemaIssue, bb as RequestSchemaLike, bc as RequestSchemaOptions, bd as RequestSchemaResult, be as RequestSchemaSuccess, bf as RequestSchemaValidator, bg as RequestSchemas, bh as RootDataListQueryEntry, bi as RootDataOperation, bj as RootDataReadByFilterQueryEntry, bk as RootDataReadByIdQueryEntry, bl as RootModelCountQueryEntry, bm as RootModelCreateQueryEntry, bn as RootModelDeleteQueryEntry, bo as RootModelDistinctQueryEntry, bp as RootModelListQueryEntry, bq as RootModelNewQueryEntry, br as RootModelOperation, bs as RootModelReadByFilterQueryEntry, bt as RootModelReadByIdQueryEntry, bu as RootModelSubBulkUpdateQueryEntry, bv as RootModelSubCreateQueryEntry, bw as RootModelSubDeleteQueryEntry, bx as RootModelSubListQueryEntry, by as RootModelSubReadQueryEntry, bz as RootModelSubUpdateQueryEntry, bA as RootModelUpdateQueryEntry, bB as RootModelUpsertQueryEntry, bC as RootOperationResult, bD as RootQueryEntry, bE as RootRouterOptions, bF as RootSubOperation, bG as RootTarget, bH as RouteGuardAccess, bI as SelectAccess, bJ as SelectedPopulatedPublicOutput, bK as SelectedPublicOutput, bL as ServiceResult, bM as SingleResult, bN as Sort, bO as SortOrder, bP as StandardSchemaFailure, bQ as StandardSchemaInferOutput, bR as StandardSchemaIssue, bS as StandardSchemaPathSegment, bT as StandardSchemaResult, bU as StandardSchemaSuccess, bV as StandardSchemaV1, bW as StatusCodes, bX as SubListBody, bY as SubPopulate, bZ as SubQueryEntry, b_ as SubReadBody, b$ as SubdocumentBulkRecord, c0 as SubdocumentBulkUpdateInput, c1 as SubdocumentCreateInput, c2 as SubdocumentCreateOptions, c3 as SubdocumentId, c4 as SubdocumentListOptions, c5 as SubdocumentName, c6 as SubdocumentParentArgs, c7 as SubdocumentParentOptions, c8 as SubdocumentReadOptions, c9 as SubdocumentRecord, ca as SuperstructFailureLike, cb as SuperstructValidateLike, cc as Task, cd as TaskType, ce as TransformAccess, cf as TypedFilter, cg as UpdateByIdArgs, ch as UpdateByIdOptions, ci as UpdateOneArgs, cj as UpdateOneOptions, ck as UpdateQueryInput, cl as UpsertArgs, cm as UpsertOptions, cn as UpsertQueryInput, co as ValibotIssueLike, cp as ValibotPathItemLike, cq as ValibotSafeParseLike, cr as ValibotSafeParseResult, cs as ValidateAccess, ct as ValidateRule, cu as Validation, cv as ValidationError, cw as VineValidationErrorLike, cx as VineValidationMessageLike, cy as VineValidatorLike, cz as YupSchemaLike, cA as YupValidationErrorLike, cB as defineRequestSchema, cC as fromAjv, cD as fromArkType, cE as fromIoTs, cF as fromJoi, cG as fromStandardSchema, cH as fromSuperstruct, cI as fromValibot, cJ as fromVine, cK as fromYup, cL as fromZod, cM as parseBody, cN as parseBodyWithSchema, cO as parseNestedBodyWithSchema, cP as parsePathParam, cQ as parseQuery } from './parsers-BidvJUu7.mjs';
2
2
  import { z } from 'zod';
3
3
  import 'mongoose';
4
4
  import 'express';
package/advanced.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AccessRouterBaseRequest, a as AccessRouterFieldKey, b as AccessRouterLogger, c as AccessRouterRequest, d as AccessRouterRequestExtensions, e as AdvancedCreateBody, f as AdvancedListBody, g as AdvancedReadBody, h as AdvancedReadFilterBody, i as AdvancedUpdateBody, j as AdvancedUpsertBody, k as AfterPersistAccess, l as AjvErrorObjectLike, m as AjvValidationErrorLike, n as AjvValidatorLike, o as ArkTypeErrorsLike, p as ArkTypeLike, q as ArkTypeProblemLike, B as BaseFilterAccess, C as Change, r as Codes, s as CorrelatedCountInclude, t as CorrelatedFilter, u as CorrelatedInclude, v as CorrelatedIncludeArgs, w as CorrelatedListInclude, x as CorrelatedReadByFilterInclude, y as CorrelatedReadByIdInclude, z as CountBody, D as CreateArgs, E as CreateOptions, F as CreateQueryInput, G as CustomHeaders, H as DATA_MIDDLEWARE, I as DataBaseFilterHook, J as DataFilter, K as DataFindArgs, L as DataFindOneArgs, M as DataFindOneOptions, N as DataFindOptions, O as DataHook, P as DataHookContext, Q as DataIdentifierHook, R as DataListHook, S as DataOverrideFilterHook, T as DataRequest, U as DataRequestSchemas, V as DataRouterOptions, W as DecorateAccess, X as DecorateAllAccess, Y as DeepFieldPath, Z as DefaultModelRouterOptions, _ as Defaults, $ as DistinctArgs, a0 as DistinctBody, a1 as DocPermissionsAccess, a2 as ErrorResult, a3 as ExistsOptions, a4 as ExtendedDataRouterOptions, a5 as ExtendedDefaultModelRouterOptions, a6 as ExtendedModelRouterOptions, a7 as Filter, a8 as FilterOperator, a9 as FindAccess, aa as FindArgs, ab as FindByIdArgs, ac as FindByIdOptions, ad as FindOneArgs, ae as FindOneOptions, af as FindOptions, ag as GlobalOptions, ah as GlobalPermissionValue, ai as GuardHook, aj as IdentifierHook, ak as Include, al as IoTsContextEntryLike, am as IoTsDecodeErrorLike, an as IoTsDecoderLike, ao as JoiSchemaLike, ap as JoiValidationErrorDetailLike, aq as KeyValueProjection, ar as LegacyInclude, as as ListQueryInput, at as ListResult, au as MIDDLEWARE, av as MaybePromise, aw as ModelBaseFilterHook, ax as ModelChangeHook, ay as ModelDeleteHook, az as ModelDocPermissionsHook, aA as ModelDocument, aB as ModelDocumentHook, aC as ModelHook, aD as ModelHookContext, aE as ModelIdentifierHook, aF as ModelListHook, aG as ModelOverrideFilterHook, aH as ModelRequest, aI as ModelRouterOptions, aJ as ModelValidateHook, aK as PERMISSIONS, aL as PERMISSION_KEYS, aM as ParentRef, aN as PathValue, aO as PermissionSchema, aP as Populate, aQ as PopulateAccess, aR as PrepareAccess, aS as Projection, aT as PublicCreateArgs, aU as PublicCreateOptions, aV as PublicErrorResult, aW as PublicListArgs, aX as PublicListOptions, aY as PublicListResult, aZ as PublicOutput, a_ as PublicReadArgs, a$ as PublicReadOptions, b0 as PublicServiceResult, b1 as PublicSingleResult, b2 as PublicUpdateArgs, b3 as PublicUpdateOptions, b4 as PublicUpsertArgs, b5 as PublicUpsertOptions, b6 as ReadQueryInput, b7 as Request, b8 as RequestSchemaAdapter, b9 as RequestSchemaFailure, ba as RequestSchemaIssue, bb as RequestSchemaLike, bc as RequestSchemaOptions, bd as RequestSchemaResult, be as RequestSchemaSuccess, bf as RequestSchemaValidator, bg as RequestSchemas, bh as RootDataListQueryEntry, bi as RootDataOperation, bj as RootDataReadByFilterQueryEntry, bk as RootDataReadByIdQueryEntry, bl as RootModelCountQueryEntry, bm as RootModelCreateQueryEntry, bn as RootModelDeleteQueryEntry, bo as RootModelDistinctQueryEntry, bp as RootModelListQueryEntry, bq as RootModelNewQueryEntry, br as RootModelOperation, bs as RootModelReadByFilterQueryEntry, bt as RootModelReadByIdQueryEntry, bu as RootModelSubBulkUpdateQueryEntry, bv as RootModelSubCreateQueryEntry, bw as RootModelSubDeleteQueryEntry, bx as RootModelSubListQueryEntry, by as RootModelSubReadQueryEntry, bz as RootModelSubUpdateQueryEntry, bA as RootModelUpdateQueryEntry, bB as RootModelUpsertQueryEntry, bC as RootOperationResult, bD as RootQueryEntry, bE as RootRouterOptions, bF as RootSubOperation, bG as RootTarget, bH as RouteGuardAccess, bI as SelectAccess, bJ as SelectedPopulatedPublicOutput, bK as SelectedPublicOutput, bL as ServiceResult, bM as SingleResult, bN as Sort, bO as SortOrder, bP as StandardSchemaFailure, bQ as StandardSchemaInferOutput, bR as StandardSchemaIssue, bS as StandardSchemaPathSegment, bT as StandardSchemaResult, bU as StandardSchemaSuccess, bV as StandardSchemaV1, bW as StatusCodes, bX as SubListBody, bY as SubPopulate, bZ as SubQueryEntry, b_ as SubReadBody, b$ as SubdocumentBulkRecord, c0 as SubdocumentBulkUpdateInput, c1 as SubdocumentCreateInput, c2 as SubdocumentCreateOptions, c3 as SubdocumentId, c4 as SubdocumentListOptions, c5 as SubdocumentName, c6 as SubdocumentParentArgs, c7 as SubdocumentParentOptions, c8 as SubdocumentReadOptions, c9 as SubdocumentRecord, ca as SuperstructFailureLike, cb as SuperstructValidateLike, cc as Task, cd as TaskType, ce as TransformAccess, cf as TypedFilter, cg as UpdateByIdArgs, ch as UpdateByIdOptions, ci as UpdateOneArgs, cj as UpdateOneOptions, ck as UpdateQueryInput, cl as UpsertArgs, cm as UpsertOptions, cn as UpsertQueryInput, co as ValibotIssueLike, cp as ValibotPathItemLike, cq as ValibotSafeParseLike, cr as ValibotSafeParseResult, cs as ValidateAccess, ct as ValidateRule, cu as Validation, cv as ValidationError, cw as VineValidationErrorLike, cx as VineValidationMessageLike, cy as VineValidatorLike, cz as YupSchemaLike, cA as YupValidationErrorLike, cB as defineRequestSchema, cC as fromAjv, cD as fromArkType, cE as fromIoTs, cF as fromJoi, cG as fromStandardSchema, cH as fromSuperstruct, cI as fromValibot, cJ as fromVine, cK as fromYup, cL as fromZod, cM as parseBody, cN as parseBodyWithSchema, cO as parseNestedBodyWithSchema, cP as parsePathParam, cQ as parseQuery } from './parsers-DppKW-Fd.js';
1
+ export { A as AccessRouterBaseRequest, a as AccessRouterFieldKey, b as AccessRouterLogger, c as AccessRouterRequest, d as AccessRouterRequestExtensions, e as AdvancedCreateBody, f as AdvancedListBody, g as AdvancedReadBody, h as AdvancedReadFilterBody, i as AdvancedUpdateBody, j as AdvancedUpsertBody, k as AfterPersistAccess, l as AjvErrorObjectLike, m as AjvValidationErrorLike, n as AjvValidatorLike, o as ArkTypeErrorsLike, p as ArkTypeLike, q as ArkTypeProblemLike, B as BaseFilterAccess, C as Change, r as Codes, s as CorrelatedCountInclude, t as CorrelatedFilter, u as CorrelatedInclude, v as CorrelatedIncludeArgs, w as CorrelatedListInclude, x as CorrelatedReadByFilterInclude, y as CorrelatedReadByIdInclude, z as CountBody, D as CreateArgs, E as CreateOptions, F as CreateQueryInput, G as CustomHeaders, H as DATA_MIDDLEWARE, I as DataBaseFilterHook, J as DataFilter, K as DataFindArgs, L as DataFindOneArgs, M as DataFindOneOptions, N as DataFindOptions, O as DataHook, P as DataHookContext, Q as DataIdentifierHook, R as DataListHook, S as DataOverrideFilterHook, T as DataRequest, U as DataRequestSchemas, V as DataRouterOptions, W as DecorateAccess, X as DecorateAllAccess, Y as DeepFieldPath, Z as DefaultModelRouterOptions, _ as Defaults, $ as DistinctArgs, a0 as DistinctBody, a1 as DocPermissionsAccess, a2 as ErrorResult, a3 as ExistsOptions, a4 as ExtendedDataRouterOptions, a5 as ExtendedDefaultModelRouterOptions, a6 as ExtendedModelRouterOptions, a7 as Filter, a8 as FilterOperator, a9 as FindAccess, aa as FindArgs, ab as FindByIdArgs, ac as FindByIdOptions, ad as FindOneArgs, ae as FindOneOptions, af as FindOptions, ag as GlobalOptions, ah as GlobalPermissionValue, ai as GuardHook, aj as IdentifierHook, ak as Include, al as IoTsContextEntryLike, am as IoTsDecodeErrorLike, an as IoTsDecoderLike, ao as JoiSchemaLike, ap as JoiValidationErrorDetailLike, aq as KeyValueProjection, ar as LegacyInclude, as as ListQueryInput, at as ListResult, au as MIDDLEWARE, av as MaybePromise, aw as ModelBaseFilterHook, ax as ModelChangeHook, ay as ModelDeleteHook, az as ModelDocPermissionsHook, aA as ModelDocument, aB as ModelDocumentHook, aC as ModelHook, aD as ModelHookContext, aE as ModelIdentifierHook, aF as ModelListHook, aG as ModelOverrideFilterHook, aH as ModelRequest, aI as ModelRouterOptions, aJ as ModelValidateHook, aK as PERMISSIONS, aL as PERMISSION_KEYS, aM as ParentRef, aN as PathValue, aO as PermissionSchema, aP as Populate, aQ as PopulateAccess, aR as PrepareAccess, aS as Projection, aT as PublicCreateArgs, aU as PublicCreateOptions, aV as PublicErrorResult, aW as PublicListArgs, aX as PublicListOptions, aY as PublicListResult, aZ as PublicOutput, a_ as PublicReadArgs, a$ as PublicReadOptions, b0 as PublicServiceResult, b1 as PublicSingleResult, b2 as PublicUpdateArgs, b3 as PublicUpdateOptions, b4 as PublicUpsertArgs, b5 as PublicUpsertOptions, b6 as ReadQueryInput, b7 as Request, b8 as RequestSchemaAdapter, b9 as RequestSchemaFailure, ba as RequestSchemaIssue, bb as RequestSchemaLike, bc as RequestSchemaOptions, bd as RequestSchemaResult, be as RequestSchemaSuccess, bf as RequestSchemaValidator, bg as RequestSchemas, bh as RootDataListQueryEntry, bi as RootDataOperation, bj as RootDataReadByFilterQueryEntry, bk as RootDataReadByIdQueryEntry, bl as RootModelCountQueryEntry, bm as RootModelCreateQueryEntry, bn as RootModelDeleteQueryEntry, bo as RootModelDistinctQueryEntry, bp as RootModelListQueryEntry, bq as RootModelNewQueryEntry, br as RootModelOperation, bs as RootModelReadByFilterQueryEntry, bt as RootModelReadByIdQueryEntry, bu as RootModelSubBulkUpdateQueryEntry, bv as RootModelSubCreateQueryEntry, bw as RootModelSubDeleteQueryEntry, bx as RootModelSubListQueryEntry, by as RootModelSubReadQueryEntry, bz as RootModelSubUpdateQueryEntry, bA as RootModelUpdateQueryEntry, bB as RootModelUpsertQueryEntry, bC as RootOperationResult, bD as RootQueryEntry, bE as RootRouterOptions, bF as RootSubOperation, bG as RootTarget, bH as RouteGuardAccess, bI as SelectAccess, bJ as SelectedPopulatedPublicOutput, bK as SelectedPublicOutput, bL as ServiceResult, bM as SingleResult, bN as Sort, bO as SortOrder, bP as StandardSchemaFailure, bQ as StandardSchemaInferOutput, bR as StandardSchemaIssue, bS as StandardSchemaPathSegment, bT as StandardSchemaResult, bU as StandardSchemaSuccess, bV as StandardSchemaV1, bW as StatusCodes, bX as SubListBody, bY as SubPopulate, bZ as SubQueryEntry, b_ as SubReadBody, b$ as SubdocumentBulkRecord, c0 as SubdocumentBulkUpdateInput, c1 as SubdocumentCreateInput, c2 as SubdocumentCreateOptions, c3 as SubdocumentId, c4 as SubdocumentListOptions, c5 as SubdocumentName, c6 as SubdocumentParentArgs, c7 as SubdocumentParentOptions, c8 as SubdocumentReadOptions, c9 as SubdocumentRecord, ca as SuperstructFailureLike, cb as SuperstructValidateLike, cc as Task, cd as TaskType, ce as TransformAccess, cf as TypedFilter, cg as UpdateByIdArgs, ch as UpdateByIdOptions, ci as UpdateOneArgs, cj as UpdateOneOptions, ck as UpdateQueryInput, cl as UpsertArgs, cm as UpsertOptions, cn as UpsertQueryInput, co as ValibotIssueLike, cp as ValibotPathItemLike, cq as ValibotSafeParseLike, cr as ValibotSafeParseResult, cs as ValidateAccess, ct as ValidateRule, cu as Validation, cv as ValidationError, cw as VineValidationErrorLike, cx as VineValidationMessageLike, cy as VineValidatorLike, cz as YupSchemaLike, cA as YupValidationErrorLike, cB as defineRequestSchema, cC as fromAjv, cD as fromArkType, cE as fromIoTs, cF as fromJoi, cG as fromStandardSchema, cH as fromSuperstruct, cI as fromValibot, cJ as fromVine, cK as fromYup, cL as fromZod, cM as parseBody, cN as parseBodyWithSchema, cO as parseNestedBodyWithSchema, cP as parsePathParam, cQ as parseQuery } from './parsers-BidvJUu7.js';
2
2
  import { z } from 'zod';
3
3
  import 'mongoose';
4
4
  import 'express';
package/advanced.js CHANGED
@@ -944,6 +944,7 @@ var AccessRuntime = class {
944
944
  this.modelAtts = {};
945
945
  this.modelInstances = {};
946
946
  this.openApiRegistry = new OpenApiRegistry();
947
+ this.openApiPathPrefix = "";
947
948
  this.allowGlobalModelLookup = options.allowGlobalModelLookup ?? false;
948
949
  ensureMongooseJsonSchemaInitialized();
949
950
  }
@@ -972,7 +973,24 @@ var AccessRuntime = class {
972
973
  return global;
973
974
  }
974
975
  registerOpenApiRoute(route) {
975
- this.openApiRegistry.register(route);
976
+ this.openApiRegistry.register(
977
+ this.openApiPathPrefix ? { ...route, path: (0, import_utils8.normalizeUrlPath)(`${this.openApiPathPrefix}/${route.path}`) } : route
978
+ );
979
+ }
980
+ /**
981
+ * Compose OpenAPI paths while synchronously constructing mounted routers.
982
+ * Prefixes apply before collision checks; prior descriptors and Express paths
983
+ * are unchanged. Nested calls compose and the prior scope is restored even on
984
+ * failure. The callback must finish registration synchronously (no async work).
985
+ */
986
+ withOpenApiPathPrefix(prefix, build) {
987
+ const previous = this.openApiPathPrefix;
988
+ this.openApiPathPrefix = (0, import_utils8.normalizeUrlPath)(`${previous}/${prefix}`);
989
+ try {
990
+ return build();
991
+ } finally {
992
+ this.openApiPathPrefix = previous;
993
+ }
976
994
  }
977
995
  /**
978
996
  * Enable strict OpenAPI collision detection for the remainder of this
@@ -1814,19 +1832,12 @@ function fromJoi(schema) {
1814
1832
  }
1815
1833
  function fromAjv(validator) {
1816
1834
  return async (value) => {
1817
- const outcome = validator(value);
1818
- if (isThenable(outcome)) {
1835
+ if (validator.$async === true) {
1819
1836
  try {
1820
- const data = await outcome;
1821
- if (data === false) {
1822
- return {
1823
- success: false,
1824
- issues: normalizeAjvIssues(validator.errors ?? [])
1825
- };
1826
- }
1837
+ const data = await validator(value);
1827
1838
  return {
1828
1839
  success: true,
1829
- data: data === true ? value : data
1840
+ data
1830
1841
  };
1831
1842
  } catch (error) {
1832
1843
  if (!isAjvValidationError(error)) {
@@ -1834,11 +1845,21 @@ function fromAjv(validator) {
1834
1845
  }
1835
1846
  return {
1836
1847
  success: false,
1837
- issues: normalizeAjvIssues(error.errors ?? [])
1848
+ issues: normalizeAjvIssues(error.errors)
1838
1849
  };
1839
1850
  }
1840
1851
  }
1841
- const errorsSnapshot = validator.errors ? [...validator.errors] : [];
1852
+ const outcome = validator(value);
1853
+ if (isThenable(outcome)) {
1854
+ void Promise.resolve(outcome).catch(() => {
1855
+ });
1856
+ throw new TypeError(
1857
+ "fromAjv: promise/thenable validators must declare $async: true and resolve with validated data"
1858
+ );
1859
+ }
1860
+ if (typeof outcome !== "boolean") {
1861
+ throw new TypeError("fromAjv: synchronous validators must return a boolean verdict");
1862
+ }
1842
1863
  if (outcome) {
1843
1864
  return {
1844
1865
  success: true,
@@ -1847,7 +1868,9 @@ function fromAjv(validator) {
1847
1868
  }
1848
1869
  return {
1849
1870
  success: false,
1850
- issues: normalizeAjvIssues(errorsSnapshot)
1871
+ // Normalize immediately, copying message/path before another call can
1872
+ // replace the errors array or mutate its entries.
1873
+ issues: normalizeAjvIssues(validator.errors ?? [])
1851
1874
  };
1852
1875
  };
1853
1876
  }
@@ -2077,14 +2100,14 @@ function isArkTypeErrors(value) {
2077
2100
  return record.arkKind === "errors" || record[" arkKind"] === "errors";
2078
2101
  }
2079
2102
  function isThenable(value) {
2080
- return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
2103
+ return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
2081
2104
  }
2082
2105
  function isAjvValidationError(error) {
2083
2106
  if (typeof error !== "object" || error === null || !("errors" in error)) {
2084
2107
  return false;
2085
2108
  }
2086
- const errors = error.errors;
2087
- return errors == null || Array.isArray(errors);
2109
+ const candidate = error;
2110
+ return candidate.ajv === true && candidate.validation === true && Array.isArray(candidate.errors);
2088
2111
  }
2089
2112
  function isVineValidationError(error) {
2090
2113
  if (typeof error !== "object" || error === null || !("messages" in error)) {
package/advanced.mjs CHANGED
@@ -56,7 +56,8 @@ import {
56
56
  isNil as isNil2,
57
57
  isPlainObject as isPlainObject9,
58
58
  isString as isString3,
59
- keys
59
+ keys,
60
+ normalizeUrlPath
60
61
  } from "@web-ts-toolkit/utils";
61
62
 
62
63
  // src/helpers/query.ts
@@ -873,6 +874,7 @@ var AccessRuntime = class {
873
874
  this.modelAtts = {};
874
875
  this.modelInstances = {};
875
876
  this.openApiRegistry = new OpenApiRegistry();
877
+ this.openApiPathPrefix = "";
876
878
  this.allowGlobalModelLookup = options.allowGlobalModelLookup ?? false;
877
879
  ensureMongooseJsonSchemaInitialized();
878
880
  }
@@ -901,7 +903,24 @@ var AccessRuntime = class {
901
903
  return global;
902
904
  }
903
905
  registerOpenApiRoute(route) {
904
- this.openApiRegistry.register(route);
906
+ this.openApiRegistry.register(
907
+ this.openApiPathPrefix ? { ...route, path: normalizeUrlPath(`${this.openApiPathPrefix}/${route.path}`) } : route
908
+ );
909
+ }
910
+ /**
911
+ * Compose OpenAPI paths while synchronously constructing mounted routers.
912
+ * Prefixes apply before collision checks; prior descriptors and Express paths
913
+ * are unchanged. Nested calls compose and the prior scope is restored even on
914
+ * failure. The callback must finish registration synchronously (no async work).
915
+ */
916
+ withOpenApiPathPrefix(prefix, build) {
917
+ const previous = this.openApiPathPrefix;
918
+ this.openApiPathPrefix = normalizeUrlPath(`${previous}/${prefix}`);
919
+ try {
920
+ return build();
921
+ } finally {
922
+ this.openApiPathPrefix = previous;
923
+ }
905
924
  }
906
925
  /**
907
926
  * Enable strict OpenAPI collision detection for the remainder of this
@@ -1743,19 +1762,12 @@ function fromJoi(schema) {
1743
1762
  }
1744
1763
  function fromAjv(validator) {
1745
1764
  return async (value) => {
1746
- const outcome = validator(value);
1747
- if (isThenable(outcome)) {
1765
+ if (validator.$async === true) {
1748
1766
  try {
1749
- const data = await outcome;
1750
- if (data === false) {
1751
- return {
1752
- success: false,
1753
- issues: normalizeAjvIssues(validator.errors ?? [])
1754
- };
1755
- }
1767
+ const data = await validator(value);
1756
1768
  return {
1757
1769
  success: true,
1758
- data: data === true ? value : data
1770
+ data
1759
1771
  };
1760
1772
  } catch (error) {
1761
1773
  if (!isAjvValidationError(error)) {
@@ -1763,11 +1775,21 @@ function fromAjv(validator) {
1763
1775
  }
1764
1776
  return {
1765
1777
  success: false,
1766
- issues: normalizeAjvIssues(error.errors ?? [])
1778
+ issues: normalizeAjvIssues(error.errors)
1767
1779
  };
1768
1780
  }
1769
1781
  }
1770
- const errorsSnapshot = validator.errors ? [...validator.errors] : [];
1782
+ const outcome = validator(value);
1783
+ if (isThenable(outcome)) {
1784
+ void Promise.resolve(outcome).catch(() => {
1785
+ });
1786
+ throw new TypeError(
1787
+ "fromAjv: promise/thenable validators must declare $async: true and resolve with validated data"
1788
+ );
1789
+ }
1790
+ if (typeof outcome !== "boolean") {
1791
+ throw new TypeError("fromAjv: synchronous validators must return a boolean verdict");
1792
+ }
1771
1793
  if (outcome) {
1772
1794
  return {
1773
1795
  success: true,
@@ -1776,7 +1798,9 @@ function fromAjv(validator) {
1776
1798
  }
1777
1799
  return {
1778
1800
  success: false,
1779
- issues: normalizeAjvIssues(errorsSnapshot)
1801
+ // Normalize immediately, copying message/path before another call can
1802
+ // replace the errors array or mutate its entries.
1803
+ issues: normalizeAjvIssues(validator.errors ?? [])
1780
1804
  };
1781
1805
  };
1782
1806
  }
@@ -2006,14 +2030,14 @@ function isArkTypeErrors(value) {
2006
2030
  return record.arkKind === "errors" || record[" arkKind"] === "errors";
2007
2031
  }
2008
2032
  function isThenable(value) {
2009
- return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
2033
+ return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
2010
2034
  }
2011
2035
  function isAjvValidationError(error) {
2012
2036
  if (typeof error !== "object" || error === null || !("errors" in error)) {
2013
2037
  return false;
2014
2038
  }
2015
- const errors = error.errors;
2016
- return errors == null || Array.isArray(errors);
2039
+ const candidate = error;
2040
+ return candidate.ajv === true && candidate.validation === true && Array.isArray(candidate.errors);
2017
2041
  }
2018
2042
  function isVineValidationError(error) {
2019
2043
  if (typeof error !== "object" || error === null || !("messages" in error)) {