@classytic/arc 2.6.3 → 2.7.3

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 (143) hide show
  1. package/README.md +98 -3
  2. package/dist/{BaseController-DzRtluEF.mjs → BaseController-CpMfCXdn.mjs} +134 -16
  3. package/dist/adapters/index.d.mts +2 -2
  4. package/dist/adapters/index.mjs +1 -1
  5. package/dist/{adapters-gM-WYjNe.mjs → adapters-BxGgSHjj.mjs} +1 -9
  6. package/dist/applyPermissionResult-D6GPMsvh.mjs +37 -0
  7. package/dist/audit/index.d.mts +1 -1
  8. package/dist/audit/index.mjs +1 -1
  9. package/dist/audit/mongodb.d.mts +1 -1
  10. package/dist/audit/mongodb.mjs +1 -1
  11. package/dist/auth/index.d.mts +4 -4
  12. package/dist/auth/index.mjs +7 -6
  13. package/dist/auth/mongoose.d.mts +191 -0
  14. package/dist/auth/mongoose.mjs +73 -0
  15. package/dist/auth/redis-session.d.mts +1 -1
  16. package/dist/{betterAuthOpenApi-lz0IRbXJ.mjs → betterAuthOpenApi-CCw3YX0g.mjs} +1 -1
  17. package/dist/cache/index.d.mts +2 -2
  18. package/dist/cache/index.mjs +2 -2
  19. package/dist/cli/commands/docs.mjs +2 -2
  20. package/dist/cli/commands/generate.mjs +1 -1
  21. package/dist/cli/commands/init.mjs +7 -5
  22. package/dist/cli/commands/introspect.mjs +1 -1
  23. package/dist/core/index.d.mts +3 -3
  24. package/dist/core/index.mjs +4 -4
  25. package/dist/{core-C1XCMtqM.mjs → core-BWekSEju.mjs} +41 -13
  26. package/dist/{createApp-D2w0LdYJ.mjs → createApp-D7e77m8C.mjs} +25 -14
  27. package/dist/{defineResource-wWMBB4GP.mjs → defineResource-DZzyl4a4.mjs} +42 -37
  28. package/dist/docs/index.d.mts +2 -2
  29. package/dist/docs/index.mjs +1 -1
  30. package/dist/dynamic/index.d.mts +2 -2
  31. package/dist/dynamic/index.mjs +2 -2
  32. package/dist/{elevation-BEdACOLB.mjs → elevation-By_p2lnn.mjs} +1 -1
  33. package/dist/elevation-D7WK0RXq.d.mts +23 -0
  34. package/dist/{errorHandler-r2595m8T.mjs → errorHandler-CH8wk1eD.mjs} +17 -2
  35. package/dist/{errorHandler-Do4vVQ1f.d.mts → errorHandler-pCpEtNd7.d.mts} +46 -2
  36. package/dist/{eventPlugin-Ba00swHF.mjs → eventPlugin-B6U_nCFU.mjs} +4 -3
  37. package/dist/{eventPlugin-DW45v4V5.d.mts → eventPlugin-CdvUoUna.d.mts} +1 -1
  38. package/dist/events/index.d.mts +3 -3
  39. package/dist/events/index.mjs +1 -1
  40. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  41. package/dist/events/transports/redis.d.mts +1 -1
  42. package/dist/factory/index.d.mts +1 -1
  43. package/dist/factory/index.mjs +1 -1
  44. package/dist/hooks/index.d.mts +1 -1
  45. package/dist/hooks/index.mjs +1 -1
  46. package/dist/idempotency/index.d.mts +3 -3
  47. package/dist/idempotency/mongodb.d.mts +1 -1
  48. package/dist/idempotency/redis.d.mts +1 -1
  49. package/dist/index-B0extFr4.d.mts +640 -0
  50. package/dist/{index-gz6iuzCp.d.mts → index-BjShrzoj.d.mts} +47 -4
  51. package/dist/{index-CHeJa4Zd.d.mts → index-C9eYNjGR.d.mts} +1 -1
  52. package/dist/index.d.mts +9 -8
  53. package/dist/index.mjs +10 -9
  54. package/dist/integrations/event-gateway.d.mts +1 -1
  55. package/dist/integrations/event-gateway.mjs +1 -1
  56. package/dist/integrations/index.d.mts +1 -1
  57. package/dist/integrations/mcp/index.d.mts +2 -2
  58. package/dist/integrations/mcp/index.mjs +8 -5
  59. package/dist/integrations/mcp/testing.d.mts +1 -1
  60. package/dist/integrations/mcp/testing.mjs +1 -1
  61. package/dist/integrations/webhooks.d.mts +58 -1
  62. package/dist/integrations/webhooks.mjs +78 -7
  63. package/dist/integrations/websocket.d.mts +7 -1
  64. package/dist/integrations/websocket.mjs +7 -1
  65. package/dist/{interface-DYH8AXGe.d.mts → interface-B91alUzq.d.mts} +151 -15
  66. package/dist/{mongodb-pMvOlR5_.d.mts → mongodb-B7zupyck.d.mts} +1 -1
  67. package/dist/{mongodb-kltrBPa1.d.mts → mongodb-Cgu9F1Nd.d.mts} +1 -1
  68. package/dist/{openapi-CBmZ6EQN.mjs → openapi-BBSTVcMm.mjs} +1 -1
  69. package/dist/org/index.d.mts +2 -2
  70. package/dist/org/index.mjs +1 -1
  71. package/dist/permissions/index.d.mts +4 -4
  72. package/dist/permissions/index.mjs +3 -2
  73. package/dist/{permissions-C8ImI8gC.mjs → permissions-CH4cNwJi.mjs} +358 -64
  74. package/dist/plugins/index.d.mts +52 -5
  75. package/dist/plugins/index.mjs +12 -11
  76. package/dist/plugins/response-cache.mjs +1 -1
  77. package/dist/plugins/tracing-entry.d.mts +1 -1
  78. package/dist/plugins/tracing-entry.mjs +1 -1
  79. package/dist/policies/index.d.mts +1 -1
  80. package/dist/presets/index.d.mts +3 -3
  81. package/dist/presets/index.mjs +1 -1
  82. package/dist/presets/multiTenant.d.mts +53 -3
  83. package/dist/presets/multiTenant.mjs +89 -47
  84. package/dist/{presets-BMfdy34e.mjs → presets-BFrGvvjL.mjs} +2 -2
  85. package/dist/{queryCachePlugin-DcmETvcB.d.mts → queryCachePlugin-Ckl71mkc.d.mts} +1 -1
  86. package/dist/{queryCachePlugin-XtFplYO9.mjs → queryCachePlugin-CwTpR04-.mjs} +2 -2
  87. package/dist/{redis-D0Qc-9EW.d.mts → redis-3TQxm2VZ.d.mts} +1 -1
  88. package/dist/{redis-stream-BW9UKLZM.d.mts → redis-stream-Dag5LFa9.d.mts} +1 -1
  89. package/dist/registry/index.d.mts +1 -1
  90. package/dist/registry/index.mjs +2 -2
  91. package/dist/replyHelpers-uDUIYh7u.mjs +40 -0
  92. package/dist/{resourceToTools-nCJWnG1r.mjs → resourceToTools-BJkoQoUP.mjs} +74 -25
  93. package/dist/rpc/index.d.mts +1 -1
  94. package/dist/rpc/index.mjs +1 -1
  95. package/dist/scope/index.d.mts +3 -2
  96. package/dist/scope/index.mjs +4 -3
  97. package/dist/{sse-BF7GR7IB.mjs → sse-6W0hjVS_.mjs} +2 -2
  98. package/dist/testing/index.d.mts +2 -2
  99. package/dist/testing/index.mjs +1 -1
  100. package/dist/types/index.d.mts +4 -3
  101. package/dist/types/index.mjs +1 -1
  102. package/dist/types--D3vvfdt.d.mts +286 -0
  103. package/dist/{types-By-5mIfn.d.mts → types-2FlNl0mL.d.mts} +44 -9
  104. package/dist/types-AOD8fxIw.mjs +229 -0
  105. package/dist/types-B4BNthET.d.mts +178 -0
  106. package/dist/{types-B4_TDdPe.d.mts → types-C5g2oRC7.d.mts} +18 -2
  107. package/dist/utils/index.d.mts +3 -3
  108. package/dist/utils/index.mjs +5 -5
  109. package/package.json +21 -6
  110. package/skills/arc/SKILL.md +314 -6
  111. package/skills/arc/references/integrations.md +32 -7
  112. package/skills/arc/references/mcp.md +31 -7
  113. package/skills/arc/references/multi-tenancy.md +208 -0
  114. package/skills/arc/references/production.md +69 -0
  115. package/dist/elevation-C_taLQrM.d.mts +0 -147
  116. package/dist/index-NGZksqM5.d.mts +0 -398
  117. package/dist/types-BNUccdcf.d.mts +0 -101
  118. package/dist/types-BhtYdxZU.mjs +0 -91
  119. /package/dist/{EventTransport-wc5hSLik.d.mts → EventTransport-C4VheKeC.d.mts} +0 -0
  120. /package/dist/{HookSystem-COkyWztM.mjs → HookSystem-D7lfx--K.mjs} +0 -0
  121. /package/dist/{ResourceRegistry-C6ngvOnn.mjs → ResourceRegistry-DsHiG9cL.mjs} +0 -0
  122. /package/dist/{caching-BSXB-Xr7.mjs → caching-5DtLwIqb.mjs} +0 -0
  123. /package/dist/{circuitBreaker-JP2GdJ4b.d.mts → circuitBreaker-BBPDt-J_.d.mts} +0 -0
  124. /package/dist/{circuitBreaker-BOBOpN2w.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
  125. /package/dist/{errors-CcVbl1-T.d.mts → errors-BS6lZvWy.d.mts} +0 -0
  126. /package/dist/{errors-NoQKsbAT.mjs → errors-Cg58SLNi.mjs} +0 -0
  127. /package/dist/{externalPaths-DpO-s7r8.d.mts → externalPaths-iba7jD3d.d.mts} +0 -0
  128. /package/dist/{fields-DFwdaWCq.d.mts → fields-D4nMDqnK.d.mts} +0 -0
  129. /package/dist/{interface-D_BWALyZ.d.mts → interface-CG7oRZjX.d.mts} +0 -0
  130. /package/dist/{interface-gr-7qo9j.d.mts → interface-CSbZdv_3.d.mts} +0 -0
  131. /package/dist/{logger-Dz3j1ItV.mjs → logger-DLg8-Ueg.mjs} +0 -0
  132. /package/dist/{memory-BFAYkf8H.mjs → memory-Cp7_cAko.mjs} +0 -0
  133. /package/dist/{metrics-Csh4nsvv.mjs → metrics-Qnvwc-LQ.mjs} +0 -0
  134. /package/dist/{mongodb-BuQ7fNTg.mjs → mongodb-B7X7P1P8.mjs} +0 -0
  135. /package/dist/{pluralize-CcT6qF0a.mjs → pluralize-Dckfq6US.mjs} +0 -0
  136. /package/dist/{registry-I-ogLgL9.mjs → registry-B3lRFBWo.mjs} +0 -0
  137. /package/dist/{requestContext-DYtmNpm5.mjs → requestContext-xHIKedG6.mjs} +0 -0
  138. /package/dist/{schemaConverter-DjzHpFam.mjs → schemaConverter-0TyONAwM.mjs} +0 -0
  139. /package/dist/{sessionManager-wbkYj2HL.d.mts → sessionManager-CEo9jwPI.d.mts} +0 -0
  140. /package/dist/{tracing-bz_U4EM1.d.mts → tracing-DEqdGkr-.d.mts} +0 -0
  141. /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
  142. /package/dist/{utils-Dc0WhlIl.mjs → utils-B-l6410F.mjs} +0 -0
  143. /package/dist/{versioning-BzfeHmhj.mjs → versioning-CdBbFefk.mjs} +0 -0
@@ -1,6 +1,6 @@
1
- import { s as RequestScope } from "./elevation-C_taLQrM.mjs";
2
- import { n as FieldPermissionMap } from "./fields-DFwdaWCq.mjs";
3
- import { i as UserBase, t as PermissionCheck } from "./types-BNUccdcf.mjs";
1
+ import { r as RequestScope } from "./types--D3vvfdt.mjs";
2
+ import { n as FieldPermissionMap } from "./fields-D4nMDqnK.mjs";
3
+ import { i as UserBase, t as PermissionCheck } from "./types-B4BNthET.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
@@ -618,17 +618,54 @@ interface ServerAccessor {
618
618
  };
619
619
  }
620
620
  /**
621
- * Request context passed to controller handlers
621
+ * Request context passed to controller handlers.
622
+ *
623
+ * **Generic parameters** (all default to safe permissive types so existing code keeps working):
624
+ * - `TBody` — request body shape (default: `unknown`)
625
+ * - `TParams` — route param shape (default: `Record<string, string>`)
626
+ * - `TQuery` — query string shape (default: `Record<string, unknown>`)
627
+ * - `TUser` — authenticated user shape (default: `UserBase`)
628
+ * - `TMetadata` — internal metadata shape (default: `Record<string, unknown>`;
629
+ * override with `ArcInternalMetadata` or your own augmentation when you
630
+ * need typed access to `_scope`, `_policyFilters`, custom hook context, etc.)
631
+ *
632
+ * @example
633
+ * ```typescript
634
+ * // Untyped (default) — req.body is `unknown`, must be narrowed
635
+ * async create(req: IRequestContext) {
636
+ * const data = req.body as Partial<Product>;
637
+ * return { success: true, data: await productRepo.create(data) };
638
+ * }
639
+ *
640
+ * // Typed body — req.body is `CreateProductInput`, narrowing not needed
641
+ * async create(req: IRequestContext<CreateProductInput>) {
642
+ * return { success: true, data: await productRepo.create(req.body) };
643
+ * }
644
+ *
645
+ * // Fully typed — body, route params, query, and metadata
646
+ * async update(
647
+ * req: IRequestContext<
648
+ * Partial<Product>,
649
+ * { id: string },
650
+ * { fields?: string },
651
+ * ArcInternalMetadata
652
+ * >,
653
+ * ) {
654
+ * const fields = req.query.fields?.split(',');
655
+ * const orgId = req.metadata?._scope ? getOrgId(req.metadata._scope) : undefined;
656
+ * return { success: true, data: await productRepo.update(req.params.id, req.body) };
657
+ * }
658
+ * ```
622
659
  */
623
- interface IRequestContext {
660
+ interface IRequestContext<TBody = unknown, TParams extends Record<string, string> = Record<string, string>, TQuery extends Record<string, unknown> = Record<string, unknown>, TUser extends UserBase = UserBase, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
624
661
  /** Route parameters (e.g., { id: '123' }) */
625
- params: Record<string, string>;
662
+ params: TParams;
626
663
  /** Query string parameters */
627
- query: Record<string, unknown>;
664
+ query: TQuery;
628
665
  /** Request body */
629
- body: unknown;
666
+ body: TBody;
630
667
  /** Authenticated user or null */
631
- user: UserBase | null;
668
+ user: TUser | null;
632
669
  /** Request headers */
633
670
  headers: Record<string, string | undefined>;
634
671
  /** Organization ID (for multi-tenant apps) */
@@ -649,8 +686,12 @@ interface IRequestContext {
649
686
  * ```
650
687
  */
651
688
  context?: RequestContext;
652
- /** Internal metadata (includes context + Arc internals like _policyFilters, log) */
653
- metadata?: Record<string, unknown>;
689
+ /**
690
+ * Internal metadata (includes context + Arc internals like `_policyFilters`,
691
+ * `_scope`, `log`). Type as `ArcInternalMetadata` for typed access to Arc's
692
+ * built-in fields, or supply your own interface to layer custom fields.
693
+ */
694
+ metadata?: TMetadata;
654
695
  /**
655
696
  * Fastify server accessor — publish events, log, and audit
656
697
  * from any handler without switching to `wrapHandler: false`.
@@ -686,18 +727,41 @@ interface IControllerResponse<T = unknown> {
686
727
  headers?: Record<string, string>;
687
728
  }
688
729
  /**
689
- * Controller handler - Arc's standard pattern
730
+ * Controller handler Arc's standard pattern.
690
731
  *
691
732
  * Receives a request context object, returns IControllerResponse.
692
733
  * Use with `wrapHandler: true` in additionalRoutes.
693
734
  *
735
+ * **Generic parameters:**
736
+ * - `TResponse` — shape of `IControllerResponse.data` (default: `unknown`)
737
+ * - `TBody` — shape of `req.body` (default: `unknown`)
738
+ * - `TParams` — shape of `req.params` (default: `Record<string, string>`)
739
+ * - `TQuery` — shape of `req.query` (default: `Record<string, unknown>`)
740
+ *
741
+ * Backward-compatible: `ControllerHandler<Product>` still works (only the
742
+ * response data is typed); add more generics as needed when you want
743
+ * type-safe access to the request body, params, or query string.
744
+ *
694
745
  * @example
695
746
  * ```typescript
747
+ * // Untyped req — body is unknown, must be narrowed
696
748
  * const createProduct: ControllerHandler<Product> = async (req) => {
697
- * const product = await productRepo.create(req.body);
749
+ * const product = await productRepo.create(req.body as Partial<Product>);
698
750
  * return { success: true, data: product, status: 201 };
699
751
  * };
700
752
  *
753
+ * // Fully typed — body, params, query, and response all inferred
754
+ * const updateProduct: ControllerHandler<
755
+ * Product,
756
+ * Partial<Product>,
757
+ * { id: string },
758
+ * { upsert?: string }
759
+ * > = async (req) => {
760
+ * const upsert = req.query.upsert === "true";
761
+ * const product = await productRepo.update(req.params.id, req.body, { upsert });
762
+ * return { success: true, data: product };
763
+ * };
764
+ *
701
765
  * additionalRoutes: [{
702
766
  * method: 'POST',
703
767
  * path: '/products',
@@ -707,7 +771,7 @@ interface IControllerResponse<T = unknown> {
707
771
  * }]
708
772
  * ```
709
773
  */
710
- type ControllerHandler<T = unknown> = (req: IRequestContext) => Promise<IControllerResponse<T>>;
774
+ type ControllerHandler<TResponse = unknown, TBody = unknown, TParams extends Record<string, string> = Record<string, string>, TQuery extends Record<string, unknown> = Record<string, unknown>> = (req: IRequestContext<TBody, TParams, TQuery>) => Promise<IControllerResponse<TResponse>>;
711
775
  /**
712
776
  * Fastify native handler
713
777
  *
@@ -731,7 +795,7 @@ type ControllerHandler<T = unknown> = (req: IRequestContext) => Promise<IControl
731
795
  * }]
732
796
  * ```
733
797
  */
734
- type FastifyHandler = (request: FastifyRequest, reply: FastifyReply) => Promise<void> | void;
798
+ type FastifyHandler<RouteGeneric extends Record<string, unknown> = Record<string, unknown>> = (request: FastifyRequest<RouteGeneric>, reply: FastifyReply) => Promise<unknown> | unknown;
735
799
  /**
736
800
  * Union type for route handlers
737
801
  */
@@ -951,6 +1015,14 @@ interface BaseControllerOptions {
951
1015
  tenantField?: string | false;
952
1016
  /**
953
1017
  * Primary key field name (default: '_id').
1018
+ *
1019
+ * If not set, the controller auto-derives it from the repository's own
1020
+ * `idField` property (e.g. MongoKit's `Repository({ idField: 'id' })`),
1021
+ * so you only need to configure it in one place.
1022
+ *
1023
+ * Set explicitly to override the repo's setting (e.g. `'_id'` to opt out
1024
+ * of native pass-through and force the slug-translation path).
1025
+ *
954
1026
  * Override for non-MongoDB adapters (e.g., 'id' for SQL databases).
955
1027
  */
956
1028
  idField?: string;
@@ -1010,6 +1082,23 @@ declare class BaseController<TDoc = AnyRecord, TRepository extends RepositoryLik
1010
1082
  private meta;
1011
1083
  /** Get hook system from request context (instance-scoped) */
1012
1084
  private getHooks;
1085
+ /**
1086
+ * Resolve the repository primary key for mutation calls (update/delete/restore).
1087
+ *
1088
+ * When the resource declares a custom `idField` (e.g. `slug`, `jobId`, UUID),
1089
+ * the default behavior is to translate the route id → the fetched doc's `_id`
1090
+ * because most Mongo repositories key their mutation methods off `_id`.
1091
+ *
1092
+ * Exception: if the repository itself exposes a matching `idField` property
1093
+ * (e.g. MongoKit's `new Repository(Model, [], {}, { idField: 'id' })`), the
1094
+ * repository already knows how to look up by that field — so we pass the
1095
+ * route id through unchanged and skip the translation.
1096
+ *
1097
+ * This makes `defineResource({ idField: 'id' })` work end-to-end with repos
1098
+ * that natively support custom primary keys, without breaking the slug-style
1099
+ * aliasing that Arc 2.6.3 introduced for repos keyed on `_id`.
1100
+ */
1101
+ private resolveRepoId;
1013
1102
  /** Resolve cache config for a specific operation, merging per-op overrides */
1014
1103
  private resolveCacheConfig;
1015
1104
  /**
@@ -1056,10 +1145,43 @@ declare class BaseController<TDoc = AnyRecord, TRepository extends RepositoryLik
1056
1145
  * Returns the merged filter, or `null` when access must be denied.
1057
1146
  */
1058
1147
  private buildBulkFilter;
1148
+ /**
1149
+ * Sanitize a bulk update data payload through the same write-permission
1150
+ * pipeline as single-doc update(). Handles both shapes:
1151
+ *
1152
+ * - Flat: `{ name: 'x', status: 'y' }`
1153
+ * - Mongo operator: `{ $set: { name: 'x' }, $inc: { views: 1 }, $unset: { tag: '' } }`
1154
+ *
1155
+ * For each operand, runs `bodySanitizer.sanitize('update', ...)` so that
1156
+ * system fields, systemManaged/readonly/immutable rules, AND field-level
1157
+ * write permissions are enforced. Without this, a tenant-scoped user could
1158
+ * pass `{ $set: { organizationId: 'org-b' } }` to move records across orgs.
1159
+ *
1160
+ * Returns the sanitized payload along with the list of stripped fields for
1161
+ * audit/error reporting.
1162
+ */
1163
+ private sanitizeBulkUpdateData;
1059
1164
  bulkUpdate(req: IRequestContext): Promise<IControllerResponse<{
1060
1165
  matchedCount: number;
1061
1166
  modifiedCount: number;
1062
1167
  }>>;
1168
+ /**
1169
+ * Bulk delete by `filter` or `ids`.
1170
+ *
1171
+ * Body shape (one of):
1172
+ * - `{ filter: { status: 'archived' } }` — delete by query filter
1173
+ * - `{ ids: ['id1', 'id2', 'id3'] }` — delete specific docs by id
1174
+ *
1175
+ * The `ids` form translates to `{ [idField]: { $in: ids } }` using the
1176
+ * resource's `idField` (so it works with custom PKs like `slug`, `jobId`,
1177
+ * UUID, etc.). Tenant scope and policy filters are merged in either way,
1178
+ * so cross-tenant deletes are blocked at the controller layer.
1179
+ *
1180
+ * Both forms perform a single `repo.deleteMany()` DB call — no per-doc
1181
+ * fetch loop. Per-doc lifecycle hooks (`before:delete`/`after:delete`) do
1182
+ * NOT fire for bulk operations; use the single-doc `delete()` if you need
1183
+ * them, or subscribe to the bulk lifecycle event from the events plugin.
1184
+ */
1063
1185
  bulkDelete(req: IRequestContext): Promise<IControllerResponse<{
1064
1186
  deletedCount: number;
1065
1187
  }>>;
@@ -2369,6 +2491,20 @@ interface RepositoryLike {
2369
2491
  create(data: unknown, options?: unknown): Promise<unknown>;
2370
2492
  update(id: string, data: unknown, options?: unknown): Promise<unknown>;
2371
2493
  delete(id: string, options?: unknown): Promise<unknown>;
2494
+ /**
2495
+ * The repository's native primary key field. When set, Arc's BaseController
2496
+ * will pass route params through to `update()`/`delete()`/`restore()` calls
2497
+ * unchanged instead of translating them to `_id`.
2498
+ *
2499
+ * Set this to match your `defineResource({ idField })` for repositories that
2500
+ * natively look up by a custom field (e.g. MongoKit's
2501
+ * `new Repository(Model, [], {}, { idField: 'id' })`). Without it, Arc will
2502
+ * try to translate route ids → fetched doc's `_id` which 404s on repos that
2503
+ * don't key on `_id`.
2504
+ *
2505
+ * Defaults to `'_id'` (Mongo). Repositories that always use `_id` may omit it.
2506
+ */
2507
+ readonly idField?: string;
2372
2508
  /** Find single doc by compound filter — used by AccessControl for idField + org/policy scoping.
2373
2509
  * Without this, Arc falls back to getById + post-fetch security checks. */
2374
2510
  getOne?(filter: Record<string, unknown>, options?: unknown): Promise<unknown>;
@@ -1,4 +1,4 @@
1
- import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-gr-7qo9j.mjs";
1
+ import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CSbZdv_3.mjs";
2
2
 
3
3
  //#region src/idempotency/stores/mongodb.d.ts
4
4
  interface MongoConnection {
@@ -1,4 +1,4 @@
1
- import { i as UserBase } from "./types-BNUccdcf.mjs";
1
+ import { i as UserBase } from "./types-B4BNthET.mjs";
2
2
 
3
3
  //#region src/audit/stores/interface.d.ts
4
4
  type AuditAction = "create" | "update" | "delete" | "restore" | "custom";
@@ -1,5 +1,5 @@
1
1
  import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
2
- import { n as convertRouteSchema } from "./schemaConverter-DjzHpFam.mjs";
2
+ import { n as convertRouteSchema } from "./schemaConverter-0TyONAwM.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/docs/openapi.ts
5
5
  const openApiPlugin = async (fastify, opts = {}) => {
@@ -1,5 +1,5 @@
1
- import { Rt as RouteHandler } from "../interface-DYH8AXGe.mjs";
2
- import { i as UserBase } from "../types-BNUccdcf.mjs";
1
+ import { Rt as RouteHandler } from "../interface-B91alUzq.mjs";
2
+ import { i as UserBase } from "../types-B4BNthET.mjs";
3
3
  import { InvitationAdapter, InvitationDoc, MemberDoc, OrgAdapter, OrgDoc, OrgPermissionStatement, OrgRole, OrganizationPluginOptions } from "./types.mjs";
4
4
  import { FastifyPluginAsync, RouteHandlerMethod } from "fastify";
5
5
 
@@ -1,4 +1,4 @@
1
- import { a as getOrgRoles, d as isElevated, f as isMember, l as hasOrgAccess, n as PUBLIC_SCOPE } from "../types-BhtYdxZU.mjs";
1
+ import { _ as isElevated, h as hasOrgAccess, n as PUBLIC_SCOPE, s as getOrgRoles, v as isMember } from "../types-AOD8fxIw.mjs";
2
2
  import fp from "fastify-plugin";
3
3
  //#region src/org/organizationPlugin.ts
4
4
  const DEFAULT_ROLES = [
@@ -1,4 +1,4 @@
1
- import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission } from "../fields-DFwdaWCq.mjs";
2
- import { a as getUserRoles, i as UserBase, n as PermissionContext, o as normalizeRoles, r as PermissionResult, t as PermissionCheck } from "../types-BNUccdcf.mjs";
3
- import { C as presets_d_exports, D as RoleHierarchy, E as readOnly, O as createRoleHierarchy, S as ownerWithAdminBypass, T as publicReadAdminWrite, _ as roles, a as allOf, b as authenticated, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgMembership, g as requireTeamMembership, h as requireRoles, i as PermissionEventBus, l as createOrgPermissions, m as requireOwnership, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgRole, r as DynamicPermissionMatrixConfig, s as anyOf, t as ConnectEventsOptions, u as denyAll, v as when, w as publicRead, x as fullPublic, y as adminOnly } from "../index-NGZksqM5.mjs";
4
- export { ConnectEventsOptions, DynamicPermissionMatrix, DynamicPermissionMatrixConfig, FieldPermission, FieldPermissionMap, FieldPermissionType, PermissionCheck, PermissionContext, PermissionEventBus, PermissionResult, RoleHierarchy, UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizeRoles, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireTeamMembership, resolveEffectiveRoles, roles, when };
1
+ import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission } from "../fields-D4nMDqnK.mjs";
2
+ import { a as getUserRoles, i as UserBase, n as PermissionContext, o as normalizeRoles, r as PermissionResult, t as PermissionCheck } from "../types-B4BNthET.mjs";
3
+ import { A as RoleHierarchy, C as authenticated, D as publicRead, E as presets_d_exports, M as applyPermissionResult, N as normalizePermissionResult, O as publicReadAdminWrite, S as adminOnly, T as ownerWithAdminBypass, _ as requireScopeContext, a as allOf, b as roles, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgInScope, g as requireRoles, h as requireOwnership, i as PermissionEventBus, j as createRoleHierarchy, k as readOnly, l as createOrgPermissions, m as requireOrgRole, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgMembership, r as DynamicPermissionMatrixConfig, s as anyOf, t as ConnectEventsOptions, u as denyAll, v as requireServiceScope, w as fullPublic, x as when, y as requireTeamMembership } from "../index-B0extFr4.mjs";
4
+ export { ConnectEventsOptions, DynamicPermissionMatrix, DynamicPermissionMatrixConfig, FieldPermission, FieldPermissionMap, FieldPermissionType, PermissionCheck, PermissionContext, PermissionEventBus, PermissionResult, RoleHierarchy, UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
@@ -1,4 +1,5 @@
1
1
  import { i as resolveEffectiveRoles, n as applyFieldWritePermissions, r as fields, t as applyFieldReadPermissions } from "../fields-ipsbIRPK.mjs";
2
2
  import { n as normalizeRoles, t as getUserRoles } from "../types-ZUu_h0jp.mjs";
3
- import { C as createRoleHierarchy, S as readOnly, _ as fullPublic, a as createOrgPermissions, b as publicRead, c as requireOrgMembership, d as requireRoles, f as requireTeamMembership, g as authenticated, h as adminOnly, i as createDynamicPermissionMatrix, l as requireOrgRole, m as when, n as allowPublic, o as denyAll, p as roles, r as anyOf, s as requireAuth, t as allOf, u as requireOwnership, v as ownerWithAdminBypass, x as publicReadAdminWrite, y as presets_exports } from "../permissions-C8ImI8gC.mjs";
4
- export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizeRoles, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireTeamMembership, resolveEffectiveRoles, roles, when };
3
+ import { n as normalizePermissionResult, t as applyPermissionResult } from "../applyPermissionResult-D6GPMsvh.mjs";
4
+ import { C as publicRead, E as createRoleHierarchy, S as presets_exports, T as readOnly, _ as when, a as createOrgPermissions, b as fullPublic, c as requireOrgInScope, d as requireOwnership, f as requireRoles, g as roles, h as requireTeamMembership, i as createDynamicPermissionMatrix, l as requireOrgMembership, m as requireServiceScope, n as allowPublic, o as denyAll, p as requireScopeContext, r as anyOf, s as requireAuth, t as allOf, u as requireOrgRole, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "../permissions-CH4cNwJi.mjs";
5
+ export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };