@classytic/arc 2.6.2 → 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 +95 -1
  2. package/dist/{BaseController-AbbRx3e0.mjs → BaseController-CpMfCXdn.mjs} +214 -16
  3. package/dist/adapters/index.d.mts +2 -2
  4. package/dist/adapters/index.mjs +1 -1
  5. package/dist/{adapters-CTn28N4y.mjs → adapters-BxGgSHjj.mjs} +7 -13
  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-Ckxg6HrZ.mjs → defineResource-DZzyl4a4.mjs} +73 -56
  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-B4uZm82R.d.mts → index-KXM8_JmQ.d.mts} +47 -4
  51. package/dist/{index-DrCqa3Jq.d.mts → index-StgFaQKD.d.mts} +3 -3
  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-CrN45qz1.d.mts → interface-Dwzqt4mn.d.mts} +204 -18
  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-DH3c3e-T.mjs → resourceToTools-CkVSSzKg.mjs} +313 -33
  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-DurlBP2N.d.mts → types-ClmkMDK1.d.mts} +1 -1
  100. package/dist/{types-C1Z28coa.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 +34 -22
  105. package/skills/arc/SKILL.md +278 -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 { Ft as IControllerResponse, It as IRequestContext, O as FastifyWithDecorators, Pt as IController, S as CrudRouterOptions, b as CrudController, rt as RequestWithExtras, tt as RequestContext } from "./interface-CrN45qz1.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 { Ht as CrudRepository, K as ParsedQuery, W as OpenApiSchemas, Z as QueryParserInterface, a as RepositoryLike, dt as RouteSchemaOptions, n as DataAdapter, o as SchemaMetadata, s as ValidationResult } from "./interface-CrN45qz1.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
@@ -29,7 +29,7 @@ interface MongooseAdapterOptions<TDoc = unknown> {
29
29
  * });
30
30
  * ```
31
31
  */
32
- schemaGenerator?: (model: Model<TDoc>, options?: RouteSchemaOptions) => OpenApiSchemas | Record<string, unknown>;
32
+ schemaGenerator?: (model: Model<TDoc>, options?: RouteSchemaOptions, context?: AdapterSchemaContext) => OpenApiSchemas | Record<string, unknown>;
33
33
  }
34
34
  /**
35
35
  * Mongoose data adapter with proper type safety
@@ -53,7 +53,7 @@ declare class MongooseAdapter<TDoc = unknown> implements DataAdapter<TDoc> {
53
53
  * If a `schemaGenerator` plugin was provided (e.g. MongoKit's buildCrudSchemasFromModel),
54
54
  * it is used instead of the built-in basic conversion.
55
55
  */
56
- generateSchemas(schemaOptions?: RouteSchemaOptions): OpenApiSchemas | Record<string, unknown> | null;
56
+ generateSchemas(schemaOptions?: RouteSchemaOptions, context?: AdapterSchemaContext): OpenApiSchemas | Record<string, unknown> | null;
57
57
  /**
58
58
  * Extract relation metadata
59
59
  */
package/dist/index.d.mts CHANGED
@@ -1,10 +1,10 @@
1
- import { $ as RegistryEntry, $t as PipelineStep, A as GracefulShutdownOptions, Bt as ResourceDefinition, C as CrudSchemas, Ct as BaseController, D as FastifyWithAuth, E as FastifyRequestExtras, F as InferResourceDoc, Ft as IControllerResponse, G as OwnershipCheck, H as MiddlewareHandler, Ht as CrudRepository, I as IntrospectionData, It as IRequestContext, J as PresetFunction, Jt as Interceptor, Kt as QueryOptions, L as IntrospectionPluginOptions, Lt as RouteHandler, M as HealthOptions, Mt as ControllerLike, N as InferAdapterDoc, O as FastifyWithDecorators, P as InferDocType, Pt as IController, Q as RateLimitConfig, Qt as PipelineContext, R as JWTPayload, S as CrudRouterOptions, V as MiddlewareConfig, Vt as defineResource, Wt as PaginatedResult, X as PresetResult, Xt as OperationFilter, Yt as NextFunction, Zt as PipelineConfig, a as RepositoryLike, at as ResourceConfig, b as CrudController, bt as ValidationResult$1, c as AdditionalRoute, ct as ResourceMetadata, dt as RouteSchemaOptions, en as Transform, et as RegistryStats, f as ArcInternalMetadata, ft as ServiceContext, gt as TypedResourceConfig, h as AuthPluginOptions, ht as TypedRepository, i as RelationMetadata, j as HealthCheck, k as FieldRule, l as AnyRecord, mt as TypedController, n as DataAdapter, nt as RequestIdOptions, o as SchemaMetadata, p as ArcRequest, qt as Guard, r as FieldMetadata, rt as RequestWithExtras, s as ValidationResult, tt as RequestContext, u as ApiResponse, ut as RouteHandlerMethod, v as ConfigError, vt as UserOrganization, w as EventDefinition, wt as BaseControllerOptions, x as CrudRouteKey, xt as envelope, yt as ValidateOptions } from "./interface-CrN45qz1.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-DrCqa3Jq.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-B4uZm82R.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-CTn28N4y.mjs";
3
- import { t as BaseController } from "./BaseController-AbbRx3e0.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-Ckxg6HrZ.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.2";
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-DurlBP2N.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 { Bt as ResourceDefinition } from "../../interface-CrN45qz1.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-DurlBP2N.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-DH3c3e-T.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-DurlBP2N.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-DH3c3e-T.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
  /**
@@ -1037,10 +1126,62 @@ declare class BaseController<TDoc = AnyRecord, TRepository extends RepositoryLik
1037
1126
  getTree(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
1038
1127
  getChildren(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
1039
1128
  bulkCreate(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
1129
+ /**
1130
+ * Build a tenant-scoped filter for bulk update/delete.
1131
+ *
1132
+ * Mirrors `AccessControl.buildIdFilter` semantics for single-doc ops:
1133
+ * - Always merge `_policyFilters` (from permission middleware)
1134
+ * - When `tenantField` is set AND a `member` scope is present, add the
1135
+ * org filter so cross-tenant data can't be touched.
1136
+ * - When the scope is `elevated` (platform admin), no org filter is
1137
+ * applied — admins can bulk-update across orgs intentionally.
1138
+ * - When the scope is `public` on a tenant-scoped resource, deny.
1139
+ * - When NO scope is present at all (e.g., direct controller calls in
1140
+ * unit tests, or app routes without auth middleware), the controller
1141
+ * stays lenient — it's the middleware layer's job to fail-close.
1142
+ * Apps that want fail-close on bulk routes should run the multi-tenant
1143
+ * preset middleware (or equivalent) ahead of these handlers.
1144
+ *
1145
+ * Returns the merged filter, or `null` when access must be denied.
1146
+ */
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;
1040
1164
  bulkUpdate(req: IRequestContext): Promise<IControllerResponse<{
1041
1165
  matchedCount: number;
1042
1166
  modifiedCount: number;
1043
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
+ */
1044
1185
  bulkDelete(req: IRequestContext): Promise<IControllerResponse<{
1045
1186
  deletedCount: number;
1046
1187
  }>>;
@@ -1523,9 +1664,22 @@ interface ResourceConfig<TDoc = AnyRecord> {
1523
1664
  tenantField?: string | false;
1524
1665
  /**
1525
1666
  * Primary key field name (default: '_id').
1526
- * Override for non-MongoDB adapters (e.g., 'id' for SQL databases).
1667
+ *
1668
+ * Type-narrowed to `keyof TDoc` when `defineResource<TDoc>` is called with
1669
+ * a typed document interface — gives autocomplete for valid field names —
1670
+ * while still accepting any string when TDoc is `unknown` / `AnyRecord` so
1671
+ * adapters with dynamic shapes still work.
1672
+ *
1673
+ * @example
1674
+ * ```ts
1675
+ * defineResource<IJob>({ idField: 'jobId' }) // ← autocompletes from IJob fields
1676
+ * defineResource({ idField: 'sku' }) // ← any string allowed
1677
+ * ```
1678
+ *
1679
+ * Override for non-MongoDB adapters (e.g., 'id' for SQL databases) or
1680
+ * resources keyed by a business identifier (slug, sku, orderNumber).
1527
1681
  */
1528
- idField?: string;
1682
+ idField?: (keyof TDoc & string) | (string & {});
1529
1683
  module?: string;
1530
1684
  events?: Record<string, EventDefinition>;
1531
1685
  skipValidation?: boolean;
@@ -2337,6 +2491,20 @@ interface RepositoryLike {
2337
2491
  create(data: unknown, options?: unknown): Promise<unknown>;
2338
2492
  update(id: string, data: unknown, options?: unknown): Promise<unknown>;
2339
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;
2340
2508
  /** Find single doc by compound filter — used by AccessControl for idField + org/policy scoping.
2341
2509
  * Without this, Arc falls back to getById + post-fetch security checks. */
2342
2510
  getOne?(filter: Record<string, unknown>, options?: unknown): Promise<unknown>;
@@ -2367,9 +2535,15 @@ interface DataAdapter<TDoc = unknown> {
2367
2535
  * For example, Mongoose adapter can use mongokit to generate schemas from Mongoose models.
2368
2536
  *
2369
2537
  * @param options - Schema generation options (field rules, populate settings, etc.)
2538
+ * @param context - Resource-level context: idField (for params schema), resourceName.
2539
+ * Adapters should honor `context.idField` when producing the params
2540
+ * schema — e.g. skip the ObjectId pattern when idField is a custom
2541
+ * string field. Backwards compatible: legacy adapters ignoring the
2542
+ * context still work because Arc strips the mismatched pattern as
2543
+ * a safety net.
2370
2544
  * @returns OpenAPI schemas for CRUD operations or null if not supported
2371
2545
  */
2372
- generateSchemas?(options?: RouteSchemaOptions): OpenApiSchemas | Record<string, unknown> | null;
2546
+ generateSchemas?(options?: RouteSchemaOptions, context?: AdapterSchemaContext): OpenApiSchemas | Record<string, unknown> | null;
2373
2547
  /** Extract schema metadata for OpenAPI/introspection */
2374
2548
  getSchemaMetadata?(): SchemaMetadata | null;
2375
2549
  /** Validate data against schema before persistence */
@@ -2385,6 +2559,18 @@ interface DataAdapter<TDoc = unknown> {
2385
2559
  /** Close/cleanup resources */
2386
2560
  close?(): Promise<void>;
2387
2561
  }
2562
+ /**
2563
+ * Context passed to `adapter.generateSchemas()` so adapters can shape the
2564
+ * output to match resource-level configuration (idField overrides, etc).
2565
+ * All fields are optional — adapters are free to ignore this argument, in
2566
+ * which case Arc applies safety-net normalization to the generated schemas.
2567
+ */
2568
+ interface AdapterSchemaContext {
2569
+ /** The idField configured on the resource. Defaults to "_id". */
2570
+ idField?: string;
2571
+ /** Resource name (for error messages / logging). */
2572
+ resourceName?: string;
2573
+ }
2388
2574
  interface SchemaMetadata {
2389
2575
  name: string;
2390
2576
  fields: Record<string, FieldMetadata>;
@@ -2426,4 +2612,4 @@ interface ValidationResult {
2426
2612
  }
2427
2613
  type AdapterFactory<TDoc> = (config: unknown) => DataAdapter<TDoc>;
2428
2614
  //#endregion
2429
- export { RegistryEntry as $, PipelineStep as $t, GracefulShutdownOptions as A, AccessControlConfig as At, LookupOption as B, ResourceDefinition as Bt, CrudSchemas as C, BaseController as Ct, FastifyWithAuth as D, BodySanitizer as Dt, FastifyRequestExtras as E, QueryResolverConfig as Et, InferResourceDoc as F, IControllerResponse as Ft, OwnershipCheck as G, PaginationParams as Gt, MiddlewareHandler as H, CrudRepository as Ht, IntrospectionData as I, IRequestContext as It, PresetFunction as J, Interceptor as Jt, ParsedQuery as K, QueryOptions as Kt, IntrospectionPluginOptions as L, RouteHandler as Lt, HealthOptions as M, ControllerLike as Mt, InferAdapterDoc as N, FastifyHandler as Nt, FastifyWithDecorators as O, BodySanitizerConfig as Ot, InferDocType as P, IController as Pt, RateLimitConfig as Q, PipelineContext as Qt, JWTPayload as R, RegisterOptions as Rt, CrudRouterOptions as S, getUserId as St, EventsDecorator as T, QueryResolver as Tt, ObjectId as U, InferDoc as Ut, MiddlewareConfig as V, defineResource as Vt, OpenApiSchemas as W, PaginatedResult as Wt, PresetResult as X, OperationFilter as Xt, PresetHook as Y, NextFunction as Yt, QueryParserInterface as Z, PipelineConfig as Zt, AuthenticatorContext as _, UserLike as _t, RepositoryLike as a, HookPhase as an, ResourceConfig as at, CrudController as b, ValidationResult$1 as bt, AdditionalRoute as c, HookSystemOptions as cn, ResourceMetadata as ct, ArcDecorator as d, afterUpdate as dn, RouteSchemaOptions as dt, Transform as en, RegistryStats as et, ArcInternalMetadata as f, beforeCreate as fn, ServiceContext as ft, Authenticator as g, defineHook as gn, TypedResourceConfig as gt, AuthPluginOptions as h, createHookSystem as hn, TypedRepository as ht, RelationMetadata as i, HookOperation as in, ResourceCacheConfig as it, HealthCheck as j, ControllerHandler as jt, FieldRule as k, AccessControl as kt, AnyRecord as l, afterCreate as ln, ResourcePermissions as lt, AuthHelpers as m, beforeUpdate as mn, TypedController as mt, DataAdapter as n, HookContext as nn, RequestIdOptions as nt, SchemaMetadata as o, HookRegistration as on, ResourceHookContext as ot, ArcRequest as p, beforeDelete as pn, TokenPair as pt, PopulateOption as q, Guard as qt, FieldMetadata as r, HookHandler as rn, RequestWithExtras as rt, ValidationResult as s, HookSystem as sn, ResourceHooks as st, AdapterFactory as t, DefineHookOptions as tn, RequestContext as tt, ApiResponse as u, afterDelete as un, RouteHandlerMethod$1 as ut, ConfigError as v, UserOrganization as vt, EventDefinition as w, BaseControllerOptions as wt, CrudRouteKey as x, envelope as xt, ControllerQueryOptions as y, ValidateOptions as yt, JwtContext as z, ResourceRegistry as zt };
2615
+ export { RateLimitConfig as $, PipelineContext as $t, FieldRule as A, AccessControl as At, JwtContext as B, ResourceRegistry as Bt, CrudRouterOptions as C, getUserId as Ct, FastifyRequestExtras as D, QueryResolverConfig as Dt, EventsDecorator as E, QueryResolver as Et, InferDocType as F, IController as Ft, OpenApiSchemas as G, PaginatedResult as Gt, MiddlewareConfig as H, defineResource as Ht, InferResourceDoc as I, IControllerResponse as It, PopulateOption as J, Guard as Jt, OwnershipCheck as K, PaginationParams as Kt, IntrospectionData as L, IRequestContext as Lt, HealthCheck as M, ControllerHandler as Mt, HealthOptions as N, ControllerLike as Nt, FastifyWithAuth as O, BodySanitizer as Ot, InferAdapterDoc as P, FastifyHandler as Pt, QueryParserInterface as Q, PipelineConfig as Qt, IntrospectionPluginOptions as R, RouteHandler as Rt, CrudRouteKey as S, envelope as St, EventDefinition as T, BaseControllerOptions as Tt, MiddlewareHandler as U, CrudRepository as Ut, LookupOption as V, ResourceDefinition as Vt, ObjectId as W, InferDoc as Wt, PresetHook as X, NextFunction as Xt, PresetFunction as Y, Interceptor as Yt, PresetResult as Z, OperationFilter as Zt, Authenticator as _, defineHook as _n, TypedResourceConfig as _t, RelationMetadata as a, HookOperation as an, ResourceCacheConfig as at, ControllerQueryOptions as b, ValidateOptions as bt, ValidationResult as c, HookSystem as cn, ResourceHooks as ct, ApiResponse as d, afterDelete as dn, RouteHandlerMethod$1 as dt, PipelineStep as en, RegistryEntry as et, ArcDecorator as f, afterUpdate as fn, RouteSchemaOptions as ft, AuthPluginOptions as g, createHookSystem as gn, TypedRepository as gt, AuthHelpers as h, beforeUpdate as hn, TypedController as ht, FieldMetadata as i, HookHandler as in, RequestWithExtras as it, GracefulShutdownOptions as j, AccessControlConfig as jt, FastifyWithDecorators as k, BodySanitizerConfig as kt, AdditionalRoute as l, HookSystemOptions as ln, ResourceMetadata as lt, ArcRequest as m, beforeDelete as mn, TokenPair as mt, AdapterSchemaContext as n, DefineHookOptions as nn, RequestContext as nt, RepositoryLike as o, HookPhase as on, ResourceConfig as ot, ArcInternalMetadata as p, beforeCreate as pn, ServiceContext as pt, ParsedQuery as q, QueryOptions as qt, DataAdapter as r, HookContext as rn, RequestIdOptions as rt, SchemaMetadata as s, HookRegistration as sn, ResourceHookContext as st, AdapterFactory as t, Transform as tn, RegistryStats as tt, AnyRecord as u, afterCreate as un, ResourcePermissions as ut, AuthenticatorContext as v, UserLike as vt, CrudSchemas as w, BaseController as wt, CrudController as x, ValidationResult$1 as xt, ConfigError as y, UserOrganization as yt, JWTPayload as z, RegisterOptions as zt };
@@ -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 { Lt as RouteHandler } from "../interface-CrN45qz1.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