@classytic/arc 2.10.3 → 2.10.8

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 +1 -1
  2. package/dist/{BaseController-CbKKIflT.mjs → BaseController-DVNKvoX4.mjs} +151 -131
  3. package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
  4. package/dist/adapters/index.d.mts +2 -2
  5. package/dist/audit/index.d.mts +2 -2
  6. package/dist/audit/index.mjs +15 -17
  7. package/dist/auth/index.d.mts +4 -4
  8. package/dist/auth/index.mjs +5 -5
  9. package/dist/auth/redis-session.d.mts +1 -1
  10. package/dist/cache/index.d.mts +2 -2
  11. package/dist/cache/index.mjs +3 -3
  12. package/dist/cli/commands/docs.mjs +2 -2
  13. package/dist/cli/commands/generate.mjs +1 -1
  14. package/dist/cli/commands/init.mjs +1 -1
  15. package/dist/cli/commands/introspect.mjs +1 -1
  16. package/dist/context/index.d.mts +58 -0
  17. package/dist/context/index.mjs +2 -0
  18. package/dist/core/index.d.mts +2 -2
  19. package/dist/core/index.mjs +2 -2
  20. package/dist/{core-CcR01lup.mjs → core-3MWJosCH.mjs} +139 -91
  21. package/dist/{createApp-BuvPma24.mjs → createApp-BwnEAO2h.mjs} +54 -20
  22. package/dist/docs/index.d.mts +2 -2
  23. package/dist/docs/index.mjs +2 -2
  24. package/dist/{elevation-C7hgL_aI.mjs → elevation-Dci0AYLT.mjs} +2 -2
  25. package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
  26. package/dist/{errorHandler-Bb49BvPD.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
  27. package/dist/{eventPlugin-DCUjuiQT.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
  28. package/dist/{eventPlugin-CxWgpd6K.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
  29. package/dist/events/index.d.mts +4 -4
  30. package/dist/events/index.mjs +69 -51
  31. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  32. package/dist/events/transports/redis.d.mts +1 -1
  33. package/dist/factory/index.d.mts +1 -1
  34. package/dist/factory/index.mjs +2 -2
  35. package/dist/{fields-Lo1VUDpt.d.mts → fields-C8Y0XLAu.d.mts} +1 -1
  36. package/dist/hooks/index.d.mts +1 -1
  37. package/dist/hooks/index.mjs +1 -1
  38. package/dist/idempotency/index.d.mts +3 -3
  39. package/dist/idempotency/index.mjs +38 -27
  40. package/dist/idempotency/redis.d.mts +1 -1
  41. package/dist/{index-Cl0uoKd5.d.mts → index-BGbpGVyM.d.mts} +2362 -2155
  42. package/dist/{index-DStwgFUK.d.mts → index-BziRPS4H.d.mts} +1 -1
  43. package/dist/{index-ChIw3776.d.mts → index-C_Noptz-.d.mts} +3 -3
  44. package/dist/{index-8qw4y6ff.d.mts → index-EqQN6p0W.d.mts} +3 -3
  45. package/dist/index.d.mts +7 -219
  46. package/dist/index.mjs +8 -128
  47. package/dist/integrations/event-gateway.d.mts +1 -1
  48. package/dist/integrations/event-gateway.mjs +1 -1
  49. package/dist/integrations/index.d.mts +1 -1
  50. package/dist/integrations/mcp/index.d.mts +2 -2
  51. package/dist/integrations/mcp/index.mjs +1 -1
  52. package/dist/integrations/mcp/testing.d.mts +1 -1
  53. package/dist/integrations/mcp/testing.mjs +1 -1
  54. package/dist/logger/index.d.mts +81 -0
  55. package/dist/{logger-DLg8-Ueg.mjs → logger/index.mjs} +1 -6
  56. package/dist/middleware/index.d.mts +109 -0
  57. package/dist/middleware/index.mjs +70 -0
  58. package/dist/multipartBody-CUQGVlM_.mjs +123 -0
  59. package/dist/{openapi-B5F8AddX.mjs → openapi-DpNpqBmo.mjs} +9 -7
  60. package/dist/org/index.d.mts +2 -2
  61. package/dist/permissions/index.d.mts +2 -2
  62. package/dist/permissions/index.mjs +3 -3
  63. package/dist/{permissions-Dk6mshja.mjs → permissions-wkqRwicB.mjs} +2 -2
  64. package/dist/pipe-CGJxqDGx.mjs +62 -0
  65. package/dist/pipeline/index.d.mts +62 -0
  66. package/dist/pipeline/index.mjs +53 -0
  67. package/dist/plugins/index.d.mts +25 -5
  68. package/dist/plugins/index.mjs +9 -9
  69. package/dist/plugins/tracing-entry.d.mts +1 -1
  70. package/dist/plugins/tracing-entry.mjs +1 -1
  71. package/dist/presets/filesUpload.d.mts +4 -4
  72. package/dist/presets/filesUpload.mjs +255 -1
  73. package/dist/presets/index.d.mts +1 -1
  74. package/dist/presets/index.mjs +2 -2
  75. package/dist/presets/multiTenant.d.mts +1 -1
  76. package/dist/presets/multiTenant.mjs +42 -8
  77. package/dist/presets/search.d.mts +2 -2
  78. package/dist/presets/search.mjs +1 -1
  79. package/dist/{presets-fLJVXdVn.mjs → presets-CrwOvuXI.mjs} +1 -1
  80. package/dist/{queryCachePlugin-DQCEfJis.mjs → queryCachePlugin-ChLNZvFT.mjs} +2 -2
  81. package/dist/{queryCachePlugin-BKbWjgDG.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
  82. package/dist/{queryParser-DBqBB6AC.mjs → queryParser-NR__Qiju.mjs} +68 -1
  83. package/dist/{redis-DqyeggCa.d.mts → redis-MXLp1oOf.d.mts} +1 -1
  84. package/dist/{redis-stream-CakIQmwR.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
  85. package/dist/registry/index.d.mts +1 -1
  86. package/dist/registry/index.mjs +2 -2
  87. package/dist/{requestContext-xHIKedG6.mjs → requestContext-C38GskNt.mjs} +1 -1
  88. package/dist/{resourceToTools-BElv3xPT.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
  89. package/dist/scope/index.d.mts +2 -2
  90. package/dist/scope/index.mjs +2 -2
  91. package/dist/{sse-yBCgOLGu.mjs → sse-D8UeDwis.mjs} +1 -1
  92. package/dist/{store-helpers-ZCSMJJAX.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
  93. package/dist/testing/index.d.mts +2 -2
  94. package/dist/testing/index.mjs +11 -2
  95. package/dist/testing/storageContract.d.mts +1 -1
  96. package/dist/types/index.d.mts +4 -4
  97. package/dist/types/index.mjs +1 -1
  98. package/dist/types/storage.d.mts +1 -1
  99. package/dist/{types-Btdda02s.d.mts → types-CVKBssX5.d.mts} +1 -1
  100. package/dist/{types-Co8k3NyS.d.mts → types-CVdgPXBW.d.mts} +22 -9
  101. package/dist/utils/index.d.mts +73 -3
  102. package/dist/utils/index.mjs +4 -4
  103. package/dist/{utils-B2fNOD_i.mjs → utils-LMwVidKy.mjs} +20 -2
  104. package/dist/versioning-CeUXHfjw.d.mts +117 -0
  105. package/package.json +22 -6
  106. package/skills/arc/SKILL.md +1 -1
  107. package/dist/errorHandler-DRQ3EqfL.d.mts +0 -218
  108. package/dist/filesUpload-t21LS-py.mjs +0 -377
  109. /package/dist/{EventTransport-CUw5NNWe.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
  110. /package/dist/{HookSystem-BNYKnrXF.mjs → HookSystem-BjFu7zf1.mjs} +0 -0
  111. /package/dist/{ResourceRegistry-BPd6NQDm.mjs → ResourceRegistry-CcN2LVrc.mjs} +0 -0
  112. /package/dist/{betterAuthOpenApi-BBRVhjQN.mjs → betterAuthOpenApi--rdY15Ld.mjs} +0 -0
  113. /package/dist/{caching-CBpK_SCM.mjs → caching-3h93rkJM.mjs} +0 -0
  114. /package/dist/{createActionRouter-Bp_5c_2b.mjs → createActionRouter-C8UUB3Px.mjs} +0 -0
  115. /package/dist/{elevation-C5SwtkAn.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  116. /package/dist/{errors-CCSsMpXE.d.mts → errors-BI8kEKsO.d.mts} +0 -0
  117. /package/dist/{errors-D5c-5BJL.mjs → errors-BqdUDja_.mjs} +0 -0
  118. /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
  119. /package/dist/{fields-bxkeltzz.mjs → fields-CTMWOUDt.mjs} +0 -0
  120. /package/dist/{interface-CSbZdv_3.d.mts → interface-B-pe8fhj.d.mts} +0 -0
  121. /package/dist/{interface-D218ikEo.d.mts → interface-yhyb_pLY.d.mts} +0 -0
  122. /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
  123. /package/dist/{loadResources-BAzJItAJ.mjs → loadResources-Bksk8ydA.mjs} +0 -0
  124. /package/dist/{memory-B5Amv9A1.mjs → memory-DqI-449b.mjs} +0 -0
  125. /package/dist/{metrics-DuhiSEZI.mjs → metrics-TuOmguhi.mjs} +0 -0
  126. /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-CWP6MB39.mjs} +0 -0
  127. /package/dist/{registry-B3lRFBWo.mjs → registry-B0Wl7uVV.mjs} +0 -0
  128. /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-BLojtuvR.mjs} +0 -0
  129. /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
  130. /package/dist/{storage-CVk_SEn2.d.mts → storage-BwGQXUpd.d.mts} +0 -0
  131. /package/dist/{tracing-65B51Dw3.d.mts → tracing-xqXzWeaf.d.mts} +0 -0
  132. /package/dist/{types-Csi3FLfq.mjs → types-CDnTEpga.mjs} +0 -0
  133. /package/dist/{types-DV9WDfeg.mjs → types-D57iXYb8.mjs} +0 -0
  134. /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
  135. /package/dist/{versioning-C2U_bLY0.mjs → versioning-B6mimogM.mjs} +0 -0
@@ -0,0 +1,58 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+
3
+ //#region src/context/requestContext.d.ts
4
+ /**
5
+ * Shape of the request-scoped context store.
6
+ * Populated by Arc's onRequest hook in arcCorePlugin.
7
+ */
8
+ interface RequestStore {
9
+ /** Unique request identifier */
10
+ requestId?: string;
11
+ /** Authenticated user (if any) */
12
+ user?: {
13
+ id?: string;
14
+ _id?: string;
15
+ roles?: string[];
16
+ [key: string]: unknown;
17
+ } | null;
18
+ /** Active organization ID (multi-tenant) */
19
+ organizationId?: string;
20
+ /** Active team ID (team-scoped resources) */
21
+ teamId?: string;
22
+ /** Current resource name (set by arcDecorator in CRUD routes) */
23
+ resourceName?: string;
24
+ /** Request start time (for timing) */
25
+ startTime: number;
26
+ /** Additional context — extensible by app */
27
+ [key: string]: unknown;
28
+ }
29
+ /**
30
+ * Request context API.
31
+ *
32
+ * - `get()` — returns current store or undefined if outside request scope
33
+ * - `run(store, fn)` — run a function with a specific store (used by Arc internals)
34
+ * - `getStore()` — alias for get() (matches Node.js API naming)
35
+ */
36
+ declare const requestContext: {
37
+ /**
38
+ * Get the current request context.
39
+ * Returns undefined if called outside a request lifecycle.
40
+ */
41
+ get(): RequestStore | undefined;
42
+ /**
43
+ * Alias for get() — matches Node.js AsyncLocalStorage API naming.
44
+ */
45
+ getStore(): RequestStore | undefined;
46
+ /**
47
+ * Run a function within a specific request context.
48
+ * Used internally by Arc's onRequest hook.
49
+ */
50
+ run<T>(store: RequestStore, fn: () => T): T;
51
+ /**
52
+ * The underlying AsyncLocalStorage instance.
53
+ * Exposed for advanced use cases (testing, custom integrations).
54
+ */
55
+ storage: AsyncLocalStorage<RequestStore>;
56
+ };
57
+ //#endregion
58
+ export { type RequestStore, requestContext };
@@ -0,0 +1,2 @@
1
+ import { t as requestContext } from "../requestContext-C38GskNt.mjs";
2
+ export { requestContext };
@@ -1,3 +1,3 @@
1
- import { G as ResourceDefinition, K as defineResource, a as QueryResolverConfig, c as AccessControl, i as QueryResolver, l as AccessControlConfig, n as BaseController, o as BodySanitizer, r as BaseControllerOptions, s as BodySanitizerConfig } from "../index-Cl0uoKd5.mjs";
2
- import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-8qw4y6ff.mjs";
1
+ import { B as ResourceDefinition, V as defineResource, an as BaseControllerOptions, cn as BodySanitizer, dn as AccessControlConfig, in as BaseController, ln as BodySanitizerConfig, on as QueryResolver, sn as QueryResolverConfig, un as AccessControl } from "../index-BGbpGVyM.mjs";
2
+ import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-EqQN6p0W.mjs";
3
3
  export { AccessControl, AccessControlConfig, BaseController, BaseControllerOptions, BodySanitizer, BodySanitizerConfig, CRUD_OPERATIONS, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,4 +1,4 @@
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-BhY1OHoH.mjs";
2
- import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-CbKKIflT.mjs";
3
- import { c as createPermissionMiddleware, d as createRequestContext, f as getControllerContext, l as createCrudHandlers, m as sendControllerResponse, n as ResourceDefinition, p as getControllerScope, r as defineResource, s as createCrudRouter, t as defineResourceVariants, u as createFastifyHandler } from "../core-CcR01lup.mjs";
2
+ import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-DVNKvoX4.mjs";
3
+ import { c as createPermissionMiddleware, d as createRequestContext, f as getControllerContext, l as createCrudHandlers, m as sendControllerResponse, n as ResourceDefinition, p as getControllerScope, r as defineResource, s as createCrudRouter, t as defineResourceVariants, u as createFastifyHandler } from "../core-3MWJosCH.mjs";
4
4
  export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,73 +1,29 @@
1
1
  import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-BhY1OHoH.mjs";
2
- import { _ as isElevated, n as PUBLIC_SCOPE, v as isMember } from "./types-AOD8fxIw.mjs";
3
- import { t as BaseController } from "./BaseController-CbKKIflT.mjs";
4
- import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-bxkeltzz.mjs";
5
- import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
6
- import { r as ForbiddenError } from "./errors-D5c-5BJL.mjs";
7
- import { t as requestContext } from "./requestContext-xHIKedG6.mjs";
2
+ import { _ as isElevated, n as PUBLIC_SCOPE, o as getOrgId, p as getUserId, v as isMember } from "./types-AOD8fxIw.mjs";
3
+ import { t as BaseController } from "./BaseController-DVNKvoX4.mjs";
4
+ import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-CTMWOUDt.mjs";
5
+ import { t as getUserRoles } from "./types-D57iXYb8.mjs";
6
+ import { t as requestContext } from "./requestContext-C38GskNt.mjs";
8
7
  import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-QhV1Pa-g.mjs";
9
- import { i as getDefaultCrudSchemas } from "./utils-B2fNOD_i.mjs";
8
+ import { i as getDefaultCrudSchemas } from "./utils-LMwVidKy.mjs";
10
9
  import { n as convertRouteSchema, t as convertOpenApiSchemas } from "./schemaConverter-BxFDdtXu.mjs";
11
10
  import { t as hasEvents } from "./typeGuards-Cj5Rgvlg.mjs";
12
- import { r as getAvailablePresets, t as applyPresets } from "./presets-fLJVXdVn.mjs";
13
- //#region src/pipeline/pipe.ts
11
+ import { t as executePipeline } from "./pipe-CGJxqDGx.mjs";
12
+ import { r as getAvailablePresets, t as applyPresets } from "./presets-CrwOvuXI.mjs";
13
+ import { t as resolveActionPermission } from "./actionPermissions-TUVR3uiZ.mjs";
14
+ //#region src/scope/projection.ts
14
15
  /**
15
- * Compose pipeline steps into an ordered array.
16
- * Accepts guards, transforms, and interceptors in any order.
16
+ * Compute the request-scope projection. Returns `undefined` when no
17
+ * scope is attached (public / unscoped routes) so hosts can idiomatically
18
+ * write `ctx.scope?.organizationId` without a double-null check.
17
19
  */
18
- function pipe(...steps) {
19
- return steps;
20
- }
21
- /**
22
- * Check if a step applies to the given operation.
23
- */
24
- function appliesTo(step, operation) {
25
- if (!step.operations || step.operations.length === 0) return true;
26
- return step.operations.includes(operation);
27
- }
28
- /**
29
- * Execute a pipeline against a request context.
30
- *
31
- * This is the core runtime that createCrudRouter uses to execute pipelines.
32
- * External usage is not needed — this is wired automatically when `pipe` is set.
33
- *
34
- * @param steps - Pipeline steps to execute
35
- * @param ctx - The pipeline context (extends IRequestContext)
36
- * @param handler - The actual controller method to call
37
- * @param operation - The CRUD operation name
38
- * @returns The controller response (possibly modified by interceptors)
39
- */
40
- async function executePipeline(steps, ctx, handler, operation) {
41
- const guards = [];
42
- const transforms = [];
43
- const interceptors = [];
44
- for (const step of steps) {
45
- if (!appliesTo(step, operation)) continue;
46
- switch (step._type) {
47
- case "guard":
48
- guards.push(step);
49
- break;
50
- case "transform":
51
- transforms.push(step);
52
- break;
53
- case "interceptor":
54
- interceptors.push(step);
55
- break;
56
- }
57
- }
58
- for (const g of guards) if (!await g.handler(ctx)) throw new ForbiddenError(`Guard '${g.name}' denied access`);
59
- let currentCtx = ctx;
60
- for (const t of transforms) {
61
- const result = await t.handler(currentCtx);
62
- if (result) currentCtx = result;
63
- }
64
- let chain = () => handler(currentCtx);
65
- for (let i = interceptors.length - 1; i >= 0; i--) {
66
- const interceptor = interceptors[i];
67
- const next = chain;
68
- chain = () => interceptor.handler(currentCtx, next);
69
- }
70
- return chain();
20
+ function buildRequestScopeProjection(scope) {
21
+ if (!scope) return void 0;
22
+ return {
23
+ organizationId: getOrgId(scope),
24
+ userId: getUserId(scope),
25
+ orgRoles: isMember(scope) ? scope.orgRoles : void 0
26
+ };
71
27
  }
72
28
  //#endregion
73
29
  //#region src/core/fastifyAdapter.ts
@@ -119,6 +75,8 @@ function createRequestContext(req) {
119
75
  queryCache: srv && "queryCache" in srv ? srv.queryCache : void 0,
120
76
  log: req.log
121
77
  };
78
+ const rawScope = reqWithExtras.scope;
79
+ const scopeProjection = buildRequestScopeProjection(rawScope);
122
80
  return {
123
81
  query: reqWithExtras.query ?? {},
124
82
  body: reqWithExtras.body ?? {},
@@ -135,10 +93,11 @@ function createRequestContext(req) {
135
93
  };
136
94
  })() : null,
137
95
  context: requestContext,
96
+ scope: scopeProjection,
138
97
  metadata: {
139
98
  ...reqWithExtras.context,
140
99
  arc: reqWithExtras.arc,
141
- _scope: reqWithExtras.scope,
100
+ _scope: rawScope,
142
101
  _ownershipCheck: reqWithExtras._ownershipCheck,
143
102
  _policyFilters: reqWithExtras._policyFilters ?? {},
144
103
  log: reqWithExtras.log
@@ -667,6 +626,52 @@ function createPermissionMiddleware(permission, resourceName, action) {
667
626
  return buildPermissionMiddleware(permission, resourceName, action);
668
627
  }
669
628
  //#endregion
629
+ //#region src/core/schemaOptions.ts
630
+ /**
631
+ * Inject the tenant-scoping field rule into `schemaOptions.fieldRules`:
632
+ *
633
+ * { [tenantField]: { systemManaged: true, preserveForElevated: true } }
634
+ *
635
+ * Why both flags: `systemManaged` tells `BodySanitizer` to strip the
636
+ * field from inbound bodies (so member clients can't forge a target
637
+ * tenant). `preserveForElevated` exempts elevated-admin scopes from the
638
+ * strip, so platform admins without a pinned org can still pick a target
639
+ * org via the request body (the only channel they have —
640
+ * `BaseController.create` can't re-stamp from scope when scope has no
641
+ * orgId).
642
+ *
643
+ * **Returns a new `RouteSchemaOptions`** — the input is never mutated.
644
+ * Callers should assign the return value to whatever config slot they
645
+ * read from downstream (always the `resolvedConfig`, never raw `config`).
646
+ *
647
+ * **No-op when:**
648
+ * - `tenantField` is `false` (platform-universal resource)
649
+ * - `tenantField` is undefined
650
+ * - The caller already declared `fieldRules[tenantField].systemManaged`
651
+ * (even as `false`) — explicit opt-outs are respected
652
+ *
653
+ * `preserveForElevated` defaults to `true` but is preserved verbatim
654
+ * when the caller set it explicitly.
655
+ */
656
+ function autoInjectTenantFieldRules(schemaOptions, tenantField) {
657
+ if (tenantField === false || tenantField === void 0) return schemaOptions;
658
+ const fieldName = tenantField || "organizationId";
659
+ const existing = schemaOptions?.fieldRules ?? {};
660
+ const existingRule = existing[fieldName];
661
+ if (existingRule && existingRule.systemManaged !== void 0) return schemaOptions;
662
+ return {
663
+ ...schemaOptions ?? {},
664
+ fieldRules: {
665
+ ...existing,
666
+ [fieldName]: {
667
+ ...existingRule ?? {},
668
+ systemManaged: true,
669
+ preserveForElevated: existingRule?.preserveForElevated ?? true
670
+ }
671
+ }
672
+ };
673
+ }
674
+ //#endregion
670
675
  //#region src/core/validateResourceConfig.ts
671
676
  /**
672
677
  * Resource Configuration Validator
@@ -926,6 +931,7 @@ function defineResource(config) {
926
931
  const originalPresets = (config.presets ?? []).map((p) => typeof p === "string" ? p : p.name);
927
932
  const resolvedConfig = config.presets?.length ? applyPresets(config, config.presets) : config;
928
933
  resolvedConfig._appliedPresets = originalPresets;
934
+ resolvedConfig.schemaOptions = autoInjectTenantFieldRules(resolvedConfig.schemaOptions, resolvedConfig.tenantField);
929
935
  let controller = resolvedConfig.controller;
930
936
  if (!controller && hasCrudRoutes && repository) {
931
937
  const qp = resolvedConfig.queryParser;
@@ -941,6 +947,7 @@ function defineResource(config) {
941
947
  maxLimit: maxLimitFromParser,
942
948
  tenantField: resolvedConfig.tenantField,
943
949
  idField: resolvedConfig.idField,
950
+ ...resolvedConfig.defaultSort !== void 0 ? { defaultSort: resolvedConfig.defaultSort } : {},
944
951
  matchesFilter: config.adapter?.matchesFilter,
945
952
  cache: resolvedConfig.cache,
946
953
  onFieldWriteDenied: resolvedConfig.onFieldWriteDenied,
@@ -965,11 +972,17 @@ function defineResource(config) {
965
972
  if (config.hooks) {
966
973
  const h = config.hooks;
967
974
  const inlineHooks = [];
968
- const toCtx = (ctx) => ({
969
- data: ctx.data ?? ctx.result ?? {},
970
- user: ctx.user,
971
- meta: ctx.meta
972
- });
975
+ const toCtx = (ctx) => {
976
+ const context = ctx.context;
977
+ const rawScope = context?._scope;
978
+ return {
979
+ data: ctx.data ?? ctx.result ?? {},
980
+ user: ctx.user,
981
+ context,
982
+ scope: buildRequestScopeProjection(rawScope),
983
+ meta: ctx.meta
984
+ };
985
+ };
973
986
  if (h.beforeCreate) {
974
987
  const fn = h.beforeCreate;
975
988
  inlineHooks.push({
@@ -1028,15 +1041,15 @@ function defineResource(config) {
1028
1041
  }
1029
1042
  if (!config.skipRegistry) try {
1030
1043
  let openApiSchemas;
1031
- if (config.adapter?.generateSchemas) {
1044
+ if (resolvedConfig.adapter?.generateSchemas) {
1032
1045
  const adapterContext = {
1033
- idField: config.idField,
1034
- resourceName: config.name
1046
+ idField: resolvedConfig.idField,
1047
+ resourceName: resolvedConfig.name
1035
1048
  };
1036
- const generated = config.adapter.generateSchemas(config.schemaOptions, adapterContext);
1049
+ const generated = resolvedConfig.adapter.generateSchemas(resolvedConfig.schemaOptions, adapterContext);
1037
1050
  if (generated) openApiSchemas = generated;
1038
1051
  }
1039
- if (config.idField && config.idField !== "_id" && openApiSchemas?.params && typeof openApiSchemas.params === "object") {
1052
+ if (resolvedConfig.idField && resolvedConfig.idField !== "_id" && openApiSchemas?.params && typeof openApiSchemas.params === "object") {
1040
1053
  const params = openApiSchemas.params;
1041
1054
  const properties = params.properties;
1042
1055
  const idProp = properties?.id;
@@ -1047,7 +1060,7 @@ function defineResource(config) {
1047
1060
  delete cleanedId.pattern;
1048
1061
  delete cleanedId.minLength;
1049
1062
  delete cleanedId.maxLength;
1050
- if (!cleanedId.description) cleanedId.description = `${config.idField} (custom ID field)`;
1063
+ if (!cleanedId.description) cleanedId.description = `${resolvedConfig.idField} (custom ID field)`;
1051
1064
  openApiSchemas = {
1052
1065
  ...openApiSchemas,
1053
1066
  params: {
@@ -1061,7 +1074,7 @@ function defineResource(config) {
1061
1074
  }
1062
1075
  }
1063
1076
  }
1064
- const queryParser = config.queryParser;
1077
+ const queryParser = resolvedConfig.queryParser;
1065
1078
  if (queryParser?.getQuerySchema) {
1066
1079
  const querySchema = queryParser.getQuerySchema();
1067
1080
  if (querySchema) openApiSchemas = {
@@ -1069,13 +1082,13 @@ function defineResource(config) {
1069
1082
  listQuery: querySchema
1070
1083
  };
1071
1084
  }
1072
- if (config.openApiSchemas) openApiSchemas = {
1085
+ if (resolvedConfig.openApiSchemas) openApiSchemas = {
1073
1086
  ...openApiSchemas,
1074
- ...config.openApiSchemas
1087
+ ...resolvedConfig.openApiSchemas
1075
1088
  };
1076
1089
  if (openApiSchemas) openApiSchemas = convertOpenApiSchemas(openApiSchemas);
1077
1090
  resource._registryMeta = {
1078
- module: config.module,
1091
+ module: resolvedConfig.module,
1079
1092
  openApiSchemas
1080
1093
  };
1081
1094
  } catch {}
@@ -1287,8 +1300,8 @@ var ResourceDefinition = class {
1287
1300
  fields: self.fields
1288
1301
  });
1289
1302
  if (self.actions && Object.keys(self.actions).length > 0) {
1290
- const { createActionRouter } = await import("./createActionRouter-Bp_5c_2b.mjs").then((n) => n.n);
1291
- createActionRouter(instance, normalizeActionsToRouterConfig(self.actions, self.actionPermissions, self.tag));
1303
+ const { createActionRouter } = await import("./createActionRouter-C8UUB3Px.mjs").then((n) => n.n);
1304
+ createActionRouter(instance, normalizeActionsToRouterConfig(self.actions, self.actionPermissions, self.tag, self.permissions, self.name, typedInstance.log));
1292
1305
  }
1293
1306
  if (self.events && Object.keys(self.events).length > 0) typedInstance.log?.debug?.(`Resource '${self.name}' defined ${Object.keys(self.events).length} events`);
1294
1307
  }, { prefix: self.prefix });
@@ -1354,18 +1367,53 @@ function capitalize(str) {
1354
1367
  return str.charAt(0).toUpperCase() + str.slice(1);
1355
1368
  }
1356
1369
  /**
1357
- * Normalize ActionsMap into the ActionRouterConfig shape that createActionRouter expects.
1370
+ * Normalize `ActionsMap` into the `ActionRouterConfig` shape that
1371
+ * `createActionRouter` expects.
1372
+ *
1373
+ * **Permission fallback chain (fail-closed, v2.10.5):**
1374
+ * Actions mutate state, so "no permission declared" historically meant
1375
+ * "authenticated users can call it" — a silent authz hole for apps using
1376
+ * the function shorthand `actions: { send: async (id, data, req) => ... }`.
1377
+ *
1378
+ * The chain is now:
1379
+ * 1. `ActionDefinition.permissions` — explicit per-action check.
1380
+ * 2. Resource-level `actionPermissions` — explicit global-for-actions.
1381
+ * 3. Resource-level `permissions.update` — sensible default (actions mutate).
1382
+ * 4. Boot-time error — forces the author to pick an explicit gate.
1383
+ *
1384
+ * When step 3 fires, we log a warning (not a throw) so upgrading apps
1385
+ * aren't bricked by the behavior change, but the gap is visible. Apps
1386
+ * that genuinely want public actions must declare `allowPublic()`
1387
+ * explicitly — auth-by-accident is no longer a supported state.
1358
1388
  */
1359
- function normalizeActionsToRouterConfig(actions, globalAuth, tag) {
1389
+ function normalizeActionsToRouterConfig(actions, globalAuth, tag, resourcePermissions, resourceName, log) {
1360
1390
  const handlers = {};
1361
1391
  const permissions = {};
1362
1392
  const schemas = {};
1363
- for (const [name, entry] of Object.entries(actions)) if (typeof entry === "function") handlers[name] = entry;
1364
- else {
1365
- const def = entry;
1366
- handlers[name] = def.handler;
1367
- if (def.permissions) permissions[name] = def.permissions;
1368
- if (def.schema) schemas[name] = def.schema;
1393
+ for (const [name, entry] of Object.entries(actions)) {
1394
+ const explicit = typeof entry !== "function" && entry.permissions ? entry.permissions : void 0;
1395
+ if (typeof entry === "function") handlers[name] = entry;
1396
+ else {
1397
+ const def = entry;
1398
+ handlers[name] = def.handler;
1399
+ if (def.permissions) permissions[name] = def.permissions;
1400
+ if (def.schema) schemas[name] = def.schema;
1401
+ }
1402
+ const effective = resolveActionPermission({
1403
+ action: entry,
1404
+ resourcePermissions,
1405
+ resourceActionPermissions: void 0,
1406
+ globalAuth
1407
+ });
1408
+ if (!explicit && !globalAuth && effective && effective === resourcePermissions?.update) {
1409
+ permissions[name] = effective;
1410
+ log?.warn?.({
1411
+ resource: resourceName,
1412
+ action: name,
1413
+ fallback: "permissions.update"
1414
+ }, `[Arc] Action '${resourceName}.${name}' has no explicit permission — falling back to the resource's \`permissions.update\` gate. Declare \`actions.${name}.permissions\` (or resource \`actionPermissions\`) to silence this.`);
1415
+ }
1416
+ if (!effective) throw new Error(`[Arc] Resource '${resourceName}': action '${name}' has no permission gate and the resource defines no \`permissions.update\` fallback. Declare one of:\n - \`actions.${name}.permissions: <PermissionCheck>\` (per-action)\n - \`actionPermissions: <PermissionCheck>\` (resource-wide)\n - \`permissions.update: <PermissionCheck>\` (inherited by actions)\nUse \`allowPublic()\` if you genuinely want the action unauthenticated.`);
1369
1417
  }
1370
1418
  return {
1371
1419
  tag,
@@ -1408,4 +1456,4 @@ function defineResourceVariants(base, variants) {
1408
1456
  return out;
1409
1457
  }
1410
1458
  //#endregion
1411
- export { formatValidationErrors as a, createPermissionMiddleware as c, createRequestContext as d, getControllerContext as f, pipe as h, assertValidConfig as i, createCrudHandlers as l, sendControllerResponse as m, ResourceDefinition as n, validateResourceConfig as o, getControllerScope as p, defineResource as r, createCrudRouter as s, defineResourceVariants as t, createFastifyHandler as u };
1459
+ export { formatValidationErrors as a, createPermissionMiddleware as c, createRequestContext as d, getControllerContext as f, assertValidConfig as i, createCrudHandlers as l, sendControllerResponse as m, ResourceDefinition as n, validateResourceConfig as o, getControllerScope as p, defineResource as r, createCrudRouter as s, defineResourceVariants as t, createFastifyHandler as u };
@@ -116,10 +116,7 @@ const developmentPreset = {
116
116
  "x-request-id"
117
117
  ]
118
118
  },
119
- rateLimit: {
120
- max: 1e3,
121
- timeWindow: "1 minute"
122
- },
119
+ rateLimit: false,
123
120
  underPressure: {
124
121
  exposeStatusRoute: true,
125
122
  maxEventLoopDelay: 5e3
@@ -207,7 +204,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
207
204
  await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
208
205
  trackPlugin("arc-core");
209
206
  if (config.arcPlugins?.events !== false) {
210
- const { default: eventPlugin } = await import("./eventPlugin-DCUjuiQT.mjs").then((n) => n.n);
207
+ const { default: eventPlugin } = await import("./eventPlugin-ByU4Cv0e.mjs").then((n) => n.n);
211
208
  const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
212
209
  await fastify.register(eventPlugin, {
213
210
  ...eventOpts,
@@ -243,15 +240,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
243
240
  trackPlugin("arc-graceful-shutdown");
244
241
  }
245
242
  if (config.arcPlugins?.caching) {
246
- const { default: cachingPlugin } = await import("./caching-CBpK_SCM.mjs").then((n) => n.r);
243
+ const { default: cachingPlugin } = await import("./caching-3h93rkJM.mjs").then((n) => n.r);
247
244
  const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
248
245
  await fastify.register(cachingPlugin, opts);
249
246
  trackPlugin("arc-caching", opts);
250
247
  }
251
248
  if (config.arcPlugins?.queryCache) {
252
- const { queryCachePlugin } = await import("./queryCachePlugin-DQCEfJis.mjs").then((n) => n.n);
249
+ const { queryCachePlugin } = await import("./queryCachePlugin-ChLNZvFT.mjs").then((n) => n.n);
253
250
  const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
254
- const store = config.stores?.queryCache ?? new (await (import("./memory-B5Amv9A1.mjs").then((n) => n.n))).MemoryCacheStore();
251
+ const store = config.stores?.queryCache ?? new (await (import("./memory-DqI-449b.mjs").then((n) => n.n))).MemoryCacheStore();
255
252
  await fastify.register(queryCachePlugin, {
256
253
  store,
257
254
  ...opts
@@ -260,19 +257,19 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
260
257
  }
261
258
  if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
262
259
  else {
263
- const { default: ssePlugin } = await import("./sse-yBCgOLGu.mjs").then((n) => n.r);
260
+ const { default: ssePlugin } = await import("./sse-D8UeDwis.mjs").then((n) => n.r);
264
261
  const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
265
262
  await fastify.register(ssePlugin, opts);
266
263
  trackPlugin("arc-sse", opts);
267
264
  }
268
265
  if (config.arcPlugins?.metrics) {
269
- const { default: metricsPlugin } = await import("./metrics-DuhiSEZI.mjs").then((n) => n.r);
266
+ const { default: metricsPlugin } = await import("./metrics-TuOmguhi.mjs").then((n) => n.r);
270
267
  const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
271
268
  await fastify.register(metricsPlugin, opts);
272
269
  trackPlugin("arc-metrics", opts);
273
270
  }
274
271
  if (config.arcPlugins?.versioning) {
275
- const { default: versioningPlugin } = await import("./versioning-C2U_bLY0.mjs").then((n) => n.r);
272
+ const { default: versioningPlugin } = await import("./versioning-B6mimogM.mjs").then((n) => n.r);
276
273
  await fastify.register(versioningPlugin, config.arcPlugins.versioning);
277
274
  trackPlugin("arc-versioning", config.arcPlugins.versioning);
278
275
  }
@@ -303,7 +300,8 @@ async function registerAuth(fastify, config, trackPlugin) {
303
300
  const { plugin, openapi } = authConfig.betterAuth;
304
301
  await fastify.register(plugin);
305
302
  trackPlugin("auth-better-auth");
306
- if (openapi && !fastify.arc.externalOpenApiPaths.includes(openapi)) fastify.arc.externalOpenApiPaths.push(openapi);
303
+ const arc = fastify.arc;
304
+ if (arc && openapi && !arc.externalOpenApiPaths.includes(openapi)) arc.externalOpenApiPaths.push(openapi);
307
305
  fastify.log.debug("Better Auth authentication enabled");
308
306
  break;
309
307
  }
@@ -340,7 +338,7 @@ async function registerAuth(fastify, config, trackPlugin) {
340
338
  */
341
339
  async function registerElevation(fastify, config, trackPlugin) {
342
340
  if (!config.elevation) return;
343
- const { elevationPlugin } = await import("./elevation-C7hgL_aI.mjs").then((n) => n.r);
341
+ const { elevationPlugin } = await import("./elevation-Dci0AYLT.mjs").then((n) => n.r);
344
342
  await fastify.register(elevationPlugin, config.elevation);
345
343
  trackPlugin("arc-elevation", config.elevation);
346
344
  fastify.log.debug("Elevation plugin enabled");
@@ -350,7 +348,7 @@ async function registerElevation(fastify, config, trackPlugin) {
350
348
  */
351
349
  async function registerErrorHandler(fastify, config, trackPlugin) {
352
350
  if (config.errorHandler === false) return;
353
- const { errorHandlerPlugin } = await import("./errorHandler-Bb49BvPD.mjs").then((n) => n.r);
351
+ const { errorHandlerPlugin } = await import("./errorHandler-CSxe7KIM.mjs").then((n) => n.r);
354
352
  const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
355
353
  await fastify.register(errorHandlerPlugin, errorOpts);
356
354
  trackPlugin("arc-error-handler", errorOpts);
@@ -417,7 +415,7 @@ async function registerResources(fastify, config) {
417
415
  fastify.log.debug(`${config.bootstrap.length} bootstrap function(s) executed`);
418
416
  }
419
417
  if (!config.resources?.length && config.resourceDir) {
420
- const { loadResources } = await import("./loadResources-BAzJItAJ.mjs").then((n) => n.n);
418
+ const { loadResources } = await import("./loadResources-Bksk8ydA.mjs").then((n) => n.n);
421
419
  const { resolve } = await import("node:path");
422
420
  const dir = resolve(config.resourceDir);
423
421
  config = {
@@ -463,6 +461,40 @@ async function registerResources(fastify, config) {
463
461
  }
464
462
  //#endregion
465
463
  //#region src/factory/registerSecurity.ts
464
+ /**
465
+ * Translate `skipPaths` sugar into a `@fastify/rate-limit` `allowList`
466
+ * function. A user-supplied `allowList` (array of IPs or function) is
467
+ * preserved and OR-ed with the path match.
468
+ */
469
+ function buildRateLimitOpts(input) {
470
+ const { skipPaths, allowList, ...rest } = input;
471
+ if (!skipPaths || skipPaths.length === 0) return allowList === void 0 ? rest : {
472
+ ...rest,
473
+ allowList
474
+ };
475
+ const matchesPath = compilePathMatcher(skipPaths);
476
+ const combined = async (req, key) => {
477
+ if (matchesPath((req.url ?? "").split("?", 1)[0] ?? "")) return true;
478
+ if (typeof allowList === "function") return await allowList(req, key);
479
+ if (Array.isArray(allowList)) return allowList.includes(key);
480
+ return false;
481
+ };
482
+ return {
483
+ ...rest,
484
+ allowList: combined
485
+ };
486
+ }
487
+ function compilePathMatcher(patterns) {
488
+ const prefixes = [];
489
+ const exact = /* @__PURE__ */ new Set();
490
+ for (const p of patterns) if (p.endsWith("*")) prefixes.push(p.slice(0, -1));
491
+ else exact.add(p);
492
+ return (path) => {
493
+ if (exact.has(path)) return true;
494
+ for (const pre of prefixes) if (path.startsWith(pre)) return true;
495
+ return false;
496
+ };
497
+ }
466
498
  const PLUGIN_REGISTRY = {
467
499
  cors: {
468
500
  package: "@fastify/cors",
@@ -532,10 +564,10 @@ async function registerSecurityPlugins(fastify, config) {
532
564
  } else fastify.log.warn("CORS disabled");
533
565
  if (config.rateLimit !== false) {
534
566
  const rateLimit = await loadPlugin("rateLimit");
535
- const rateLimitOpts = config.rateLimit ?? {
567
+ const rateLimitOpts = buildRateLimitOpts(config.rateLimit ?? {
536
568
  max: 100,
537
569
  timeWindow: "1 minute"
538
- };
570
+ });
539
571
  await fastify.register(rateLimit, rateLimitOpts);
540
572
  if (!(typeof rateLimitOpts === "object" && "store" in rateLimitOpts)) {
541
573
  if (config.runtime === "distributed") throw new Error("[Arc] runtime: 'distributed' with rate limiting requires a shared store.\nProvide rateLimit: { store: new RedisStore({ ... }) } or disable rate limiting: rateLimit: false");
@@ -676,7 +708,7 @@ function validateDistributedRuntime(options) {
676
708
  */
677
709
  async function createApp(options) {
678
710
  if (options.debug !== void 0 && options.debug !== false) {
679
- const { configureArcLogger } = await import("./logger-DLg8-Ueg.mjs").then((n) => n.r);
711
+ const { configureArcLogger } = await import("./logger/index.mjs");
680
712
  configureArcLogger({ debug: options.debug });
681
713
  }
682
714
  validateAuthOptions(options);
@@ -717,7 +749,9 @@ async function createApp(options) {
717
749
  await registerSecurityPlugins(fastify, config);
718
750
  await registerUtilityPlugins(fastify, config);
719
751
  const trackPlugin = (name, opts) => {
720
- fastify.arc.plugins.set(name, {
752
+ const arc = fastify.arc;
753
+ if (!arc) return;
754
+ arc.plugins.set(name, {
721
755
  name,
722
756
  options: opts,
723
757
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -730,7 +764,7 @@ async function createApp(options) {
730
764
  await registerErrorHandler(fastify, config, trackPlugin);
731
765
  await registerResources(fastify, config);
732
766
  if (config.replyHelpers) {
733
- const { replyHelpersPlugin } = await import("./replyHelpers-CXtJDAZ0.mjs").then((n) => n.n);
767
+ const { replyHelpersPlugin } = await import("./replyHelpers-BLojtuvR.mjs").then((n) => n.n);
734
768
  await fastify.register(replyHelpersPlugin);
735
769
  }
736
770
  if (config.serializeBigInt) fastify.addHook("preSerialization", async (_request, _reply, payload) => {
@@ -1,5 +1,5 @@
1
- import { x as RegistryEntry } from "../index-Cl0uoKd5.mjs";
2
- import { t as ExternalOpenApiPaths } from "../externalPaths-BQ8QijNH.mjs";
1
+ import { p as RegistryEntry } from "../index-BGbpGVyM.mjs";
2
+ import { t as ExternalOpenApiPaths } from "../externalPaths-Bapitwvd.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
4
 
5
5
  //#region src/docs/openapi.d.ts
@@ -1,5 +1,5 @@
1
- import { t as getUserRoles } from "../types-DV9WDfeg.mjs";
2
- import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-B5F8AddX.mjs";
1
+ import { t as getUserRoles } from "../types-D57iXYb8.mjs";
2
+ import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-DpNpqBmo.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/docs/scalar.ts
5
5
  const scalarPlugin = async (fastify, opts = {}) => {
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
3
- import { t as arcLog } from "./logger-DLg8-Ueg.mjs";
2
+ import { arcLog } from "./logger/index.mjs";
3
+ import { t as getUserRoles } from "./types-D57iXYb8.mjs";
4
4
  import fp from "fastify-plugin";
5
5
  //#region src/scope/elevation.ts
6
6
  var elevation_exports = /* @__PURE__ */ __exportAll({