@classytic/arc 2.10.8 → 2.11.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.
- package/dist/{BaseController-DVNKvoX4.mjs → BaseController-JNV08qOT.mjs} +480 -442
- package/dist/{queryCachePlugin-Dumka73q.d.mts → QueryCache-DOBNHBE0.d.mts} +2 -32
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-BXY4i-hw.mjs → adapters-D0tT2Tyo.mjs} +54 -0
- package/dist/audit/index.d.mts +1 -1
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.mjs +5 -5
- package/dist/{betterAuthOpenApi--rdY15Ld.mjs → betterAuthOpenApi-DwxtK3uG.mjs} +1 -1
- package/dist/cache/index.d.mts +3 -2
- package/dist/cache/index.mjs +3 -3
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +37 -27
- package/dist/cli/commands/init.mjs +46 -33
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/context/index.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -3
- package/dist/core-DXdSSFW-.mjs +1037 -0
- package/dist/createActionRouter-BwaSM0No.mjs +166 -0
- package/dist/{createApp-BwnEAO2h.mjs → createApp-P1d6rjPy.mjs} +75 -27
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-Dci0AYLT.mjs → elevation-DOFoxoDs.mjs} +1 -1
- package/dist/{errorHandler-CSxe7KIM.mjs → errorHandler-BQm8ZxTK.mjs} +1 -1
- package/dist/{eventPlugin-ByU4Cv0e.mjs → eventPlugin--5HIkdPU.mjs} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +2 -2
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/factory/index.d.mts +2 -2
- package/dist/factory/index.mjs +2 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-C_Noptz-.d.mts → index-BYCqHCVu.d.mts} +2 -2
- package/dist/{index-BGbpGVyM.d.mts → index-C_bgx9o4.d.mts} +712 -500
- package/dist/{index-BziRPS4H.d.mts → index-CvM1e09j.d.mts} +29 -10
- package/dist/{index-EqQN6p0W.d.mts → index-pUczGjO0.d.mts} +11 -8
- package/dist/index-smCAoA5W.d.mts +1179 -0
- package/dist/index.d.mts +6 -38
- package/dist/index.mjs +9 -9
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/streamline.d.mts +46 -5
- package/dist/integrations/streamline.mjs +50 -21
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +2 -154
- package/dist/integrations/websocket.mjs +292 -224
- package/dist/{keys-nWQGUTu1.mjs → keys-CARyUjiR.mjs} +2 -0
- package/dist/{loadResources-Bksk8ydA.mjs → loadResources-CPpkyKfM.mjs} +32 -8
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/{openapi-DpNpqBmo.mjs → openapi-C0L9ar7m.mjs} +4 -4
- package/dist/org/index.d.mts +1 -1
- package/dist/permissions/index.d.mts +1 -1
- package/dist/permissions/index.mjs +2 -4
- package/dist/{permissions-wkqRwicB.mjs → permissions-B4vU9L0Q.mjs} +221 -3
- package/dist/{pipe-CGJxqDGx.mjs → pipe-DVoIheVC.mjs} +1 -1
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +42 -24
- package/dist/presets/filesUpload.d.mts +1 -1
- package/dist/presets/filesUpload.mjs +3 -3
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +6 -0
- package/dist/presets/search.d.mts +1 -1
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-CrwOvuXI.mjs → presets-k604Lj99.mjs} +1 -1
- package/dist/queryCachePlugin-BUXBSm4F.d.mts +34 -0
- package/dist/{queryCachePlugin-ChLNZvFT.mjs → queryCachePlugin-Bq6bO6vc.mjs} +3 -3
- package/dist/{redis-MXLp1oOf.d.mts → redis-Cm1gnRDf.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{resourceToTools-BhF3JV5p.mjs → resourceToTools--okX6QBr.mjs} +534 -420
- package/dist/routerShared-DeESFp4a.mjs +515 -0
- package/dist/schemaIR-BlG9bY7v.mjs +137 -0
- package/dist/scope/index.mjs +2 -2
- package/dist/testing/index.d.mts +367 -711
- package/dist/testing/index.mjs +637 -1434
- package/dist/{tracing-xqXzWeaf.d.mts → tracing-DokiEsuz.d.mts} +9 -4
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +1 -3
- package/dist/{types-CVdgPXBW.d.mts → types-BdA4uMBV.d.mts} +191 -28
- package/dist/{types-CVKBssX5.d.mts → types-Bh_gEJBi.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -968
- package/dist/utils/index.mjs +5 -6
- package/dist/utils-D3Yxnrwr.mjs +1639 -0
- package/dist/websocket-CyJ1VIFI.d.mts +186 -0
- package/package.json +7 -5
- package/skills/arc/SKILL.md +124 -39
- package/skills/arc/references/testing.md +212 -183
- package/dist/applyPermissionResult-QhV1Pa-g.mjs +0 -37
- package/dist/core-3MWJosCH.mjs +0 -1459
- package/dist/createActionRouter-C8UUB3Px.mjs +0 -249
- package/dist/errors-BI8kEKsO.d.mts +0 -140
- package/dist/fields-CTMWOUDt.mjs +0 -126
- package/dist/queryParser-NR__Qiju.mjs +0 -419
- package/dist/types-CDnTEpga.mjs +0 -27
- package/dist/utils-LMwVidKy.mjs +0 -947
- /package/dist/{HookSystem-BjFu7zf1.mjs → HookSystem-CGsMd6oK.mjs} +0 -0
- /package/dist/{ResourceRegistry-CcN2LVrc.mjs → ResourceRegistry-DkAeAuTX.mjs} +0 -0
- /package/dist/{actionPermissions-TUVR3uiZ.mjs → actionPermissions-C8YYU92K.mjs} +0 -0
- /package/dist/{caching-3h93rkJM.mjs → caching-CheW3m-S.mjs} +0 -0
- /package/dist/{errorHandler-2ii4RIYr.d.mts → errorHandler-Co3lnVmJ.d.mts} +0 -0
- /package/dist/{errors-BqdUDja_.mjs → errors-D5c-5BJL.mjs} +0 -0
- /package/dist/{eventPlugin-D1ThQ1Pp.d.mts → eventPlugin-CUNjYYRY.d.mts} +0 -0
- /package/dist/{interface-B-pe8fhj.d.mts → interface-CkkWm5uR.d.mts} +0 -0
- /package/dist/{interface-yhyb_pLY.d.mts → interface-Da0r7Lna.d.mts} +0 -0
- /package/dist/{memory-DqI-449b.mjs → memory-DikHSvWa.mjs} +0 -0
- /package/dist/{metrics-TuOmguhi.mjs → metrics-Csh4nsvv.mjs} +0 -0
- /package/dist/{multipartBody-CUQGVlM_.mjs → multipartBody-CvTR1Un6.mjs} +0 -0
- /package/dist/{pluralize-CWP6MB39.mjs → pluralize-BneOJkpi.mjs} +0 -0
- /package/dist/{redis-stream-bkO88VHx.d.mts → redis-stream-CM8TXTix.d.mts} +0 -0
- /package/dist/{registry-B0Wl7uVV.mjs → registry-D63ee7fl.mjs} +0 -0
- /package/dist/{replyHelpers-BLojtuvR.mjs → replyHelpers-ByllIXXV.mjs} +0 -0
- /package/dist/{requestContext-C38GskNt.mjs → requestContext-CfRkaxwf.mjs} +0 -0
- /package/dist/{schemaConverter-BxFDdtXu.mjs → schemaConverter-B0oKLuqI.mjs} +0 -0
- /package/dist/{sse-D8UeDwis.mjs → sse-V7aXc3bW.mjs} +0 -0
- /package/dist/{store-helpers-DYYUQbQN.mjs → store-helpers-BhrzxvyQ.mjs} +0 -0
- /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
- /package/dist/{types-D57iXYb8.mjs → types-DV9WDfeg.mjs} +0 -0
- /package/dist/{versioning-B6mimogM.mjs → versioning-CGPjkqAg.mjs} +0 -0
- /package/dist/{versioning-CeUXHfjw.d.mts → versioning-M9lNLhO8.d.mts} +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import { a as buildAuthMiddlewareForPermissions, c as buildPreHandlerChain, d as resolveRouterPluginMw, f as selectPluginMw, l as buildRateLimitConfig, n as buildActionPipelineHandler, r as buildArcDecorator, t as buildActionPermissionMw, u as resolvePipelineSteps, v as sendControllerResponse } from "./routerShared-DeESFp4a.mjs";
|
|
3
|
+
import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-BlG9bY7v.mjs";
|
|
4
|
+
//#region src/core/createActionRouter.ts
|
|
5
|
+
var createActionRouter_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
buildActionBodySchema: () => buildActionBodySchema,
|
|
7
|
+
createActionRouter: () => createActionRouter
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Register the unified action endpoint: `POST /:id/action`.
|
|
11
|
+
*
|
|
12
|
+
* Shares every lifecycle primitive with the CRUD router — the preHandler
|
|
13
|
+
* chain, the arc decorator, idempotency, rate-limit, and the response
|
|
14
|
+
* shaper. The only thing that stays local is the dynamic permission check
|
|
15
|
+
* (keyed by `body.action` at request time).
|
|
16
|
+
*/
|
|
17
|
+
function createActionRouter(fastify, config) {
|
|
18
|
+
const { tag, resourceName = tag ?? "action", actions, actionPermissions = {}, actionSchemas = {}, globalAuth, onError, fields: fieldPermissions, schemaOptions, permissions: resourcePermissions, routeGuards = [], pipeline, rateLimit } = config;
|
|
19
|
+
const actionEnum = Object.keys(actions);
|
|
20
|
+
if (actionEnum.length === 0) {
|
|
21
|
+
fastify.log.warn("[createActionRouter] No actions defined, skipping route creation");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const bodySchema = buildActionBodySchema(actionEnum, actionSchemas);
|
|
25
|
+
const routeSchema = {
|
|
26
|
+
tags: tag ? [tag] : void 0,
|
|
27
|
+
summary: `Perform action (${actionEnum.join("/")})`,
|
|
28
|
+
description: buildActionDescription(actions, actionPermissions),
|
|
29
|
+
params: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: { id: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Resource ID"
|
|
34
|
+
} },
|
|
35
|
+
required: ["id"]
|
|
36
|
+
},
|
|
37
|
+
body: bodySchema
|
|
38
|
+
};
|
|
39
|
+
const arcDecorator = buildArcDecorator({
|
|
40
|
+
resourceName,
|
|
41
|
+
schemaOptions,
|
|
42
|
+
permissions: resourcePermissions,
|
|
43
|
+
hooks: fastify.arc?.hooks,
|
|
44
|
+
events: fastify.events,
|
|
45
|
+
fields: fieldPermissions
|
|
46
|
+
});
|
|
47
|
+
const authMw = buildAuthMiddlewareForPermissions(fastify, actionEnum.map((name) => actionPermissions[name] ?? globalAuth));
|
|
48
|
+
const pluginMw = resolveRouterPluginMw(fastify, false);
|
|
49
|
+
const wrappedHandlers = /* @__PURE__ */ new Map();
|
|
50
|
+
for (const [name, handler] of Object.entries(actions)) {
|
|
51
|
+
const steps = resolvePipelineSteps(pipeline, name);
|
|
52
|
+
wrappedHandlers.set(name, buildActionPipelineHandler(handler, steps, name, resourceName));
|
|
53
|
+
}
|
|
54
|
+
const preHandler = buildPreHandlerChain({
|
|
55
|
+
arcDecorator,
|
|
56
|
+
authMw,
|
|
57
|
+
permissionMw: buildActionPermissionMw(actionEnum, actionPermissions, globalAuth, resourceName),
|
|
58
|
+
pluginMw: selectPluginMw("POST", pluginMw),
|
|
59
|
+
routeGuards
|
|
60
|
+
});
|
|
61
|
+
const rateLimitConfig = buildRateLimitConfig(rateLimit);
|
|
62
|
+
fastify.route({
|
|
63
|
+
method: "POST",
|
|
64
|
+
url: "/:id/action",
|
|
65
|
+
schema: routeSchema,
|
|
66
|
+
preHandler: preHandler.length > 0 ? preHandler : void 0,
|
|
67
|
+
...rateLimitConfig ? { config: rateLimitConfig } : {},
|
|
68
|
+
handler: async (req, reply) => {
|
|
69
|
+
const { action, ...data } = req.body;
|
|
70
|
+
const { id } = req.params;
|
|
71
|
+
const handler = wrappedHandlers.get(action);
|
|
72
|
+
if (!handler) return sendControllerResponse(reply, {
|
|
73
|
+
success: false,
|
|
74
|
+
status: 400,
|
|
75
|
+
error: `Invalid action '${action}'. Valid actions: ${actionEnum.join(", ")}`,
|
|
76
|
+
meta: { validActions: actionEnum }
|
|
77
|
+
}, req);
|
|
78
|
+
try {
|
|
79
|
+
return sendControllerResponse(reply, await handler(id, data, req), req);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (onError) {
|
|
82
|
+
const { statusCode, error: errorMsg, code } = onError(error, action, id);
|
|
83
|
+
return sendControllerResponse(reply, {
|
|
84
|
+
success: false,
|
|
85
|
+
status: statusCode,
|
|
86
|
+
error: errorMsg,
|
|
87
|
+
...code ? { meta: { code } } : {}
|
|
88
|
+
}, req);
|
|
89
|
+
}
|
|
90
|
+
const err = error;
|
|
91
|
+
const statusCode = err.statusCode || err.status || 500;
|
|
92
|
+
const errorCode = err.code || "ACTION_FAILED";
|
|
93
|
+
if (statusCode >= 500) req.log.error({
|
|
94
|
+
err: error,
|
|
95
|
+
action,
|
|
96
|
+
id
|
|
97
|
+
}, "Action handler error");
|
|
98
|
+
return sendControllerResponse(reply, {
|
|
99
|
+
success: false,
|
|
100
|
+
status: statusCode,
|
|
101
|
+
error: err.message || `Failed to execute '${action}' action`,
|
|
102
|
+
meta: { code: errorCode }
|
|
103
|
+
}, req);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
fastify.log.debug({
|
|
108
|
+
actions: actionEnum,
|
|
109
|
+
tag,
|
|
110
|
+
resourceName
|
|
111
|
+
}, "[createActionRouter] Registered action endpoint: POST /:id/action");
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Build a discriminated body schema for the unified action endpoint.
|
|
115
|
+
*
|
|
116
|
+
* Produces a schema of the form:
|
|
117
|
+
* ```json
|
|
118
|
+
* {
|
|
119
|
+
* "type": "object",
|
|
120
|
+
* "required": ["action"],
|
|
121
|
+
* "oneOf": [
|
|
122
|
+
* { "properties": { "action": { "const": "dispatch" }, "carrier": {...} }, "required": ["action", "carrier"] },
|
|
123
|
+
* { "properties": { "action": { "const": "approve" } }, "required": ["action"] }
|
|
124
|
+
* ]
|
|
125
|
+
* }
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* AJV validates this natively, so an action call missing required fields is
|
|
129
|
+
* rejected with HTTP 400 before the handler ever runs.
|
|
130
|
+
*
|
|
131
|
+
* Exported so OpenAPI generation and MCP tool generation can reuse the same
|
|
132
|
+
* schema shape (single source of truth).
|
|
133
|
+
*/
|
|
134
|
+
function buildActionBodySchema(actionEnum, actionSchemas = {}) {
|
|
135
|
+
const branches = [];
|
|
136
|
+
for (const actionName of actionEnum) {
|
|
137
|
+
const ir = normalizeSchemaIR(actionSchemas[actionName]);
|
|
138
|
+
branches.push(schemaIRToJsonSchemaBranch(ir, {
|
|
139
|
+
properties: { action: {
|
|
140
|
+
type: "string",
|
|
141
|
+
const: actionName
|
|
142
|
+
} },
|
|
143
|
+
required: ["action"]
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
type: "object",
|
|
148
|
+
required: ["action"],
|
|
149
|
+
oneOf: branches
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Build OpenAPI description with action list + role hints.
|
|
154
|
+
* Reads `_roles` metadata from permission checks for docs.
|
|
155
|
+
*/
|
|
156
|
+
function buildActionDescription(actions, actionPermissions) {
|
|
157
|
+
const lines = ["Unified action endpoint for state transitions.\n\n**Available actions:**"];
|
|
158
|
+
Object.keys(actions).forEach((action) => {
|
|
159
|
+
const roles = actionPermissions[action]?._roles;
|
|
160
|
+
const roleStr = roles?.length ? ` (requires: ${roles.join(" or ")})` : "";
|
|
161
|
+
lines.push(`- \`${action}\`${roleStr}`);
|
|
162
|
+
});
|
|
163
|
+
return lines.join("\n");
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
export { createActionRouter_exports as n, buildActionBodySchema as t };
|
|
@@ -204,7 +204,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
204
204
|
await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
|
|
205
205
|
trackPlugin("arc-core");
|
|
206
206
|
if (config.arcPlugins?.events !== false) {
|
|
207
|
-
const { default: eventPlugin } = await import("./eventPlugin
|
|
207
|
+
const { default: eventPlugin } = await import("./eventPlugin--5HIkdPU.mjs").then((n) => n.n);
|
|
208
208
|
const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
|
|
209
209
|
await fastify.register(eventPlugin, {
|
|
210
210
|
...eventOpts,
|
|
@@ -240,15 +240,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
240
240
|
trackPlugin("arc-graceful-shutdown");
|
|
241
241
|
}
|
|
242
242
|
if (config.arcPlugins?.caching) {
|
|
243
|
-
const { default: cachingPlugin } = await import("./caching-
|
|
243
|
+
const { default: cachingPlugin } = await import("./caching-CheW3m-S.mjs").then((n) => n.r);
|
|
244
244
|
const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
|
|
245
245
|
await fastify.register(cachingPlugin, opts);
|
|
246
246
|
trackPlugin("arc-caching", opts);
|
|
247
247
|
}
|
|
248
248
|
if (config.arcPlugins?.queryCache) {
|
|
249
|
-
const { queryCachePlugin } = await import("./queryCachePlugin-
|
|
249
|
+
const { queryCachePlugin } = await import("./queryCachePlugin-Bq6bO6vc.mjs").then((n) => n.n);
|
|
250
250
|
const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
|
|
251
|
-
const store = config.stores?.queryCache ?? new (await (import("./memory-
|
|
251
|
+
const store = config.stores?.queryCache ?? new (await (import("./memory-DikHSvWa.mjs").then((n) => n.n))).MemoryCacheStore();
|
|
252
252
|
await fastify.register(queryCachePlugin, {
|
|
253
253
|
store,
|
|
254
254
|
...opts
|
|
@@ -257,19 +257,19 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
257
257
|
}
|
|
258
258
|
if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
|
|
259
259
|
else {
|
|
260
|
-
const { default: ssePlugin } = await import("./sse-
|
|
260
|
+
const { default: ssePlugin } = await import("./sse-V7aXc3bW.mjs").then((n) => n.r);
|
|
261
261
|
const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
|
|
262
262
|
await fastify.register(ssePlugin, opts);
|
|
263
263
|
trackPlugin("arc-sse", opts);
|
|
264
264
|
}
|
|
265
265
|
if (config.arcPlugins?.metrics) {
|
|
266
|
-
const { default: metricsPlugin } = await import("./metrics-
|
|
266
|
+
const { default: metricsPlugin } = await import("./metrics-Csh4nsvv.mjs").then((n) => n.r);
|
|
267
267
|
const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
|
|
268
268
|
await fastify.register(metricsPlugin, opts);
|
|
269
269
|
trackPlugin("arc-metrics", opts);
|
|
270
270
|
}
|
|
271
271
|
if (config.arcPlugins?.versioning) {
|
|
272
|
-
const { default: versioningPlugin } = await import("./versioning-
|
|
272
|
+
const { default: versioningPlugin } = await import("./versioning-CGPjkqAg.mjs").then((n) => n.r);
|
|
273
273
|
await fastify.register(versioningPlugin, config.arcPlugins.versioning);
|
|
274
274
|
trackPlugin("arc-versioning", config.arcPlugins.versioning);
|
|
275
275
|
}
|
|
@@ -338,7 +338,7 @@ async function registerAuth(fastify, config, trackPlugin) {
|
|
|
338
338
|
*/
|
|
339
339
|
async function registerElevation(fastify, config, trackPlugin) {
|
|
340
340
|
if (!config.elevation) return;
|
|
341
|
-
const { elevationPlugin } = await import("./elevation-
|
|
341
|
+
const { elevationPlugin } = await import("./elevation-DOFoxoDs.mjs").then((n) => n.r);
|
|
342
342
|
await fastify.register(elevationPlugin, config.elevation);
|
|
343
343
|
trackPlugin("arc-elevation", config.elevation);
|
|
344
344
|
fastify.log.debug("Elevation plugin enabled");
|
|
@@ -348,7 +348,7 @@ async function registerElevation(fastify, config, trackPlugin) {
|
|
|
348
348
|
*/
|
|
349
349
|
async function registerErrorHandler(fastify, config, trackPlugin) {
|
|
350
350
|
if (config.errorHandler === false) return;
|
|
351
|
-
const { errorHandlerPlugin } = await import("./errorHandler-
|
|
351
|
+
const { errorHandlerPlugin } = await import("./errorHandler-BQm8ZxTK.mjs").then((n) => n.r);
|
|
352
352
|
const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
|
|
353
353
|
await fastify.register(errorHandlerPlugin, errorOpts);
|
|
354
354
|
trackPlugin("arc-error-handler", errorOpts);
|
|
@@ -386,6 +386,9 @@ function createOptionalAuthenticate(authenticate) {
|
|
|
386
386
|
}
|
|
387
387
|
//#endregion
|
|
388
388
|
//#region src/factory/registerResources.ts
|
|
389
|
+
function isResourcesFactory(value) {
|
|
390
|
+
return typeof value === "function";
|
|
391
|
+
}
|
|
389
392
|
/** Register a single resource with descriptive error on failure. */
|
|
390
393
|
async function registerOne(parent, resource) {
|
|
391
394
|
const name = resource.name ?? "unknown";
|
|
@@ -394,18 +397,31 @@ async function registerOne(parent, resource) {
|
|
|
394
397
|
} catch (err) {
|
|
395
398
|
const msg = err instanceof Error ? err.message : String(err);
|
|
396
399
|
parent.log.error(`Failed to register resource "${name}": ${msg}`);
|
|
397
|
-
throw new Error(`Resource "${name}" failed to register: ${msg}. Check the resource definition, adapter, and permissions
|
|
400
|
+
throw new Error(`Resource "${name}" failed to register: ${msg}. Check the resource definition, adapter, and permissions.`, { cause: err });
|
|
398
401
|
}
|
|
399
402
|
}
|
|
400
403
|
/**
|
|
401
404
|
* Execute the full resource lifecycle:
|
|
402
|
-
* 1. plugins()
|
|
403
|
-
* 2. bootstrap[]
|
|
404
|
-
* 3. resources
|
|
405
|
-
*
|
|
406
|
-
*
|
|
405
|
+
* 1. plugins() — infra (DB, docs, webhooks)
|
|
406
|
+
* 2. bootstrap[] — domain init (singletons, event handlers)
|
|
407
|
+
* 3. resources factory (if any) — resolved AFTER bootstrap, so engine-backed
|
|
408
|
+
* adapters can `await ensureEngine()` and pass
|
|
409
|
+
* live models/repos into `defineResource(...)`
|
|
410
|
+
* 4. resources[] — register each (split by prefix)
|
|
411
|
+
* 5. afterResources() — post-registration wiring
|
|
412
|
+
* 6. onReady/onClose — lifecycle hooks
|
|
407
413
|
*/
|
|
408
414
|
async function registerResources(fastify, config) {
|
|
415
|
+
if (config.preset === "production") {
|
|
416
|
+
if (config.strictResources === void 0) config = {
|
|
417
|
+
...config,
|
|
418
|
+
strictResources: true
|
|
419
|
+
};
|
|
420
|
+
if (config.strictResourceDir === void 0) config = {
|
|
421
|
+
...config,
|
|
422
|
+
strictResourceDir: true
|
|
423
|
+
};
|
|
424
|
+
}
|
|
409
425
|
if (config.plugins) {
|
|
410
426
|
await config.plugins(fastify);
|
|
411
427
|
fastify.log.debug("Custom plugins registered");
|
|
@@ -414,33 +430,65 @@ async function registerResources(fastify, config) {
|
|
|
414
430
|
for (const init of config.bootstrap) await init(fastify);
|
|
415
431
|
fastify.log.debug(`${config.bootstrap.length} bootstrap function(s) executed`);
|
|
416
432
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
433
|
+
let resolvedResources;
|
|
434
|
+
if (isResourcesFactory(config.resources)) {
|
|
435
|
+
try {
|
|
436
|
+
resolvedResources = await config.resources(fastify);
|
|
437
|
+
} catch (err) {
|
|
438
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
439
|
+
fastify.log.error(`Resources factory threw during boot: ${msg}`);
|
|
440
|
+
throw new Error(`[arc] resources factory threw: ${msg}. Check engine bootstrap order (did you forget a bootstrap step?) and that \`defineResource(...)\` calls inside the factory receive fully-booted adapters / repositories.`, { cause: err });
|
|
441
|
+
}
|
|
421
442
|
config = {
|
|
422
443
|
...config,
|
|
423
|
-
resources:
|
|
444
|
+
resources: resolvedResources
|
|
424
445
|
};
|
|
446
|
+
} else resolvedResources = config.resources;
|
|
447
|
+
let discoveryRawDir;
|
|
448
|
+
let discoveryPath;
|
|
449
|
+
let discoveryYieldedZero = false;
|
|
450
|
+
if (resolvedResources === void 0 && config.resourceDir) {
|
|
451
|
+
const { loadResources } = await import("./loadResources-CPpkyKfM.mjs").then((n) => n.n);
|
|
452
|
+
const { resolve, dirname } = await import("node:path");
|
|
453
|
+
const { fileURLToPath } = await import("node:url");
|
|
454
|
+
const rawDir = config.resourceDir;
|
|
455
|
+
const dir = rawDir.startsWith("file://") ? dirname(fileURLToPath(rawDir)) : resolve(rawDir);
|
|
456
|
+
discoveryRawDir = rawDir;
|
|
457
|
+
discoveryPath = dir;
|
|
458
|
+
const discovered = await loadResources(dir, { logger: fastify.log });
|
|
459
|
+
if (discovered.length === 0) {
|
|
460
|
+
if (config.strictResourceDir) throw new Error(`[arc] loadResources: resourceDir "${rawDir}" resolved to "${dir}" but yielded 0 resources. Check the path, file naming (*.resource.{ts,js,mts,mjs}), and runtime layout (src/ vs dist/). Use \`strictResourceDir: true\` to fail boot.`);
|
|
461
|
+
discoveryYieldedZero = true;
|
|
462
|
+
}
|
|
463
|
+
resolvedResources = discovered;
|
|
425
464
|
}
|
|
426
|
-
if (
|
|
465
|
+
if (resolvedResources && resolvedResources.length > 0) {
|
|
427
466
|
const seen = /* @__PURE__ */ new Set();
|
|
428
|
-
for (const resource of
|
|
429
|
-
if (seen.has(resource.name))
|
|
467
|
+
for (const resource of resolvedResources) if (resource.name) {
|
|
468
|
+
if (seen.has(resource.name)) {
|
|
469
|
+
const msg = `Duplicate resource name "${resource.name}" detected. This will cause route conflicts. Check your resources array and loadResources() output. Common cause: stale compiled files in dist/ alongside src/. Use \`strictResources: true\` to fail boot.`;
|
|
470
|
+
if (config.strictResources) throw new Error(msg);
|
|
471
|
+
fastify.log.warn(msg);
|
|
472
|
+
}
|
|
430
473
|
seen.add(resource.name);
|
|
431
474
|
}
|
|
432
475
|
const prefixed = [];
|
|
433
476
|
const root = [];
|
|
434
|
-
for (const resource of
|
|
477
|
+
for (const resource of resolvedResources) if (resource.skipGlobalPrefix) root.push(resource);
|
|
435
478
|
else prefixed.push(resource);
|
|
436
479
|
for (const resource of root) await registerOne(fastify, resource);
|
|
437
480
|
if (prefixed.length) if (config.resourcePrefix) await fastify.register(async (scoped) => {
|
|
438
481
|
for (const resource of prefixed) await registerOne(scoped, resource);
|
|
439
482
|
}, { prefix: config.resourcePrefix });
|
|
440
483
|
else for (const resource of prefixed) await registerOne(fastify, resource);
|
|
441
|
-
const names =
|
|
484
|
+
const names = resolvedResources.map((r) => r.name ?? "?").join(", ");
|
|
485
|
+
const prefix = config.resourcePrefix ? ` (prefix: ${config.resourcePrefix})` : "";
|
|
486
|
+
fastify.log.info(`${resolvedResources.length} resource(s) registered${prefix}: ${names}`);
|
|
487
|
+
} else {
|
|
442
488
|
const prefix = config.resourcePrefix ? ` (prefix: ${config.resourcePrefix})` : "";
|
|
443
|
-
|
|
489
|
+
const scanned = discoveryPath ? ` — resourceDir "${discoveryRawDir}" resolved to "${discoveryPath}"` : "";
|
|
490
|
+
const hints = discoveryYieldedZero ? ` but yielded 0 resources. Check the path, file naming (*.resource.{ts,js,mts,mjs}), and runtime layout (src/ vs dist/). Use \`strictResourceDir: true\` to fail boot.` : "";
|
|
491
|
+
fastify.log.warn(`0 resources registered${prefix}${scanned}${hints}`);
|
|
444
492
|
}
|
|
445
493
|
if (config.afterResources) {
|
|
446
494
|
await config.afterResources(fastify);
|
|
@@ -764,7 +812,7 @@ async function createApp(options) {
|
|
|
764
812
|
await registerErrorHandler(fastify, config, trackPlugin);
|
|
765
813
|
await registerResources(fastify, config);
|
|
766
814
|
if (config.replyHelpers) {
|
|
767
|
-
const { replyHelpersPlugin } = await import("./replyHelpers-
|
|
815
|
+
const { replyHelpersPlugin } = await import("./replyHelpers-ByllIXXV.mjs").then((n) => n.n);
|
|
768
816
|
await fastify.register(replyHelpersPlugin);
|
|
769
817
|
}
|
|
770
818
|
if (config.serializeBigInt) fastify.addHook("preSerialization", async (_request, _reply, payload) => {
|
package/dist/docs/index.d.mts
CHANGED
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as getUserRoles } from "../types-
|
|
2
|
-
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-
|
|
1
|
+
import { t as getUserRoles } from "../types-DV9WDfeg.mjs";
|
|
2
|
+
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-C0L9ar7m.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
2
|
import { arcLog } from "./logger/index.mjs";
|
|
3
|
-
import { t as getUserRoles } from "./types-
|
|
3
|
+
import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/scope/elevation.ts
|
|
6
6
|
var elevation_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { p as isArcError } from "./errors-
|
|
2
|
+
import { p as isArcError } from "./errors-D5c-5BJL.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/plugins/errorHandler.ts
|
|
5
5
|
var errorHandler_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { t as requestContext } from "./requestContext-
|
|
2
|
+
import { t as requestContext } from "./requestContext-CfRkaxwf.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/events/EventTransport.ts
|
|
5
5
|
/**
|
package/dist/events/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jn as RepositoryLike } from "../index-C_bgx9o4.mjs";
|
|
2
2
|
import { a as EventMeta, c as MemoryEventTransportOptions, d as createEvent, i as EventLogger, l as PublishManyResult, n as DomainEvent, o as EventTransport, r as EventHandler, s as MemoryEventTransport, t as DeadLetteredEvent, u as createChildEvent } from "../EventTransport-CfVEGaEl.mjs";
|
|
3
|
-
import { a as withRetry, c as EventDefinitionOutput, d as EventSchema, f as ValidationResult, i as createDeadLetterPublisher, l as EventRegistry, m as defineEvent, n as eventPlugin, o as CustomValidator, p as createEventRegistry, r as RetryOptions, s as EventDefinitionInput, t as EventPluginOptions, u as EventRegistryOptions } from "../eventPlugin-
|
|
3
|
+
import { a as withRetry, c as EventDefinitionOutput, d as EventSchema, f as ValidationResult, i as createDeadLetterPublisher, l as EventRegistry, m as defineEvent, n as eventPlugin, o as CustomValidator, p as createEventRegistry, r as RetryOptions, s as EventDefinitionInput, t as EventPluginOptions, u as EventRegistryOptions } from "../eventPlugin-CUNjYYRY.mjs";
|
|
4
4
|
import { RedisEventTransportOptions, RedisLike } from "./transports/redis.mjs";
|
|
5
|
-
import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-
|
|
5
|
+
import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-CM8TXTix.mjs";
|
|
6
6
|
|
|
7
7
|
//#region src/events/eventTypes.d.ts
|
|
8
8
|
/**
|
package/dist/events/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as MemoryEventTransport, i as withRetry, o as createChildEvent, r as createDeadLetterPublisher, s as createEvent, t as eventPlugin } from "../eventPlugin
|
|
2
|
-
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-
|
|
1
|
+
import { a as MemoryEventTransport, i as withRetry, o as createChildEvent, r as createDeadLetterPublisher, s as createEvent, t as eventPlugin } from "../eventPlugin--5HIkdPU.mjs";
|
|
2
|
+
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-BhrzxvyQ.mjs";
|
|
3
3
|
import { and, anyOf, eq, lte, ne, or } from "@classytic/repo-core/filter";
|
|
4
4
|
import { update } from "@classytic/repo-core/update";
|
|
5
5
|
//#region src/events/defineEvent.ts
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-
|
|
1
|
+
import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-CM8TXTix.mjs";
|
|
2
2
|
export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
|
package/dist/factory/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as
|
|
1
|
+
import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as ResourceModule, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, p as loadResources, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-BdA4uMBV.mjs";
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/factory/createApp.d.ts
|
|
@@ -95,4 +95,4 @@ declare const edgePreset: Partial<CreateAppOptions>;
|
|
|
95
95
|
*/
|
|
96
96
|
declare function getPreset(name: "production" | "development" | "testing" | "edge"): Partial<CreateAppOptions>;
|
|
97
97
|
//#endregion
|
|
98
|
-
export { ArcFactory, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type MultipartOptions, type RawBodyOptions, type ResourceLike, type UnderPressureOptions, createApp, developmentPreset, edgePreset, getPreset, loadResources, productionPreset, testingPreset, toFetchHandler };
|
|
98
|
+
export { ArcFactory, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type MultipartOptions, type RawBodyOptions, type ResourceLike, type ResourceModule, type UnderPressureOptions, createApp, developmentPreset, edgePreset, getPreset, loadResources, productionPreset, testingPreset, toFetchHandler };
|
package/dist/factory/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-
|
|
2
|
-
import { t as loadResources } from "../loadResources-
|
|
1
|
+
import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-P1d6rjPy.mjs";
|
|
2
|
+
import { t as loadResources } from "../loadResources-CPpkyKfM.mjs";
|
|
3
3
|
//#region src/factory/edge.ts
|
|
4
4
|
/**
|
|
5
5
|
* Convert a Fastify app into a Web Standards fetch handler.
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cn as beforeUpdate, Sn as beforeDelete, Tn as defineHook, _n as HookSystemOptions, bn as afterUpdate, dn as HookContext, fn as HookHandler, gn as HookSystem, hn as HookRegistration, mn as HookPhase, pn as HookOperation, un as DefineHookOptions, vn as afterCreate, wn as createHookSystem, xn as beforeCreate, yn as afterDelete } from "../index-C_bgx9o4.mjs";
|
|
2
2
|
export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
package/dist/hooks/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-
|
|
1
|
+
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-CGsMd6oK.mjs";
|
|
2
2
|
export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-
|
|
3
|
-
import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-
|
|
1
|
+
import { jn as RepositoryLike } from "../index-C_bgx9o4.mjs";
|
|
2
|
+
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-CkkWm5uR.mjs";
|
|
3
|
+
import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-Cm1gnRDf.mjs";
|
|
4
4
|
import { FastifyPluginAsync } from "fastify";
|
|
5
5
|
|
|
6
6
|
//#region src/idempotency/idempotencyPlugin.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-
|
|
1
|
+
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-BhrzxvyQ.mjs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
import { and, eq, exists, gt, lt, or, startsWith } from "@classytic/repo-core/filter";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-
|
|
1
|
+
import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-Cm1gnRDf.mjs";
|
|
2
2
|
export { type IoredisLike, type RedisClient, RedisIdempotencyStore, type RedisIdempotencyStoreOptions, type UpstashRedisLike, ioredisAsIdempotencyClient, upstashAsIdempotencyClient };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { r as CacheStore, t as CacheLogger } from "./interface-Da0r7Lna.mjs";
|
|
1
2
|
import { r as RequestScope } from "./types-tgR4Pt8F.mjs";
|
|
2
3
|
import { c as PermissionCheck, l as PermissionContext, u as PermissionResult } from "./fields-C8Y0XLAu.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { FastifyRequest } from "fastify";
|
|
4
|
+
import { FastifyReply, FastifyRequest } from "fastify";
|
|
5
5
|
|
|
6
6
|
//#region src/permissions/applyPermissionResult.d.ts
|
|
7
7
|
/**
|