@classytic/arc 2.6.3 → 2.7.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 (135) hide show
  1. package/README.md +84 -1
  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-B_nvKNAQ.mjs} +11 -11
  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-Dm-HTBCt.d.mts +23 -0
  34. package/dist/{errorHandler-Do4vVQ1f.d.mts → errorHandler-COa51ho_.d.mts} +1 -1
  35. package/dist/{errorHandler-r2595m8T.mjs → errorHandler-DXUttWEO.mjs} +1 -1
  36. package/dist/{eventPlugin-DW45v4V5.d.mts → eventPlugin-BgLxJkIB.d.mts} +1 -1
  37. package/dist/{eventPlugin-Ba00swHF.mjs → eventPlugin-DsaNNXzZ.mjs} +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-BYpRGXif.d.mts +640 -0
  50. package/dist/{index-gz6iuzCp.d.mts → index-KXM8_JmQ.d.mts} +47 -4
  51. package/dist/{index-CHeJa4Zd.d.mts → index-StgFaQKD.d.mts} +1 -1
  52. package/dist/index.d.mts +8 -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 +1 -1
  59. package/dist/integrations/mcp/testing.d.mts +1 -1
  60. package/dist/integrations/mcp/testing.mjs +1 -1
  61. package/dist/{interface-DYH8AXGe.d.mts → interface-Dwzqt4mn.d.mts} +150 -14
  62. package/dist/{mongodb-pMvOlR5_.d.mts → mongodb-Bq90j-Uj.d.mts} +1 -1
  63. package/dist/{mongodb-kltrBPa1.d.mts → mongodb-DdyYlIXg.d.mts} +1 -1
  64. package/dist/{openapi-CBmZ6EQN.mjs → openapi-C5UhIeWu.mjs} +1 -1
  65. package/dist/org/index.d.mts +2 -2
  66. package/dist/org/index.mjs +1 -1
  67. package/dist/permissions/index.d.mts +4 -4
  68. package/dist/permissions/index.mjs +3 -2
  69. package/dist/{permissions-C8ImI8gC.mjs → permissions-CH4cNwJi.mjs} +358 -64
  70. package/dist/plugins/index.d.mts +4 -4
  71. package/dist/plugins/index.mjs +10 -10
  72. package/dist/plugins/response-cache.mjs +1 -1
  73. package/dist/plugins/tracing-entry.d.mts +1 -1
  74. package/dist/plugins/tracing-entry.mjs +1 -1
  75. package/dist/policies/index.d.mts +1 -1
  76. package/dist/presets/index.d.mts +3 -3
  77. package/dist/presets/index.mjs +1 -1
  78. package/dist/presets/multiTenant.d.mts +53 -3
  79. package/dist/presets/multiTenant.mjs +89 -47
  80. package/dist/{presets-BMfdy34e.mjs → presets-BFrGvvjL.mjs} +2 -2
  81. package/dist/{queryCachePlugin-DcmETvcB.d.mts → queryCachePlugin-Bw8XyJpX.d.mts} +1 -1
  82. package/dist/{queryCachePlugin-XtFplYO9.mjs → queryCachePlugin-CwTpR04-.mjs} +2 -2
  83. package/dist/{redis-D0Qc-9EW.d.mts → redis-CyCntzTO.d.mts} +1 -1
  84. package/dist/{redis-stream-BW9UKLZM.d.mts → redis-stream-We_Ucl9-.d.mts} +1 -1
  85. package/dist/registry/index.d.mts +1 -1
  86. package/dist/registry/index.mjs +2 -2
  87. package/dist/{resourceToTools-nCJWnG1r.mjs → resourceToTools-CkVSSzKg.mjs} +64 -21
  88. package/dist/rpc/index.d.mts +1 -1
  89. package/dist/rpc/index.mjs +1 -1
  90. package/dist/scope/index.d.mts +3 -2
  91. package/dist/scope/index.mjs +4 -3
  92. package/dist/{sse-BF7GR7IB.mjs → sse-Bp3dabF1.mjs} +2 -2
  93. package/dist/testing/index.d.mts +2 -2
  94. package/dist/testing/index.mjs +1 -1
  95. package/dist/types/index.d.mts +4 -3
  96. package/dist/types/index.mjs +1 -1
  97. package/dist/types-AOD8fxIw.mjs +229 -0
  98. package/dist/types-CNEbix8T.d.mts +286 -0
  99. package/dist/{types-B4_TDdPe.d.mts → types-ClmkMDK1.d.mts} +1 -1
  100. package/dist/{types-By-5mIfn.d.mts → types-D0qf0Mf4.d.mts} +9 -9
  101. package/dist/types-DPsC0taJ.d.mts +178 -0
  102. package/dist/utils/index.d.mts +3 -3
  103. package/dist/utils/index.mjs +5 -5
  104. package/package.json +17 -5
  105. package/skills/arc/SKILL.md +253 -6
  106. package/skills/arc/references/multi-tenancy.md +208 -0
  107. package/dist/elevation-C_taLQrM.d.mts +0 -147
  108. package/dist/index-NGZksqM5.d.mts +0 -398
  109. package/dist/types-BNUccdcf.d.mts +0 -101
  110. package/dist/types-BhtYdxZU.mjs +0 -91
  111. /package/dist/{EventTransport-wc5hSLik.d.mts → EventTransport-CUpRK_Lg.d.mts} +0 -0
  112. /package/dist/{HookSystem-COkyWztM.mjs → HookSystem-D7lfx--K.mjs} +0 -0
  113. /package/dist/{ResourceRegistry-C6ngvOnn.mjs → ResourceRegistry-DsHiG9cL.mjs} +0 -0
  114. /package/dist/{caching-BSXB-Xr7.mjs → caching-5DtLwIqb.mjs} +0 -0
  115. /package/dist/{circuitBreaker-JP2GdJ4b.d.mts → circuitBreaker-DwxrljLB.d.mts} +0 -0
  116. /package/dist/{circuitBreaker-BOBOpN2w.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
  117. /package/dist/{errors-CcVbl1-T.d.mts → errors-CCSsMpXE.d.mts} +0 -0
  118. /package/dist/{errors-NoQKsbAT.mjs → errors-Cg58SLNi.mjs} +0 -0
  119. /package/dist/{externalPaths-DpO-s7r8.d.mts → externalPaths-Dg7OLsKo.d.mts} +0 -0
  120. /package/dist/{fields-DFwdaWCq.d.mts → fields-CYuLMJPD.d.mts} +0 -0
  121. /package/dist/{interface-gr-7qo9j.d.mts → interface-B9rHWPxD.d.mts} +0 -0
  122. /package/dist/{interface-D_BWALyZ.d.mts → interface-CnluRL4_.d.mts} +0 -0
  123. /package/dist/{logger-Dz3j1ItV.mjs → logger-DLg8-Ueg.mjs} +0 -0
  124. /package/dist/{memory-BFAYkf8H.mjs → memory-Cp7_cAko.mjs} +0 -0
  125. /package/dist/{metrics-Csh4nsvv.mjs → metrics-Qnvwc-LQ.mjs} +0 -0
  126. /package/dist/{mongodb-BuQ7fNTg.mjs → mongodb-mlgxkYI3.mjs} +0 -0
  127. /package/dist/{pluralize-CcT6qF0a.mjs → pluralize-COpOVar8.mjs} +0 -0
  128. /package/dist/{registry-I-ogLgL9.mjs → registry-B3lRFBWo.mjs} +0 -0
  129. /package/dist/{requestContext-DYtmNpm5.mjs → requestContext-xHIKedG6.mjs} +0 -0
  130. /package/dist/{schemaConverter-DjzHpFam.mjs → schemaConverter-0TyONAwM.mjs} +0 -0
  131. /package/dist/{sessionManager-wbkYj2HL.d.mts → sessionManager-IW4sbIea.d.mts} +0 -0
  132. /package/dist/{tracing-bz_U4EM1.d.mts → tracing-65B51Dw3.d.mts} +0 -0
  133. /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
  134. /package/dist/{utils-Dc0WhlIl.mjs → utils-B-l6410F.mjs} +0 -0
  135. /package/dist/{versioning-BzfeHmhj.mjs → versioning-aUUVziBY.mjs} +0 -0
@@ -1,6 +1,6 @@
1
- import { s as RequestScope } from "./elevation-C_taLQrM.mjs";
2
- import { C as CrudRouterOptions, Ft as IController, It as IControllerResponse, Lt as IRequestContext, it as RequestWithExtras, k as FastifyWithDecorators, nt as RequestContext, x as CrudController } from "./interface-DYH8AXGe.mjs";
3
- import { t as PermissionCheck } from "./types-BNUccdcf.mjs";
1
+ import { r as RequestScope } from "./types-CNEbix8T.mjs";
2
+ import { C as CrudRouterOptions, Ft as IController, It as IControllerResponse, Lt as IRequestContext, Vt as ResourceDefinition, it as RequestWithExtras, k as FastifyWithDecorators, nt as RequestContext, ot as ResourceConfig, u as AnyRecord, x as CrudController } from "./interface-Dwzqt4mn.mjs";
3
+ import { t as PermissionCheck } from "./types-DPsC0taJ.mjs";
4
4
  import { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
5
5
 
6
6
  //#region src/constants.d.ts
@@ -144,6 +144,49 @@ declare function createCrudRouter<TDoc = unknown>(fastify: FastifyWithDecorators
144
144
  */
145
145
  declare function createPermissionMiddleware(permission: PermissionCheck, resourceName: string, action: string): RouteHandlerMethod | null;
146
146
  //#endregion
147
+ //#region src/core/defineResourceVariants.d.ts
148
+ /**
149
+ * Required identity fields for each variant. The user MUST provide a unique
150
+ * `name` (registry collision prevention) and a unique `prefix` (route
151
+ * collision prevention) for every variant.
152
+ */
153
+ type VariantIdentity = Required<Pick<ResourceConfig, "name" | "prefix">>;
154
+ /**
155
+ * A variant override = identity (name + prefix) + any other ResourceConfig
156
+ * field that should differ from the base.
157
+ */
158
+ type VariantOverride<TDoc = AnyRecord> = VariantIdentity & Partial<ResourceConfig<TDoc>>;
159
+ /**
160
+ * Map of variant key → override config. The key becomes the property name in
161
+ * the returned object (e.g. `{ articlePublic: ... }` → `result.articlePublic`).
162
+ */
163
+ type VariantsMap<TDoc = AnyRecord> = Record<string, VariantOverride<TDoc>>;
164
+ /**
165
+ * Result type — preserves the variant keys so destructuring is type-safe:
166
+ * `const { articlePublic, articleAdmin } = defineResourceVariants(...)`.
167
+ */
168
+ type VariantsResult<TDoc, V extends VariantsMap<TDoc>> = { [K in keyof V]: ResourceDefinition<TDoc> };
169
+ /**
170
+ * Define multiple resources from a shared base config and per-variant overrides.
171
+ *
172
+ * Each variant is independently passed through `defineResource()` — the
173
+ * returned `ResourceDefinition`s are real, fully-registered resources.
174
+ * Register each one's plugin in your app:
175
+ *
176
+ * ```typescript
177
+ * await app.register(articlePublic.toPlugin());
178
+ * await app.register(articleAdmin.toPlugin());
179
+ * ```
180
+ *
181
+ * @param base Shared config — adapter, queryParser, schemaOptions, hooks, etc.
182
+ * Must NOT include `name` or `prefix` (those are per-variant).
183
+ * @param variants Map of variant key → override. Each variant must declare
184
+ * its own `name` and `prefix`. Other fields override the base.
185
+ * @returns A record where each key from `variants` maps to a real
186
+ * `ResourceDefinition` ready for `.toPlugin()` registration.
187
+ */
188
+ declare function defineResourceVariants<TDoc = AnyRecord, V extends VariantsMap<TDoc> = VariantsMap<TDoc>>(base: Omit<ResourceConfig<TDoc>, "name" | "prefix">, variants: V): VariantsResult<TDoc, V>;
189
+ //#endregion
147
190
  //#region src/core/fastifyAdapter.d.ts
148
191
  /**
149
192
  * Create IRequestContext from Fastify request
@@ -212,4 +255,4 @@ declare function createCrudHandlers<TDoc>(controller: IController<TDoc>): {
212
255
  delete: (req: FastifyRequest, reply: FastifyReply) => Promise<void>;
213
256
  };
214
257
  //#endregion
215
- export { RESERVED_QUERY_PARAMS as A, HookOperation as C, MAX_SEARCH_LENGTH as D, MAX_REGEX_LENGTH as E, MUTATION_OPERATIONS as O, HOOK_PHASES as S, MAX_FILTER_DEPTH as T, DEFAULT_MAX_LIMIT as _, getControllerScope as a, DEFAULT_UPDATE_METHOD as b, createPermissionMiddleware as c, IdempotencyService as d, createActionRouter as f, DEFAULT_LIMIT as g, DEFAULT_ID_FIELD as h, getControllerContext as i, SYSTEM_FIELDS as j, MutationOperation as k, ActionHandler as l, CrudOperation as m, createFastifyHandler as n, sendControllerResponse as o, CRUD_OPERATIONS as p, createRequestContext as r, createCrudRouter as s, createCrudHandlers as t, ActionRouterConfig as u, DEFAULT_SORT as v, HookPhase as w, HOOK_OPERATIONS as x, DEFAULT_TENANT_FIELD as y };
258
+ export { MutationOperation as A, HOOK_PHASES as C, MAX_REGEX_LENGTH as D, MAX_FILTER_DEPTH as E, SYSTEM_FIELDS as M, MAX_SEARCH_LENGTH as O, HOOK_OPERATIONS as S, HookPhase as T, DEFAULT_LIMIT as _, getControllerScope as a, DEFAULT_TENANT_FIELD as b, createCrudRouter as c, ActionRouterConfig as d, IdempotencyService as f, DEFAULT_ID_FIELD as g, CrudOperation as h, getControllerContext as i, RESERVED_QUERY_PARAMS as j, MUTATION_OPERATIONS as k, createPermissionMiddleware as l, CRUD_OPERATIONS as m, createFastifyHandler as n, sendControllerResponse as o, createActionRouter as p, createRequestContext as r, defineResourceVariants as s, createCrudHandlers as t, ActionHandler as u, DEFAULT_MAX_LIMIT as v, HookOperation as w, DEFAULT_UPDATE_METHOD as x, DEFAULT_SORT as y };
@@ -1,4 +1,4 @@
1
- import { G as OpenApiSchemas, Q as QueryParserInterface, Ut as CrudRepository, c as ValidationResult, ft as RouteSchemaOptions, n as AdapterSchemaContext, o as RepositoryLike, q as ParsedQuery, r as DataAdapter, s as SchemaMetadata } from "./interface-DYH8AXGe.mjs";
1
+ import { G as OpenApiSchemas, Q as QueryParserInterface, Ut as CrudRepository, c as ValidationResult, ft as RouteSchemaOptions, n as AdapterSchemaContext, o as RepositoryLike, q as ParsedQuery, r as DataAdapter, s as SchemaMetadata } from "./interface-Dwzqt4mn.mjs";
2
2
  import { Model } from "mongoose";
3
3
 
4
4
  //#region src/adapters/mongoose.d.ts
package/dist/index.d.mts CHANGED
@@ -1,10 +1,10 @@
1
- import { $ as RateLimitConfig, $t as PipelineContext, A as FieldRule, C as CrudRouterOptions, D as FastifyRequestExtras, F as InferDocType, Ft as IController, Gt as PaginatedResult, H as MiddlewareConfig, Ht as defineResource, I as InferResourceDoc, It as IControllerResponse, Jt as Guard, K as OwnershipCheck, L as IntrospectionData, Lt as IRequestContext, M as HealthCheck, N as HealthOptions, Nt as ControllerLike, O as FastifyWithAuth, P as InferAdapterDoc, Qt as PipelineConfig, R as IntrospectionPluginOptions, Rt as RouteHandler, S as CrudRouteKey, St as envelope, T as EventDefinition, Tt as BaseControllerOptions, U as MiddlewareHandler, Ut as CrudRepository, Vt as ResourceDefinition, Xt as NextFunction, Y as PresetFunction, Yt as Interceptor, Z as PresetResult, Zt as OperationFilter, _t as TypedResourceConfig, a as RelationMetadata, bt as ValidateOptions, c as ValidationResult, d as ApiResponse, dt as RouteHandlerMethod, en as PipelineStep, et as RegistryEntry, ft as RouteSchemaOptions, g as AuthPluginOptions, gt as TypedRepository, ht as TypedController, i as FieldMetadata, it as RequestWithExtras, j as GracefulShutdownOptions, k as FastifyWithDecorators, l as AdditionalRoute, lt as ResourceMetadata, m as ArcRequest, nt as RequestContext, o as RepositoryLike, ot as ResourceConfig, p as ArcInternalMetadata, pt as ServiceContext, qt as QueryOptions, r as DataAdapter, rt as RequestIdOptions, s as SchemaMetadata, tn as Transform, tt as RegistryStats, u as AnyRecord, w as CrudSchemas, wt as BaseController, x as CrudController, xt as ValidationResult$1, y as ConfigError, yt as UserOrganization, z as JWTPayload } from "./interface-DYH8AXGe.mjs";
2
- import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, t as FieldPermission } from "./fields-DFwdaWCq.mjs";
3
- import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "./types-BNUccdcf.mjs";
4
- import { l as createMongooseAdapter, o as createPrismaAdapter, s as MongooseAdapter, t as PrismaAdapter } from "./index-CHeJa4Zd.mjs";
5
- import { A as RESERVED_QUERY_PARAMS, C as HookOperation, D as MAX_SEARCH_LENGTH, E as MAX_REGEX_LENGTH, O as MUTATION_OPERATIONS, S as HOOK_PHASES, T as MAX_FILTER_DEPTH, _ as DEFAULT_MAX_LIMIT, a as getControllerScope, b as DEFAULT_UPDATE_METHOD, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, j as SYSTEM_FIELDS, k as MutationOperation, m as CrudOperation, p as CRUD_OPERATIONS, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "./index-gz6iuzCp.mjs";
6
- import { C as presets_d_exports, E as readOnly, S as ownerWithAdminBypass, T as publicReadAdminWrite, a as allOf, b as authenticated, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgMembership, g as requireTeamMembership, h as requireRoles, l as createOrgPermissions, m as requireOwnership, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgRole, r as DynamicPermissionMatrixConfig, s as anyOf, u as denyAll, v as when, w as publicRead, x as fullPublic, y as adminOnly } from "./index-NGZksqM5.mjs";
7
- import { a as NotFoundError, d as ValidationError, f as createDomainError, i as ForbiddenError, t as ArcError, u as UnauthorizedError } from "./errors-CcVbl1-T.mjs";
1
+ import { $ as RateLimitConfig, $t as PipelineContext, A as FieldRule, C as CrudRouterOptions, D as FastifyRequestExtras, F as InferDocType, Ft as IController, Gt as PaginatedResult, H as MiddlewareConfig, Ht as defineResource, I as InferResourceDoc, It as IControllerResponse, Jt as Guard, K as OwnershipCheck, L as IntrospectionData, Lt as IRequestContext, M as HealthCheck, N as HealthOptions, Nt as ControllerLike, O as FastifyWithAuth, P as InferAdapterDoc, Qt as PipelineConfig, R as IntrospectionPluginOptions, Rt as RouteHandler, S as CrudRouteKey, St as envelope, T as EventDefinition, Tt as BaseControllerOptions, U as MiddlewareHandler, Ut as CrudRepository, Vt as ResourceDefinition, Xt as NextFunction, Y as PresetFunction, Yt as Interceptor, Z as PresetResult, Zt as OperationFilter, _t as TypedResourceConfig, a as RelationMetadata, bt as ValidateOptions, c as ValidationResult, d as ApiResponse, dt as RouteHandlerMethod, en as PipelineStep, et as RegistryEntry, ft as RouteSchemaOptions, g as AuthPluginOptions, gt as TypedRepository, ht as TypedController, i as FieldMetadata, it as RequestWithExtras, j as GracefulShutdownOptions, k as FastifyWithDecorators, l as AdditionalRoute, lt as ResourceMetadata, m as ArcRequest, nt as RequestContext, o as RepositoryLike, ot as ResourceConfig, p as ArcInternalMetadata, pt as ServiceContext, qt as QueryOptions, r as DataAdapter, rt as RequestIdOptions, s as SchemaMetadata, tn as Transform, tt as RegistryStats, u as AnyRecord, w as CrudSchemas, wt as BaseController, x as CrudController, xt as ValidationResult$1, y as ConfigError, yt as UserOrganization, z as JWTPayload } from "./interface-Dwzqt4mn.mjs";
2
+ import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, t as FieldPermission } from "./fields-CYuLMJPD.mjs";
3
+ import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "./types-DPsC0taJ.mjs";
4
+ import { l as createMongooseAdapter, o as createPrismaAdapter, s as MongooseAdapter, t as PrismaAdapter } from "./index-StgFaQKD.mjs";
5
+ import { A as MutationOperation, C as HOOK_PHASES, D as MAX_REGEX_LENGTH, E as MAX_FILTER_DEPTH, M as SYSTEM_FIELDS, O as MAX_SEARCH_LENGTH, S as HOOK_OPERATIONS, T as HookPhase, _ as DEFAULT_LIMIT, a as getControllerScope, b as DEFAULT_TENANT_FIELD, g as DEFAULT_ID_FIELD, h as CrudOperation, j as RESERVED_QUERY_PARAMS, k as MUTATION_OPERATIONS, m as CRUD_OPERATIONS, s as defineResourceVariants, v as DEFAULT_MAX_LIMIT, w as HookOperation, x as DEFAULT_UPDATE_METHOD, y as DEFAULT_SORT } from "./index-KXM8_JmQ.mjs";
6
+ import { C as authenticated, D as publicRead, E as presets_d_exports, O as publicReadAdminWrite, S as adminOnly, T as ownerWithAdminBypass, _ as requireScopeContext, a as allOf, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgInScope, g as requireRoles, h as requireOwnership, k as readOnly, l as createOrgPermissions, m as requireOrgRole, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgMembership, r as DynamicPermissionMatrixConfig, s as anyOf, u as denyAll, v as requireServiceScope, w as fullPublic, x as when, y as requireTeamMembership } from "./index-BYpRGXif.mjs";
7
+ import { a as NotFoundError, d as ValidationError, f as createDomainError, i as ForbiddenError, t as ArcError, u as UnauthorizedError } from "./errors-CCSsMpXE.mjs";
8
8
  import { AsyncLocalStorage } from "node:async_hooks";
9
9
 
10
10
  //#region src/context/requestContext.d.ts
@@ -252,4 +252,4 @@ declare function arcLog(module: string): ArcLogger;
252
252
  //#region src/index.d.ts
253
253
  declare const version: string;
254
254
  //#endregion
255
- export { type ValidationResult as AdapterValidationResult, type AdditionalRoute, type AnyRecord, type ApiResponse, ArcError, type ArcInternalMetadata, type ArcLogWriter, type ArcLogger, type ArcLoggerOptions, type ArcRequest, type AuthPluginOptions, BaseController, type BaseControllerOptions, CRUD_OPERATIONS, type ConfigError, type ControllerLike, type CrudController, CrudOperation, type CrudRepository, type CrudRouteKey, type CrudRouterOptions, type CrudSchemas, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DataAdapter, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type EventDefinition, type FastifyRequestExtras, type FastifyWithAuth, type FastifyWithDecorators, type FieldMetadata, type FieldPermission, type FieldPermissionMap, type FieldRule, ForbiddenError, type GracefulShutdownOptions, type Guard, HOOK_OPERATIONS, HOOK_PHASES, type HealthCheck, type HealthOptions, HookOperation, HookPhase, type IController, type IControllerResponse, type IRequestContext, type InferAdapterDoc, type InferDocType, type InferResourceDoc, type Interceptor, type IntrospectionData, type IntrospectionPluginOptions, type JWTPayload, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, type MiddlewareConfig, MongooseAdapter, MutationOperation, type NamedMiddleware, NotFoundError, type OwnershipCheck, type PaginatedResult, type PermissionCheck, type PermissionContext, type PermissionResult, type PipelineConfig, type PipelineContext, type PipelineStep, type PresetFunction, type PresetResult, PrismaAdapter, type QueryOptions, RESERVED_QUERY_PARAMS, type RateLimitConfig, type RegistryEntry, type RegistryStats, type RelationMetadata, type RepositoryLike, type RequestContext, type RequestIdOptions, type RequestStore, type RequestWithExtras, type ResourceConfig, ResourceDefinition, type ResourceMetadata, type RouteHandler, type RouteHandlerMethod, type RouteSchemaOptions, SYSTEM_FIELDS, type SchemaMetadata, type ServiceContext, type Transform, type TypedController, type TypedRepository, type TypedResourceConfig, UnauthorizedError, type UserBase, type UserOrganization, type ValidateOptions, ValidationError, type ValidationResult$1 as ValidationResult, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_d_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
255
+ export { type ValidationResult as AdapterValidationResult, type AdditionalRoute, type AnyRecord, type ApiResponse, ArcError, type ArcInternalMetadata, type ArcLogWriter, type ArcLogger, type ArcLoggerOptions, type ArcRequest, type AuthPluginOptions, BaseController, type BaseControllerOptions, CRUD_OPERATIONS, type ConfigError, type ControllerLike, type CrudController, CrudOperation, type CrudRepository, type CrudRouteKey, type CrudRouterOptions, type CrudSchemas, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DataAdapter, type DynamicPermissionMatrix, type DynamicPermissionMatrixConfig, type EventDefinition, type FastifyRequestExtras, type FastifyWithAuth, type FastifyWithDecorators, type FieldMetadata, type FieldPermission, type FieldPermissionMap, type FieldRule, ForbiddenError, type GracefulShutdownOptions, type Guard, HOOK_OPERATIONS, HOOK_PHASES, type HealthCheck, type HealthOptions, HookOperation, HookPhase, type IController, type IControllerResponse, type IRequestContext, type InferAdapterDoc, type InferDocType, type InferResourceDoc, type Interceptor, type IntrospectionData, type IntrospectionPluginOptions, type JWTPayload, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, type MiddlewareConfig, MongooseAdapter, MutationOperation, type NamedMiddleware, NotFoundError, type OwnershipCheck, type PaginatedResult, type PermissionCheck, type PermissionContext, type PermissionResult, type PipelineConfig, type PipelineContext, type PipelineStep, type PresetFunction, type PresetResult, PrismaAdapter, type QueryOptions, RESERVED_QUERY_PARAMS, type RateLimitConfig, type RegistryEntry, type RegistryStats, type RelationMetadata, type RepositoryLike, type RequestContext, type RequestIdOptions, type RequestStore, type RequestWithExtras, type ResourceConfig, ResourceDefinition, type ResourceMetadata, type RouteHandler, type RouteHandlerMethod, type RouteSchemaOptions, SYSTEM_FIELDS, type SchemaMetadata, type ServiceContext, type Transform, type TypedController, type TypedRepository, type TypedResourceConfig, UnauthorizedError, type UserBase, type UserOrganization, type ValidateOptions, ValidationError, type ValidationResult$1 as ValidationResult, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, defineResourceVariants, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_d_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
package/dist/index.mjs CHANGED
@@ -1,13 +1,14 @@
1
1
  import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "./constants-Cxde4rpC.mjs";
2
- import { a as createMongooseAdapter, i as MongooseAdapter, r as createPrismaAdapter, t as PrismaAdapter } from "./adapters-gM-WYjNe.mjs";
3
- import { t as BaseController } from "./BaseController-DzRtluEF.mjs";
2
+ import { a as createMongooseAdapter, i as MongooseAdapter, r as createPrismaAdapter, t as PrismaAdapter } from "./adapters-BxGgSHjj.mjs";
3
+ import { t as BaseController } from "./BaseController-CpMfCXdn.mjs";
4
4
  import { envelope } from "./types/index.mjs";
5
5
  import { n as applyFieldWritePermissions, r as fields, t as applyFieldReadPermissions } from "./fields-ipsbIRPK.mjs";
6
- import { t as requestContext } from "./requestContext-DYtmNpm5.mjs";
7
- import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-NoQKsbAT.mjs";
8
- import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-wWMBB4GP.mjs";
9
- import { 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, 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";
10
- import { n as configureArcLogger, t as arcLog } from "./logger-Dz3j1ItV.mjs";
6
+ import { t as defineResourceVariants } from "./core-BWekSEju.mjs";
7
+ import { t as requestContext } from "./requestContext-xHIKedG6.mjs";
8
+ import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-Cg58SLNi.mjs";
9
+ import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-DZzyl4a4.mjs";
10
+ import { C as publicRead, S as presets_exports, T as readOnly, _ as when, a as createOrgPermissions, b as fullPublic, c as requireOrgInScope, d as requireOwnership, f as requireRoles, 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";
11
+ import { n as configureArcLogger, t as arcLog } from "./logger-DLg8-Ueg.mjs";
11
12
  //#region src/middleware/middleware.ts
12
13
  /**
13
14
  * Named Middleware — Priority-based, conditional middleware execution.
@@ -127,6 +128,6 @@ function transform(name, handlerOrOptions) {
127
128
  }
128
129
  //#endregion
129
130
  //#region src/index.ts
130
- const version = "2.6.3";
131
+ const version = "2.7.1";
131
132
  //#endregion
132
- export { ArcError, BaseController, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MongooseAdapter, NotFoundError, PrismaAdapter, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
133
+ export { ArcError, BaseController, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MongooseAdapter, NotFoundError, PrismaAdapter, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, defineResourceVariants, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
@@ -1,4 +1,4 @@
1
- import { t as DomainEvent } from "../EventTransport-wc5hSLik.mjs";
1
+ import { t as DomainEvent } from "../EventTransport-CUpRK_Lg.mjs";
2
2
  import { WebSocketClient, WebSocketMessage } from "./websocket.mjs";
3
3
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
4
4
 
@@ -4,7 +4,7 @@ const eventGatewayPluginImpl = async (fastify, opts = {}) => {
4
4
  const { auth = true, orgScoped = false, roomPolicy, maxMessageBytes, maxSubscriptionsPerClient, authenticate } = opts;
5
5
  if (auth && !authenticate && !fastify.hasDecorator("authenticate")) throw new Error("[arc-event-gateway] auth is true but fastify.authenticate is not registered. Register an auth plugin first, provide a custom authenticate function, or set auth: false.");
6
6
  if (opts.sse !== false) {
7
- const { default: ssePlugin } = await import("../sse-BF7GR7IB.mjs").then((n) => n.r);
7
+ const { default: ssePlugin } = await import("../sse-Bp3dabF1.mjs").then((n) => n.r);
8
8
  await fastify.register(ssePlugin, {
9
9
  path: opts.sse?.path ?? "/events/stream",
10
10
  requireAuth: auth,
@@ -1,7 +1,7 @@
1
1
  import { WebSocketClient, WebSocketMessage, WebSocketPluginOptions } from "./websocket.mjs";
2
2
  import { EventGatewayOptions } from "./event-gateway.mjs";
3
3
  import { JobDefinition, JobDispatchOptions, JobDispatcher, JobMeta, JobsPluginOptions, QueueStats } from "./jobs.mjs";
4
- import { c as McpResourceConfig, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler } from "../types-B4_TDdPe.mjs";
4
+ import { c as McpResourceConfig, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler } from "../types-ClmkMDK1.mjs";
5
5
  import { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike } from "./streamline.mjs";
6
6
  import { WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription } from "./webhooks.mjs";
7
7
  export { type BetterAuthHandler, type CallToolResult, type CreateMcpServerConfig, type CrudOperation, type EventGatewayOptions, type JobDefinition, type JobDispatchOptions, type JobDispatcher, type JobMeta, type JobsPluginOptions, type McpAuthResult, type McpPluginOptions, type McpResourceConfig, type PromptDefinition, type QueueStats, type StreamlinePluginOptions, type ToolAnnotations, type ToolContext, type ToolDefinition, type WebSocketClient, type WebSocketMessage, type WebSocketPluginOptions, type WebhookDeliveryRecord, type WebhookManager, type WebhookPluginOptions, type WebhookStore, type WebhookSubscription, type WorkflowLike, type WorkflowRunLike };
@@ -1,5 +1,5 @@
1
- import { Vt as ResourceDefinition } from "../../interface-DYH8AXGe.mjs";
2
- import { a as McpAuthResolver, c as McpResourceConfig, d as SessionEntry, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler, u as PromptResult } from "../../types-B4_TDdPe.mjs";
1
+ import { Vt as ResourceDefinition } from "../../interface-Dwzqt4mn.mjs";
2
+ import { a as McpAuthResolver, c as McpResourceConfig, d as SessionEntry, f as ToolAnnotations, i as CrudOperation, l as PromptDefinition, m as ToolDefinition, n as CallToolResult, o as McpAuthResult, p as ToolContext, r as CreateMcpServerConfig, s as McpPluginOptions, t as BetterAuthHandler, u as PromptResult } from "../../types-ClmkMDK1.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
4
  import { z } from "zod";
5
5
 
@@ -1,4 +1,4 @@
1
- import { n as fieldRulesToZod, r as createMcpServer, t as resourceToTools } from "../../resourceToTools-nCJWnG1r.mjs";
1
+ import { n as fieldRulesToZod, r as createMcpServer, t as resourceToTools } from "../../resourceToTools-CkVSSzKg.mjs";
2
2
  import { createHash } from "node:crypto";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/integrations/mcp/definePrompt.ts
@@ -1,4 +1,4 @@
1
- import { o as McpAuthResult, s as McpPluginOptions } from "../../types-B4_TDdPe.mjs";
1
+ import { o as McpAuthResult, s as McpPluginOptions } from "../../types-ClmkMDK1.mjs";
2
2
 
3
3
  //#region src/integrations/mcp/testing.d.ts
4
4
  interface TestMcpClientOptions {
@@ -1,4 +1,4 @@
1
- import { r as createMcpServer, t as resourceToTools } from "../../resourceToTools-nCJWnG1r.mjs";
1
+ import { r as createMcpServer, t as resourceToTools } from "../../resourceToTools-CkVSSzKg.mjs";
2
2
  //#region src/integrations/mcp/testing.ts
3
3
  /**
4
4
  * @classytic/arc/mcp/testing — MCP Test Utilities
@@ -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-CNEbix8T.mjs";
2
+ import { n as FieldPermissionMap } from "./fields-CYuLMJPD.mjs";
3
+ import { i as UserBase, t as PermissionCheck } from "./types-DPsC0taJ.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
  *
@@ -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-B9rHWPxD.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-DPsC0taJ.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-Dwzqt4mn.mjs";
2
+ import { i as UserBase } from "../types-DPsC0taJ.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-CYuLMJPD.mjs";
2
+ import { a as getUserRoles, i as UserBase, n as PermissionContext, o as normalizeRoles, r as PermissionResult, t as PermissionCheck } from "../types-DPsC0taJ.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-BYpRGXif.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 };