@classytic/arc 2.3.0 → 2.4.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 (174) hide show
  1. package/README.md +187 -18
  2. package/bin/arc.js +11 -3
  3. package/dist/BaseController-CkM5dUh_.mjs +1031 -0
  4. package/dist/{EventTransport-BkUDYZEb.d.mts → EventTransport-wc5hSLik.d.mts} +1 -1
  5. package/dist/{HookSystem-BsGV-j2l.mjs → HookSystem-COkyWztM.mjs} +2 -3
  6. package/dist/{ResourceRegistry-7Ic20ZMw.mjs → ResourceRegistry-DeCIFlix.mjs} +8 -5
  7. package/dist/adapters/index.d.mts +3 -5
  8. package/dist/adapters/index.mjs +2 -3
  9. package/dist/{prisma-DJbMt3yf.mjs → adapters-DTC4Ug66.mjs} +45 -12
  10. package/dist/audit/index.d.mts +4 -7
  11. package/dist/audit/index.mjs +2 -29
  12. package/dist/audit/mongodb.d.mts +1 -4
  13. package/dist/audit/mongodb.mjs +2 -3
  14. package/dist/auth/index.d.mts +7 -9
  15. package/dist/auth/index.mjs +65 -63
  16. package/dist/auth/redis-session.d.mts +1 -1
  17. package/dist/auth/redis-session.mjs +1 -2
  18. package/dist/{betterAuthOpenApi-DjWDddNc.mjs → betterAuthOpenApi-lz0IRbXJ.mjs} +4 -6
  19. package/dist/cache/index.d.mts +23 -23
  20. package/dist/cache/index.mjs +4 -6
  21. package/dist/{caching-GSDJcA6-.mjs → caching-BSXB-Xr7.mjs} +2 -24
  22. package/dist/chunk-BpYLSNr0.mjs +14 -0
  23. package/dist/circuitBreaker-BOBOpN2w.mjs +284 -0
  24. package/dist/circuitBreaker-JP2GdJ4b.d.mts +206 -0
  25. package/dist/cli/commands/describe.mjs +24 -7
  26. package/dist/cli/commands/docs.mjs +6 -7
  27. package/dist/cli/commands/doctor.d.mts +10 -0
  28. package/dist/cli/commands/doctor.mjs +156 -0
  29. package/dist/cli/commands/generate.mjs +66 -17
  30. package/dist/cli/commands/init.mjs +315 -45
  31. package/dist/cli/commands/introspect.mjs +2 -4
  32. package/dist/cli/index.d.mts +1 -10
  33. package/dist/cli/index.mjs +4 -153
  34. package/dist/{constants-DdXFXQtN.mjs → constants-Cxde4rpC.mjs} +1 -2
  35. package/dist/core/index.d.mts +3 -5
  36. package/dist/core/index.mjs +5 -4
  37. package/dist/core-C1XCMtqM.mjs +185 -0
  38. package/dist/{createApp-CgKOPhA4.mjs → createApp-ByWNRsZj.mjs} +64 -35
  39. package/dist/{defineResource-DWbpJYtm.mjs → defineResource-D9aY5Cy6.mjs} +108 -1157
  40. package/dist/discovery/index.mjs +37 -5
  41. package/dist/docs/index.d.mts +6 -9
  42. package/dist/docs/index.mjs +3 -21
  43. package/dist/dynamic/index.d.mts +93 -0
  44. package/dist/dynamic/index.mjs +122 -0
  45. package/dist/{elevation-DSTbVvYj.mjs → elevation-BEdACOLB.mjs} +5 -36
  46. package/dist/{elevation-DGo5shaX.d.mts → elevation-Ca_yveIO.d.mts} +41 -7
  47. package/dist/{errorHandler-C3GY3_ow.mjs → errorHandler--zp54tGc.mjs} +3 -5
  48. package/dist/errorHandler-Do4vVQ1f.d.mts +139 -0
  49. package/dist/{errors-DBANPbGr.mjs → errors-rxhfP7Hf.mjs} +1 -2
  50. package/dist/{eventPlugin-BEOvaDqo.mjs → eventPlugin-Ba00swHF.mjs} +25 -27
  51. package/dist/{eventPlugin-H6wDDjGO.d.mts → eventPlugin-iGrSEmwJ.d.mts} +105 -5
  52. package/dist/events/index.d.mts +72 -7
  53. package/dist/events/index.mjs +216 -4
  54. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  55. package/dist/events/transports/redis-stream-entry.mjs +19 -7
  56. package/dist/events/transports/redis.d.mts +1 -1
  57. package/dist/events/transports/redis.mjs +3 -4
  58. package/dist/factory/index.d.mts +23 -9
  59. package/dist/factory/index.mjs +48 -3
  60. package/dist/{fields-Bi_AVKSo.d.mts → fields-DFwdaWCq.d.mts} +1 -1
  61. package/dist/{fields-CTd_CrKr.mjs → fields-ipsbIRPK.mjs} +1 -2
  62. package/dist/hooks/index.d.mts +1 -3
  63. package/dist/hooks/index.mjs +2 -3
  64. package/dist/idempotency/index.d.mts +5 -5
  65. package/dist/idempotency/index.mjs +3 -7
  66. package/dist/idempotency/mongodb.d.mts +1 -1
  67. package/dist/idempotency/mongodb.mjs +4 -5
  68. package/dist/idempotency/redis.d.mts +1 -1
  69. package/dist/idempotency/redis.mjs +2 -5
  70. package/dist/{fastifyAdapter-6b_eRDBw.d.mts → index-BL8CaQih.d.mts} +56 -57
  71. package/dist/index-Diqcm14c.d.mts +369 -0
  72. package/dist/{prisma-Dy5S5F5i.d.mts → index-yhxyjqNb.d.mts} +4 -5
  73. package/dist/index.d.mts +100 -105
  74. package/dist/index.mjs +85 -58
  75. package/dist/integrations/event-gateway.d.mts +1 -1
  76. package/dist/integrations/event-gateway.mjs +8 -4
  77. package/dist/integrations/index.d.mts +4 -2
  78. package/dist/integrations/index.mjs +1 -1
  79. package/dist/integrations/jobs.d.mts +2 -2
  80. package/dist/integrations/jobs.mjs +63 -14
  81. package/dist/integrations/mcp/index.d.mts +219 -0
  82. package/dist/integrations/mcp/index.mjs +572 -0
  83. package/dist/integrations/mcp/testing.d.mts +53 -0
  84. package/dist/integrations/mcp/testing.mjs +104 -0
  85. package/dist/integrations/streamline.mjs +39 -19
  86. package/dist/integrations/webhooks.d.mts +56 -0
  87. package/dist/integrations/webhooks.mjs +139 -0
  88. package/dist/integrations/websocket-redis.d.mts +46 -0
  89. package/dist/integrations/websocket-redis.mjs +50 -0
  90. package/dist/integrations/websocket.d.mts +68 -2
  91. package/dist/integrations/websocket.mjs +96 -13
  92. package/dist/{interface-CSNjltAc.d.mts → interface-B4awm1RJ.d.mts} +2 -2
  93. package/dist/interface-DGmPxakH.d.mts +2213 -0
  94. package/dist/{keys-DhqDRxv3.mjs → keys-qcD-TVJl.mjs} +3 -4
  95. package/dist/{logger-ByrvQWZO.mjs → logger-Dz3j1ItV.mjs} +2 -4
  96. package/dist/{memory-B2v7KrCB.mjs → memory-Cb_7iy9e.mjs} +2 -4
  97. package/dist/metrics-Csh4nsvv.mjs +224 -0
  98. package/dist/migrations/index.mjs +3 -7
  99. package/dist/{mongodb-DNKEExbf.mjs → mongodb-BuQ7fNTg.mjs} +1 -4
  100. package/dist/{mongodb-ClykrfGo.d.mts → mongodb-CUpYfxfD.d.mts} +2 -3
  101. package/dist/{mongodb-Dg8O_gvd.d.mts → mongodb-bga9AbkD.d.mts} +2 -2
  102. package/dist/{openapi-9nB_kiuR.mjs → openapi-CBmZ6EQN.mjs} +4 -21
  103. package/dist/org/index.d.mts +12 -14
  104. package/dist/org/index.mjs +92 -119
  105. package/dist/org/types.d.mts +2 -2
  106. package/dist/org/types.mjs +1 -1
  107. package/dist/permissions/index.d.mts +4 -278
  108. package/dist/permissions/index.mjs +4 -579
  109. package/dist/permissions-CA5zg0yK.mjs +751 -0
  110. package/dist/plugins/index.d.mts +104 -107
  111. package/dist/plugins/index.mjs +203 -313
  112. package/dist/plugins/response-cache.mjs +4 -69
  113. package/dist/plugins/tracing-entry.d.mts +1 -1
  114. package/dist/plugins/tracing-entry.mjs +24 -11
  115. package/dist/{pluralize-CM-jZg7p.mjs → pluralize-CcT6qF0a.mjs} +12 -13
  116. package/dist/policies/index.d.mts +2 -2
  117. package/dist/policies/index.mjs +80 -83
  118. package/dist/presets/index.d.mts +26 -19
  119. package/dist/presets/index.mjs +2 -142
  120. package/dist/presets/multiTenant.d.mts +1 -4
  121. package/dist/presets/multiTenant.mjs +4 -6
  122. package/dist/presets-C9QXJV1u.mjs +422 -0
  123. package/dist/{queryCachePlugin-B6R0d4av.mjs → queryCachePlugin-ClosZdNS.mjs} +6 -27
  124. package/dist/{queryCachePlugin-Q6SYuHZ6.d.mts → queryCachePlugin-DcmETvcB.d.mts} +3 -3
  125. package/dist/queryParser-CgCtsjti.mjs +352 -0
  126. package/dist/{redis-UwjEp8Ea.d.mts → redis-CQ5YxMC5.d.mts} +2 -2
  127. package/dist/{redis-stream-CBg0upHI.d.mts → redis-stream-BW9UKLZM.d.mts} +9 -2
  128. package/dist/registry/index.d.mts +1 -4
  129. package/dist/registry/index.mjs +3 -4
  130. package/dist/{introspectionPlugin-B3JkrjwU.mjs → registry-I-ogLgL9.mjs} +1 -8
  131. package/dist/{requestContext-xi6OKBL-.mjs → requestContext-DYtmNpm5.mjs} +1 -3
  132. package/dist/resourceToTools-B6ZN9Ing.mjs +489 -0
  133. package/dist/rpc/index.d.mts +90 -0
  134. package/dist/rpc/index.mjs +248 -0
  135. package/dist/{schemaConverter-Dtg0Kt9T.mjs → schemaConverter-DjzHpFam.mjs} +1 -2
  136. package/dist/schemas/index.d.mts +30 -30
  137. package/dist/schemas/index.mjs +2 -4
  138. package/dist/scope/index.d.mts +13 -2
  139. package/dist/scope/index.mjs +18 -5
  140. package/dist/{sessionManager-D_iEHjQl.d.mts → sessionManager-wbkYj2HL.d.mts} +2 -2
  141. package/dist/{sse-DkqQ1uxb.mjs → sse-BkViJPlT.mjs} +4 -25
  142. package/dist/testing/index.d.mts +551 -567
  143. package/dist/testing/index.mjs +1744 -1799
  144. package/dist/{tracing-8CEbhF0w.d.mts → tracing-bz_U4EM1.d.mts} +6 -1
  145. package/dist/{typeGuards-DwxA1t_L.mjs → typeGuards-Cj5Rgvlg.mjs} +1 -2
  146. package/dist/types/index.d.mts +4 -946
  147. package/dist/types/index.mjs +2 -4
  148. package/dist/types-BJmgxNbF.d.mts +275 -0
  149. package/dist/{types-RLkFVgaw.d.mts → types-BNUccdcf.d.mts} +2 -2
  150. package/dist/{types-Beqn1Un7.mjs → types-C6TQjtdi.mjs} +30 -2
  151. package/dist/{types-tKwaViYB.d.mts → types-Dt0-AI6E.d.mts} +68 -27
  152. package/dist/{types-DelU6kln.mjs → types-ZUu_h0jp.mjs} +1 -2
  153. package/dist/utils/index.d.mts +254 -351
  154. package/dist/utils/index.mjs +7 -6
  155. package/dist/utils-Dc0WhlIl.mjs +594 -0
  156. package/dist/versioning-BzfeHmhj.mjs +37 -0
  157. package/package.json +44 -10
  158. package/skills/arc/SKILL.md +506 -0
  159. package/skills/arc/references/auth.md +250 -0
  160. package/skills/arc/references/events.md +272 -0
  161. package/skills/arc/references/integrations.md +385 -0
  162. package/skills/arc/references/mcp.md +386 -0
  163. package/skills/arc/references/production.md +610 -0
  164. package/skills/arc/references/testing.md +183 -0
  165. package/dist/audited-CGdLiSlE.mjs +0 -140
  166. package/dist/chunk-C7Uep-_p.mjs +0 -20
  167. package/dist/circuitBreaker-CSS2VvL6.mjs +0 -1109
  168. package/dist/errorHandler-CW3OOeYq.d.mts +0 -72
  169. package/dist/interface-BtdYtQUA.d.mts +0 -1114
  170. package/dist/presets-BTeYbw7h.d.mts +0 -57
  171. package/dist/presets-CeFtfDR8.mjs +0 -119
  172. /package/dist/{errors-DAWRdiYP.d.mts → errors-CPpvPHT0.d.mts} +0 -0
  173. /package/dist/{externalPaths-SyPF2tgK.d.mts → externalPaths-DpO-s7r8.d.mts} +0 -0
  174. /package/dist/{interface-DTbsvIWe.d.mts → interface-D_BWALyZ.d.mts} +0 -0
@@ -1,156 +1,7 @@
1
+ import describe from "./commands/describe.mjs";
2
+ import { exportDocs } from "./commands/docs.mjs";
3
+ import { doctor } from "./commands/doctor.mjs";
1
4
  import generate from "./commands/generate.mjs";
2
5
  import init from "./commands/init.mjs";
3
6
  import introspect from "./commands/introspect.mjs";
4
- import describe from "./commands/describe.mjs";
5
- import { exportDocs } from "./commands/docs.mjs";
6
- import { existsSync, readFileSync } from "node:fs";
7
- import { join, resolve } from "node:path";
8
-
9
- //#region src/cli/commands/doctor.ts
10
- /**
11
- * Arc CLI - Doctor Command
12
- *
13
- * Health check utility that validates the development environment.
14
- * Checks Node.js version, dependencies, configuration, and env variables.
15
- */
16
- async function doctor(_args = []) {
17
- console.log("\nArc Doctor\n");
18
- const results = [];
19
- const cwd = process.cwd();
20
- const nodeVersion = process.versions.node;
21
- if (parseInt(nodeVersion.split(".")[0] ?? "0", 10) >= 22) results.push({
22
- status: "pass",
23
- label: `Node.js ${nodeVersion}`,
24
- detail: "required: >=22"
25
- });
26
- else results.push({
27
- status: "fail",
28
- label: `Node.js ${nodeVersion}`,
29
- detail: "required: >=22"
30
- });
31
- const pkg = findPackageJson(cwd);
32
- const allDeps = {
33
- ...pkg?.dependencies ?? {},
34
- ...pkg?.devDependencies ?? {}
35
- };
36
- const arcVersion = allDeps["@classytic/arc"];
37
- if (arcVersion) results.push({
38
- status: "pass",
39
- label: `@classytic/arc ${arcVersion}`
40
- });
41
- else results.push({
42
- status: "warn",
43
- label: "@classytic/arc not found in dependencies"
44
- });
45
- const fastifyVersion = allDeps["fastify"];
46
- if (fastifyVersion) {
47
- const clean = fastifyVersion.replace(/^[\^~>=<]+/, "");
48
- if (parseInt(clean.split(".")[0] ?? "0", 10) >= 5) results.push({
49
- status: "pass",
50
- label: `fastify ${fastifyVersion}`,
51
- detail: "required: ^5.0.0"
52
- });
53
- else results.push({
54
- status: "fail",
55
- label: `fastify ${fastifyVersion}`,
56
- detail: "required: ^5.0.0 — Arc requires Fastify 5"
57
- });
58
- } else results.push({
59
- status: "fail",
60
- label: "fastify not found in dependencies",
61
- detail: "required: ^5.0.0"
62
- });
63
- const tsconfigPath = resolve(cwd, "tsconfig.json");
64
- if (existsSync(tsconfigPath)) try {
65
- const stripped = readFileSync(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "");
66
- const moduleRes = JSON.parse(stripped)?.compilerOptions?.moduleResolution;
67
- if (moduleRes && ![
68
- "nodenext",
69
- "node16",
70
- "bundler"
71
- ].includes(moduleRes.toLowerCase())) results.push({
72
- status: "warn",
73
- label: "tsconfig.json found",
74
- detail: `moduleResolution "${moduleRes}" — recommend "NodeNext" or "Bundler"`
75
- });
76
- else results.push({
77
- status: "pass",
78
- label: "tsconfig.json found"
79
- });
80
- } catch {
81
- results.push({
82
- status: "pass",
83
- label: "tsconfig.json found"
84
- });
85
- }
86
- else results.push({
87
- status: "warn",
88
- label: "tsconfig.json not found"
89
- });
90
- for (const dep of [
91
- {
92
- name: "@fastify/rate-limit",
93
- purpose: "rate limiting"
94
- },
95
- {
96
- name: "@fastify/helmet",
97
- purpose: "security headers"
98
- },
99
- {
100
- name: "@fastify/cors",
101
- purpose: "CORS support"
102
- }
103
- ]) if (allDeps[dep.name]) results.push({
104
- status: "pass",
105
- label: `${dep.name} installed`
106
- });
107
- else results.push({
108
- status: "warn",
109
- label: `${dep.name} not installed`,
110
- detail: `${dep.purpose} disabled`
111
- });
112
- if (allDeps["better-auth"]) results.push({
113
- status: "pass",
114
- label: `better-auth ${allDeps["better-auth"]}`
115
- });
116
- for (const env of [{
117
- name: "MONGO_URI",
118
- severity: "warn",
119
- detail: "required at runtime for MongoDB"
120
- }, {
121
- name: "BETTER_AUTH_SECRET",
122
- severity: "warn",
123
- detail: "required for Better Auth session encryption"
124
- }]) if (process.env[env.name]) results.push({
125
- status: "pass",
126
- label: `${env.name} set`
127
- });
128
- else results.push({
129
- status: env.severity,
130
- label: `${env.name} not set`,
131
- detail: env.detail
132
- });
133
- let passCount = 0;
134
- let warnCount = 0;
135
- let failCount = 0;
136
- for (const r of results) {
137
- const icon = r.status === "pass" ? "[pass]" : r.status === "warn" ? "[warn]" : "[FAIL]";
138
- const detail = r.detail ? ` (${r.detail})` : "";
139
- console.log(` ${icon} ${r.label}${detail}`);
140
- if (r.status === "pass") passCount++;
141
- else if (r.status === "warn") warnCount++;
142
- else failCount++;
143
- }
144
- console.log(`\n${passCount} passed, ${warnCount} warnings, ${failCount} failures\n`);
145
- if (failCount > 0) process.exitCode = 1;
146
- }
147
- function findPackageJson(dir) {
148
- const paths = [join(dir, "package.json"), join(dir, "..", "package.json")];
149
- for (const p of paths) try {
150
- if (existsSync(p)) return JSON.parse(readFileSync(p, "utf-8"));
151
- } catch {}
152
- return null;
153
- }
154
-
155
- //#endregion
156
- export { describe, doctor, exportDocs, generate, init, introspect };
7
+ export { describe, doctor, exportDocs, generate, init, introspect };
@@ -79,6 +79,5 @@ const RESERVED_QUERY_PARAMS = Object.freeze(new Set([
79
79
  "lean",
80
80
  "_policyFilters"
81
81
  ]));
82
-
83
82
  //#endregion
84
- export { DEFAULT_SORT as a, HOOK_OPERATIONS as c, MAX_REGEX_LENGTH as d, MAX_SEARCH_LENGTH as f, SYSTEM_FIELDS as h, DEFAULT_MAX_LIMIT as i, HOOK_PHASES as l, RESERVED_QUERY_PARAMS as m, DEFAULT_ID_FIELD as n, DEFAULT_TENANT_FIELD as o, MUTATION_OPERATIONS as p, DEFAULT_LIMIT as r, DEFAULT_UPDATE_METHOD as s, CRUD_OPERATIONS as t, MAX_FILTER_DEPTH as u };
83
+ export { DEFAULT_SORT as a, HOOK_OPERATIONS as c, MAX_REGEX_LENGTH as d, MAX_SEARCH_LENGTH as f, SYSTEM_FIELDS as h, DEFAULT_MAX_LIMIT as i, HOOK_PHASES as l, RESERVED_QUERY_PARAMS as m, DEFAULT_ID_FIELD as n, DEFAULT_TENANT_FIELD as o, MUTATION_OPERATIONS as p, DEFAULT_LIMIT as r, DEFAULT_UPDATE_METHOD as s, CRUD_OPERATIONS as t, MAX_FILTER_DEPTH as u };
@@ -1,5 +1,3 @@
1
- import "../elevation-DGo5shaX.mjs";
2
- import { E as defineResource, T as ResourceDefinition, c as BaseController, d as QueryResolverConfig, f as BodySanitizer, h as AccessControlConfig, l as BaseControllerOptions, m as AccessControl, p as BodySanitizerConfig, u as QueryResolver } from "../interface-BtdYtQUA.mjs";
3
- import "../types-RLkFVgaw.mjs";
4
- import { A as createCrudRouter, C as MutationOperation, D as ActionRouterConfig, E as ActionHandler, O as IdempotencyService, S as MUTATION_OPERATIONS, T as SYSTEM_FIELDS, _ as HookOperation, a as getControllerScope, b as MAX_REGEX_LENGTH, c as CrudOperation, d as DEFAULT_MAX_LIMIT, f as DEFAULT_SORT, g as HOOK_PHASES, h as HOOK_OPERATIONS, i as getControllerContext, j as createPermissionMiddleware, k as createActionRouter, l as DEFAULT_ID_FIELD, m as DEFAULT_UPDATE_METHOD, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_TENANT_FIELD, r as createRequestContext, s as CRUD_OPERATIONS, t as createCrudHandlers, u as DEFAULT_LIMIT, v as HookPhase, w as RESERVED_QUERY_PARAMS, x as MAX_SEARCH_LENGTH, y as MAX_FILTER_DEPTH } from "../fastifyAdapter-6b_eRDBw.mjs";
5
- export { AccessControl, type AccessControlConfig, type ActionHandler, type ActionRouterConfig, BaseController, type BaseControllerOptions, BodySanitizer, type 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, type IdempotencyService, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, type QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
1
+ import { Ct as QueryResolverConfig, Dt as AccessControlConfig, Et as AccessControl, Lt as ResourceDefinition, Rt as defineResource, St as QueryResolver, Tt as BodySanitizerConfig, bt as BaseController, wt as BodySanitizer, xt as BaseControllerOptions } from "../interface-DGmPxakH.mjs";
2
+ 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, c as createPermissionMiddleware, d as IdempotencyService, f as createActionRouter, g as DEFAULT_LIMIT, h as DEFAULT_ID_FIELD, i as getControllerContext, j as SYSTEM_FIELDS, k as MutationOperation, l as ActionHandler, m as CrudOperation, n as createFastifyHandler, o as sendControllerResponse, p as CRUD_OPERATIONS, r as createRequestContext, s as createCrudRouter, t as createCrudHandlers, u as ActionRouterConfig, v as DEFAULT_SORT, w as HookPhase, x as HOOK_OPERATIONS, y as DEFAULT_TENANT_FIELD } from "../index-BL8CaQih.mjs";
3
+ export { AccessControl, AccessControlConfig, ActionHandler, ActionRouterConfig, 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, IdempotencyService, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,4 +1,5 @@
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-DdXFXQtN.mjs";
2
- import { _ as QueryResolver, c as createPermissionMiddleware, d as createFastifyHandler, f as createRequestContext, g as BaseController, h as sendControllerResponse, m as getControllerScope, n as defineResource, o as createActionRouter, p as getControllerContext, s as createCrudRouter, t as ResourceDefinition, u as createCrudHandlers, v as BodySanitizer, y as AccessControl } from "../defineResource-DWbpJYtm.mjs";
3
-
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, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
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 { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-CkM5dUh_.mjs";
3
+ import { t as createActionRouter } from "../core-C1XCMtqM.mjs";
4
+ import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-D9aY5Cy6.mjs";
5
+ 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, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, getControllerContext, getControllerScope, sendControllerResponse };
@@ -0,0 +1,185 @@
1
+ //#region src/core/createActionRouter.ts
2
+ /**
3
+ * Create action-based state transition endpoint
4
+ *
5
+ * Registers: POST /:id/action
6
+ * Body: { action: string, ...actionData }
7
+ *
8
+ * @param fastify - Fastify instance
9
+ * @param config - Action router configuration
10
+ */
11
+ function createActionRouter(fastify, config) {
12
+ const { tag, actions, actionPermissions = {}, actionSchemas = {}, globalAuth, idempotencyService, onError } = config;
13
+ const actionEnum = Object.keys(actions);
14
+ if (actionEnum.length === 0) {
15
+ fastify.log.warn("[createActionRouter] No actions defined, skipping route creation");
16
+ return;
17
+ }
18
+ const bodyProperties = { action: {
19
+ type: "string",
20
+ enum: actionEnum,
21
+ description: `Action to perform: ${actionEnum.join(" | ")}`
22
+ } };
23
+ Object.entries(actionSchemas).forEach(([actionName, schema]) => {
24
+ if (schema && typeof schema === "object") Object.entries(schema).forEach(([propName, propSchema]) => {
25
+ bodyProperties[propName] = {
26
+ ...propSchema,
27
+ description: `${propSchema.description || ""} (for ${actionName} action)`.trim()
28
+ };
29
+ });
30
+ });
31
+ const routeSchema = {
32
+ tags: tag ? [tag] : void 0,
33
+ summary: `Perform action (${actionEnum.join("/")})`,
34
+ description: buildActionDescription(actions, actionPermissions),
35
+ params: {
36
+ type: "object",
37
+ properties: { id: {
38
+ type: "string",
39
+ description: "Resource ID"
40
+ } },
41
+ required: ["id"]
42
+ },
43
+ body: {
44
+ type: "object",
45
+ properties: bodyProperties,
46
+ required: ["action"]
47
+ }
48
+ };
49
+ const preHandler = [];
50
+ const hasPublicActions = Object.entries(actionPermissions).some(([, p]) => p?._isPublic) || globalAuth && globalAuth?._isPublic;
51
+ const hasProtectedActions = Object.entries(actionPermissions).some(([, p]) => !p?._isPublic) || globalAuth && !globalAuth?._isPublic;
52
+ if (hasProtectedActions && !hasPublicActions && fastify.authenticate) preHandler.push(fastify.authenticate);
53
+ fastify.post("/:id/action", {
54
+ schema: routeSchema,
55
+ preHandler: preHandler.length ? preHandler : void 0
56
+ }, async (req, reply) => {
57
+ const { action, ...data } = req.body;
58
+ const { id } = req.params;
59
+ const rawIdempotencyKey = req.headers["idempotency-key"];
60
+ const idempotencyKey = Array.isArray(rawIdempotencyKey) ? rawIdempotencyKey[0] : rawIdempotencyKey;
61
+ const handler = actions[action];
62
+ if (!handler) return reply.code(400).send({
63
+ success: false,
64
+ error: `Invalid action '${action}'. Valid actions: ${actionEnum.join(", ")}`,
65
+ validActions: actionEnum
66
+ });
67
+ const permissionCheck = actionPermissions[action] ?? globalAuth;
68
+ if (hasPublicActions && hasProtectedActions && permissionCheck) {
69
+ if (!permissionCheck?._isPublic && fastify.authenticate) {
70
+ try {
71
+ await fastify.authenticate(req, reply);
72
+ } catch {
73
+ if (!reply.sent) return reply.code(401).send({
74
+ success: false,
75
+ error: "Authentication required"
76
+ });
77
+ return;
78
+ }
79
+ if (reply.sent) return;
80
+ }
81
+ }
82
+ if (permissionCheck) {
83
+ const context = {
84
+ user: req.user ?? null,
85
+ request: req,
86
+ resource: tag ?? "action",
87
+ action,
88
+ resourceId: id,
89
+ params: req.params,
90
+ data
91
+ };
92
+ let result;
93
+ try {
94
+ result = await permissionCheck(context);
95
+ } catch (err) {
96
+ req.log?.warn?.({
97
+ err,
98
+ resource: tag ?? "action",
99
+ action
100
+ }, "Permission check threw");
101
+ return reply.code(403).send({
102
+ success: false,
103
+ error: "Permission denied"
104
+ });
105
+ }
106
+ if (typeof result === "boolean") {
107
+ if (!result) return reply.code(context.user ? 403 : 401).send({
108
+ success: false,
109
+ error: context.user ? `Permission denied for '${action}'` : "Authentication required"
110
+ });
111
+ } else {
112
+ const permResult = result;
113
+ if (!permResult.granted) return reply.code(context.user ? 403 : 401).send({
114
+ success: false,
115
+ error: permResult.reason ?? (context.user ? `Permission denied for '${action}'` : "Authentication required")
116
+ });
117
+ }
118
+ }
119
+ try {
120
+ if (idempotencyKey && idempotencyService) {
121
+ const user = req.user;
122
+ const payloadForHash = {
123
+ action,
124
+ id,
125
+ data,
126
+ userId: (user?._id)?.toString?.() || user?.id || null
127
+ };
128
+ const idempotencyResult = await idempotencyService.check(idempotencyKey, payloadForHash);
129
+ if (!idempotencyResult.isNew && "existingResult" in idempotencyResult) return reply.send({
130
+ success: true,
131
+ data: idempotencyResult.existingResult,
132
+ cached: true
133
+ });
134
+ }
135
+ const result = await handler(id, data, req);
136
+ if (idempotencyService) await idempotencyService.complete(idempotencyKey, result);
137
+ return reply.send({
138
+ success: true,
139
+ data: result
140
+ });
141
+ } catch (error) {
142
+ if (idempotencyService) await idempotencyService.fail(idempotencyKey, error);
143
+ if (onError) {
144
+ const { statusCode, error: errorMsg, code } = onError(error, action, id);
145
+ return reply.code(statusCode).send({
146
+ success: false,
147
+ error: errorMsg,
148
+ code
149
+ });
150
+ }
151
+ const err = error;
152
+ const statusCode = err.statusCode || err.status || 500;
153
+ const errorCode = err.code || "ACTION_FAILED";
154
+ if (statusCode >= 500) req.log.error({
155
+ err: error,
156
+ action,
157
+ id
158
+ }, "Action handler error");
159
+ return reply.code(statusCode).send({
160
+ success: false,
161
+ error: err.message || `Failed to execute '${action}' action`,
162
+ code: errorCode
163
+ });
164
+ }
165
+ });
166
+ fastify.log.debug({
167
+ actions: actionEnum,
168
+ tag
169
+ }, "[createActionRouter] Registered action endpoint: POST /:id/action");
170
+ }
171
+ /**
172
+ * Build description with action details
173
+ * Uses _roles metadata from PermissionCheck functions for OpenAPI docs
174
+ */
175
+ function buildActionDescription(actions, actionPermissions) {
176
+ const lines = ["Unified action endpoint for state transitions.\n\n**Available actions:**"];
177
+ Object.keys(actions).forEach((action) => {
178
+ const roles = actionPermissions[action]?._roles;
179
+ const roleStr = roles?.length ? ` (requires: ${roles.join(" or ")})` : "";
180
+ lines.push(`- \`${action}\`${roleStr}`);
181
+ });
182
+ return lines.join("\n");
183
+ }
184
+ //#endregion
185
+ export { createActionRouter as t };
@@ -1,8 +1,7 @@
1
- import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
2
- import { n as PUBLIC_SCOPE } from "./types-Beqn1Un7.mjs";
1
+ import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
+ import { n as PUBLIC_SCOPE } from "./types-C6TQjtdi.mjs";
3
3
  import Fastify from "fastify";
4
4
  import qs from "qs";
5
-
6
5
  //#region src/factory/presets.ts
7
6
  /**
8
7
  * Production preset - strict security, performance optimized
@@ -61,7 +60,7 @@ const productionPreset = {
61
60
  },
62
61
  underPressure: {
63
62
  exposeStatusRoute: true,
64
- maxEventLoopDelay: 1e3,
63
+ maxEventLoopDelay: 3e3,
65
64
  maxHeapUsedBytes: 1024 * 1024 * 1024,
66
65
  maxRssBytes: 1024 * 1024 * 1024
67
66
  }
@@ -128,18 +127,29 @@ const testingPreset = {
128
127
  } }
129
128
  };
130
129
  /**
131
- * Edge/Serverless preset - minimal cold-start overhead
130
+ * Edge/Serverless preset minimal cold-start overhead
132
131
  *
133
- * Optimized for AWS Lambda, Vercel, Cloudflare Workers, and similar environments.
134
- * Disables all heavy plugins that add cold-start latency:
135
- * - Security headers (handled by API Gateway / CDN)
136
- * - Rate limiting (handled by API Gateway / CDN)
137
- * - Health monitoring (Lambda has its own health checks)
138
- * - File uploads (use pre-signed URLs instead)
139
- * - Raw body parsing (register per-route if needed)
132
+ * Strips non-essential plugins to reduce startup time. Designed for:
133
+ * - Cloudflare Workers (requires `nodejs_compat` flag + `toFetchHandler()`)
134
+ * - AWS Lambda via `@fastify/aws-lambda` or `toFetchHandler()`
135
+ * - Vercel Serverless Functions (Node.js runtime)
136
+ * - Google Cloud Functions (Node.js runtime)
137
+ * - Any environment where the platform handles security, rate limiting, and health checks
140
138
  *
141
- * Arc core plugins (requestId, health, gracefulShutdown) are also disabled
142
- * since the serverless runtime manages request lifecycle.
139
+ * Use with `toFetchHandler()` from `@classytic/arc/factory` for edge runtimes:
140
+ * ```typescript
141
+ * import { createApp, toFetchHandler } from '@classytic/arc/factory';
142
+ * const app = await createApp({ preset: 'edge' });
143
+ * export default { fetch: toFetchHandler(app) };
144
+ * ```
145
+ *
146
+ * **Edge runtime requirements:**
147
+ * - Cloudflare Workers: enable `nodejs_compat` in wrangler.toml
148
+ * - Vercel: use Node.js runtime (not Edge Runtime) or enable nodejs compat
149
+ *
150
+ * Arc uses `node:crypto` and `AsyncLocalStorage` — both supported by
151
+ * modern edge runtimes with Node.js compat flags. No TCP server is needed
152
+ * when using `toFetchHandler()` (routes through Fastify's `.inject()`).
143
153
  */
144
154
  const edgePreset = {
145
155
  logger: { level: "warn" },
@@ -170,7 +180,6 @@ function getPreset(name) {
170
180
  default: throw new Error(`Unknown preset: ${name}`);
171
181
  }
172
182
  }
173
-
174
183
  //#endregion
175
184
  //#region src/factory/createApp.ts
176
185
  /**
@@ -280,7 +289,7 @@ async function loadPlugin(name, logger) {
280
289
  */
281
290
  async function createApp(options) {
282
291
  if (options.debug !== void 0 && options.debug !== false) {
283
- const { configureArcLogger } = await import("./logger-ByrvQWZO.mjs").then((n) => n.r);
292
+ const { configureArcLogger } = await import("./logger-Dz3j1ItV.mjs").then((n) => n.r);
284
293
  configureArcLogger({ debug: options.debug });
285
294
  }
286
295
  const authConfig = options.auth;
@@ -288,15 +297,19 @@ async function createApp(options) {
288
297
  if (!isAuthDisabled && authConfig && authConfig.type === "jwt") {
289
298
  if (!authConfig.jwt?.secret && !authConfig.authenticate) throw new Error("createApp: JWT secret required when Arc auth is enabled.\nProvide auth.jwt.secret, auth.authenticate, or set auth: false to disable.\nExample: auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } }");
290
299
  }
300
+ const deferredWarnings = [];
291
301
  if (options.runtime === "distributed") {
292
302
  const MEMORY_NAMES = new Set(["memory", "memory-cache"]);
293
303
  const missing = [];
294
304
  const eventsTransport = options.stores?.events;
295
305
  if (!eventsTransport || MEMORY_NAMES.has(eventsTransport.name)) missing.push("events transport");
296
- const cacheStore = options.stores?.cache;
297
- if (!cacheStore || MEMORY_NAMES.has(cacheStore.name)) missing.push("cache store");
306
+ if (options.arcPlugins?.caching) {
307
+ const cacheStore = options.stores?.cache;
308
+ if (!cacheStore || MEMORY_NAMES.has(cacheStore.name)) missing.push("cache store");
309
+ }
298
310
  const idempotencyStore = options.stores?.idempotency;
299
- if (!idempotencyStore || MEMORY_NAMES.has(idempotencyStore.name)) missing.push("idempotency store");
311
+ if (idempotencyStore && MEMORY_NAMES.has(idempotencyStore.name)) missing.push("idempotency store (memory-backed in distributed mode)");
312
+ else if (!idempotencyStore) deferredWarnings.push("runtime: 'distributed' — no idempotency store configured. Write-path deduplication will be instance-local. If resources use the idempotency plugin, provide stores.idempotency with a Redis/MongoDB store.");
300
313
  if (options.arcPlugins?.queryCache) {
301
314
  const qcStore = options.stores?.queryCache;
302
315
  if (!qcStore || MEMORY_NAMES.has(qcStore.name)) missing.push("queryCache store");
@@ -307,7 +320,7 @@ async function createApp(options) {
307
320
  ...options.preset ? getPreset(options.preset) : {},
308
321
  ...options
309
322
  };
310
- let fastify = Fastify({
323
+ const fastify = Fastify({
311
324
  logger: config.logger ?? true,
312
325
  trustProxy: config.trustProxy ?? false,
313
326
  routerOptions: { querystringParser: (str) => qs.parse(str) },
@@ -318,6 +331,7 @@ async function createApp(options) {
318
331
  keywords: ["example", ...config.ajv?.keywords ?? []]
319
332
  } }
320
333
  });
334
+ for (const warning of deferredWarnings) fastify.log.warn(warning);
321
335
  if (config.typeProvider === "typebox") try {
322
336
  const { TypeBoxValidatorCompiler } = await import("@fastify/type-provider-typebox");
323
337
  fastify.setValidatorCompiler(TypeBoxValidatorCompiler);
@@ -342,7 +356,7 @@ async function createApp(options) {
342
356
  if (config.cors !== false) {
343
357
  const cors = await loadPlugin("cors");
344
358
  const corsOptions = { ...config.cors ?? {} };
345
- if (config.preset === "production" && (!corsOptions || !("origin" in corsOptions))) throw new Error("CORS origin must be explicitly configured in production.\nSet cors.origin to allowed domains or set cors: false to disable.\nExample: cors: { origin: ['https://yourdomain.com'] }\nDocs: https://github.com/classytic/arc#security");
359
+ if (config.preset === "production" && corsOptions && !("origin" in corsOptions)) fastify.log.warn("CORS origin is not explicitly configured in production. Set cors.origin to allowed domains, cors: { origin: '*' }, or cors: false to disable.");
346
360
  if (corsOptions.credentials && corsOptions.origin === "*") corsOptions.origin = true;
347
361
  await fastify.register(cors, corsOptions);
348
362
  fastify.log.debug("CORS enabled");
@@ -354,8 +368,11 @@ async function createApp(options) {
354
368
  timeWindow: "1 minute"
355
369
  };
356
370
  await fastify.register(rateLimit, rateLimitOpts);
357
- if (config.preset === "production") {
358
- if (!(typeof rateLimitOpts === "object" && "store" in rateLimitOpts)) fastify.log.warn("Rate limiting is using in-memory store. In multi-instance deployments, each instance tracks limits independently. Configure a Redis store for distributed rate limiting: rateLimit: { store: new RedisStore({ ... }) }");
371
+ if (!(typeof rateLimitOpts === "object" && "store" in rateLimitOpts)) {
372
+ if (config.runtime === "distributed") {
373
+ fastify.log.error("Rate limiting is using in-memory store in distributed mode. Each instance tracks limits independently — this breaks rate limiting. Configure a Redis store: rateLimit: { store: new RedisStore({ ... }) }");
374
+ throw new Error("[Arc] runtime: 'distributed' with rate limiting requires a shared store.\nProvide rateLimit: { store: new RedisStore({ ... }) } or disable rate limiting: rateLimit: false");
375
+ } else if (config.preset === "production") fastify.log.warn("Rate limiting is using in-memory store. In multi-instance deployments, each instance tracks limits independently. Configure a Redis store for distributed rate limiting: rateLimit: { store: new RedisStore({ ... }) }");
359
376
  }
360
377
  fastify.log.debug("Rate limiting enabled");
361
378
  } else fastify.log.warn("Rate limiting disabled");
@@ -409,7 +426,7 @@ async function createApp(options) {
409
426
  };
410
427
  trackPlugin("arc-core");
411
428
  if (config.arcPlugins?.events !== false) {
412
- const { default: eventPlugin } = await import("./eventPlugin-BEOvaDqo.mjs").then((n) => n.n);
429
+ const { default: eventPlugin } = await import("./eventPlugin-Ba00swHF.mjs").then((n) => n.n);
413
430
  const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
414
431
  await fastify.register(eventPlugin, {
415
432
  ...eventOpts,
@@ -434,16 +451,16 @@ async function createApp(options) {
434
451
  fastify.log.debug("Arc gracefulShutdown plugin enabled");
435
452
  }
436
453
  if (config.arcPlugins?.caching) {
437
- const { default: cachingPlugin } = await import("./caching-GSDJcA6-.mjs").then((n) => n.r);
454
+ const { default: cachingPlugin } = await import("./caching-BSXB-Xr7.mjs").then((n) => n.r);
438
455
  const cachingOpts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
439
456
  await fastify.register(cachingPlugin, cachingOpts);
440
457
  trackPlugin("arc-caching", cachingOpts);
441
458
  fastify.log.debug("Arc caching plugin enabled");
442
459
  }
443
460
  if (config.arcPlugins?.queryCache) {
444
- const { queryCachePlugin } = await import("./queryCachePlugin-B6R0d4av.mjs").then((n) => n.n);
461
+ const { queryCachePlugin } = await import("./queryCachePlugin-ClosZdNS.mjs").then((n) => n.n);
445
462
  const qcOpts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
446
- const store = options.stores?.queryCache ?? new (await (import("./memory-B2v7KrCB.mjs").then((n) => n.n))).MemoryCacheStore();
463
+ const store = options.stores?.queryCache ?? new (await (import("./memory-Cb_7iy9e.mjs").then((n) => n.n))).MemoryCacheStore();
447
464
  await fastify.register(queryCachePlugin, {
448
465
  store,
449
466
  ...qcOpts
@@ -453,12 +470,25 @@ async function createApp(options) {
453
470
  }
454
471
  if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
455
472
  else {
456
- const { default: ssePlugin } = await import("./sse-DkqQ1uxb.mjs").then((n) => n.r);
473
+ const { default: ssePlugin } = await import("./sse-BkViJPlT.mjs").then((n) => n.r);
457
474
  const sseOpts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
458
475
  await fastify.register(ssePlugin, sseOpts);
459
476
  trackPlugin("arc-sse", sseOpts);
460
477
  fastify.log.debug("Arc SSE plugin enabled");
461
478
  }
479
+ if (config.arcPlugins?.metrics) {
480
+ const { default: metricsPlugin } = await import("./metrics-Csh4nsvv.mjs").then((n) => n.r);
481
+ const metricsOpts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
482
+ await fastify.register(metricsPlugin, metricsOpts);
483
+ trackPlugin("arc-metrics", metricsOpts);
484
+ fastify.log.debug("Arc metrics plugin enabled");
485
+ }
486
+ if (config.arcPlugins?.versioning) {
487
+ const { default: versioningPlugin } = await import("./versioning-BzfeHmhj.mjs").then((n) => n.r);
488
+ await fastify.register(versioningPlugin, config.arcPlugins.versioning);
489
+ trackPlugin("arc-versioning", config.arcPlugins.versioning);
490
+ fastify.log.debug("Arc versioning plugin enabled");
491
+ }
462
492
  fastify.decorateRequest("scope", null);
463
493
  fastify.addHook("onRequest", async (request) => {
464
494
  if (!request.scope) request.scope = PUBLIC_SCOPE;
@@ -480,13 +510,13 @@ async function createApp(options) {
480
510
  break;
481
511
  case "authenticator": {
482
512
  const { authenticate, optionalAuthenticate } = authConfig;
483
- fastify.decorate("authenticate", async function(request, reply) {
513
+ fastify.decorate("authenticate", async (request, reply) => {
484
514
  await authenticate(request, reply);
485
515
  });
486
- if (!fastify.hasDecorator("optionalAuthenticate")) if (optionalAuthenticate) fastify.decorate("optionalAuthenticate", async function(request, reply) {
516
+ if (!fastify.hasDecorator("optionalAuthenticate")) if (optionalAuthenticate) fastify.decorate("optionalAuthenticate", async (request, reply) => {
487
517
  await optionalAuthenticate(request, reply);
488
518
  });
489
- else fastify.decorate("optionalAuthenticate", async function(request, reply) {
519
+ else fastify.decorate("optionalAuthenticate", async (request, reply) => {
490
520
  let intercepted = false;
491
521
  const proxyReply = new Proxy(reply, { get(target, prop) {
492
522
  if (prop === "code") return (statusCode) => {
@@ -521,13 +551,13 @@ async function createApp(options) {
521
551
  }
522
552
  }
523
553
  if (config.elevation) {
524
- const { elevationPlugin } = await import("./elevation-DSTbVvYj.mjs").then((n) => n.r);
554
+ const { elevationPlugin } = await import("./elevation-BEdACOLB.mjs").then((n) => n.r);
525
555
  await fastify.register(elevationPlugin, config.elevation);
526
556
  trackPlugin("arc-elevation", config.elevation);
527
557
  fastify.log.debug("Elevation plugin enabled");
528
558
  }
529
559
  if (config.errorHandler !== false) {
530
- const { errorHandlerPlugin } = await import("./errorHandler-C3GY3_ow.mjs").then((n) => n.n);
560
+ const { errorHandlerPlugin } = await import("./errorHandler--zp54tGc.mjs").then((n) => n.n);
531
561
  const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
532
562
  await fastify.register(errorHandlerPlugin, errorOpts);
533
563
  trackPlugin("arc-error-handler", errorOpts);
@@ -583,6 +613,5 @@ const ArcFactory = {
583
613
  });
584
614
  }
585
615
  };
586
-
587
616
  //#endregion
588
- export { getPreset as a, developmentPreset as i, createApp as n, productionPreset as o, createApp_exports as r, testingPreset as s, ArcFactory as t };
617
+ export { getPreset as a, developmentPreset as i, createApp as n, productionPreset as o, createApp_exports as r, testingPreset as s, ArcFactory as t };