@classytic/arc 2.15.3 → 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.
- package/README.md +1 -0
- package/bin/arc.js +12 -0
- package/dist/{BaseController-dx3m2J8V.mjs → BaseController-DlCCTIxJ.mjs} +61 -19
- package/dist/{HookSystem-Iiebom92.mjs → HookSystem-Cmf7-Etp.mjs} +8 -4
- package/dist/{QueryCache-D41bfdBB.d.mts → QueryCache-SvmT_9ti.d.mts} +1 -1
- package/dist/{ResourceRegistry-CTERg_2x.mjs → ResourceRegistry-f48hFk3m.mjs} +52 -9
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +4 -2
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +4 -4
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi--M_i87dQ.mjs → betterAuthOpenApi-ClWxaceA.mjs} +10 -6
- package/dist/buildHandler-BZX6zzDM.mjs +300 -0
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/{caching-SM8gghN6.mjs → caching-TeHE8G-v.mjs} +1 -1
- package/dist/cli/commands/describe.d.mts +35 -1
- package/dist/cli/commands/describe.mjs +52 -12
- package/dist/cli/commands/docs.d.mts +1 -4
- package/dist/cli/commands/docs.mjs +4 -16
- package/dist/cli/commands/generate.d.mts +2 -20
- package/dist/cli/commands/generate.mjs +1 -546
- package/dist/cli/commands/init.d.mts +2 -40
- package/dist/cli/commands/init.mjs +1 -3036
- package/dist/cli/commands/introspect.mjs +53 -64
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/{constants-Cxde4rpC.mjs → constants-TrJVIJl0.mjs} +7 -0
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/{core-CvmOqEms.mjs → core-DBJ_j6rX.mjs} +222 -44
- package/dist/createActionRouter-DUpN3Dd1.mjs +288 -0
- package/dist/{createAggregationRouter-B0bPDf5b.mjs → createAggregationRouter-Dq-TUCuY.mjs} +3 -2
- package/dist/{createApp-PFegs47-.mjs → createApp-DNccuhyI.mjs} +16 -14
- package/dist/{defineEvent-D5h7EvAx.mjs → defineEvent-DRwY0fYm.mjs} +1 -1
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{errorHandler-Bk-AGhkU.mjs → errorHandler-DpoXQHZ9.mjs} +17 -14
- package/dist/errors-C1lX_jlm.d.mts +91 -0
- package/dist/{eventPlugin-CaKTYkYM.mjs → eventPlugin-C2cGqtRO.mjs} +1 -1
- package/dist/{eventPlugin-qXpqTebY.d.mts → eventPlugin-CtHC_av1.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +5 -5
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +2 -2
- package/dist/{fields-COhcH3fk.d.mts → fields-Anj0xdih.d.mts} +1 -1
- package/dist/generate-BWFwgcCM.d.mts +38 -0
- package/dist/generate-CYac-OLv.mjs +654 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +2 -2
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-BTqLEvhu.d.mts → index-3oIimXQn.d.mts} +12 -12
- package/dist/{index-BstGxcc3.d.mts → index-B-ulKx5P.d.mts} +55 -4
- package/dist/{index-BswOSJCE.d.mts → index-CkW0flkU.d.mts} +355 -16
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -8
- package/dist/init-Dv71MsJr.d.mts +71 -0
- package/dist/init-HDvoO9L5.mjs +3098 -0
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/jobs.mjs +3 -3
- package/dist/integrations/mcp/index.d.mts +239 -7
- package/dist/integrations/mcp/index.mjs +2 -528
- package/dist/integrations/mcp/testing.d.mts +2 -2
- package/dist/integrations/mcp/testing.mjs +6 -10
- package/dist/integrations/streamline.d.mts +71 -2
- package/dist/integrations/streamline.mjs +81 -8
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +1 -0
- package/dist/loadResourcesFromEntry-BLMEI2Xa.mjs +51 -0
- package/dist/{resourceToTools-tFYUNmM0.mjs → mcpPlugin-7vGV51ED.mjs} +1021 -318
- package/dist/{memory-UBydS5ku.mjs → memory-QOLe11D5.mjs} +2 -0
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/{openapi-BHXhoX8O.mjs → openapi-34T9yNwd.mjs} +47 -36
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +1 -1
- package/dist/{permissions-ohQyv50e.mjs → permissions-CTxMrreC.mjs} +2 -2
- package/dist/{pipe-Zr0KXjQe.mjs → pipe-DiCyvyPN.mjs} +1 -0
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +5 -5
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +5 -5
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{pluralize-DQgqgifU.mjs → pluralize-B9M8xvy-.mjs} +2 -1
- package/dist/presets/filesUpload.d.mts +4 -4
- package/dist/presets/filesUpload.mjs +2 -2
- 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 +4 -3
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-BbkjdPeH.mjs → presets-C9BE6WaZ.mjs} +2 -2
- package/dist/{queryCachePlugin-m1XsgAIJ.mjs → queryCachePlugin-B4XMSSe7.mjs} +2 -2
- package/dist/{queryCachePlugin-CqMdLI2-.d.mts → queryCachePlugin-Biqzfbi5.d.mts} +2 -2
- package/dist/{redis-DiMkdHEl.d.mts → redis-Cyzrz6SX.d.mts} +1 -1
- package/dist/{redis-stream-D6HzR1Z_.d.mts → redis-stream-DT-YjzrB.d.mts} +1 -1
- package/dist/registry/index.d.mts +319 -2
- package/dist/registry/index.mjs +3 -3
- package/dist/registry-BBE23CDj.mjs +576 -0
- package/dist/{routerShared-DrOa-26E.mjs → routerShared-CZV5aabX.mjs} +3 -3
- package/dist/scope/index.d.mts +3 -3
- package/dist/scope/index.mjs +3 -3
- package/dist/{sse-Bz-5ZeTt.mjs → sse-BY6sTy4P.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +16 -7
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-C_s5moIu.mjs → types-Bi0r0vjG.mjs} +53 -1
- package/dist/{types-BQsjgQzS.d.mts → types-BsJMEQ4D.d.mts} +106 -12
- package/dist/{types-DrBaUwyV.d.mts → types-D-fYtKjb.d.mts} +33 -10
- package/dist/{types-CTYvcwHe.d.mts → types-DVfpSfx2.d.mts} +42 -1
- package/dist/utils/index.d.mts +1286 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/{utils-_h9B3c57.mjs → utils-DC5ycPfr.mjs} +89 -40
- package/dist/{buildHandler-CcFOpJLh.mjs → validate-By96rH0r.mjs} +8 -299
- package/dist/{versioning-hmkPcDlX.d.mts → versioning-ZwX9tmbS.d.mts} +1 -1
- package/package.json +22 -29
- package/skills/arc/SKILL.md +299 -689
- package/skills/arc/references/auth.md +19 -7
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/arc-cheatsheet.md +100 -322
- package/dist/createActionRouter-S3MLVYot.mjs +0 -220
- package/dist/index-bRjYu21O.d.mts +0 -1320
- package/dist/org/index.d.mts +0 -66
- package/dist/org/index.mjs +0 -486
- package/dist/org/types.d.mts +0 -82
- package/dist/org/types.mjs +0 -1
- package/dist/registry-I-ogLgL9.mjs +0 -46
- /package/dist/{EventTransport-CT_52aWU.d.mts → EventTransport-C-2oAHtw.d.mts} +0 -0
- /package/dist/{EventTransport-DLWoUMHy.mjs → EventTransport-Hxvv5QQz.mjs} +0 -0
- /package/dist/{actionPermissions-CyUkQu6O.mjs → actionPermissions-Bjmvn7Eb.mjs} +0 -0
- /package/dist/{elevation-BXOWoGCF.d.mts → elevation-0YBpa663.d.mts} +0 -0
- /package/dist/{elevation-DgoeTyfX.mjs → elevation-Dci0AYLT.mjs} +0 -0
- /package/dist/{errorHandler-DFr45ZG4.d.mts → errorHandler-mHuyWzZE.d.mts} +0 -0
- /package/dist/{externalPaths-BD5nw6St.d.mts → externalPaths-DFg-2KTp.d.mts} +0 -0
- /package/dist/{interface-beEtJyWM.d.mts → interface-CH0OQudo.d.mts} +0 -0
- /package/dist/{interface-DfLGcus7.d.mts → interface-NwJ_qPlY.d.mts} +0 -0
- /package/dist/{keys-CGcCbNyu.mjs → keys-DopsCuyQ.mjs} +0 -0
- /package/dist/{loadResources-DBMQg_Aj.mjs → loadResources-ChQEj8ih.mjs} +0 -0
- /package/dist/{metrics-Qnvwc-LQ.mjs → metrics-TuOmguhi.mjs} +0 -0
- /package/dist/{replyHelpers-CK-FNO8E.mjs → replyHelpers-C-gD32oF.mjs} +0 -0
- /package/dist/{schemaIR-lYhC2gE5.mjs → schemaIR-Ctc89DSn.mjs} +0 -0
- /package/dist/{sessionManager-C4Le_UB3.d.mts → sessionManager-BqFegc0W.d.mts} +0 -0
- /package/dist/{storage-Dfzt4VTl.d.mts → storage-D2KZJAmn.d.mts} +0 -0
- /package/dist/{store-helpers-BkIN9-vu.mjs → store-helpers-B0sunfZZ.mjs} +0 -0
- /package/dist/{tracing-QJVprktp.d.mts → tracing-Dm8n7Cnn.d.mts} +0 -0
- /package/dist/{versioning-BUrT5aP4.mjs → versioning-B6mimogM.mjs} +0 -0
- /package/dist/{websocket-ChC2rqe1.d.mts → websocket-BkjeGZRn.d.mts} +0 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import "./constants-TrJVIJl0.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-CZV5aabX.mjs";
|
|
5
|
+
import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-Ctc89DSn.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, idLessActionNames = [] } = config;
|
|
21
|
+
const allActionNames = Object.keys(actions);
|
|
22
|
+
if (allActionNames.length === 0) {
|
|
23
|
+
fastify.log.warn("[createActionRouter] No actions defined, skipping route creation");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const idLessSet = new Set(idLessActionNames);
|
|
27
|
+
const idBoundActionNames = allActionNames.filter((name) => !idLessSet.has(name));
|
|
28
|
+
const idLessActions = allActionNames.filter((name) => idLessSet.has(name));
|
|
29
|
+
for (const name of idLessActionNames) if (!Object.hasOwn(actions, name)) throw new Error(`[Arc/Actions] Resource '${resourceName}': idLess action '${name}' is not declared in the actions map. Valid actions: ${allActionNames.join(", ")}.`);
|
|
30
|
+
const arcDecorator = buildArcDecorator({
|
|
31
|
+
resourceName,
|
|
32
|
+
schemaOptions,
|
|
33
|
+
permissions: resourcePermissions,
|
|
34
|
+
hooks: fastify.arc?.hooks,
|
|
35
|
+
events: fastify.events,
|
|
36
|
+
fields: fieldPermissions,
|
|
37
|
+
idField
|
|
38
|
+
});
|
|
39
|
+
const pluginMw = resolveRouterPluginMw(fastify, false);
|
|
40
|
+
const wrappedHandlers = /* @__PURE__ */ new Map();
|
|
41
|
+
for (const [name, handler] of Object.entries(actions)) {
|
|
42
|
+
const steps = resolvePipelineSteps(pipeline, name);
|
|
43
|
+
wrappedHandlers.set(name, buildActionPipelineHandler(handler, steps, name, resourceName));
|
|
44
|
+
}
|
|
45
|
+
const rateLimitConfig = buildRateLimitConfig(rateLimit);
|
|
46
|
+
/**
|
|
47
|
+
* Register one action mount point. Called once per mount (id-bound and/or
|
|
48
|
+
* id-less). Each mount has its OWN AJV `oneOf` body schema filtered to
|
|
49
|
+
* just `actionSubset` so the mount-point boundary is also a contract
|
|
50
|
+
* boundary: hitting `POST /<prefix>/action` with an id-bound action name
|
|
51
|
+
* fails at AJV (the discriminator enum excludes it) — and the
|
|
52
|
+
* formatter's "wrong mount" message points the caller at the right URL.
|
|
53
|
+
*/
|
|
54
|
+
const registerActionRoute = (mountOpts) => {
|
|
55
|
+
const { urlPath, actionSubset, hasId } = mountOpts;
|
|
56
|
+
if (actionSubset.length === 0) return;
|
|
57
|
+
const subsetSet = new Set(actionSubset);
|
|
58
|
+
const authMw = buildAuthMiddlewareForPermissions(fastify, actionSubset.map((name) => actionPermissions[name] ?? globalAuth));
|
|
59
|
+
const subsetPermissions = {};
|
|
60
|
+
for (const name of actionSubset) {
|
|
61
|
+
const perm = actionPermissions[name];
|
|
62
|
+
if (perm) subsetPermissions[name] = perm;
|
|
63
|
+
}
|
|
64
|
+
const permissionMw = buildActionPermissionMw(actionSubset, subsetPermissions, globalAuth, resourceName);
|
|
65
|
+
const subsetSchemas = {};
|
|
66
|
+
for (const name of actionSubset) if (actionSchemas[name]) subsetSchemas[name] = actionSchemas[name];
|
|
67
|
+
const bodySchema = buildActionBodySchema(actionSubset, subsetSchemas);
|
|
68
|
+
const routeSchema = {
|
|
69
|
+
tags: tag ? [tag] : void 0,
|
|
70
|
+
summary: `Perform action (${actionSubset.join("/")})`,
|
|
71
|
+
description: buildActionDescription(Object.fromEntries(actionSubset.map((name) => [name, actions[name]])), subsetPermissions),
|
|
72
|
+
body: bodySchema
|
|
73
|
+
};
|
|
74
|
+
if (hasId) routeSchema.params = {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: { id: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Resource ID"
|
|
79
|
+
} },
|
|
80
|
+
required: ["id"]
|
|
81
|
+
};
|
|
82
|
+
const actionValidationFormatter = async (req, _reply) => {
|
|
83
|
+
const validationError = req.validationError;
|
|
84
|
+
if (!validationError) return;
|
|
85
|
+
const body = req.body;
|
|
86
|
+
const submitted = typeof body?.action === "string" ? body.action : void 0;
|
|
87
|
+
if (!submitted || !subsetSet.has(submitted)) {
|
|
88
|
+
const wrongMount = submitted && allActionNames.includes(submitted) ? submitted : void 0;
|
|
89
|
+
const otherMount = hasId ? "/action" : "/:id/action";
|
|
90
|
+
throw createError(400, wrongMount ? `Action '${wrongMount}' on '${resourceName}' is mounted at 'POST ${otherMount}', not 'POST ${urlPath}'` : submitted ? `Unknown action '${submitted}' on '${resourceName}'. Valid at 'POST ${urlPath}': ${actionSubset.join(", ")}` : `Missing 'action' field on '${resourceName}'. Valid at 'POST ${urlPath}': ${actionSubset.join(", ")}`, {
|
|
91
|
+
code: "arc.invalid_action",
|
|
92
|
+
validActions: actionSubset,
|
|
93
|
+
mount: urlPath,
|
|
94
|
+
...submitted ? { submitted } : {},
|
|
95
|
+
...wrongMount ? { mountedAt: otherMount } : {}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const branchPath = `/oneOf/${actionSubset.indexOf(submitted)}/`;
|
|
99
|
+
const ajvErrors = validationError.validation ?? [];
|
|
100
|
+
const scoped = ajvErrors.filter((e) => e.keyword !== "oneOf" && (e.schemaPath?.includes(branchPath) || !e.schemaPath?.includes("/oneOf/")));
|
|
101
|
+
const useErrors = scoped.length > 0 ? scoped : ajvErrors;
|
|
102
|
+
const scopedError = /* @__PURE__ */ new Error(`Validation failed for action '${submitted}' on '${resourceName}'`);
|
|
103
|
+
scopedError.statusCode = 400;
|
|
104
|
+
scopedError.code = "arc.validation_error";
|
|
105
|
+
scopedError.validation = useErrors;
|
|
106
|
+
scopedError.validationContext = "body";
|
|
107
|
+
scopedError.meta = { action: submitted };
|
|
108
|
+
throw scopedError;
|
|
109
|
+
};
|
|
110
|
+
const preHandler = [actionValidationFormatter, ...buildPreHandlerChain({
|
|
111
|
+
arcDecorator,
|
|
112
|
+
authMw,
|
|
113
|
+
permissionMw,
|
|
114
|
+
pluginMw: selectPluginMw("POST", pluginMw),
|
|
115
|
+
routeGuards
|
|
116
|
+
})];
|
|
117
|
+
fastify.route({
|
|
118
|
+
method: "POST",
|
|
119
|
+
url: urlPath,
|
|
120
|
+
schema: routeSchema,
|
|
121
|
+
attachValidation: true,
|
|
122
|
+
preHandler: preHandler.length > 0 ? preHandler : void 0,
|
|
123
|
+
...rateLimitConfig ? { config: rateLimitConfig } : {},
|
|
124
|
+
handler: async (req, reply) => {
|
|
125
|
+
const { action, ...data } = req.body;
|
|
126
|
+
const id = hasId ? req.params.id : "";
|
|
127
|
+
if (hasId) {
|
|
128
|
+
const reqWithExtras = req;
|
|
129
|
+
reqWithExtras.arc = {
|
|
130
|
+
...reqWithExtras.arc ?? {},
|
|
131
|
+
entityId: id
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const handler = wrappedHandlers.get(action);
|
|
135
|
+
if (!handler) throw createError(400, `Invalid action '${action}'. Valid actions: ${actionSubset.join(", ")}`, { validActions: actionSubset });
|
|
136
|
+
try {
|
|
137
|
+
return sendControllerResponse(reply, await handler(id, data, req), req);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (onError) {
|
|
140
|
+
const { statusCode, error: errorMsg, code } = onError(error, action, id);
|
|
141
|
+
throw createError(statusCode, errorMsg, code ? { code } : void 0);
|
|
142
|
+
}
|
|
143
|
+
const err = error;
|
|
144
|
+
const statusCode = err.statusCode || err.status || 500;
|
|
145
|
+
const errorCode = err.code || "ACTION_FAILED";
|
|
146
|
+
if (statusCode >= 500) req.log.error({
|
|
147
|
+
err: error,
|
|
148
|
+
action,
|
|
149
|
+
id
|
|
150
|
+
}, "Action handler error");
|
|
151
|
+
if (error?.name === "ArcError" || error instanceof Error === false) throw error;
|
|
152
|
+
throw createError(statusCode, err.message || `Failed to execute '${action}' action`, { code: errorCode });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
fastify.log.debug({
|
|
157
|
+
actions: actionSubset,
|
|
158
|
+
mount: urlPath,
|
|
159
|
+
tag,
|
|
160
|
+
resourceName
|
|
161
|
+
}, "[createActionRouter] Registered action endpoint");
|
|
162
|
+
};
|
|
163
|
+
registerActionRoute({
|
|
164
|
+
urlPath: "/:id/action",
|
|
165
|
+
actionSubset: idBoundActionNames,
|
|
166
|
+
hasId: true
|
|
167
|
+
});
|
|
168
|
+
registerActionRoute({
|
|
169
|
+
urlPath: "/action",
|
|
170
|
+
actionSubset: idLessActions,
|
|
171
|
+
hasId: false
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Build a discriminated body schema for the unified action endpoint.
|
|
176
|
+
*
|
|
177
|
+
* Produces a schema of the form:
|
|
178
|
+
* ```json
|
|
179
|
+
* {
|
|
180
|
+
* "type": "object",
|
|
181
|
+
* "required": ["action"],
|
|
182
|
+
* "properties": {
|
|
183
|
+
* "action": { "type": "string", "enum": ["dispatch", "approve"] },
|
|
184
|
+
* "carrier": { "type": "string" }
|
|
185
|
+
* },
|
|
186
|
+
* "oneOf": [
|
|
187
|
+
* {
|
|
188
|
+
* "properties": {
|
|
189
|
+
* "action": { "const": "dispatch" },
|
|
190
|
+
* "carrier": { "type": "string" } // ← every branch lists the union
|
|
191
|
+
* },
|
|
192
|
+
* "required": ["action", "carrier"]
|
|
193
|
+
* },
|
|
194
|
+
* {
|
|
195
|
+
* "properties": {
|
|
196
|
+
* "action": { "const": "approve" },
|
|
197
|
+
* "carrier": { "type": "string" } // ← even though approve doesn't use it
|
|
198
|
+
* },
|
|
199
|
+
* "required": ["action"]
|
|
200
|
+
* }
|
|
201
|
+
* ]
|
|
202
|
+
* }
|
|
203
|
+
* ```
|
|
204
|
+
*
|
|
205
|
+
* **Why every branch carries the full property union.** AJV's
|
|
206
|
+
* `removeAdditional: 'all'` (Fastify's framework default) interacts badly
|
|
207
|
+
* with `oneOf`: when a branch's `properties` lacks a field, AJV strips it
|
|
208
|
+
* from the body during that branch's evaluation — *even if a different
|
|
209
|
+
* branch would have allowed it*. The strip mutates the body before
|
|
210
|
+
* `oneOf` finishes discriminating, so by the time the matching branch
|
|
211
|
+
* wins, the body has already lost fields. Concretely: `actions: { verify:
|
|
212
|
+
* {}, hold: { schema: z.object({ amount, reason }.optional()) } }` +
|
|
213
|
+
* `POST { action: 'hold', amount: 1, reason }` lands at the handler as
|
|
214
|
+
* `{ action: 'hold' }`. Empirically reproduced and locked at
|
|
215
|
+
* [tests/core/action-discriminator-strip.test.ts](../../tests/core/action-discriminator-strip.test.ts).
|
|
216
|
+
*
|
|
217
|
+
* Listing every action's properties on every branch makes per-branch
|
|
218
|
+
* removeAdditional walks see every caller field as "in this branch's
|
|
219
|
+
* properties," so nothing gets stripped during oneOf evaluation. The
|
|
220
|
+
* `required` array stays per-action, so the handler still gets called
|
|
221
|
+
* only when the matching branch's required-field contract is satisfied.
|
|
222
|
+
* Per-branch `additionalProperties: false` (Zod v4 default) carries
|
|
223
|
+
* through but, under host removeAdditional: 'all', it can no longer
|
|
224
|
+
* reject sibling-action fields — those become silently stripped at top
|
|
225
|
+
* level instead. That's the host's opt-in to stripping; arc's job is to
|
|
226
|
+
* stop accidentally losing the action's *own* declared fields.
|
|
227
|
+
*
|
|
228
|
+
* Under arc's own `createApp` (`removeAdditional: false`), strict-mode
|
|
229
|
+
* rejection still functions normally — see
|
|
230
|
+
* [tests/core/action-strict-schema-parity.test.ts](../../tests/core/action-strict-schema-parity.test.ts).
|
|
231
|
+
*
|
|
232
|
+
* Exported so OpenAPI generation and MCP tool generation can reuse the same
|
|
233
|
+
* schema shape (single source of truth).
|
|
234
|
+
*/
|
|
235
|
+
function buildActionBodySchema(actionEnum, actionSchemas = {}) {
|
|
236
|
+
const unionProperties = {};
|
|
237
|
+
const irs = [];
|
|
238
|
+
for (const actionName of actionEnum) {
|
|
239
|
+
const ir = normalizeSchemaIR(actionSchemas[actionName]);
|
|
240
|
+
irs.push({
|
|
241
|
+
name: actionName,
|
|
242
|
+
ir
|
|
243
|
+
});
|
|
244
|
+
for (const [key, val] of Object.entries(ir.properties)) unionProperties[key] = val;
|
|
245
|
+
}
|
|
246
|
+
const branches = [];
|
|
247
|
+
for (const { name, ir } of irs) branches.push(schemaIRToJsonSchemaBranch({
|
|
248
|
+
...ir,
|
|
249
|
+
properties: {
|
|
250
|
+
...unionProperties,
|
|
251
|
+
...ir.properties
|
|
252
|
+
}
|
|
253
|
+
}, {
|
|
254
|
+
properties: { action: {
|
|
255
|
+
type: "string",
|
|
256
|
+
const: name
|
|
257
|
+
} },
|
|
258
|
+
required: ["action"]
|
|
259
|
+
}));
|
|
260
|
+
return {
|
|
261
|
+
type: "object",
|
|
262
|
+
required: ["action"],
|
|
263
|
+
properties: {
|
|
264
|
+
action: {
|
|
265
|
+
type: "string",
|
|
266
|
+
enum: [...actionEnum]
|
|
267
|
+
},
|
|
268
|
+
...unionProperties
|
|
269
|
+
},
|
|
270
|
+
oneOf: branches
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Build OpenAPI description for an action mount from the action map + the
|
|
275
|
+
* permission map for THAT mount's subset. Used by both `/:id/action` and
|
|
276
|
+
* `/action` to render an "Available actions" list with role hints.
|
|
277
|
+
*/
|
|
278
|
+
function buildActionDescription(actions, actionPermissions) {
|
|
279
|
+
const lines = ["Unified action endpoint for state transitions.\n\n**Available actions:**"];
|
|
280
|
+
for (const action of Object.keys(actions)) {
|
|
281
|
+
const roles = actionPermissions[action]?._roles;
|
|
282
|
+
const roleStr = roles?.length ? ` (requires: ${roles.join(" or ")})` : "";
|
|
283
|
+
lines.push(`- \`${action}\`${roleStr}`);
|
|
284
|
+
}
|
|
285
|
+
return lines.join("\n");
|
|
286
|
+
}
|
|
287
|
+
//#endregion
|
|
288
|
+
export { createActionRouter_exports as n, buildActionBodySchema as t };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { f as createError, l as UnauthorizedError, r as ForbiddenError } from "./errors-j4aJm1Wg.mjs";
|
|
2
|
-
import { c as buildPreHandlerChain, f as resolveRouterPluginMw, i as buildAuthMiddleware, l as buildRateLimitConfig, p as selectPluginMw, r as buildArcDecorator } from "./routerShared-
|
|
3
|
-
import { r as validateAggregations
|
|
2
|
+
import { c as buildPreHandlerChain, f as resolveRouterPluginMw, i as buildAuthMiddleware, l as buildRateLimitConfig, p as selectPluginMw, r as buildArcDecorator } from "./routerShared-CZV5aabX.mjs";
|
|
3
|
+
import { r as validateAggregations } from "./validate-By96rH0r.mjs";
|
|
4
|
+
import { t as buildAggregationHandler } from "./buildHandler-BZX6zzDM.mjs";
|
|
4
5
|
//#region src/core/aggregation/createAggregationRouter.ts
|
|
5
6
|
/**
|
|
6
7
|
* Register one Fastify route per aggregation. No-op when the map is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
2
|
import { arcLog } from "./logger/index.mjs";
|
|
3
|
-
import { n as PUBLIC_SCOPE } from "./types-
|
|
3
|
+
import { n as PUBLIC_SCOPE } from "./types-Bi0r0vjG.mjs";
|
|
4
4
|
import Fastify from "fastify";
|
|
5
5
|
import qs from "qs";
|
|
6
6
|
//#region src/factory/presets.ts
|
|
@@ -202,7 +202,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
202
202
|
await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
|
|
203
203
|
trackPlugin("arc-core");
|
|
204
204
|
if (config.arcPlugins?.events !== false) {
|
|
205
|
-
const { default: eventPlugin } = await import("./eventPlugin-
|
|
205
|
+
const { default: eventPlugin } = await import("./eventPlugin-C2cGqtRO.mjs").then((n) => n.n);
|
|
206
206
|
const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
|
|
207
207
|
await fastify.register(eventPlugin, {
|
|
208
208
|
...eventOpts,
|
|
@@ -239,15 +239,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
239
239
|
trackPlugin("arc-graceful-shutdown");
|
|
240
240
|
}
|
|
241
241
|
if (config.arcPlugins?.caching) {
|
|
242
|
-
const { default: cachingPlugin } = await import("./caching-
|
|
242
|
+
const { default: cachingPlugin } = await import("./caching-TeHE8G-v.mjs").then((n) => n.r);
|
|
243
243
|
const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
|
|
244
244
|
await fastify.register(cachingPlugin, opts);
|
|
245
245
|
trackPlugin("arc-caching", opts);
|
|
246
246
|
}
|
|
247
247
|
if (config.arcPlugins?.queryCache) {
|
|
248
|
-
const { queryCachePlugin } = await import("./queryCachePlugin-
|
|
248
|
+
const { queryCachePlugin } = await import("./queryCachePlugin-B4XMSSe7.mjs").then((n) => n.n);
|
|
249
249
|
const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
|
|
250
|
-
const store = config.stores?.queryCache ?? new (await (import("./memory-
|
|
250
|
+
const store = config.stores?.queryCache ?? new (await (import("./memory-QOLe11D5.mjs").then((n) => n.n))).MemoryCacheStore();
|
|
251
251
|
await fastify.register(queryCachePlugin, {
|
|
252
252
|
store,
|
|
253
253
|
...opts
|
|
@@ -256,19 +256,19 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
256
256
|
}
|
|
257
257
|
if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
|
|
258
258
|
else {
|
|
259
|
-
const { default: ssePlugin } = await import("./sse-
|
|
259
|
+
const { default: ssePlugin } = await import("./sse-BY6sTy4P.mjs").then((n) => n.r);
|
|
260
260
|
const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
|
|
261
261
|
await fastify.register(ssePlugin, opts);
|
|
262
262
|
trackPlugin("arc-sse", opts);
|
|
263
263
|
}
|
|
264
264
|
if (config.arcPlugins?.metrics) {
|
|
265
|
-
const { default: metricsPlugin } = await import("./metrics-
|
|
265
|
+
const { default: metricsPlugin } = await import("./metrics-TuOmguhi.mjs").then((n) => n.r);
|
|
266
266
|
const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
|
|
267
267
|
await fastify.register(metricsPlugin, opts);
|
|
268
268
|
trackPlugin("arc-metrics", opts);
|
|
269
269
|
}
|
|
270
270
|
if (config.arcPlugins?.versioning) {
|
|
271
|
-
const { default: versioningPlugin } = await import("./versioning-
|
|
271
|
+
const { default: versioningPlugin } = await import("./versioning-B6mimogM.mjs").then((n) => n.r);
|
|
272
272
|
await fastify.register(versioningPlugin, config.arcPlugins.versioning);
|
|
273
273
|
trackPlugin("arc-versioning", config.arcPlugins.versioning);
|
|
274
274
|
}
|
|
@@ -337,7 +337,7 @@ async function registerAuth(fastify, config, trackPlugin) {
|
|
|
337
337
|
*/
|
|
338
338
|
async function registerElevation(fastify, config, trackPlugin) {
|
|
339
339
|
if (!config.elevation) return;
|
|
340
|
-
const { elevationPlugin } = await import("./elevation-
|
|
340
|
+
const { elevationPlugin } = await import("./elevation-Dci0AYLT.mjs").then((n) => n.r);
|
|
341
341
|
await fastify.register(elevationPlugin, config.elevation);
|
|
342
342
|
trackPlugin("arc-elevation", config.elevation);
|
|
343
343
|
fastify.log.debug("Elevation plugin enabled");
|
|
@@ -347,7 +347,7 @@ async function registerElevation(fastify, config, trackPlugin) {
|
|
|
347
347
|
*/
|
|
348
348
|
async function registerErrorHandler(fastify, config, trackPlugin) {
|
|
349
349
|
if (config.errorHandler === false) return;
|
|
350
|
-
const { errorHandlerPlugin } = await import("./errorHandler-
|
|
350
|
+
const { errorHandlerPlugin } = await import("./errorHandler-DpoXQHZ9.mjs").then((n) => n.r);
|
|
351
351
|
const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
|
|
352
352
|
await fastify.register(errorHandlerPlugin, errorOpts);
|
|
353
353
|
trackPlugin("arc-error-handler", errorOpts);
|
|
@@ -448,7 +448,7 @@ async function registerResources(fastify, config) {
|
|
|
448
448
|
let discoveryPath;
|
|
449
449
|
let discoveryYieldedZero = false;
|
|
450
450
|
if (resolvedResources === void 0 && config.resourceDir) {
|
|
451
|
-
const { loadResources } = await import("./loadResources-
|
|
451
|
+
const { loadResources } = await import("./loadResources-ChQEj8ih.mjs").then((n) => n.n);
|
|
452
452
|
const { resolve, dirname } = await import("node:path");
|
|
453
453
|
const { fileURLToPath } = await import("node:url");
|
|
454
454
|
const rawDir = config.resourceDir;
|
|
@@ -575,7 +575,6 @@ const PLUGIN_REGISTRY = {
|
|
|
575
575
|
optional: true
|
|
576
576
|
}
|
|
577
577
|
};
|
|
578
|
-
/** Load a plugin from the registry with helpful error messages. */
|
|
579
578
|
async function loadPlugin(name, logger) {
|
|
580
579
|
const entry = PLUGIN_REGISTRY[name];
|
|
581
580
|
if (!entry) throw new Error(`Unknown plugin: ${name}`);
|
|
@@ -828,7 +827,10 @@ async function createApp(options) {
|
|
|
828
827
|
pluginTimeout: config.pluginTimeout ?? 1e4,
|
|
829
828
|
...config.bodyLimit !== void 0 ? { bodyLimit: config.bodyLimit } : {},
|
|
830
829
|
allowErrorHandlerOverride: true,
|
|
831
|
-
routerOptions: {
|
|
830
|
+
routerOptions: {
|
|
831
|
+
querystringParser: (str) => qs.parse(str),
|
|
832
|
+
maxParamLength: config.maxParamLength ?? 400
|
|
833
|
+
},
|
|
832
834
|
ajv: { customOptions: {
|
|
833
835
|
coerceTypes: true,
|
|
834
836
|
useDefaults: true,
|
|
@@ -872,7 +874,7 @@ async function createApp(options) {
|
|
|
872
874
|
await registerErrorHandler(fastify, config, trackPlugin);
|
|
873
875
|
await registerResources(fastify, config);
|
|
874
876
|
if (config.replyHelpers) {
|
|
875
|
-
const { replyHelpersPlugin } = await import("./replyHelpers-
|
|
877
|
+
const { replyHelpersPlugin } = await import("./replyHelpers-C-gD32oF.mjs").then((n) => n.n);
|
|
876
878
|
await fastify.register(replyHelpersPlugin);
|
|
877
879
|
}
|
|
878
880
|
if (config.serializeBigInt) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { n as createEvent } from "./EventTransport-
|
|
2
|
+
import { n as createEvent } from "./EventTransport-Hxvv5QQz.mjs";
|
|
3
3
|
//#region src/events/defineEvent.ts
|
|
4
4
|
/**
|
|
5
5
|
* defineEvent — Typed Event Definitions with Optional Schema Validation
|
package/dist/docs/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as RegistryEntry } from "../index-
|
|
2
|
-
import { t as ExternalOpenApiPaths } from "../externalPaths-
|
|
1
|
+
import { p as RegistryEntry } from "../index-CkW0flkU.mjs";
|
|
2
|
+
import { t as ExternalOpenApiPaths } from "../externalPaths-DFg-2KTp.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
|
|
5
5
|
//#region src/docs/openapi/types.d.ts
|
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as getUserRoles } from "../types-D57iXYb8.mjs";
|
|
2
|
-
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-
|
|
2
|
+
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-34T9yNwd.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/docs/scalar.ts
|
|
5
5
|
const scalarPlugin = async (fastify, opts = {}) => {
|
|
@@ -114,25 +114,28 @@ function classify(error, ctx) {
|
|
|
114
114
|
}
|
|
115
115
|
if (isArcError(error) || isHttpError(error)) return toErrorContract(error);
|
|
116
116
|
const fastifyErr = error;
|
|
117
|
-
if (Array.isArray(fastifyErr.validation))
|
|
118
|
-
code
|
|
119
|
-
message: "Validation failed"
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
if (Array.isArray(fastifyErr.validation)) {
|
|
118
|
+
const arcInternalCode = typeof fastifyErr.code === "string" && fastifyErr.code.startsWith("arc.") ? fastifyErr.code : void 0;
|
|
119
|
+
const message = arcInternalCode ? error.message || "Validation failed" : "Validation failed";
|
|
120
|
+
return {
|
|
121
|
+
code: arcInternalCode ?? "arc.validation_error",
|
|
122
|
+
message,
|
|
123
|
+
status: typeof fastifyErr.statusCode === "number" ? fastifyErr.statusCode : 400,
|
|
124
|
+
details: fastifyValidationDetails(fastifyErr),
|
|
125
|
+
...fastifyErr.meta ? { meta: fastifyErr.meta } : {}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
123
128
|
if (typeof fastifyErr.statusCode === "number") return {
|
|
124
129
|
code: statusToArcCode(fastifyErr.statusCode),
|
|
125
130
|
message: error.message || "Error",
|
|
126
131
|
status: fastifyErr.statusCode
|
|
127
132
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
};
|
|
135
|
-
}
|
|
133
|
+
const namedMapping = error.name ? ctx.errorMap[error.name] : void 0;
|
|
134
|
+
if (namedMapping) return {
|
|
135
|
+
code: namedMapping.code,
|
|
136
|
+
message: namedMapping.message ?? error.message,
|
|
137
|
+
status: namedMapping.statusCode
|
|
138
|
+
};
|
|
136
139
|
if (error.name === "ValidationError" && "errors" in error) {
|
|
137
140
|
const errs = error.errors;
|
|
138
141
|
return {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { HttpError } from "@classytic/repo-core/errors";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/errors.d.ts
|
|
4
|
+
interface ErrorOptions {
|
|
5
|
+
code?: string;
|
|
6
|
+
statusCode?: number;
|
|
7
|
+
details?: Record<string, unknown>;
|
|
8
|
+
cause?: Error;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Base Arc Error. Implements the canonical `HttpError` contract — `status`
|
|
12
|
+
* mirrors `statusCode` and `meta` mirrors `details`, so consumers reading
|
|
13
|
+
* either name see the same value without adapter glue.
|
|
14
|
+
*/
|
|
15
|
+
declare class ArcError extends Error implements HttpError {
|
|
16
|
+
name: string;
|
|
17
|
+
readonly code: string;
|
|
18
|
+
readonly statusCode: number;
|
|
19
|
+
readonly details?: Record<string, unknown>;
|
|
20
|
+
readonly cause?: Error;
|
|
21
|
+
constructor(message: string, options?: ErrorOptions);
|
|
22
|
+
/** `HttpError.status` mirror — repo-core's `toErrorContract` reads this. */
|
|
23
|
+
get status(): number;
|
|
24
|
+
/** `HttpError.meta` mirror — `details` under the canonical name. */
|
|
25
|
+
get meta(): Record<string, unknown> | undefined;
|
|
26
|
+
}
|
|
27
|
+
declare class NotFoundError extends ArcError {
|
|
28
|
+
constructor(resource: string, identifier?: string);
|
|
29
|
+
}
|
|
30
|
+
declare class ValidationError extends ArcError {
|
|
31
|
+
readonly errors: ReadonlyArray<{
|
|
32
|
+
field: string;
|
|
33
|
+
message: string;
|
|
34
|
+
}>;
|
|
35
|
+
constructor(message: string, errors?: Array<{
|
|
36
|
+
field: string;
|
|
37
|
+
message: string;
|
|
38
|
+
}>);
|
|
39
|
+
}
|
|
40
|
+
declare class UnauthorizedError extends ArcError {
|
|
41
|
+
constructor(message?: string);
|
|
42
|
+
}
|
|
43
|
+
declare class ForbiddenError extends ArcError {
|
|
44
|
+
constructor(message?: string);
|
|
45
|
+
}
|
|
46
|
+
declare class ConflictError extends ArcError {
|
|
47
|
+
constructor(message: string, field?: string);
|
|
48
|
+
}
|
|
49
|
+
declare class OrgRequiredError extends ArcError {
|
|
50
|
+
readonly organizations?: ReadonlyArray<{
|
|
51
|
+
id: string;
|
|
52
|
+
roles?: string[];
|
|
53
|
+
}>;
|
|
54
|
+
constructor(message: string, organizations?: Array<{
|
|
55
|
+
id: string;
|
|
56
|
+
roles?: string[];
|
|
57
|
+
}>);
|
|
58
|
+
}
|
|
59
|
+
declare class OrgAccessDeniedError extends ArcError {
|
|
60
|
+
constructor(orgId?: string);
|
|
61
|
+
}
|
|
62
|
+
declare class RateLimitError extends ArcError {
|
|
63
|
+
readonly retryAfter?: number;
|
|
64
|
+
constructor(message?: string, retryAfter?: number);
|
|
65
|
+
}
|
|
66
|
+
declare class ServiceUnavailableError extends ArcError {
|
|
67
|
+
constructor(message?: string);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Quick `ArcError` constructor when the bundled subclasses don't fit.
|
|
71
|
+
*
|
|
72
|
+
* If `details.code` is a string, it's lifted to the top-level `error.code`
|
|
73
|
+
* (the canonical wire slot for business signals — `'ORG_CONTEXT_REQUIRED'`,
|
|
74
|
+
* `'ALL_FIELDS_STRIPPED'`, etc). The same code stays in `details` so
|
|
75
|
+
* in-process consumers reading `error.details.code` still work. Without
|
|
76
|
+
* this lift, business codes get buried in `details` and the wire envelope
|
|
77
|
+
* carries only the status-derived `arc.forbidden` / `arc.bad_request`
|
|
78
|
+
* fallback — `repo-core`'s `toErrorContract` doesn't surface free-form
|
|
79
|
+
* `details` objects (its `details[]` array is reserved for validation /
|
|
80
|
+
* duplicate-key items).
|
|
81
|
+
*/
|
|
82
|
+
declare function createError(statusCode: number, message: string, details?: Record<string, unknown>): ArcError;
|
|
83
|
+
/**
|
|
84
|
+
* Domain-error escape hatch. Use a hierarchical code that scopes the error
|
|
85
|
+
* to your package (`'commerce.cart.locked'`, `'payment.gateway.timeout'`).
|
|
86
|
+
*/
|
|
87
|
+
declare function createDomainError(code: string, message: string, statusCode?: number, details?: Record<string, unknown>): ArcError;
|
|
88
|
+
/** Type guard. */
|
|
89
|
+
declare function isArcError(error: unknown): error is ArcError;
|
|
90
|
+
//#endregion
|
|
91
|
+
export { NotFoundError as a, RateLimitError as c, ValidationError as d, createDomainError as f, ForbiddenError as i, ServiceUnavailableError as l, isArcError as m, ConflictError as n, OrgAccessDeniedError as o, createError as p, ErrorOptions as r, OrgRequiredError as s, ArcError as t, UnauthorizedError as u };
|
|
@@ -2,7 +2,7 @@ import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
|
2
2
|
import { arcLog } from "./logger/index.mjs";
|
|
3
3
|
import { d as createDomainError } from "./errors-j4aJm1Wg.mjs";
|
|
4
4
|
import { t as requestContext } from "./requestContext-SSaaTgW8.mjs";
|
|
5
|
-
import { n as createEvent, t as MemoryEventTransport } from "./EventTransport-
|
|
5
|
+
import { n as createEvent, t as MemoryEventTransport } from "./EventTransport-Hxvv5QQz.mjs";
|
|
6
6
|
import fp from "fastify-plugin";
|
|
7
7
|
//#region src/events/retry.ts
|
|
8
8
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "./EventTransport-
|
|
1
|
+
import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "./EventTransport-C-2oAHtw.mjs";
|
|
2
2
|
import { FastifyPluginAsync } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/events/defineEvent.d.ts
|
package/dist/events/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as EventTransport, i as EventLogger, n as DomainEvent, o as MemoryEventTransport, r as EventHandler, s as MemoryEventTransportOptions, t as DeadLetteredEvent } from "../EventTransport-
|
|
2
|
-
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-
|
|
1
|
+
import { a as EventTransport, i as EventLogger, n as DomainEvent, o as MemoryEventTransport, r as EventHandler, s as MemoryEventTransportOptions, t as DeadLetteredEvent } from "../EventTransport-C-2oAHtw.mjs";
|
|
2
|
+
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-CtHC_av1.mjs";
|
|
3
3
|
import { RedisEventTransportOptions, RedisLike } from "./transports/redis.mjs";
|
|
4
|
-
import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-
|
|
4
|
+
import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-DT-YjzrB.mjs";
|
|
5
5
|
import { RepositoryLike } from "@classytic/repo-core/adapter";
|
|
6
6
|
|
|
7
7
|
//#region src/events/eventTypes.d.ts
|
package/dist/events/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as MemoryEventTransport } from "../EventTransport-
|
|
2
|
-
import { n as defineEvent, t as createEventRegistry } from "../defineEvent-
|
|
3
|
-
import { i as withRetry, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-
|
|
4
|
-
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-
|
|
1
|
+
import { t as MemoryEventTransport } from "../EventTransport-Hxvv5QQz.mjs";
|
|
2
|
+
import { n as defineEvent, t as createEventRegistry } from "../defineEvent-DRwY0fYm.mjs";
|
|
3
|
+
import { i as withRetry, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-C2cGqtRO.mjs";
|
|
4
|
+
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-B0sunfZZ.mjs";
|
|
5
5
|
import { and, anyOf, eq, lte, ne, or } from "@classytic/repo-core/filter";
|
|
6
6
|
import { update } from "@classytic/repo-core/update";
|
|
7
7
|
//#region src/events/eventTypes.ts
|
|
@@ -716,7 +716,7 @@ function wrapWithSchema(definition, handler, options = {}) {
|
|
|
716
716
|
if (validate && definition.schema) result = validate(definition.schema, event.payload);
|
|
717
717
|
else if (registry) result = registry.validate(definition.name, event.payload, eventVersion);
|
|
718
718
|
else if (definition.schema) {
|
|
719
|
-
const { createEventRegistry } = await import("../defineEvent-
|
|
719
|
+
const { createEventRegistry } = await import("../defineEvent-DRwY0fYm.mjs").then((n) => n.r);
|
|
720
720
|
const adhoc = createEventRegistry();
|
|
721
721
|
adhoc.register(definition);
|
|
722
722
|
result = adhoc.validate(definition.name, event.payload);
|
|
@@ -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-DT-YjzrB.mjs";
|
|
2
2
|
export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "../../EventTransport-
|
|
1
|
+
import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "../../EventTransport-C-2oAHtw.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/events/transports/redis.d.ts
|
|
4
4
|
interface RedisLike {
|
package/dist/factory/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-
|
|
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-D-fYtKjb.mjs";
|
|
2
2
|
import { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/factory/createApp.d.ts
|
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-DNccuhyI.mjs";
|
|
2
|
+
import { t as loadResources } from "../loadResources-ChQEj8ih.mjs";
|
|
3
3
|
//#region src/factory/edge.ts
|
|
4
4
|
/**
|
|
5
5
|
* Convert a Fastify app into a Web Standards fetch handler.
|