@classytic/arc 2.15.4 → 2.16.0

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 (158) hide show
  1. package/README.md +1 -0
  2. package/bin/arc.js +12 -0
  3. package/dist/{BaseController-dx3m2J8V.mjs → BaseController-DlCCTIxJ.mjs} +61 -19
  4. package/dist/{HookSystem-Iiebom92.mjs → HookSystem-Cmf7-Etp.mjs} +8 -4
  5. package/dist/{QueryCache-D41bfdBB.d.mts → QueryCache-SvmT_9ti.d.mts} +1 -1
  6. package/dist/{ResourceRegistry-CTERg_2x.mjs → ResourceRegistry-f48hFk3m.mjs} +52 -9
  7. package/dist/audit/index.d.mts +1 -1
  8. package/dist/audit/index.mjs +4 -2
  9. package/dist/auth/index.d.mts +4 -4
  10. package/dist/auth/index.mjs +4 -4
  11. package/dist/auth/redis-session.d.mts +1 -1
  12. package/dist/{betterAuthOpenApi--M_i87dQ.mjs → betterAuthOpenApi-ClWxaceA.mjs} +10 -6
  13. package/dist/buildHandler-BZX6zzDM.mjs +300 -0
  14. package/dist/cache/index.d.mts +3 -3
  15. package/dist/cache/index.mjs +3 -3
  16. package/dist/{caching-SM8gghN6.mjs → caching-TeHE8G-v.mjs} +1 -1
  17. package/dist/cli/commands/describe.d.mts +35 -1
  18. package/dist/cli/commands/describe.mjs +52 -12
  19. package/dist/cli/commands/docs.d.mts +1 -4
  20. package/dist/cli/commands/docs.mjs +4 -16
  21. package/dist/cli/commands/generate.d.mts +2 -20
  22. package/dist/cli/commands/generate.mjs +1 -546
  23. package/dist/cli/commands/init.d.mts +2 -40
  24. package/dist/cli/commands/init.mjs +1 -3045
  25. package/dist/cli/commands/introspect.mjs +53 -64
  26. package/dist/cli/index.d.mts +2 -2
  27. package/dist/cli/index.mjs +2 -2
  28. package/dist/{constants-Cxde4rpC.mjs → constants-TrJVIJl0.mjs} +7 -0
  29. package/dist/core/index.d.mts +3 -3
  30. package/dist/core/index.mjs +5 -5
  31. package/dist/{core-CvmOqEms.mjs → core-DBJ_j6rX.mjs} +222 -44
  32. package/dist/createActionRouter-DUpN3Dd1.mjs +288 -0
  33. package/dist/{createAggregationRouter-B0bPDf5b.mjs → createAggregationRouter-Dq-TUCuY.mjs} +3 -2
  34. package/dist/{createApp-PFegs47-.mjs → createApp-DNccuhyI.mjs} +16 -14
  35. package/dist/{defineEvent-D5h7EvAx.mjs → defineEvent-DRwY0fYm.mjs} +1 -1
  36. package/dist/docs/index.d.mts +2 -2
  37. package/dist/docs/index.mjs +1 -1
  38. package/dist/{errorHandler-Bk-AGhkU.mjs → errorHandler-DpoXQHZ9.mjs} +17 -14
  39. package/dist/errors-C1lX_jlm.d.mts +91 -0
  40. package/dist/{eventPlugin-CaKTYkYM.mjs → eventPlugin-C2cGqtRO.mjs} +1 -1
  41. package/dist/{eventPlugin-qXpqTebY.d.mts → eventPlugin-CtHC_av1.d.mts} +1 -1
  42. package/dist/events/index.d.mts +3 -3
  43. package/dist/events/index.mjs +5 -5
  44. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  45. package/dist/events/transports/redis.d.mts +1 -1
  46. package/dist/factory/index.d.mts +1 -1
  47. package/dist/factory/index.mjs +2 -2
  48. package/dist/{fields-COhcH3fk.d.mts → fields-Anj0xdih.d.mts} +1 -1
  49. package/dist/generate-BWFwgcCM.d.mts +38 -0
  50. package/dist/generate-CYac-OLv.mjs +654 -0
  51. package/dist/hooks/index.d.mts +1 -1
  52. package/dist/hooks/index.mjs +1 -1
  53. package/dist/idempotency/index.d.mts +2 -2
  54. package/dist/idempotency/index.mjs +1 -1
  55. package/dist/idempotency/redis.d.mts +1 -1
  56. package/dist/{index-BTqLEvhu.d.mts → index-3oIimXQn.d.mts} +12 -12
  57. package/dist/{index-BstGxcc3.d.mts → index-B-ulKx5P.d.mts} +55 -4
  58. package/dist/{index-BswOSJCE.d.mts → index-CkW0flkU.d.mts} +355 -16
  59. package/dist/index.d.mts +6 -6
  60. package/dist/index.mjs +7 -8
  61. package/dist/init-Dv71MsJr.d.mts +71 -0
  62. package/dist/init-HDvoO9L5.mjs +3098 -0
  63. package/dist/integrations/event-gateway.d.mts +2 -2
  64. package/dist/integrations/event-gateway.mjs +1 -1
  65. package/dist/integrations/index.d.mts +2 -2
  66. package/dist/integrations/jobs.mjs +3 -3
  67. package/dist/integrations/mcp/index.d.mts +239 -7
  68. package/dist/integrations/mcp/index.mjs +2 -528
  69. package/dist/integrations/mcp/testing.d.mts +2 -2
  70. package/dist/integrations/mcp/testing.mjs +6 -10
  71. package/dist/integrations/streamline.mjs +26 -1
  72. package/dist/integrations/websocket-redis.d.mts +1 -1
  73. package/dist/integrations/websocket.d.mts +1 -1
  74. package/dist/integrations/websocket.mjs +1 -0
  75. package/dist/loadResourcesFromEntry-BLMEI2Xa.mjs +51 -0
  76. package/dist/{resourceToTools-tFYUNmM0.mjs → mcpPlugin-7vGV51ED.mjs} +1021 -318
  77. package/dist/{memory-UBydS5ku.mjs → memory-QOLe11D5.mjs} +2 -0
  78. package/dist/middleware/index.d.mts +1 -1
  79. package/dist/middleware/index.mjs +1 -1
  80. package/dist/{openapi-BHXhoX8O.mjs → openapi-34T9yNwd.mjs} +47 -36
  81. package/dist/permissions/index.d.mts +2 -2
  82. package/dist/permissions/index.mjs +1 -1
  83. package/dist/{permissions-ohQyv50e.mjs → permissions-CTxMrreC.mjs} +2 -2
  84. package/dist/{pipe-Zr0KXjQe.mjs → pipe-DiCyvyPN.mjs} +1 -0
  85. package/dist/pipeline/index.d.mts +1 -1
  86. package/dist/pipeline/index.mjs +1 -1
  87. package/dist/plugins/index.d.mts +5 -5
  88. package/dist/plugins/index.mjs +10 -10
  89. package/dist/plugins/response-cache.mjs +5 -5
  90. package/dist/plugins/tracing-entry.d.mts +1 -1
  91. package/dist/plugins/tracing-entry.mjs +1 -1
  92. package/dist/{pluralize-DQgqgifU.mjs → pluralize-B9M8xvy-.mjs} +2 -1
  93. package/dist/presets/filesUpload.d.mts +4 -4
  94. package/dist/presets/filesUpload.mjs +2 -2
  95. package/dist/presets/index.d.mts +1 -1
  96. package/dist/presets/index.mjs +1 -1
  97. package/dist/presets/multiTenant.d.mts +1 -1
  98. package/dist/presets/multiTenant.mjs +4 -3
  99. package/dist/presets/search.d.mts +2 -2
  100. package/dist/presets/search.mjs +1 -1
  101. package/dist/{presets-BbkjdPeH.mjs → presets-C9BE6WaZ.mjs} +2 -2
  102. package/dist/{queryCachePlugin-m1XsgAIJ.mjs → queryCachePlugin-B4XMSSe7.mjs} +2 -2
  103. package/dist/{queryCachePlugin-CqMdLI2-.d.mts → queryCachePlugin-Biqzfbi5.d.mts} +2 -2
  104. package/dist/{redis-DiMkdHEl.d.mts → redis-Cyzrz6SX.d.mts} +1 -1
  105. package/dist/{redis-stream-D6HzR1Z_.d.mts → redis-stream-DT-YjzrB.d.mts} +1 -1
  106. package/dist/registry/index.d.mts +319 -2
  107. package/dist/registry/index.mjs +3 -3
  108. package/dist/registry-BBE23CDj.mjs +576 -0
  109. package/dist/{routerShared-DrOa-26E.mjs → routerShared-CZV5aabX.mjs} +3 -3
  110. package/dist/scope/index.d.mts +3 -3
  111. package/dist/scope/index.mjs +3 -3
  112. package/dist/{sse-Bz-5ZeTt.mjs → sse-BY6sTy4P.mjs} +1 -1
  113. package/dist/testing/index.d.mts +2 -2
  114. package/dist/testing/index.mjs +16 -7
  115. package/dist/testing/storageContract.d.mts +1 -1
  116. package/dist/types/index.d.mts +5 -5
  117. package/dist/types/storage.d.mts +1 -1
  118. package/dist/{types-C_s5moIu.mjs → types-Bi0r0vjG.mjs} +53 -1
  119. package/dist/{types-BQsjgQzS.d.mts → types-BsJMEQ4D.d.mts} +106 -12
  120. package/dist/{types-DrBaUwyV.d.mts → types-D-fYtKjb.d.mts} +33 -10
  121. package/dist/{types-CTYvcwHe.d.mts → types-DVfpSfx2.d.mts} +42 -1
  122. package/dist/utils/index.d.mts +1286 -2
  123. package/dist/utils/index.mjs +1 -1
  124. package/dist/{utils-_h9B3c57.mjs → utils-DC5ycPfr.mjs} +89 -40
  125. package/dist/{buildHandler-CcFOpJLh.mjs → validate-By96rH0r.mjs} +8 -299
  126. package/dist/{versioning-hmkPcDlX.d.mts → versioning-ZwX9tmbS.d.mts} +1 -1
  127. package/package.json +21 -28
  128. package/skills/arc/SKILL.md +300 -706
  129. package/skills/arc/references/auth.md +19 -7
  130. package/skills/arc-code-review/SKILL.md +1 -1
  131. package/skills/arc-code-review/references/arc-cheatsheet.md +100 -322
  132. package/dist/createActionRouter-S3MLVYot.mjs +0 -220
  133. package/dist/index-bRjYu21O.d.mts +0 -1320
  134. package/dist/org/index.d.mts +0 -66
  135. package/dist/org/index.mjs +0 -486
  136. package/dist/org/types.d.mts +0 -82
  137. package/dist/org/types.mjs +0 -1
  138. package/dist/registry-I-ogLgL9.mjs +0 -46
  139. /package/dist/{EventTransport-CT_52aWU.d.mts → EventTransport-C-2oAHtw.d.mts} +0 -0
  140. /package/dist/{EventTransport-DLWoUMHy.mjs → EventTransport-Hxvv5QQz.mjs} +0 -0
  141. /package/dist/{actionPermissions-CyUkQu6O.mjs → actionPermissions-Bjmvn7Eb.mjs} +0 -0
  142. /package/dist/{elevation-BXOWoGCF.d.mts → elevation-0YBpa663.d.mts} +0 -0
  143. /package/dist/{elevation-DgoeTyfX.mjs → elevation-Dci0AYLT.mjs} +0 -0
  144. /package/dist/{errorHandler-DFr45ZG4.d.mts → errorHandler-mHuyWzZE.d.mts} +0 -0
  145. /package/dist/{externalPaths-BD5nw6St.d.mts → externalPaths-DFg-2KTp.d.mts} +0 -0
  146. /package/dist/{interface-beEtJyWM.d.mts → interface-CH0OQudo.d.mts} +0 -0
  147. /package/dist/{interface-DfLGcus7.d.mts → interface-NwJ_qPlY.d.mts} +0 -0
  148. /package/dist/{keys-CGcCbNyu.mjs → keys-DopsCuyQ.mjs} +0 -0
  149. /package/dist/{loadResources-DBMQg_Aj.mjs → loadResources-ChQEj8ih.mjs} +0 -0
  150. /package/dist/{metrics-Qnvwc-LQ.mjs → metrics-TuOmguhi.mjs} +0 -0
  151. /package/dist/{replyHelpers-CK-FNO8E.mjs → replyHelpers-C-gD32oF.mjs} +0 -0
  152. /package/dist/{schemaIR-lYhC2gE5.mjs → schemaIR-Ctc89DSn.mjs} +0 -0
  153. /package/dist/{sessionManager-C4Le_UB3.d.mts → sessionManager-BqFegc0W.d.mts} +0 -0
  154. /package/dist/{storage-Dfzt4VTl.d.mts → storage-D2KZJAmn.d.mts} +0 -0
  155. /package/dist/{store-helpers-BkIN9-vu.mjs → store-helpers-B0sunfZZ.mjs} +0 -0
  156. /package/dist/{tracing-QJVprktp.d.mts → tracing-Dm8n7Cnn.d.mts} +0 -0
  157. /package/dist/{versioning-BUrT5aP4.mjs → versioning-B6mimogM.mjs} +0 -0
  158. /package/dist/{websocket-ChC2rqe1.d.mts → websocket-BkjeGZRn.d.mts} +0 -0
@@ -1,220 +0,0 @@
1
- import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import "./constants-Cxde4rpC.mjs";
3
- import { f as createError } from "./errors-j4aJm1Wg.mjs";
4
- import { a as buildAuthMiddlewareForPermissions, c as buildPreHandlerChain, f as resolveRouterPluginMw, l as buildRateLimitConfig, n as buildActionPipelineHandler, p as selectPluginMw, r as buildArcDecorator, t as buildActionPermissionMw, u as resolvePipelineSteps, y as sendControllerResponse } from "./routerShared-DrOa-26E.mjs";
5
- import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-lYhC2gE5.mjs";
6
- //#region src/core/createActionRouter.ts
7
- var createActionRouter_exports = /* @__PURE__ */ __exportAll({
8
- buildActionBodySchema: () => buildActionBodySchema,
9
- createActionRouter: () => createActionRouter
10
- });
11
- /**
12
- * Register the unified action endpoint: `POST /:id/action`.
13
- *
14
- * Shares every lifecycle primitive with the CRUD router — the preHandler
15
- * chain, the arc decorator, idempotency, rate-limit, and the response
16
- * shaper. The only thing that stays local is the dynamic permission check
17
- * (keyed by `body.action` at request time).
18
- */
19
- function createActionRouter(fastify, config) {
20
- const { tag, resourceName = tag ?? "action", actions, actionPermissions = {}, actionSchemas = {}, globalAuth, onError, fields: fieldPermissions, schemaOptions, idField = "_id", permissions: resourcePermissions, routeGuards = [], pipeline, rateLimit } = config;
21
- const actionEnum = Object.keys(actions);
22
- if (actionEnum.length === 0) {
23
- fastify.log.warn("[createActionRouter] No actions defined, skipping route creation");
24
- return;
25
- }
26
- const bodySchema = buildActionBodySchema(actionEnum, actionSchemas);
27
- const routeSchema = {
28
- tags: tag ? [tag] : void 0,
29
- summary: `Perform action (${actionEnum.join("/")})`,
30
- description: buildActionDescription(actions, actionPermissions),
31
- params: {
32
- type: "object",
33
- properties: { id: {
34
- type: "string",
35
- description: "Resource ID"
36
- } },
37
- required: ["id"]
38
- },
39
- body: bodySchema
40
- };
41
- const arcDecorator = buildArcDecorator({
42
- resourceName,
43
- schemaOptions,
44
- permissions: resourcePermissions,
45
- hooks: fastify.arc?.hooks,
46
- events: fastify.events,
47
- fields: fieldPermissions,
48
- idField
49
- });
50
- const authMw = buildAuthMiddlewareForPermissions(fastify, actionEnum.map((name) => actionPermissions[name] ?? globalAuth));
51
- const pluginMw = resolveRouterPluginMw(fastify, false);
52
- const wrappedHandlers = /* @__PURE__ */ new Map();
53
- for (const [name, handler] of Object.entries(actions)) {
54
- const steps = resolvePipelineSteps(pipeline, name);
55
- wrappedHandlers.set(name, buildActionPipelineHandler(handler, steps, name, resourceName));
56
- }
57
- const preHandler = buildPreHandlerChain({
58
- arcDecorator,
59
- authMw,
60
- permissionMw: buildActionPermissionMw(actionEnum, actionPermissions, globalAuth, resourceName),
61
- pluginMw: selectPluginMw("POST", pluginMw),
62
- routeGuards
63
- });
64
- const rateLimitConfig = buildRateLimitConfig(rateLimit);
65
- fastify.route({
66
- method: "POST",
67
- url: "/:id/action",
68
- schema: routeSchema,
69
- preHandler: preHandler.length > 0 ? preHandler : void 0,
70
- ...rateLimitConfig ? { config: rateLimitConfig } : {},
71
- handler: async (req, reply) => {
72
- const { action, ...data } = req.body;
73
- const { id } = req.params;
74
- const reqWithExtras = req;
75
- reqWithExtras.arc = {
76
- ...reqWithExtras.arc ?? {},
77
- entityId: id
78
- };
79
- const handler = wrappedHandlers.get(action);
80
- if (!handler) throw createError(400, `Invalid action '${action}'. Valid actions: ${actionEnum.join(", ")}`, { validActions: actionEnum });
81
- try {
82
- return sendControllerResponse(reply, await handler(id, data, req), req);
83
- } catch (error) {
84
- if (onError) {
85
- const { statusCode, error: errorMsg, code } = onError(error, action, id);
86
- throw createError(statusCode, errorMsg, code ? { code } : void 0);
87
- }
88
- const err = error;
89
- const statusCode = err.statusCode || err.status || 500;
90
- const errorCode = err.code || "ACTION_FAILED";
91
- if (statusCode >= 500) req.log.error({
92
- err: error,
93
- action,
94
- id
95
- }, "Action handler error");
96
- if (error?.name === "ArcError" || error instanceof Error === false) throw error;
97
- throw createError(statusCode, err.message || `Failed to execute '${action}' action`, { code: errorCode });
98
- }
99
- }
100
- });
101
- fastify.log.debug({
102
- actions: actionEnum,
103
- tag,
104
- resourceName
105
- }, "[createActionRouter] Registered action endpoint: POST /:id/action");
106
- }
107
- /**
108
- * Build a discriminated body schema for the unified action endpoint.
109
- *
110
- * Produces a schema of the form:
111
- * ```json
112
- * {
113
- * "type": "object",
114
- * "required": ["action"],
115
- * "properties": {
116
- * "action": { "type": "string", "enum": ["dispatch", "approve"] },
117
- * "carrier": { "type": "string" }
118
- * },
119
- * "oneOf": [
120
- * {
121
- * "properties": {
122
- * "action": { "const": "dispatch" },
123
- * "carrier": { "type": "string" } // ← every branch lists the union
124
- * },
125
- * "required": ["action", "carrier"]
126
- * },
127
- * {
128
- * "properties": {
129
- * "action": { "const": "approve" },
130
- * "carrier": { "type": "string" } // ← even though approve doesn't use it
131
- * },
132
- * "required": ["action"]
133
- * }
134
- * ]
135
- * }
136
- * ```
137
- *
138
- * **Why every branch carries the full property union.** AJV's
139
- * `removeAdditional: 'all'` (Fastify's framework default) interacts badly
140
- * with `oneOf`: when a branch's `properties` lacks a field, AJV strips it
141
- * from the body during that branch's evaluation — *even if a different
142
- * branch would have allowed it*. The strip mutates the body before
143
- * `oneOf` finishes discriminating, so by the time the matching branch
144
- * wins, the body has already lost fields. Concretely: `actions: { verify:
145
- * {}, hold: { schema: z.object({ amount, reason }.optional()) } }` +
146
- * `POST { action: 'hold', amount: 1, reason }` lands at the handler as
147
- * `{ action: 'hold' }`. Empirically reproduced and locked at
148
- * [tests/core/action-discriminator-strip.test.ts](../../tests/core/action-discriminator-strip.test.ts).
149
- *
150
- * Listing every action's properties on every branch makes per-branch
151
- * removeAdditional walks see every caller field as "in this branch's
152
- * properties," so nothing gets stripped during oneOf evaluation. The
153
- * `required` array stays per-action, so the handler still gets called
154
- * only when the matching branch's required-field contract is satisfied.
155
- * Per-branch `additionalProperties: false` (Zod v4 default) carries
156
- * through but, under host removeAdditional: 'all', it can no longer
157
- * reject sibling-action fields — those become silently stripped at top
158
- * level instead. That's the host's opt-in to stripping; arc's job is to
159
- * stop accidentally losing the action's *own* declared fields.
160
- *
161
- * Under arc's own `createApp` (`removeAdditional: false`), strict-mode
162
- * rejection still functions normally — see
163
- * [tests/core/action-strict-schema-parity.test.ts](../../tests/core/action-strict-schema-parity.test.ts).
164
- *
165
- * Exported so OpenAPI generation and MCP tool generation can reuse the same
166
- * schema shape (single source of truth).
167
- */
168
- function buildActionBodySchema(actionEnum, actionSchemas = {}) {
169
- const unionProperties = {};
170
- const irs = [];
171
- for (const actionName of actionEnum) {
172
- const ir = normalizeSchemaIR(actionSchemas[actionName]);
173
- irs.push({
174
- name: actionName,
175
- ir
176
- });
177
- for (const [key, val] of Object.entries(ir.properties)) unionProperties[key] = val;
178
- }
179
- const branches = [];
180
- for (const { name, ir } of irs) branches.push(schemaIRToJsonSchemaBranch({
181
- ...ir,
182
- properties: {
183
- ...unionProperties,
184
- ...ir.properties
185
- }
186
- }, {
187
- properties: { action: {
188
- type: "string",
189
- const: name
190
- } },
191
- required: ["action"]
192
- }));
193
- return {
194
- type: "object",
195
- required: ["action"],
196
- properties: {
197
- action: {
198
- type: "string",
199
- enum: [...actionEnum]
200
- },
201
- ...unionProperties
202
- },
203
- oneOf: branches
204
- };
205
- }
206
- /**
207
- * Build OpenAPI description with action list + role hints.
208
- * Reads `_roles` metadata from permission checks for docs.
209
- */
210
- function buildActionDescription(actions, actionPermissions) {
211
- const lines = ["Unified action endpoint for state transitions.\n\n**Available actions:**"];
212
- Object.keys(actions).forEach((action) => {
213
- const roles = actionPermissions[action]?._roles;
214
- const roleStr = roles?.length ? ` (requires: ${roles.join(" or ")})` : "";
215
- lines.push(`- \`${action}\`${roleStr}`);
216
- });
217
- return lines.join("\n");
218
- }
219
- //#endregion
220
- export { createActionRouter_exports as n, buildActionBodySchema as t };