@classytic/arc 2.8.5 → 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 (140) hide show
  1. package/README.md +88 -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 +16 -8
  8. package/dist/auth/index.mjs +13 -6
  9. package/dist/auth/redis-session.d.mts +1 -1
  10. package/dist/{betterAuthOpenApi-BuUcUEJq.mjs → betterAuthOpenApi--rdY15Ld.mjs} +1 -1
  11. package/dist/cache/index.d.mts +2 -2
  12. package/dist/cache/index.mjs +2 -2
  13. package/dist/cli/commands/docs.mjs +2 -2
  14. package/dist/cli/commands/introspect.mjs +1 -1
  15. package/dist/core/index.d.mts +3 -3
  16. package/dist/core/index.mjs +4 -5
  17. package/dist/{core-F0QoWBt2.mjs → core-DNncu0xF.mjs} +1 -1
  18. package/dist/{createActionRouter-BORM8f17.mjs → createActionRouter-DH1YFL9m.mjs} +3 -3
  19. package/dist/{createApp-B1EY8zxa.mjs → createApp-CBJUJKGP.mjs} +13 -12
  20. package/dist/{defineResource-tcgySDo1.mjs → defineResource-C__jkwvs.mjs} +22 -57
  21. package/dist/docs/index.d.mts +2 -2
  22. package/dist/docs/index.mjs +1 -1
  23. package/dist/dynamic/index.d.mts +1 -1
  24. package/dist/dynamic/index.mjs +3 -3
  25. package/dist/{elevation-DtFxrG0s.mjs → elevation-DxQ6ACbt.mjs} +21 -7
  26. package/dist/{errorHandler-f869_8PQ.mjs → errorHandler-CZDW4EXS.mjs} +59 -7
  27. package/dist/{errorHandler-Bah5JhBd.d.mts → errorHandler-DixGcttC.d.mts} +37 -2
  28. package/dist/{eventPlugin-D9DKB2zM.d.mts → eventPlugin-BxvaCIZF.d.mts} +14 -2
  29. package/dist/{eventPlugin-CDjVTM82.mjs → eventPlugin-Dl7MoVWH.mjs} +83 -5
  30. package/dist/events/index.d.mts +147 -36
  31. package/dist/events/index.mjs +338 -101
  32. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  33. package/dist/events/transports/redis.d.mts +1 -1
  34. package/dist/factory/index.d.mts +1 -1
  35. package/dist/factory/index.mjs +2 -2
  36. package/dist/{fields-DpZQa_Q3.d.mts → fields-BC7zcmI9.d.mts} +15 -3
  37. package/dist/{fields-ipsbIRPK.mjs → fields-CU6FlaDV.mjs} +18 -5
  38. package/dist/{filesUpload-C7r7HIeA.mjs → filesUpload-q8oHt--L.mjs} +65 -7
  39. package/dist/hooks/index.d.mts +1 -1
  40. package/dist/hooks/index.mjs +1 -1
  41. package/dist/idempotency/index.d.mts +29 -5
  42. package/dist/idempotency/index.mjs +111 -2
  43. package/dist/idempotency/redis.d.mts +1 -1
  44. package/dist/{index-BLXBmWud.d.mts → index-C-xjcA6F.d.mts} +1 -1
  45. package/dist/{index-DtDzOBn8.d.mts → index-Cibkchnx.d.mts} +3 -134
  46. package/dist/{index-C1meYuDn.d.mts → index-CtGKT0lf.d.mts} +1 -1
  47. package/dist/index.d.mts +7 -7
  48. package/dist/index.mjs +9 -9
  49. package/dist/integrations/event-gateway.d.mts +1 -1
  50. package/dist/integrations/event-gateway.mjs +1 -1
  51. package/dist/integrations/index.d.mts +1 -1
  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-CMRutPfe.d.mts → interface-YrWsmKqE.d.mts} +287 -179
  59. package/dist/{openapi-CbKUJY_m.mjs → openapi-CXuTG1M9.mjs} +2 -2
  60. package/dist/org/index.d.mts +1 -1
  61. package/dist/permissions/index.d.mts +2 -2
  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 +7 -7
  65. package/dist/plugins/index.mjs +11 -11
  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 +25 -32
  70. package/dist/presets/filesUpload.d.mts +26 -4
  71. package/dist/presets/filesUpload.mjs +1 -1
  72. package/dist/presets/index.d.mts +3 -2
  73. package/dist/presets/index.mjs +4 -3
  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-BJJGBTlu.d.mts → queryCachePlugin-CnTZZTC5.d.mts} +1 -1
  80. package/dist/{queryCachePlugin-BH-fidlv.mjs → queryCachePlugin-DbUVroUG.mjs} +2 -2
  81. package/dist/{redis-BM00zaPB.d.mts → redis-MXLp1oOf.d.mts} +1 -1
  82. package/dist/{redis-stream-CrsfUmPt.d.mts → redis-stream-Bz-4q96t.d.mts} +1 -1
  83. package/dist/registry/index.d.mts +1 -1
  84. package/dist/registry/index.mjs +2 -2
  85. package/dist/{resourceToTools-8s-EsCCe.mjs → resourceToTools-C3cWymnW.mjs} +64 -47
  86. package/dist/rpc/index.d.mts +1 -1
  87. package/dist/rpc/index.mjs +1 -1
  88. package/dist/{schemaConverter-Y7nCYaLJ.mjs → schemaConverter-BxFDdtXu.mjs} +1 -1
  89. package/dist/scope/index.mjs +1 -1
  90. package/dist/{sse-Ad7ypl9e.mjs → sse-CJpt7LGI.mjs} +1 -1
  91. package/dist/store-helpers-DFiZl5TL.mjs +57 -0
  92. package/dist/testing/index.d.mts +5 -14
  93. package/dist/testing/index.mjs +21 -75
  94. package/dist/testing/storageContract.d.mts +1 -1
  95. package/dist/types/index.d.mts +2 -2
  96. package/dist/types/storage.d.mts +1 -1
  97. package/dist/{types-BsbNMEDR.d.mts → types-CoSzA-s-.d.mts} +1 -1
  98. package/dist/{types-Ch9pTQbf.d.mts → types-CunEX4UX.d.mts} +10 -8
  99. package/dist/utils/index.d.mts +4 -4
  100. package/dist/utils/index.mjs +6 -6
  101. package/dist/{utils-yYT3HDXt.mjs → utils-B7FuRr9w.mjs} +1 -1
  102. package/package.json +8 -11
  103. package/skills/arc/SKILL.md +92 -14
  104. package/skills/arc/references/auth.md +94 -0
  105. package/skills/arc/references/events.md +200 -12
  106. package/skills/arc/references/mcp.md +4 -17
  107. package/skills/arc/references/multi-tenancy.md +43 -0
  108. package/skills/arc/references/production.md +34 -19
  109. package/dist/EventTransport-BXja8NOc.d.mts +0 -135
  110. package/dist/audit/mongodb.d.mts +0 -2
  111. package/dist/audit/mongodb.mjs +0 -2
  112. package/dist/idempotency/mongodb.d.mts +0 -2
  113. package/dist/idempotency/mongodb.mjs +0 -123
  114. package/dist/mongodb-BsP-WbhN.d.mts +0 -127
  115. package/dist/mongodb-CTcp0hQZ.d.mts +0 -80
  116. package/dist/mongodb-Utc5k_-0.mjs +0 -90
  117. /package/dist/{HookSystem-HprTmvVY.mjs → HookSystem-BjFu7zf1.mjs} +0 -0
  118. /package/dist/{ResourceRegistry-C6uXlWe3.mjs → ResourceRegistry-Dq3_zBQP.mjs} +0 -0
  119. /package/dist/{applyPermissionResult-D6GPMsvh.mjs → applyPermissionResult-bqGpo9ML.mjs} +0 -0
  120. /package/dist/{caching-IMuYVjTL.mjs → caching-CjybdRwx.mjs} +0 -0
  121. /package/dist/{circuitBreaker-dTtG-UyS.d.mts → circuitBreaker-CvXkjfrW.d.mts} +0 -0
  122. /package/dist/{circuitBreaker-cmi5XDv5.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
  123. /package/dist/{errors-Ck2h67pm.d.mts → errors-BI8kEKsO.d.mts} +0 -0
  124. /package/dist/{errors-BF2bIOIS.mjs → errors-CqWnSqM-.mjs} +0 -0
  125. /package/dist/{externalPaths-BnkYrNzp.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
  126. /package/dist/{interface-DfLGcus7.d.mts → interface-B-pe8fhj.d.mts} +0 -0
  127. /package/dist/{interface-4y979v99.d.mts → interface-DplgQO2e.d.mts} +0 -0
  128. /package/dist/{loadResources-PWd0OCpV.mjs → loadResources-Bksk8ydA.mjs} +0 -0
  129. /package/dist/{logger-D1YrIImS.mjs → logger-CDjpjySd.mjs} +0 -0
  130. /package/dist/{memory-Cp7_cAko.mjs → memory-BFAYkf8H.mjs} +0 -0
  131. /package/dist/{metrics-B-PU4-Yu.mjs → metrics-TuOmguhi.mjs} +0 -0
  132. /package/dist/{queryParser-CgCtsjti.mjs → queryParser-Cs-6SHQK.mjs} +0 -0
  133. /package/dist/{registry-BiTKT1Dg.mjs → registry-B0Wl7uVV.mjs} +0 -0
  134. /package/dist/{replyHelpers-CxkYGT81.mjs → replyHelpers-BLojtuvR.mjs} +0 -0
  135. /package/dist/{requestContext-DYvHl113.mjs → requestContext-DYtmNpm5.mjs} +0 -0
  136. /package/dist/{sessionManager-DDCmiNIo.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
  137. /package/dist/{storage-Dfzt4VTl.d.mts → storage-BwGQXUpd.d.mts} +0 -0
  138. /package/dist/{tracing-DdN2-wHJ.d.mts → tracing-xqXzWeaf.d.mts} +0 -0
  139. /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-Cj5Rgvlg.mjs} +0 -0
  140. /package/dist/{versioning-CDugduqI.mjs → versioning-Cm8qoFDg.mjs} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { r as RequestScope } from "./types-BD85MlEK.mjs";
2
- import { n as FieldPermissionMap } from "./fields-DpZQa_Q3.mjs";
2
+ import { n as FieldPermissionMap } from "./fields-BC7zcmI9.mjs";
3
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
 
@@ -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
@@ -2891,6 +2904,23 @@ interface AuthPluginOptions {
2891
2904
  * ```
2892
2905
  */
2893
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;
2894
2924
  }
2895
2925
  interface IntrospectionPluginOptions {
2896
2926
  path?: string;
@@ -2909,8 +2939,8 @@ interface CrudRouterOptions {
2909
2939
  schemas?: Partial<CrudSchemas>;
2910
2940
  /** Middlewares for each CRUD operation */
2911
2941
  middlewares?: MiddlewareConfig;
2912
- /** Additional custom routes (from presets or user-defined) */
2913
- additionalRoutes?: AdditionalRoute[];
2942
+ /** Custom routes (from presets or user-defined) */
2943
+ routes?: readonly RouteDefinition[];
2914
2944
  /** Disable all default CRUD routes */
2915
2945
  disableDefaultRoutes?: boolean;
2916
2946
  /** Disable specific CRUD routes */
@@ -3095,6 +3125,29 @@ type TypedRepository<TDoc> = CrudRepository<TDoc>;
3095
3125
  *
3096
3126
  * See [CrudRepository](../types/repository.ts) for full prose-level docs
3097
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.
3098
3151
  */
3099
3152
  interface RepositoryLike {
3100
3153
  /**
@@ -3115,12 +3168,50 @@ interface RepositoryLike {
3115
3168
  getById(id: string, options?: QueryOptions): Promise<unknown>;
3116
3169
  create(data: unknown, options?: WriteOptions): Promise<unknown>;
3117
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>;
3118
3193
  /**
3119
3194
  * Delete by primary key. Pass `{ mode: 'hard' }` to bypass soft-delete
3120
3195
  * interception (required by arc's hard-delete flow — `?hard=true` on
3121
3196
  * the DELETE route forwards this option).
3122
3197
  */
3123
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;
3124
3215
  /**
3125
3216
  * Find a single doc by compound filter. Used by AccessControl for
3126
3217
  * `idField + org + policy` scoping. Without this, arc falls back to
@@ -3145,10 +3236,27 @@ interface RepositoryLike {
3145
3236
  getDeleted?(params?: PaginationParams, options?: QueryOptions): Promise<PaginationResult<unknown> | unknown[]>;
3146
3237
  aggregate?: unknown;
3147
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;
3148
3250
  withTransaction?<T>(callback: (session: RepositorySession) => Promise<T>, options?: Record<string, unknown>): Promise<T>;
3149
3251
  getBySlug?(slug: string, options?: QueryOptions): Promise<unknown>;
3150
3252
  getTree?(options?: QueryOptions): Promise<unknown>;
3151
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[]>;
3152
3260
  [key: string]: unknown;
3153
3261
  }
3154
3262
  interface DataAdapter<TDoc = unknown> {
@@ -3246,4 +3354,4 @@ interface ValidationResult {
3246
3354
  }
3247
3355
  type AdapterFactory<TDoc> = (config: unknown) => DataAdapter<TDoc>;
3248
3356
  //#endregion
3249
- 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 };
@@ -1,6 +1,6 @@
1
1
  import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
2
- import { n as convertRouteSchema } from "./schemaConverter-Y7nCYaLJ.mjs";
3
- import { t as buildActionBodySchema } from "./createActionRouter-BORM8f17.mjs";
2
+ import { n as convertRouteSchema } from "./schemaConverter-BxFDdtXu.mjs";
3
+ import { t as buildActionBodySchema } from "./createActionRouter-DH1YFL9m.mjs";
4
4
  import fp from "fastify-plugin";
5
5
  //#region src/docs/openapi.ts
6
6
  const openApiPlugin = async (fastify, opts = {}) => {
@@ -1,4 +1,4 @@
1
- import { Wt as RouteHandler } from "../interface-CMRutPfe.mjs";
1
+ import { Ut as RouteHandler } from "../interface-YrWsmKqE.mjs";
2
2
  import { i as UserBase } from "../types-DZi1aYhm.mjs";
3
3
  import { InvitationAdapter, InvitationDoc, MemberDoc, OrgAdapter, OrgDoc, OrgPermissionStatement, OrgRole, OrganizationPluginOptions } from "./types.mjs";
4
4
  import { FastifyPluginAsync, RouteHandlerMethod } from "fastify";