@classytic/arc 2.8.4 → 2.9.1

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.
Files changed (130) hide show
  1. package/README.md +116 -5
  2. package/dist/{BaseController-DAGGc5Xn.mjs → BaseController-Vu2yc56T.mjs} +188 -102
  3. package/dist/EventTransport-CqZ8FyM_.d.mts +293 -0
  4. package/dist/adapters/index.d.mts +2 -2
  5. package/dist/audit/index.d.mts +100 -11
  6. package/dist/audit/index.mjs +71 -18
  7. package/dist/auth/index.d.mts +15 -7
  8. package/dist/auth/index.mjs +13 -6
  9. package/dist/{betterAuthOpenApi-C5lDyRH2.mjs → betterAuthOpenApi--rdY15Ld.mjs} +1 -1
  10. package/dist/cache/index.d.mts +71 -1
  11. package/dist/cache/index.mjs +96 -3
  12. package/dist/cli/commands/docs.mjs +1 -1
  13. package/dist/cli/commands/generate.mjs +1 -1
  14. package/dist/core/index.d.mts +3 -3
  15. package/dist/core/index.mjs +4 -5
  16. package/dist/{core-DKSwNSXf.mjs → core-DNncu0xF.mjs} +1 -1
  17. package/dist/{createActionRouter-Df1BuawX.mjs → createActionRouter-DH1YFL9m.mjs} +3 -3
  18. package/dist/{createApp-BOYjBgdI.mjs → createApp-CBJUJKGP.mjs} +6 -5
  19. package/dist/{defineResource-Bb_Bdhtw.mjs → defineResource-C__jkwvs.mjs} +22 -57
  20. package/dist/docs/index.d.mts +1 -1
  21. package/dist/docs/index.mjs +1 -1
  22. package/dist/dynamic/index.d.mts +2 -2
  23. package/dist/dynamic/index.mjs +3 -3
  24. package/dist/{elevation-BBGFjzIP.mjs → elevation-DxQ6ACbt.mjs} +20 -6
  25. package/dist/{errorHandler-mzqk4cGl.mjs → errorHandler-CZDW4EXS.mjs} +59 -7
  26. package/dist/{errorHandler-CdZDavNH.d.mts → errorHandler-DixGcttC.d.mts} +37 -2
  27. package/dist/{eventPlugin-CVxlE6De.d.mts → eventPlugin-BxvaCIZF.d.mts} +14 -2
  28. package/dist/{eventPlugin-D91S2YF4.mjs → eventPlugin-Dl7MoVWH.mjs} +83 -5
  29. package/dist/events/index.d.mts +147 -36
  30. package/dist/events/index.mjs +338 -101
  31. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  32. package/dist/events/transports/redis.d.mts +1 -1
  33. package/dist/factory/index.d.mts +1 -1
  34. package/dist/factory/index.mjs +1 -1
  35. package/dist/{fields-DC4So2M2.d.mts → fields-BC7zcmI9.d.mts} +15 -3
  36. package/dist/{fields-ipsbIRPK.mjs → fields-CU6FlaDV.mjs} +18 -5
  37. package/dist/filesUpload-q8oHt--L.mjs +377 -0
  38. package/dist/hooks/index.d.mts +1 -1
  39. package/dist/idempotency/index.d.mts +28 -4
  40. package/dist/idempotency/index.mjs +111 -2
  41. package/dist/idempotency/redis.d.mts +2 -2
  42. package/dist/idempotency/redis.mjs +134 -13
  43. package/dist/{index-CSkeivBx.d.mts → index-C-xjcA6F.d.mts} +2 -2
  44. package/dist/{index-CpTSDqmD.d.mts → index-Cibkchnx.d.mts} +5 -136
  45. package/dist/{index-BgmMdpm8.d.mts → index-CtGKT0lf.d.mts} +1 -1
  46. package/dist/index.d.mts +8 -8
  47. package/dist/index.mjs +8 -8
  48. package/dist/integrations/event-gateway.d.mts +1 -1
  49. package/dist/integrations/index.d.mts +1 -1
  50. package/dist/integrations/jobs.d.mts +25 -3
  51. package/dist/integrations/jobs.mjs +63 -4
  52. package/dist/integrations/mcp/index.d.mts +26 -8
  53. package/dist/integrations/mcp/index.mjs +96 -17
  54. package/dist/integrations/mcp/testing.d.mts +1 -1
  55. package/dist/integrations/mcp/testing.mjs +1 -1
  56. package/dist/integrations/webhooks.d.mts +5 -0
  57. package/dist/integrations/webhooks.mjs +6 -0
  58. package/dist/{interface-BVuMfeVv.d.mts → interface-YrWsmKqE.d.mts} +324 -194
  59. package/dist/{openapi-CYCuekCn.mjs → openapi-CXuTG1M9.mjs} +3 -3
  60. package/dist/org/index.d.mts +2 -2
  61. package/dist/permissions/index.d.mts +3 -3
  62. package/dist/permissions/index.mjs +3 -3
  63. package/dist/{permissions-CH4cNwJi.mjs → permissions-oNZawnkR.mjs} +1 -1
  64. package/dist/plugins/index.d.mts +6 -6
  65. package/dist/plugins/index.mjs +4 -4
  66. package/dist/plugins/response-cache.mjs +1 -1
  67. package/dist/plugins/tracing-entry.d.mts +1 -1
  68. package/dist/plugins/tracing-entry.mjs +1 -1
  69. package/dist/policies/index.d.mts +26 -33
  70. package/dist/presets/filesUpload.d.mts +71 -0
  71. package/dist/presets/filesUpload.mjs +2 -0
  72. package/dist/presets/index.d.mts +4 -2
  73. package/dist/presets/index.mjs +4 -2
  74. package/dist/presets/multiTenant.d.mts +1 -1
  75. package/dist/presets/multiTenant.mjs +1 -1
  76. package/dist/presets/search.d.mts +91 -0
  77. package/dist/presets/search.mjs +150 -0
  78. package/dist/{presets-C2xgzW6x.mjs → presets-hM4WhNWY.mjs} +1 -1
  79. package/dist/{queryCachePlugin-D0iIVhW_.mjs → queryCachePlugin-DbUVroUG.mjs} +2 -2
  80. package/dist/redis-MXLp1oOf.d.mts +115 -0
  81. package/dist/{redis-stream-D54N5oXs.d.mts → redis-stream-Bz-4q96t.d.mts} +1 -1
  82. package/dist/registry/index.d.mts +1 -1
  83. package/dist/{resourceToTools-O_HwWXFa.mjs → resourceToTools-C3cWymnW.mjs} +65 -48
  84. package/dist/rpc/index.mjs +1 -1
  85. package/dist/{schemaConverter-OxfCshus.mjs → schemaConverter-BxFDdtXu.mjs} +25 -9
  86. package/dist/scope/index.d.mts +2 -2
  87. package/dist/scope/index.mjs +1 -1
  88. package/dist/storage-BwGQXUpd.d.mts +146 -0
  89. package/dist/store-helpers-DFiZl5TL.mjs +57 -0
  90. package/dist/testing/index.d.mts +7 -15
  91. package/dist/testing/index.mjs +23 -76
  92. package/dist/testing/storageContract.d.mts +26 -0
  93. package/dist/testing/storageContract.mjs +216 -0
  94. package/dist/types/index.d.mts +5 -5
  95. package/dist/types/storage.d.mts +2 -0
  96. package/dist/types/storage.mjs +1 -0
  97. package/dist/{types-CcG4avic.d.mts → types-CoSzA-s-.d.mts} +1 -1
  98. package/dist/{types-Bg2X42_m.d.mts → types-CunEX4UX.d.mts} +7 -5
  99. package/dist/{types-CVC4HOKi.d.mts → types-DZi1aYhm.d.mts} +1 -1
  100. package/dist/utils/index.d.mts +26 -8
  101. package/dist/utils/index.mjs +6 -6
  102. package/dist/{utils-yYT3HDXt.mjs → utils-B7FuRr9w.mjs} +1 -1
  103. package/package.json +23 -11
  104. package/skills/arc/SKILL.md +92 -14
  105. package/skills/arc/references/auth.md +94 -0
  106. package/skills/arc/references/events.md +229 -12
  107. package/skills/arc/references/mcp.md +4 -17
  108. package/skills/arc/references/multi-tenancy.md +43 -0
  109. package/skills/arc/references/production.md +34 -19
  110. package/dist/EventTransport-CinyO7zQ.d.mts +0 -135
  111. package/dist/audit/mongodb.d.mts +0 -2
  112. package/dist/audit/mongodb.mjs +0 -2
  113. package/dist/idempotency/mongodb.d.mts +0 -2
  114. package/dist/idempotency/mongodb.mjs +0 -123
  115. package/dist/mongodb-B5O6xaW1.mjs +0 -90
  116. package/dist/mongodb-B8U2xaLj.d.mts +0 -127
  117. package/dist/mongodb-X7LbEjTN.d.mts +0 -80
  118. package/dist/redis-z3sFr1UP.d.mts +0 -49
  119. /package/dist/{applyPermissionResult-D6GPMsvh.mjs → applyPermissionResult-bqGpo9ML.mjs} +0 -0
  120. /package/dist/{circuitBreaker-cmi5XDv5.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
  121. /package/dist/{elevation-s5ykdNHr.d.mts → elevation-B6S5csVA.d.mts} +0 -0
  122. /package/dist/{errors-Bmn3eZT6.d.mts → errors-BI8kEKsO.d.mts} +0 -0
  123. /package/dist/{errors-BF2bIOIS.mjs → errors-CqWnSqM-.mjs} +0 -0
  124. /package/dist/{memory-Cp7_cAko.mjs → memory-BFAYkf8H.mjs} +0 -0
  125. /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-CWP6MB39.mjs} +0 -0
  126. /package/dist/{queryParser-CgCtsjti.mjs → queryParser-Cs-6SHQK.mjs} +0 -0
  127. /package/dist/{requestContext-DYvHl113.mjs → requestContext-DYtmNpm5.mjs} +0 -0
  128. /package/dist/{tracing-DxjKk7eW.d.mts → tracing-xqXzWeaf.d.mts} +0 -0
  129. /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-Cj5Rgvlg.mjs} +0 -0
  130. /package/dist/{types-C72d3NDn.d.mts → types-BD85MlEK.d.mts} +0 -0
@@ -1,6 +1,6 @@
1
- import { r as RequestScope } from "./types-C72d3NDn.mjs";
2
- import { n as FieldPermissionMap } from "./fields-DC4So2M2.mjs";
3
- import { i as UserBase, t as PermissionCheck } from "./types-CVC4HOKi.mjs";
1
+ import { r as RequestScope } from "./types-BD85MlEK.mjs";
2
+ import { n as FieldPermissionMap } from "./fields-BC7zcmI9.mjs";
3
+ import { i as UserBase, t as PermissionCheck } from "./types-DZi1aYhm.mjs";
4
4
  import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, RouteHandlerMethod, RouteHandlerMethod as RouteHandlerMethod$1 } from "fastify";
5
5
 
6
6
  //#region src/hooks/HookSystem.d.ts
@@ -472,6 +472,23 @@ interface DeleteOptions extends QueryOptions {
472
472
  */
473
473
  mode?: "hard" | "soft";
474
474
  }
475
+ /**
476
+ * Options for the atomic `findOneAndUpdate` compare-and-set primitive.
477
+ *
478
+ * Kit-agnostic — every backend implements the core knobs (`sort`,
479
+ * `returnDocument`, `upsert`, `session`). The index signature lets kits
480
+ * thread through backend-specific options (mongoose `arrayFilters`,
481
+ * `collation`, `maxTimeMS`; prisma `select`, `include`; etc.) without arc
482
+ * having to know about them.
483
+ */
484
+ interface FindOneAndUpdateOptions extends QueryOptions {
485
+ /** Sort spec disambiguating when filter matches multiple docs (FIFO claim). */
486
+ sort?: Record<string, unknown>;
487
+ /** Return doc state before or after the update. Default: 'after'. */
488
+ returnDocument?: "before" | "after";
489
+ /** Insert if no doc matches. Default: false. */
490
+ upsert?: boolean;
491
+ }
475
492
  /**
476
493
  * Result of a single delete operation.
477
494
  *
@@ -593,10 +610,24 @@ interface PaginationParams<TDoc = unknown> {
593
610
  *
594
611
  * `method` is optional so legacy adapters returning the bare `{ docs, page,
595
612
  * limit, total, pages, hasNext, hasPrev }` shape still satisfy the type.
613
+ *
614
+ * ## Extending with kit-specific fields
615
+ *
616
+ * Kits are free to return extra metadata (query timing, region, index hit-rate,
617
+ * cursor version, …). Supply them via the `TExtra` generic and they appear
618
+ * at the top level alongside the standard fields — no wrapper object, no
619
+ * narrowing gymnastics:
620
+ *
621
+ * ```ts
622
+ * type ProductPage = OffsetPaginatedResult<Product, { tookMs: number; region: string }>;
623
+ * // ^? { method?: "offset"; docs: Product[]; page: number; ...; tookMs: number; region: string }
624
+ * ```
625
+ *
626
+ * Default `TExtra = {}` preserves the standard shape for every caller that
627
+ * doesn't care about extras.
596
628
  */
597
- interface OffsetPaginatedResult<TDoc> {
598
- /** Discriminator — omitted or `"offset"` */
599
- method?: "offset";
629
+ type OffsetPaginatedResult<TDoc, TExtra = {}> = {
630
+ /** Discriminator — omitted or `"offset"` */method?: "offset";
600
631
  docs: TDoc[];
601
632
  page: number;
602
633
  limit: number;
@@ -604,20 +635,29 @@ interface OffsetPaginatedResult<TDoc> {
604
635
  pages: number;
605
636
  hasNext: boolean;
606
637
  hasPrev: boolean;
607
- }
638
+ /**
639
+ * Optional performance warning surfaced by the underlying kit for deep
640
+ * offset pagination (e.g. mongokit emits one when `page * limit` exceeds
641
+ * its `deepPageThreshold`). Kits that don't produce warnings leave it
642
+ * absent.
643
+ */
644
+ warning?: string;
645
+ } & TExtra;
608
646
  /**
609
647
  * Keyset-based paginated result (returned when `sort` is provided without
610
648
  * `page`). Ideal for infinite scroll — no `count()` query, O(1) per page.
649
+ *
650
+ * Cursor tokens are opaque by design; kits encode their own versioning
651
+ * (mongokit carries a `ver` field inside the token). Surface kit-specific
652
+ * extras (e.g. `cursor.version`, `queryPlan`) via the `TExtra` generic.
611
653
  */
612
- interface KeysetPaginatedResult<TDoc> {
613
- /** Discriminator — always `"keyset"` */
614
- method: "keyset";
654
+ type KeysetPaginatedResult<TDoc, TExtra = {}> = {
655
+ /** Discriminator — always `"keyset"` */method: "keyset";
615
656
  docs: TDoc[];
616
657
  limit: number;
617
- hasMore: boolean;
618
- /** Opaque cursor token for the next page, or `null` at the end */
658
+ hasMore: boolean; /** Opaque cursor token for the next page, or `null` at the end */
619
659
  next: string | null;
620
- }
660
+ } & TExtra;
621
661
  /**
622
662
  * Discriminated union of all pagination result shapes.
623
663
  * Consumers narrow on the `method` discriminator.
@@ -632,14 +672,14 @@ interface KeysetPaginatedResult<TDoc> {
632
672
  * }
633
673
  * ```
634
674
  */
635
- type PaginationResult<TDoc> = OffsetPaginatedResult<TDoc> | KeysetPaginatedResult<TDoc>;
675
+ type PaginationResult<TDoc, TExtra = {}> = OffsetPaginatedResult<TDoc, TExtra> | KeysetPaginatedResult<TDoc, TExtra>;
636
676
  /**
637
677
  * Legacy alias. Existing code typed as `PaginatedResult<TDoc>` continues
638
678
  * to work unchanged — it resolves to the offset shape, which is the most
639
679
  * common. New code should prefer `PaginationResult<TDoc>` for the full
640
680
  * discriminated union.
641
681
  */
642
- type PaginatedResult<TDoc> = OffsetPaginatedResult<TDoc>;
682
+ type PaginatedResult<TDoc, TExtra = {}> = OffsetPaginatedResult<TDoc, TExtra>;
643
683
  /**
644
684
  * Standard CRUD Repository Interface
645
685
  *
@@ -691,11 +731,47 @@ interface CrudRepository<TDoc> {
691
731
  create(data: Partial<TDoc>, options?: WriteOptions): Promise<TDoc>;
692
732
  /** Update a document by primary key. Returns the updated doc or null. */
693
733
  update(id: string, data: Partial<TDoc>, options?: WriteOptions): Promise<TDoc | null>;
734
+ /**
735
+ * Atomic compare-and-set — match one document and mutate it in a single
736
+ * round-trip. Returns the resulting document (post-update by default), or
737
+ * `null` when no match and `upsert` is false.
738
+ *
739
+ * **Why this is a first-class contract method (vs an optional capability):**
740
+ * arc's outbox, distributed-lock, and workflow-semaphore patterns all
741
+ * depend on compare-and-set semantics. Without an atomic primitive they
742
+ * either race or require a two-phase pattern that doesn't translate
743
+ * cleanly to every backend. Every kit targeting arc 2.10+ should
744
+ * implement this.
745
+ *
746
+ * Plugins wire into `before:findOneAndUpdate` / `after:findOneAndUpdate`
747
+ * and read the filter from `context.query` — the canonical field name.
748
+ *
749
+ * @example FIFO claim-lease for an outbox relay
750
+ * ```ts
751
+ * const claimed = await outboxRepo.findOneAndUpdate(
752
+ * { status: 'pending', visibleAt: { $lte: new Date() } },
753
+ * { $set: { status: 'processing', leasedBy: workerId, leaseExpiresAt } },
754
+ * { sort: { createdAt: 1 }, returnDocument: 'after' },
755
+ * );
756
+ * ```
757
+ */
758
+ findOneAndUpdate?(filter: Record<string, unknown>, update: Record<string, unknown> | Record<string, unknown>[], options?: FindOneAndUpdateOptions): Promise<TDoc | null>;
694
759
  /**
695
760
  * Delete a document by primary key. Pass `{ mode: 'hard' }` to bypass
696
761
  * soft-delete interception.
697
762
  */
698
763
  delete(id: string, options?: DeleteOptions): Promise<DeleteResult>;
764
+ /**
765
+ * Classify an error thrown by a write as a unique-index / duplicate-key
766
+ * violation. Used by arc's idempotency and outbox adapters to distinguish
767
+ * "this write already landed" from "transient DB error".
768
+ *
769
+ * Each backend signals this differently (MongoDB `code 11000`,
770
+ * Prisma `P2002`, Postgres `23505`, etc.) — classification lives in the
771
+ * kit that knows its driver. Arc falls back to a Mongo default if absent;
772
+ * non-mongo kits must implement to participate in idempotency semantics.
773
+ */
774
+ isDuplicateKeyError?(err: unknown): boolean;
699
775
  /**
700
776
  * Find a single doc by a compound filter. Used by arc's AccessControl to
701
777
  * combine `idField + orgId + policy` in one query. Without it, arc falls
@@ -771,6 +847,37 @@ interface CrudRepository<TDoc> {
771
847
  * — structurally `unknown`, type-safe at the call site.
772
848
  */
773
849
  aggregatePaginate?: unknown;
850
+ /**
851
+ * Fluent aggregation pipeline builder.
852
+ *
853
+ * Same `unknown` reasoning as `aggregate` — each kit returns its own
854
+ * builder class (mongokit returns `AggregationBuilder`, others may
855
+ * return SQL builders, Prisma chains, etc.). Cast at the call site:
856
+ *
857
+ * ```ts
858
+ * import type { AggregationBuilder } from '@classytic/mongokit';
859
+ * const pipeline = (repo.buildAggregation?.() as AggregationBuilder)
860
+ * .match({ status: 'active' })
861
+ * .group({ _id: '$category', count: { $sum: 1 } })
862
+ * .build();
863
+ * ```
864
+ */
865
+ buildAggregation?(): unknown;
866
+ /**
867
+ * Fluent `$lookup` stage builder. Same kit-specific reasoning as
868
+ * `buildAggregation` — cast at the call site.
869
+ *
870
+ * ```ts
871
+ * import type { LookupBuilder } from '@classytic/mongokit';
872
+ * const stages = (repo.buildLookup?.('departments') as LookupBuilder)
873
+ * .localField('deptSlug')
874
+ * .foreignField('slug')
875
+ * .as('department')
876
+ * .single()
877
+ * .build();
878
+ * ```
879
+ */
880
+ buildLookup?(from?: string): unknown;
774
881
  /**
775
882
  * Run `callback` inside a transaction. Adapters should auto-retry on
776
883
  * transient transaction errors and expose a `session` the callback can
@@ -827,17 +934,7 @@ declare class ResourceDefinition<TDoc = AnyRecord> {
827
934
  readonly schemaOptions: RouteSchemaOptions;
828
935
  readonly customSchemas: CrudSchemas;
829
936
  readonly permissions: ResourcePermissions;
830
- readonly additionalRoutes: AdditionalRoute[];
831
- /**
832
- * Original v2.8 `routes` declaration — retained for downstream consumers
833
- * (OpenAPI, MCP, registry, CLI introspect). Preserves fields dropped during
834
- * normalization to `additionalRoutes` (notably `mcp`, `description`,
835
- * `annotations`). Undefined when the resource was defined with the legacy
836
- * `additionalRoutes` shape.
837
- *
838
- * Added in 2.8.1 — the source-of-truth fix for "canonical resource manifest".
839
- */
840
- readonly routes?: readonly RouteDefinition[];
937
+ readonly routes: readonly RouteDefinition[];
841
938
  readonly middlewares: MiddlewareConfig;
842
939
  readonly routeGuards?: RouteHandlerMethod$1[];
843
940
  readonly disableDefaultRoutes: boolean;
@@ -1205,6 +1302,15 @@ interface ControllerLike {
1205
1302
  }
1206
1303
  //#endregion
1207
1304
  //#region src/core/AccessControl.d.ts
1305
+ /** Denial reason codes returned by `fetchDetailed()`. */
1306
+ type FetchDenialReason = "NOT_FOUND" | "POLICY_FILTERED" | "ORG_SCOPE_DENIED";
1307
+ /** Result of a detailed fetch with access control. */
1308
+ interface FetchResult<TDoc> {
1309
+ /** The document, or null if denied. */
1310
+ doc: TDoc | null;
1311
+ /** Null when the doc was found. A string code when denied. */
1312
+ reason: FetchDenialReason | null;
1313
+ }
1208
1314
  interface AccessControlConfig {
1209
1315
  /** Field name used for multi-tenant scoping (default: 'organizationId'). Set to `false` to disable org filtering. */
1210
1316
  tenantField: string | false;
@@ -1265,6 +1371,19 @@ declare class AccessControl {
1265
1371
  * buildIdFilter -> getOne (or getById + checkOrgScope + checkPolicyFilters)
1266
1372
  */
1267
1373
  fetchWithAccessControl<TDoc>(id: string, req: IRequestContext, repository: AccessControlRepository, queryOptions?: QueryOptions): Promise<TDoc | null>;
1374
+ /**
1375
+ * Same as `fetchWithAccessControl` but returns a structured result with
1376
+ * a denial reason so callers can distinguish "doc doesn't exist" from
1377
+ * "doc exists but was filtered by policy/org scope" from "repo threw".
1378
+ *
1379
+ * Codes:
1380
+ * - `null` — doc was found, no denial
1381
+ * - `'NOT_FOUND'` — doc genuinely doesn't exist in the DB
1382
+ * - `'POLICY_FILTERED'` — doc exists but the request's policy filters exclude it
1383
+ * - `'ORG_SCOPE_DENIED'` — doc exists but the caller's org context doesn't match
1384
+ * - `'REPO_ERROR'` — the repository threw a "not found" error (mongokit style)
1385
+ */
1386
+ fetchDetailed<TDoc>(id: string, req: IRequestContext, repository: AccessControlRepository, queryOptions?: QueryOptions): Promise<FetchResult<TDoc>>;
1268
1387
  /**
1269
1388
  * Post-fetch access control validation for items fetched by non-ID queries
1270
1389
  * (e.g., getBySlug, restore). Applies org scope, policy filters, and
@@ -1300,12 +1419,27 @@ declare class AccessControl {
1300
1419
  }
1301
1420
  //#endregion
1302
1421
  //#region src/core/BodySanitizer.d.ts
1422
+ /**
1423
+ * Policy for handling fields the caller lacks write permission for.
1424
+ *
1425
+ * - `'reject'` (default, secure): throw 403 listing the denied fields so
1426
+ * misconfigurations and attacks surface instead of silently disappearing.
1427
+ * - `'strip'` (legacy): silently drop the field and continue. Preserved for
1428
+ * apps that relied on the pre-2.9 behaviour — new code should not use it.
1429
+ */
1430
+ type FieldWriteDenialPolicy = "reject" | "strip";
1303
1431
  interface BodySanitizerConfig {
1304
1432
  /** Schema options for field sanitization */
1305
1433
  schemaOptions: RouteSchemaOptions;
1434
+ /**
1435
+ * What to do when a request contains fields the caller can't write.
1436
+ * Default: `'reject'` — surface the misconfiguration as a 403.
1437
+ */
1438
+ onFieldWriteDenied?: FieldWriteDenialPolicy;
1306
1439
  }
1307
1440
  declare class BodySanitizer {
1308
1441
  private schemaOptions;
1442
+ private onFieldWriteDenied;
1309
1443
  constructor(config: BodySanitizerConfig);
1310
1444
  /**
1311
1445
  * Strip readonly and system-managed fields from request body.
@@ -1415,6 +1549,16 @@ interface BaseControllerOptions {
1415
1549
  slugField?: string;
1416
1550
  parentField?: string;
1417
1551
  };
1552
+ /**
1553
+ * Policy for requests that include fields the caller can't write.
1554
+ *
1555
+ * - `'reject'` (default): 403 with the denied field names. Surfaces
1556
+ * misconfigurations and attempts to set protected fields instead of
1557
+ * silently dropping them.
1558
+ * - `'strip'`: legacy silent-drop behaviour. Only opt in when migrating
1559
+ * code that relied on the pre-2.9 permissive default.
1560
+ */
1561
+ onFieldWriteDenied?: FieldWriteDenialPolicy;
1418
1562
  }
1419
1563
  /**
1420
1564
  * Framework-agnostic base controller implementing IController.
@@ -1475,6 +1619,16 @@ declare class BaseController<TDoc = AnyRecord, TRepository extends RepositoryLik
1475
1619
  * aliasing that Arc 2.6.3 introduced for repos keyed on `_id`.
1476
1620
  */
1477
1621
  private resolveRepoId;
1622
+ /**
1623
+ * Centralized 404 response builder. Maps the denial reason from
1624
+ * `fetchDetailed()` into a structured `details.code` so consumers can
1625
+ * programmatically distinguish "doc doesn't exist" from "doc filtered
1626
+ * by policy/org scope" without parsing error strings.
1627
+ *
1628
+ * Error messages are intentionally vague in the `error` field (don't
1629
+ * leak whether the doc exists) — the detail is in `details.code` only.
1630
+ */
1631
+ private notFoundResponse;
1478
1632
  /** Resolve cache config for a specific operation, merging per-op overrides */
1479
1633
  private resolveCacheConfig;
1480
1634
  /**
@@ -2027,6 +2181,16 @@ interface ResourceConfig<TDoc = AnyRecord> {
2027
2181
  * ```
2028
2182
  */
2029
2183
  fields?: FieldPermissionMap;
2184
+ /**
2185
+ * Policy for requests that include fields the caller can't write.
2186
+ *
2187
+ * - `'reject'` (default, secure): 403 with the denied field names. Surfaces
2188
+ * misconfigurations and write-side permission violations instead of
2189
+ * silently dropping them.
2190
+ * - `'strip'`: legacy silent-drop behaviour — only opt in when migrating
2191
+ * code that relied on the pre-2.9 permissive default.
2192
+ */
2193
+ onFieldWriteDenied?: 'reject' | 'strip';
2030
2194
  middlewares?: MiddlewareConfig;
2031
2195
  /**
2032
2196
  * PreHandler guards auto-applied to **every** route on this resource
@@ -2113,22 +2277,6 @@ interface ResourceConfig<TDoc = AnyRecord> {
2113
2277
  skipValidation?: boolean;
2114
2278
  skipRegistry?: boolean;
2115
2279
  _appliedPresets?: string[];
2116
- /**
2117
- * Called during plugin registration with the scoped Fastify instance.
2118
- * Use for wiring singletons, reading decorators, or setting up resource-specific
2119
- * services that need access to the Fastify instance.
2120
- *
2121
- * @example
2122
- * ```typescript
2123
- * defineResource({
2124
- * name: 'notification',
2125
- * onRegister: (fastify) => {
2126
- * setSseManager(fastify.sseManager);
2127
- * },
2128
- * })
2129
- * ```
2130
- */
2131
- onRegister?: (fastify: FastifyInstance) => void | Promise<void>;
2132
2280
  /** HTTP method for update routes. Default: 'PATCH' */
2133
2281
  updateMethod?: 'PUT' | 'PATCH' | 'both';
2134
2282
  /**
@@ -2231,141 +2379,6 @@ interface ResourceHooks {
2231
2379
  /** Runs after delete — ctx.data is the deleted doc, ctx.meta.id has the resource ID */
2232
2380
  afterDelete?: (ctx: ResourceHookContext) => Promise<void> | void;
2233
2381
  }
2234
- /**
2235
- * Additional route definition for custom endpoints
2236
- */
2237
- interface AdditionalRoute {
2238
- /** HTTP method */
2239
- method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
2240
- /** Route path (relative to resource prefix) */
2241
- path: string;
2242
- /**
2243
- * Handler - string (controller method name) or function.
2244
- *
2245
- * When `wrapHandler: true`:
2246
- * - `string` — calls controller method by name (e.g., `'approve'`)
2247
- * - `ControllerHandler` — receives `IRequestContext`, returns `IControllerResponse`
2248
- *
2249
- * When `wrapHandler: false`:
2250
- * - Fastify handler `(request, reply) => unknown`
2251
- */
2252
- handler: string | ControllerHandler | RouteHandlerMethod | ((request: FastifyRequest<any>, reply: FastifyReply) => unknown);
2253
- /** Permission check - REQUIRED */
2254
- permissions: PermissionCheck;
2255
- /**
2256
- * Handler type - REQUIRED, no auto-detection
2257
- * true = ControllerHandler (receives context object)
2258
- * false = FastifyHandler (receives request, reply)
2259
- */
2260
- wrapHandler: boolean;
2261
- /**
2262
- * Logical operation name for pipeline keys and permission actions.
2263
- * Defaults to handler name (string handlers) or method+path slug.
2264
- * Prevents collisions when multiple routes share the same HTTP method.
2265
- *
2266
- * @example
2267
- * operation: 'listDeleted' // Used as pipeline key and permission action
2268
- * operation: 'restore'
2269
- */
2270
- operation?: string;
2271
- /** OpenAPI summary */
2272
- summary?: string;
2273
- /** OpenAPI description */
2274
- description?: string;
2275
- /** OpenAPI tags */
2276
- tags?: string[];
2277
- /**
2278
- * Custom route-level middleware
2279
- * Can be an array of handlers or a function that receives fastify and returns handlers
2280
- * @example
2281
- * // Direct array
2282
- * preHandler: [myMiddleware]
2283
- * // Function that receives fastify (for accessing decorators)
2284
- * preHandler: (fastify) => [fastify.customerContext({ required: true })]
2285
- */
2286
- preHandler?: RouteHandlerMethod[] | ((fastify: FastifyInstance) => RouteHandlerMethod[]);
2287
- /**
2288
- * Pre-auth handlers — run BEFORE authentication middleware.
2289
- * Use for promoting query params to headers (e.g., EventSource ?token= → Authorization).
2290
- *
2291
- * @example
2292
- * ```typescript
2293
- * preAuth: [(req) => {
2294
- * const token = (req.query as Record<string, string>)?.token;
2295
- * if (token) req.headers.authorization = `Bearer ${token}`;
2296
- * }]
2297
- * ```
2298
- */
2299
- preAuth?: RouteHandlerMethod[];
2300
- /**
2301
- * Streaming response mode — designed for SSE and AI streaming routes.
2302
- * When `true`:
2303
- * - Forces `wrapHandler: false` (no `{ success, data }` wrapper)
2304
- * - Sets SSE headers: `Content-Type: text/event-stream`, `Cache-Control: no-cache`, `Connection: keep-alive`
2305
- * - `request.signal` (Fastify 5 built-in) is available for abort-on-disconnect
2306
- *
2307
- * @example
2308
- * ```typescript
2309
- * {
2310
- * method: 'POST',
2311
- * path: '/stream',
2312
- * streamResponse: true,
2313
- * permissions: requireAuth(),
2314
- * handler: async (request, reply) => {
2315
- * const { stream } = await generateStream({ abortSignal: request.signal });
2316
- * return reply.send(stream);
2317
- * },
2318
- * }
2319
- * ```
2320
- */
2321
- streamResponse?: boolean;
2322
- /** Fastify route schema */
2323
- schema?: Record<string, unknown>;
2324
- /**
2325
- * MCP handler for routes with `wrapHandler: false`.
2326
- * When set, this route becomes an MCP tool without needing `wrapHandler: true`.
2327
- * The HTTP handler stays a plain Fastify handler; MCP gets a parallel entry point.
2328
- *
2329
- * @example
2330
- * ```typescript
2331
- * additionalRoutes: [{
2332
- * method: 'GET',
2333
- * path: '/stats',
2334
- * handler: (req, reply) => reply.send(getStats()),
2335
- * wrapHandler: false,
2336
- * permissions: isAuthenticated,
2337
- * mcpHandler: async (input) => ({
2338
- * content: [{ type: 'text', text: JSON.stringify(await getStats()) }],
2339
- * }),
2340
- * }]
2341
- * ```
2342
- */
2343
- mcpHandler?: (input: Record<string, unknown>) => Promise<{
2344
- content: Array<{
2345
- type: string;
2346
- text: string;
2347
- }>;
2348
- isError?: boolean;
2349
- }>;
2350
- /**
2351
- * MCP tool generation config preserved from v2.8 `routes`.
2352
- * - `false`: skip MCP tool generation for this route
2353
- * - `true` / omitted: auto-generate when the route goes through Arc's pipeline
2354
- * - object: explicit description/annotations overrides
2355
- *
2356
- * Added in 2.8.1 — previously dropped during `routes → additionalRoutes`
2357
- * normalization, breaking MCP opt-out and per-route annotations.
2358
- */
2359
- mcp?: boolean | {
2360
- readonly description?: string;
2361
- readonly annotations?: {
2362
- readonly readOnlyHint?: boolean;
2363
- readonly destructiveHint?: boolean;
2364
- readonly idempotentHint?: boolean;
2365
- readonly openWorldHint?: boolean;
2366
- };
2367
- };
2368
- }
2369
2382
  /** HTTP methods for custom routes */
2370
2383
  type RouteMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
2371
2384
  /** MCP tool configuration for a route or action */
@@ -2381,7 +2394,7 @@ interface RouteMcpConfig {
2381
2394
  };
2382
2395
  }
2383
2396
  /**
2384
- * Route definition — replaces additionalRoutes.
2397
+ * Route definition — the single custom-route shape (user-facing + internal).
2385
2398
  *
2386
2399
  * - `handler: 'string'` → controller method → full Arc pipeline + MCP tool
2387
2400
  * - `handler: function` → inline handler → full Arc pipeline + MCP tool
@@ -2419,8 +2432,20 @@ interface RouteDefinition {
2419
2432
  readonly preAuth?: RouteHandlerMethod[];
2420
2433
  /** SSE streaming mode */
2421
2434
  readonly streamResponse?: boolean;
2422
- /** Fastify route schema */
2423
- readonly schema?: Record<string, unknown>;
2435
+ /**
2436
+ * Fastify route schema. Each slot (`body`, `querystring`, `params`, `headers`,
2437
+ * `response[status]`) accepts a plain JSON Schema object **or** a Zod v4 schema —
2438
+ * arc auto-converts via `convertRouteSchema` at registration time. Slot values
2439
+ * are typed `unknown` so class-based Zod schemas assign without casts.
2440
+ */
2441
+ readonly schema?: {
2442
+ body?: unknown;
2443
+ querystring?: unknown;
2444
+ params?: unknown;
2445
+ headers?: unknown;
2446
+ response?: Record<number | string, unknown>;
2447
+ [key: string]: unknown;
2448
+ };
2424
2449
  /**
2425
2450
  * MCP tool generation:
2426
2451
  * - omitted/true: auto-generate (non-raw routes only)
@@ -2452,8 +2477,11 @@ interface ActionDefinition {
2452
2477
  readonly handler: ActionHandlerFn;
2453
2478
  /** Per-action permission check (overrides resource-level actionPermissions) */
2454
2479
  readonly permissions?: PermissionCheck;
2455
- /** JSON Schema for action-specific body fields */
2456
- readonly schema?: Record<string, Record<string, unknown>>;
2480
+ /**
2481
+ * JSON Schema or Zod v4 schema for action-specific body fields.
2482
+ * Per-field values are typed `unknown` so Zod class instances assign without casts.
2483
+ */
2484
+ readonly schema?: Record<string, unknown>;
2457
2485
  /** Description for OpenAPI docs and MCP tool */
2458
2486
  readonly description?: string;
2459
2487
  /**
@@ -2506,47 +2534,54 @@ interface FieldRule {
2506
2534
  /**
2507
2535
  * CRUD Route Schemas (Fastify Native Format)
2508
2536
  *
2537
+ * Each slot accepts either a plain JSON Schema object **or** a Zod v4 schema —
2538
+ * arc's `convertRouteSchema` feature-detects at runtime. The slot values are
2539
+ * typed `unknown` (not `Record<string, unknown>`) so class-based Zod schemas
2540
+ * assign cleanly without `as unknown as Record<string, unknown>` casts.
2541
+ *
2509
2542
  * @example
2543
+ * ```ts
2510
2544
  * {
2511
2545
  * list: {
2512
2546
  * querystring: { type: 'object', properties: { page: { type: 'number' } } },
2513
- * response: { 200: { type: 'object', properties: { docs: { type: 'array' } } } }
2547
+ * response: { 200: z.object({ docs: z.array(EntitySchema) }) }
2514
2548
  * },
2515
2549
  * create: {
2516
- * body: { type: 'object', properties: { name: { type: 'string' } } },
2517
- * response: { 201: { type: 'object' } }
2550
+ * body: z.object({ name: z.string(), size: z.number().int().positive() }),
2551
+ * response: { 201: EntitySchema }
2518
2552
  * }
2519
2553
  * }
2554
+ * ```
2520
2555
  */
2521
2556
  interface CrudSchemas {
2522
2557
  /** GET / - List all resources */
2523
2558
  list?: {
2524
- querystring?: Record<string, unknown>;
2559
+ /** Plain JSON Schema or Zod schema (auto-converted). */querystring?: unknown; /** Map of HTTP status code → JSON Schema or Zod schema. */
2525
2560
  response?: Record<number, unknown>;
2526
2561
  [key: string]: unknown;
2527
2562
  };
2528
2563
  /** GET /:id - Get single resource */
2529
2564
  get?: {
2530
- params?: Record<string, unknown>;
2565
+ params?: unknown;
2531
2566
  response?: Record<number, unknown>;
2532
2567
  [key: string]: unknown;
2533
2568
  };
2534
2569
  /** POST / - Create resource */
2535
2570
  create?: {
2536
- body?: Record<string, unknown>;
2571
+ body?: unknown;
2537
2572
  response?: Record<number, unknown>;
2538
2573
  [key: string]: unknown;
2539
2574
  };
2540
2575
  /** PATCH /:id - Update resource */
2541
2576
  update?: {
2542
- params?: Record<string, unknown>;
2543
- body?: Record<string, unknown>;
2577
+ params?: unknown;
2578
+ body?: unknown;
2544
2579
  response?: Record<number, unknown>;
2545
2580
  [key: string]: unknown;
2546
2581
  };
2547
2582
  /** DELETE /:id - Delete resource */
2548
2583
  delete?: {
2549
- params?: Record<string, unknown>;
2584
+ params?: unknown;
2550
2585
  response?: Record<number, unknown>;
2551
2586
  [key: string]: unknown;
2552
2587
  };
@@ -2869,6 +2904,23 @@ interface AuthPluginOptions {
2869
2904
  * ```
2870
2905
  */
2871
2906
  isRevoked?: (decoded: Record<string, unknown>) => boolean | Promise<boolean>;
2907
+ /**
2908
+ * Enforce strict JWT `type` claim validation (default: `true`).
2909
+ *
2910
+ * When enabled, `authenticate` requires `decoded.type === "access"`.
2911
+ * Tokens with a missing or unexpected `type` claim are rejected — defence in
2912
+ * depth for apps that reuse the JWT secret to sign other token kinds (invite
2913
+ * links, one-time verification codes, legacy tokens from a third-party
2914
+ * issuer).
2915
+ *
2916
+ * Arc's own token issuance (`issueTokens`) always sets `type: "access"` or
2917
+ * `type: "refresh"`, so this default is safe for arc-generated tokens.
2918
+ *
2919
+ * Set to `false` ONLY when you must accept tokens signed without a `type`
2920
+ * claim (e.g. a legacy issuer you don't control). In that mode arc still
2921
+ * rejects tokens explicitly marked `type: "refresh"`.
2922
+ */
2923
+ strictTokenType?: boolean;
2872
2924
  }
2873
2925
  interface IntrospectionPluginOptions {
2874
2926
  path?: string;
@@ -2887,8 +2939,8 @@ interface CrudRouterOptions {
2887
2939
  schemas?: Partial<CrudSchemas>;
2888
2940
  /** Middlewares for each CRUD operation */
2889
2941
  middlewares?: MiddlewareConfig;
2890
- /** Additional custom routes (from presets or user-defined) */
2891
- additionalRoutes?: AdditionalRoute[];
2942
+ /** Custom routes (from presets or user-defined) */
2943
+ routes?: readonly RouteDefinition[];
2892
2944
  /** Disable all default CRUD routes */
2893
2945
  disableDefaultRoutes?: boolean;
2894
2946
  /** Disable specific CRUD routes */
@@ -3073,6 +3125,29 @@ type TypedRepository<TDoc> = CrudRepository<TDoc>;
3073
3125
  *
3074
3126
  * See [CrudRepository](../types/repository.ts) for full prose-level docs
3075
3127
  * on each method and the design rationale behind the tiering.
3128
+ *
3129
+ * ## Store-backing contract (audit / outbox / idempotency)
3130
+ *
3131
+ * Arc's pluggable stores (audit log, event outbox, HTTP idempotency) all
3132
+ * consume a `RepositoryLike` directly — no wrapper classes, no adapters to
3133
+ * register. If you want to back one of these subsystems with any database,
3134
+ * pass a repository satisfying the method subset below. `mongokit ≥3.8`
3135
+ * implements every method; other kits must match the relevant subset.
3136
+ *
3137
+ * | Subsystem | Required methods |
3138
+ * |--------------------|---------------------------------------------------------|
3139
+ * | `auditPlugin` | `create`, `findAll` |
3140
+ * | `idempotencyPlugin`| `getOne`, `deleteMany`, `findOneAndUpdate` |
3141
+ * | `EventOutbox` | `create`, `getOne`, `findAll`, `deleteMany`, `findOneAndUpdate` |
3142
+ *
3143
+ * The outbox is the strictest — its atomic FIFO claim-lease loop depends
3144
+ * on `findOneAndUpdate` returning the post-update doc. Kits without atomic
3145
+ * CAS cannot back the outbox; use an in-memory / transport-native store
3146
+ * (`MemoryOutboxStore`, Redis Streams, etc.) instead.
3147
+ *
3148
+ * Every store adapter throws at construction with the list of missing
3149
+ * methods if the repository doesn't satisfy its subset, so misconfigurations
3150
+ * fail fast rather than at first request.
3076
3151
  */
3077
3152
  interface RepositoryLike {
3078
3153
  /**
@@ -3093,12 +3168,50 @@ interface RepositoryLike {
3093
3168
  getById(id: string, options?: QueryOptions): Promise<unknown>;
3094
3169
  create(data: unknown, options?: WriteOptions): Promise<unknown>;
3095
3170
  update(id: string, data: unknown, options?: WriteOptions): Promise<unknown>;
3171
+ /**
3172
+ * Atomic compare-and-set — match one document and mutate it in a single
3173
+ * round-trip. Returns the post-update document (or pre-update when
3174
+ * `returnDocument: 'before'`), or `null` when no document matches and
3175
+ * `upsert` is false.
3176
+ *
3177
+ * Used by the transactional outbox, distributed locks, and workflow
3178
+ * semaphores. Kits without atomic CAS can omit this method — arc stores
3179
+ * that require it throw a clear capability error at construction.
3180
+ *
3181
+ * Options follow mongokit's {@link https://github.com/classytic/mongokit | FindOneAndUpdateOptions}
3182
+ * shape: `{ sort, returnDocument, upsert, session, ... }`. Plugins reading
3183
+ * the hook context find the filter under `context.query` (the canonical
3184
+ * field name across every method on this contract).
3185
+ */
3186
+ findOneAndUpdate?(filter: Record<string, unknown>, update: Record<string, unknown> | Record<string, unknown>[], options?: {
3187
+ sort?: Record<string, unknown>;
3188
+ returnDocument?: "before" | "after";
3189
+ upsert?: boolean;
3190
+ session?: RepositorySession;
3191
+ [key: string]: unknown;
3192
+ }): Promise<unknown>;
3096
3193
  /**
3097
3194
  * Delete by primary key. Pass `{ mode: 'hard' }` to bypass soft-delete
3098
3195
  * interception (required by arc's hard-delete flow — `?hard=true` on
3099
3196
  * the DELETE route forwards this option).
3100
3197
  */
3101
3198
  delete(id: string, options?: DeleteOptions): Promise<unknown>;
3199
+ /**
3200
+ * Classify an error thrown by `create` / `findOneAndUpdate` / `update` as
3201
+ * a unique-index / duplicate-key violation.
3202
+ *
3203
+ * Arc's idempotency and outbox adapters need to distinguish "this write
3204
+ * already landed (idempotent no-op)" from "transient DB error (retry)".
3205
+ * Since every backend signals dup-key differently — MongoDB `code 11000`,
3206
+ * Prisma `P2002`, Postgres `23505`, SQLite `UNIQUE constraint failed` —
3207
+ * we put the classification back in the kit that knows its driver.
3208
+ *
3209
+ * If a kit omits this predicate, arc falls back to a conservative MongoDB
3210
+ * check (`code === 11000 || codeName === "DuplicateKey"`), so mongokit
3211
+ * ≤3.8 keeps working without changes. Non-mongo kits MUST implement it to
3212
+ * participate in idempotency semantics.
3213
+ */
3214
+ isDuplicateKeyError?(err: unknown): boolean;
3102
3215
  /**
3103
3216
  * Find a single doc by compound filter. Used by AccessControl for
3104
3217
  * `idField + org + policy` scoping. Without this, arc falls back to
@@ -3123,10 +3236,27 @@ interface RepositoryLike {
3123
3236
  getDeleted?(params?: PaginationParams, options?: QueryOptions): Promise<PaginationResult<unknown> | unknown[]>;
3124
3237
  aggregate?: unknown;
3125
3238
  aggregatePaginate?: unknown;
3239
+ /**
3240
+ * Fluent aggregation builder. Mongokit returns `AggregationBuilder`;
3241
+ * other kits may return their own builder class. Cast at the call site
3242
+ * — arc never calls this internally. See [CrudRepository.buildAggregation](../types/repository.ts).
3243
+ */
3244
+ buildAggregation?(): unknown;
3245
+ /**
3246
+ * Fluent `$lookup` stage builder. Mongokit returns `LookupBuilder`;
3247
+ * other kits may return nothing. Cast at the call site.
3248
+ */
3249
+ buildLookup?(from?: string): unknown;
3126
3250
  withTransaction?<T>(callback: (session: RepositorySession) => Promise<T>, options?: Record<string, unknown>): Promise<T>;
3127
3251
  getBySlug?(slug: string, options?: QueryOptions): Promise<unknown>;
3128
3252
  getTree?(options?: QueryOptions): Promise<unknown>;
3129
3253
  getChildren?(parentId: string, options?: QueryOptions): Promise<unknown>;
3254
+ /** Full-text / engine-backed search. Present when e.g. mongokit's `elasticSearchPlugin` is registered. */
3255
+ search?(query: unknown, options?: unknown): Promise<unknown>;
3256
+ /** Semantic / vector similarity search. Present when e.g. mongokit's `vectorPlugin` is registered. */
3257
+ searchSimilar?(query: unknown, options?: unknown): Promise<unknown>;
3258
+ /** Embed a text/media input into its vector representation. */
3259
+ embed?(input: unknown): Promise<number[]>;
3130
3260
  [key: string]: unknown;
3131
3261
  }
3132
3262
  interface DataAdapter<TDoc = unknown> {
@@ -3224,4 +3354,4 @@ interface ValidationResult {
3224
3354
  }
3225
3355
  type AdapterFactory<TDoc> = (config: unknown) => DataAdapter<TDoc>;
3226
3356
  //#endregion
3227
- export { PresetFunction as $, DeleteOptions as $t, EventsDecorator as A, beforeCreate as An, BaseController as At, InferResourceDoc as B, FastifyHandler as Bt, ConfigError as C, HookPhase as Cn, TypedResourceConfig as Ct, CrudRouterOptions as D, afterCreate as Dn, ValidationResult$1 as Dt, CrudRouteKey as E, HookSystemOptions as En, ValidateOptions as Et, GracefulShutdownOptions as F, BodySanitizerConfig as Ft, LookupOption as G, RegisterOptions as Gt, IntrospectionPluginOptions as H, IControllerResponse as Ht, HealthCheck as I, AccessControl as It, ObjectId as J, defineResource as Jt, MiddlewareConfig as K, ResourceRegistry as Kt, HealthOptions as L, AccessControlConfig as Lt, FastifyWithAuth as M, beforeUpdate as Mn, QueryResolver as Mt, FastifyWithDecorators as N, createHookSystem as Nn, QueryResolverConfig as Nt, CrudSchemas as O, afterDelete as On, envelope as Ot, FieldRule as P, defineHook as Pn, BodySanitizer as Pt, PopulateOption as Q, DeleteManyResult as Qt, InferAdapterDoc as R, ControllerHandler as Rt, AuthenticatorContext as S, HookOperation as Sn, TypedRepository as St, CrudController as T, HookSystem as Tn, UserOrganization as Tt, JWTPayload as U, IRequestContext as Ut, IntrospectionData as V, IController as Vt, JwtContext as W, RouteHandler as Wt, OwnershipCheck as X, BulkWriteResult as Xt, OpenApiSchemas as Y, BulkWriteOperation as Yt, ParsedQuery as Z, CrudRepository as Zt, ArcInternalMetadata as _, PipelineStep as _n, RouteMcpConfig as _t, RelationMetadata as a, PaginationParams as an, RegistryStats as at, AuthPluginOptions as b, HookContext as bn, TokenPair as bt, ValidationResult as c, RepositorySession as cn, RequestWithExtras as ct, ActionHandlerFn as d, Guard as dn, ResourceHookContext as dt, DeleteResult as en, PresetHook as et, ActionsMap as f, Interceptor as fn, ResourceHooks as ft, ArcDecorator as g, PipelineContext as gn, RouteHandlerMethod$1 as gt, ApiResponse as h, PipelineConfig as hn, RouteDefinition as ht, FieldMetadata as i, PaginatedResult as in, RegistryEntry as it, FastifyRequestExtras as j, beforeDelete as jn, BaseControllerOptions as jt, EventDefinition as k, afterUpdate as kn, getUserId as kt, ActionDefinition as l, UpdateManyResult as ln, ResourceCacheConfig as lt, AnyRecord as m, OperationFilter as mn, ResourcePermissions as mt, AdapterSchemaContext as n, KeysetPaginatedResult as nn, QueryParserInterface as nt, RepositoryLike as o, PaginationResult as on, RequestContext as ot, AdditionalRoute as p, NextFunction as pn, ResourceMetadata as pt, MiddlewareHandler as q, ResourceDefinition as qt, DataAdapter as r, OffsetPaginatedResult as rn, RateLimitConfig as rt, SchemaMetadata as s, QueryOptions as sn, RequestIdOptions as st, AdapterFactory as t, InferDoc as tn, PresetResult as tt, ActionEntry as u, WriteOptions as un, ResourceConfig as ut, ArcRequest as v, Transform as vn, RouteSchemaOptions as vt, ControllerQueryOptions as w, HookRegistration as wn, UserLike as wt, Authenticator as x, HookHandler as xn, TypedController as xt, AuthHelpers as y, DefineHookOptions as yn, ServiceContext as yt, InferDocType as z, ControllerLike as zt };
3357
+ export { PresetHook as $, DeleteResult as $t, FastifyRequestExtras as A, beforeCreate as An, BaseControllerOptions as At, IntrospectionData as B, IController as Bt, ControllerQueryOptions as C, HookPhase as Cn, UserLike as Ct, CrudSchemas as D, afterCreate as Dn, envelope as Dt, CrudRouterOptions as E, HookSystemOptions as En, ValidationResult$1 as Et, HealthCheck as F, AccessControl as Ft, MiddlewareConfig as G, ResourceRegistry as Gt, JWTPayload as H, IRequestContext as Ht, HealthOptions as I, AccessControlConfig as It, OpenApiSchemas as J, BulkWriteOperation as Jt, MiddlewareHandler as K, ResourceDefinition as Kt, InferAdapterDoc as L, ControllerHandler as Lt, FastifyWithDecorators as M, beforeUpdate as Mn, QueryResolverConfig as Mt, FieldRule as N, createHookSystem as Nn, BodySanitizer as Nt, EventDefinition as O, afterDelete as On, getUserId as Ot, GracefulShutdownOptions as P, defineHook as Pn, BodySanitizerConfig as Pt, PresetFunction as Q, DeleteOptions as Qt, InferDocType as R, ControllerLike as Rt, ConfigError as S, HookOperation as Sn, TypedResourceConfig as St, CrudRouteKey as T, HookSystem as Tn, ValidateOptions as Tt, JwtContext as U, RouteHandler as Ut, IntrospectionPluginOptions as V, IControllerResponse as Vt, LookupOption as W, RegisterOptions as Wt, ParsedQuery as X, CrudRepository as Xt, OwnershipCheck as Y, BulkWriteResult as Yt, PopulateOption as Z, DeleteManyResult as Zt, ArcRequest as _, PipelineStep as _n, RouteSchemaOptions as _t, RelationMetadata as a, PaginationParams as an, RequestContext as at, Authenticator as b, HookContext as bn, TypedController as bt, ValidationResult as c, RepositorySession as cn, ResourceCacheConfig as ct, ActionHandlerFn as d, Guard as dn, ResourceHooks as dt, FindOneAndUpdateOptions as en, PresetResult as et, ActionsMap as f, Interceptor as fn, ResourceMetadata as ft, ArcInternalMetadata as g, PipelineContext as gn, RouteMcpConfig as gt, ArcDecorator as h, PipelineConfig as hn, RouteHandlerMethod$1 as ht, FieldMetadata as i, PaginatedResult as in, RegistryStats as it, FastifyWithAuth as j, beforeDelete as jn, QueryResolver as jt, EventsDecorator as k, afterUpdate as kn, BaseController as kt, ActionDefinition as l, UpdateManyResult as ln, ResourceConfig as lt, ApiResponse as m, OperationFilter as mn, RouteDefinition as mt, AdapterSchemaContext as n, KeysetPaginatedResult as nn, RateLimitConfig as nt, RepositoryLike as o, PaginationResult as on, RequestIdOptions as ot, AnyRecord as p, NextFunction as pn, ResourcePermissions as pt, ObjectId as q, defineResource as qt, DataAdapter as r, OffsetPaginatedResult as rn, RegistryEntry as rt, SchemaMetadata as s, QueryOptions as sn, RequestWithExtras as st, AdapterFactory as t, InferDoc as tn, QueryParserInterface as tt, ActionEntry as u, WriteOptions as un, ResourceHookContext as ut, AuthHelpers as v, Transform as vn, ServiceContext as vt, CrudController as w, HookRegistration as wn, UserOrganization as wt, AuthenticatorContext as x, HookHandler as xn, TypedRepository as xt, AuthPluginOptions as y, DefineHookOptions as yn, TokenPair as yt, InferResourceDoc as z, FastifyHandler as zt };