@classytic/arc 2.8.5 → 2.9.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/README.md +88 -5
- package/dist/{BaseController-DAGGc5Xn.mjs → BaseController-Vu2yc56T.mjs} +188 -102
- package/dist/EventTransport-CqZ8FyM_.d.mts +293 -0
- package/dist/adapters/index.d.mts +2 -2
- package/dist/audit/index.d.mts +100 -11
- package/dist/audit/index.mjs +71 -18
- package/dist/auth/index.d.mts +16 -8
- package/dist/auth/index.mjs +13 -6
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-BuUcUEJq.mjs → betterAuthOpenApi--rdY15Ld.mjs} +1 -1
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +2 -2
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -5
- package/dist/{core-F0QoWBt2.mjs → core-DNncu0xF.mjs} +1 -1
- package/dist/{createActionRouter-BORM8f17.mjs → createActionRouter-DH1YFL9m.mjs} +3 -3
- package/dist/{createApp-B1EY8zxa.mjs → createApp-CBJUJKGP.mjs} +13 -12
- package/dist/{defineResource-tcgySDo1.mjs → defineResource-C__jkwvs.mjs} +22 -57
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.d.mts +1 -1
- package/dist/dynamic/index.mjs +3 -3
- package/dist/{elevation-DtFxrG0s.mjs → elevation-DxQ6ACbt.mjs} +21 -7
- package/dist/{errorHandler-f869_8PQ.mjs → errorHandler-CZDW4EXS.mjs} +59 -7
- package/dist/{errorHandler-Bah5JhBd.d.mts → errorHandler-DixGcttC.d.mts} +37 -2
- package/dist/{eventPlugin-D9DKB2zM.d.mts → eventPlugin-BxvaCIZF.d.mts} +14 -2
- package/dist/{eventPlugin-CDjVTM82.mjs → eventPlugin-Dl7MoVWH.mjs} +83 -5
- package/dist/events/index.d.mts +147 -36
- package/dist/events/index.mjs +338 -101
- 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-DpZQa_Q3.d.mts → fields-BC7zcmI9.d.mts} +15 -3
- package/dist/{fields-ipsbIRPK.mjs → fields-CU6FlaDV.mjs} +18 -5
- package/dist/{filesUpload-C7r7HIeA.mjs → filesUpload-q8oHt--L.mjs} +65 -7
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +29 -5
- package/dist/idempotency/index.mjs +111 -2
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-BLXBmWud.d.mts → index-C-xjcA6F.d.mts} +1 -1
- package/dist/{index-DtDzOBn8.d.mts → index-Cibkchnx.d.mts} +3 -134
- package/dist/{index-C1meYuDn.d.mts → index-CtGKT0lf.d.mts} +1 -1
- package/dist/index.d.mts +7 -7
- 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 +1 -1
- package/dist/integrations/mcp/index.d.mts +26 -8
- package/dist/integrations/mcp/index.mjs +96 -17
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/webhooks.d.mts +5 -0
- package/dist/integrations/webhooks.mjs +6 -0
- package/dist/{interface-CMRutPfe.d.mts → interface-YrWsmKqE.d.mts} +287 -179
- package/dist/{openapi-CbKUJY_m.mjs → openapi-CXuTG1M9.mjs} +2 -2
- package/dist/org/index.d.mts +1 -1
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +3 -3
- package/dist/{permissions-CH4cNwJi.mjs → permissions-oNZawnkR.mjs} +1 -1
- package/dist/plugins/index.d.mts +7 -7
- package/dist/plugins/index.mjs +11 -11
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/policies/index.d.mts +25 -32
- package/dist/presets/filesUpload.d.mts +26 -4
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +3 -2
- package/dist/presets/index.mjs +4 -3
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +1 -1
- package/dist/presets/search.d.mts +91 -0
- package/dist/presets/search.mjs +150 -0
- package/dist/{presets-C2xgzW6x.mjs → presets-hM4WhNWY.mjs} +1 -1
- package/dist/{queryCachePlugin-BJJGBTlu.d.mts → queryCachePlugin-CnTZZTC5.d.mts} +1 -1
- package/dist/{queryCachePlugin-BH-fidlv.mjs → queryCachePlugin-DbUVroUG.mjs} +2 -2
- package/dist/{redis-BM00zaPB.d.mts → redis-MXLp1oOf.d.mts} +1 -1
- package/dist/{redis-stream-CrsfUmPt.d.mts → redis-stream-Bz-4q96t.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{resourceToTools-8s-EsCCe.mjs → resourceToTools-C3cWymnW.mjs} +64 -47
- package/dist/rpc/index.d.mts +1 -1
- package/dist/rpc/index.mjs +1 -1
- package/dist/{schemaConverter-Y7nCYaLJ.mjs → schemaConverter-BxFDdtXu.mjs} +1 -1
- package/dist/scope/index.mjs +1 -1
- package/dist/{sse-Ad7ypl9e.mjs → sse-CJpt7LGI.mjs} +1 -1
- package/dist/store-helpers-DFiZl5TL.mjs +57 -0
- package/dist/testing/index.d.mts +5 -14
- package/dist/testing/index.mjs +21 -75
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +2 -2
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-BsbNMEDR.d.mts → types-CoSzA-s-.d.mts} +1 -1
- package/dist/{types-Ch9pTQbf.d.mts → types-CunEX4UX.d.mts} +10 -8
- package/dist/utils/index.d.mts +4 -4
- package/dist/utils/index.mjs +6 -6
- package/dist/{utils-yYT3HDXt.mjs → utils-B7FuRr9w.mjs} +1 -1
- package/package.json +8 -11
- package/skills/arc/SKILL.md +92 -14
- package/skills/arc/references/auth.md +94 -0
- package/skills/arc/references/events.md +200 -12
- package/skills/arc/references/mcp.md +4 -17
- package/skills/arc/references/multi-tenancy.md +43 -0
- package/skills/arc/references/production.md +34 -19
- package/dist/EventTransport-BXja8NOc.d.mts +0 -135
- package/dist/audit/mongodb.d.mts +0 -2
- package/dist/audit/mongodb.mjs +0 -2
- package/dist/idempotency/mongodb.d.mts +0 -2
- package/dist/idempotency/mongodb.mjs +0 -123
- package/dist/mongodb-BsP-WbhN.d.mts +0 -127
- package/dist/mongodb-CTcp0hQZ.d.mts +0 -80
- package/dist/mongodb-Utc5k_-0.mjs +0 -90
- /package/dist/{HookSystem-HprTmvVY.mjs → HookSystem-BjFu7zf1.mjs} +0 -0
- /package/dist/{ResourceRegistry-C6uXlWe3.mjs → ResourceRegistry-Dq3_zBQP.mjs} +0 -0
- /package/dist/{applyPermissionResult-D6GPMsvh.mjs → applyPermissionResult-bqGpo9ML.mjs} +0 -0
- /package/dist/{caching-IMuYVjTL.mjs → caching-CjybdRwx.mjs} +0 -0
- /package/dist/{circuitBreaker-dTtG-UyS.d.mts → circuitBreaker-CvXkjfrW.d.mts} +0 -0
- /package/dist/{circuitBreaker-cmi5XDv5.mjs → circuitBreaker-l18oRgL5.mjs} +0 -0
- /package/dist/{errors-Ck2h67pm.d.mts → errors-BI8kEKsO.d.mts} +0 -0
- /package/dist/{errors-BF2bIOIS.mjs → errors-CqWnSqM-.mjs} +0 -0
- /package/dist/{externalPaths-BnkYrNzp.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
- /package/dist/{interface-DfLGcus7.d.mts → interface-B-pe8fhj.d.mts} +0 -0
- /package/dist/{interface-4y979v99.d.mts → interface-DplgQO2e.d.mts} +0 -0
- /package/dist/{loadResources-PWd0OCpV.mjs → loadResources-Bksk8ydA.mjs} +0 -0
- /package/dist/{logger-D1YrIImS.mjs → logger-CDjpjySd.mjs} +0 -0
- /package/dist/{memory-Cp7_cAko.mjs → memory-BFAYkf8H.mjs} +0 -0
- /package/dist/{metrics-B-PU4-Yu.mjs → metrics-TuOmguhi.mjs} +0 -0
- /package/dist/{queryParser-CgCtsjti.mjs → queryParser-Cs-6SHQK.mjs} +0 -0
- /package/dist/{registry-BiTKT1Dg.mjs → registry-B0Wl7uVV.mjs} +0 -0
- /package/dist/{replyHelpers-CxkYGT81.mjs → replyHelpers-BLojtuvR.mjs} +0 -0
- /package/dist/{requestContext-DYvHl113.mjs → requestContext-DYtmNpm5.mjs} +0 -0
- /package/dist/{sessionManager-DDCmiNIo.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
- /package/dist/{storage-Dfzt4VTl.d.mts → storage-BwGQXUpd.d.mts} +0 -0
- /package/dist/{tracing-DdN2-wHJ.d.mts → tracing-xqXzWeaf.d.mts} +0 -0
- /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-Cj5Rgvlg.mjs} +0 -0
- /package/dist/{versioning-CDugduqI.mjs → versioning-Cm8qoFDg.mjs} +0 -0
package/dist/cache/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as CacheStore, n as CacheSetOptions, r as CacheStats, t as CacheLogger } from "../interface-
|
|
2
|
-
import { a as CacheEnvelope, c as QueryCache, i as queryCachePlugin, l as QueryCacheConfig, n as QueryCacheDefaults, o as CacheResult, r as QueryCachePluginOptions, s as CacheStatus, t as CrossResourceRule } from "../queryCachePlugin-
|
|
1
|
+
import { i as CacheStore, n as CacheSetOptions, r as CacheStats, t as CacheLogger } from "../interface-DplgQO2e.mjs";
|
|
2
|
+
import { a as CacheEnvelope, c as QueryCache, i as queryCachePlugin, l as QueryCacheConfig, n as QueryCacheDefaults, o as CacheResult, r as QueryCachePluginOptions, s as CacheStatus, t as CrossResourceRule } from "../queryCachePlugin-CnTZZTC5.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/cache/keys.d.ts
|
|
5
5
|
/**
|
package/dist/cache/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-qcD-TVJl.mjs";
|
|
2
|
-
import { t as MemoryCacheStore } from "../memory-
|
|
3
|
-
import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-
|
|
2
|
+
import { t as MemoryCacheStore } from "../memory-BFAYkf8H.mjs";
|
|
3
|
+
import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-DbUVroUG.mjs";
|
|
4
4
|
//#region src/cache/redis.ts
|
|
5
5
|
/**
|
|
6
6
|
* Redis-backed cache store.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as ResourceRegistry } from "../../ResourceRegistry-
|
|
2
|
-
import { t as buildOpenApiSpec } from "../../openapi-
|
|
1
|
+
import { t as ResourceRegistry } from "../../ResourceRegistry-Dq3_zBQP.mjs";
|
|
2
|
+
import { t as buildOpenApiSpec } from "../../openapi-CXuTG1M9.mjs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ResourceRegistry } from "../../ResourceRegistry-
|
|
1
|
+
import { t as ResourceRegistry } from "../../ResourceRegistry-Dq3_zBQP.mjs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
//#region src/cli/commands/introspect.ts
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { At as
|
|
2
|
-
import {
|
|
3
|
-
export { AccessControl, AccessControlConfig,
|
|
1
|
+
import { At as BaseControllerOptions, Ft as AccessControl, It as AccessControlConfig, Kt as ResourceDefinition, Mt as QueryResolverConfig, Nt as BodySanitizer, Pt as BodySanitizerConfig, jt as QueryResolver, kt as BaseController, qt as defineResource } from "../interface-YrWsmKqE.mjs";
|
|
2
|
+
import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-Cibkchnx.mjs";
|
|
3
|
+
export { AccessControl, AccessControlConfig, BaseController, BaseControllerOptions, BodySanitizer, BodySanitizerConfig, CRUD_OPERATIONS, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-Cxde4rpC.mjs";
|
|
2
|
-
import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, buildActionBodySchema, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
|
2
|
+
import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-Vu2yc56T.mjs";
|
|
3
|
+
import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-C__jkwvs.mjs";
|
|
4
|
+
import { t as defineResourceVariants } from "../core-DNncu0xF.mjs";
|
|
5
|
+
export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as defineResource } from "./defineResource-
|
|
1
|
+
import { n as defineResource } from "./defineResource-C__jkwvs.mjs";
|
|
2
2
|
//#region src/core/defineResourceVariants.ts
|
|
3
3
|
/**
|
|
4
4
|
* Define multiple resources from a shared base config and per-variant overrides.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-
|
|
3
|
-
import { a as toJsonSchema } from "./schemaConverter-
|
|
2
|
+
import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-bqGpo9ML.mjs";
|
|
3
|
+
import { a as toJsonSchema } from "./schemaConverter-BxFDdtXu.mjs";
|
|
4
4
|
//#region src/core/createActionRouter.ts
|
|
5
5
|
var createActionRouter_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
buildActionBodySchema: () => buildActionBodySchema,
|
|
@@ -246,4 +246,4 @@ function buildActionDescription(actions, actionPermissions) {
|
|
|
246
246
|
return lines.join("\n");
|
|
247
247
|
}
|
|
248
248
|
//#endregion
|
|
249
|
-
export {
|
|
249
|
+
export { createActionRouter_exports as n, buildActionBodySchema as t };
|
|
@@ -207,7 +207,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
207
207
|
await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
|
|
208
208
|
trackPlugin("arc-core");
|
|
209
209
|
if (config.arcPlugins?.events !== false) {
|
|
210
|
-
const { default: eventPlugin } = await import("./eventPlugin-
|
|
210
|
+
const { default: eventPlugin } = await import("./eventPlugin-Dl7MoVWH.mjs").then((n) => n.n);
|
|
211
211
|
const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
|
|
212
212
|
await fastify.register(eventPlugin, {
|
|
213
213
|
...eventOpts,
|
|
@@ -243,15 +243,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
243
243
|
trackPlugin("arc-graceful-shutdown");
|
|
244
244
|
}
|
|
245
245
|
if (config.arcPlugins?.caching) {
|
|
246
|
-
const { default: cachingPlugin } = await import("./caching-
|
|
246
|
+
const { default: cachingPlugin } = await import("./caching-CjybdRwx.mjs").then((n) => n.r);
|
|
247
247
|
const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
|
|
248
248
|
await fastify.register(cachingPlugin, opts);
|
|
249
249
|
trackPlugin("arc-caching", opts);
|
|
250
250
|
}
|
|
251
251
|
if (config.arcPlugins?.queryCache) {
|
|
252
|
-
const { queryCachePlugin } = await import("./queryCachePlugin-
|
|
252
|
+
const { queryCachePlugin } = await import("./queryCachePlugin-DbUVroUG.mjs").then((n) => n.n);
|
|
253
253
|
const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
|
|
254
|
-
const store = config.stores?.queryCache ?? new (await (import("./memory-
|
|
254
|
+
const store = config.stores?.queryCache ?? new (await (import("./memory-BFAYkf8H.mjs").then((n) => n.n))).MemoryCacheStore();
|
|
255
255
|
await fastify.register(queryCachePlugin, {
|
|
256
256
|
store,
|
|
257
257
|
...opts
|
|
@@ -260,19 +260,19 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
260
260
|
}
|
|
261
261
|
if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
|
|
262
262
|
else {
|
|
263
|
-
const { default: ssePlugin } = await import("./sse-
|
|
263
|
+
const { default: ssePlugin } = await import("./sse-CJpt7LGI.mjs").then((n) => n.r);
|
|
264
264
|
const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
|
|
265
265
|
await fastify.register(ssePlugin, opts);
|
|
266
266
|
trackPlugin("arc-sse", opts);
|
|
267
267
|
}
|
|
268
268
|
if (config.arcPlugins?.metrics) {
|
|
269
|
-
const { default: metricsPlugin } = await import("./metrics-
|
|
269
|
+
const { default: metricsPlugin } = await import("./metrics-TuOmguhi.mjs").then((n) => n.r);
|
|
270
270
|
const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
|
|
271
271
|
await fastify.register(metricsPlugin, opts);
|
|
272
272
|
trackPlugin("arc-metrics", opts);
|
|
273
273
|
}
|
|
274
274
|
if (config.arcPlugins?.versioning) {
|
|
275
|
-
const { default: versioningPlugin } = await import("./versioning-
|
|
275
|
+
const { default: versioningPlugin } = await import("./versioning-Cm8qoFDg.mjs").then((n) => n.r);
|
|
276
276
|
await fastify.register(versioningPlugin, config.arcPlugins.versioning);
|
|
277
277
|
trackPlugin("arc-versioning", config.arcPlugins.versioning);
|
|
278
278
|
}
|
|
@@ -340,7 +340,7 @@ async function registerAuth(fastify, config, trackPlugin) {
|
|
|
340
340
|
*/
|
|
341
341
|
async function registerElevation(fastify, config, trackPlugin) {
|
|
342
342
|
if (!config.elevation) return;
|
|
343
|
-
const { elevationPlugin } = await import("./elevation-
|
|
343
|
+
const { elevationPlugin } = await import("./elevation-DxQ6ACbt.mjs").then((n) => n.r);
|
|
344
344
|
await fastify.register(elevationPlugin, config.elevation);
|
|
345
345
|
trackPlugin("arc-elevation", config.elevation);
|
|
346
346
|
fastify.log.debug("Elevation plugin enabled");
|
|
@@ -350,7 +350,7 @@ async function registerElevation(fastify, config, trackPlugin) {
|
|
|
350
350
|
*/
|
|
351
351
|
async function registerErrorHandler(fastify, config, trackPlugin) {
|
|
352
352
|
if (config.errorHandler === false) return;
|
|
353
|
-
const { errorHandlerPlugin } = await import("./errorHandler-
|
|
353
|
+
const { errorHandlerPlugin } = await import("./errorHandler-CZDW4EXS.mjs").then((n) => n.r);
|
|
354
354
|
const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
|
|
355
355
|
await fastify.register(errorHandlerPlugin, errorOpts);
|
|
356
356
|
trackPlugin("arc-error-handler", errorOpts);
|
|
@@ -417,7 +417,7 @@ async function registerResources(fastify, config) {
|
|
|
417
417
|
fastify.log.debug(`${config.bootstrap.length} bootstrap function(s) executed`);
|
|
418
418
|
}
|
|
419
419
|
if (!config.resources?.length && config.resourceDir) {
|
|
420
|
-
const { loadResources } = await import("./loadResources-
|
|
420
|
+
const { loadResources } = await import("./loadResources-Bksk8ydA.mjs").then((n) => n.n);
|
|
421
421
|
const { resolve } = await import("node:path");
|
|
422
422
|
const dir = resolve(config.resourceDir);
|
|
423
423
|
config = {
|
|
@@ -676,7 +676,7 @@ function validateDistributedRuntime(options) {
|
|
|
676
676
|
*/
|
|
677
677
|
async function createApp(options) {
|
|
678
678
|
if (options.debug !== void 0 && options.debug !== false) {
|
|
679
|
-
const { configureArcLogger } = await import("./logger-
|
|
679
|
+
const { configureArcLogger } = await import("./logger-CDjpjySd.mjs").then((n) => n.r);
|
|
680
680
|
configureArcLogger({ debug: options.debug });
|
|
681
681
|
}
|
|
682
682
|
validateAuthOptions(options);
|
|
@@ -688,6 +688,7 @@ async function createApp(options) {
|
|
|
688
688
|
const fastify = Fastify({
|
|
689
689
|
logger: config.logger ?? true,
|
|
690
690
|
trustProxy: config.trustProxy ?? false,
|
|
691
|
+
pluginTimeout: config.pluginTimeout ?? 1e4,
|
|
691
692
|
routerOptions: { querystringParser: (str) => qs.parse(str) },
|
|
692
693
|
ajv: { customOptions: {
|
|
693
694
|
coerceTypes: true,
|
|
@@ -729,7 +730,7 @@ async function createApp(options) {
|
|
|
729
730
|
await registerErrorHandler(fastify, config, trackPlugin);
|
|
730
731
|
await registerResources(fastify, config);
|
|
731
732
|
if (config.replyHelpers) {
|
|
732
|
-
const { replyHelpersPlugin } = await import("./replyHelpers-
|
|
733
|
+
const { replyHelpersPlugin } = await import("./replyHelpers-BLojtuvR.mjs").then((n) => n.n);
|
|
733
734
|
await fastify.register(replyHelpersPlugin);
|
|
734
735
|
}
|
|
735
736
|
if (config.serializeBigInt) fastify.addHook("preSerialization", async (_request, _reply, payload) => {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-Cxde4rpC.mjs";
|
|
2
2
|
import { _ as isElevated, n as PUBLIC_SCOPE, v as isMember } from "./types-AOD8fxIw.mjs";
|
|
3
|
-
import { t as BaseController } from "./BaseController-
|
|
4
|
-
import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-
|
|
3
|
+
import { t as BaseController } from "./BaseController-Vu2yc56T.mjs";
|
|
4
|
+
import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-CU6FlaDV.mjs";
|
|
5
5
|
import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { t as
|
|
9
|
-
import { i as getDefaultCrudSchemas } from "./utils-
|
|
10
|
-
import {
|
|
11
|
-
import { t as hasEvents } from "./typeGuards-
|
|
12
|
-
import { r as getAvailablePresets, t as applyPresets } from "./presets-
|
|
6
|
+
import { r as ForbiddenError } from "./errors-CqWnSqM-.mjs";
|
|
7
|
+
import { t as requestContext } from "./requestContext-DYtmNpm5.mjs";
|
|
8
|
+
import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-bqGpo9ML.mjs";
|
|
9
|
+
import { i as getDefaultCrudSchemas } from "./utils-B7FuRr9w.mjs";
|
|
10
|
+
import { n as convertRouteSchema, t as convertOpenApiSchemas } from "./schemaConverter-BxFDdtXu.mjs";
|
|
11
|
+
import { t as hasEvents } from "./typeGuards-Cj5Rgvlg.mjs";
|
|
12
|
+
import { r as getAvailablePresets, t as applyPresets } from "./presets-hM4WhNWY.mjs";
|
|
13
13
|
//#region src/pipeline/pipe.ts
|
|
14
14
|
/**
|
|
15
15
|
* Compose pipeline steps into an ordered array.
|
|
@@ -387,24 +387,26 @@ function buildPermissionMiddleware(permissionCheck, resourceName, action) {
|
|
|
387
387
|
};
|
|
388
388
|
}
|
|
389
389
|
/**
|
|
390
|
-
*
|
|
390
|
+
* Mount custom routes (from presets or user-defined `routes`) on Fastify.
|
|
391
|
+
* `wrapHandler` is derived inline from `!route.raw`.
|
|
391
392
|
*/
|
|
392
|
-
function
|
|
393
|
+
function createCustomRoutes(fastify, routes, controller, options) {
|
|
393
394
|
const { tag, resourceName, arcDecorator, rateLimitConfig, cacheMw, idempotencyMw, pipeline, routeGuards } = options;
|
|
394
395
|
for (const route of routes) {
|
|
395
396
|
const opName = route.operation ?? (typeof route.handler === "string" ? route.handler : `${route.method.toLowerCase()}${route.path.replace(/[/:]/g, "_")}`);
|
|
397
|
+
const wrapHandler = !route.raw;
|
|
396
398
|
let handler;
|
|
397
399
|
if (typeof route.handler === "string") {
|
|
398
400
|
if (!controller) throw new Error(`Route ${route.method} ${route.path}: string handler '${route.handler}' requires a controller. Either provide a controller or use a function handler instead.`);
|
|
399
401
|
const method = controller[route.handler];
|
|
400
402
|
if (typeof method !== "function") throw new Error(`Handler '${route.handler}' not found on controller`);
|
|
401
403
|
const boundMethod = method.bind(controller);
|
|
402
|
-
if (
|
|
404
|
+
if (wrapHandler) {
|
|
403
405
|
const steps = pipeline ? resolvePipelineSteps(pipeline, opName) : [];
|
|
404
406
|
if (steps.length > 0) handler = createPipelineHandler(boundMethod, steps, opName, resourceName);
|
|
405
407
|
else handler = createFastifyHandler(boundMethod);
|
|
406
408
|
} else handler = boundMethod;
|
|
407
|
-
} else if (
|
|
409
|
+
} else if (wrapHandler) {
|
|
408
410
|
const steps = pipeline ? resolvePipelineSteps(pipeline, opName) : [];
|
|
409
411
|
if (steps.length > 0) handler = createPipelineHandler(route.handler, steps, opName, resourceName);
|
|
410
412
|
else handler = createFastifyHandler(route.handler);
|
|
@@ -480,7 +482,7 @@ function createPipelineHandler(controllerMethod, steps, operation, resourceName)
|
|
|
480
482
|
* @param options - Router configuration
|
|
481
483
|
*/
|
|
482
484
|
function createCrudRouter(fastify, controller, options = {}) {
|
|
483
|
-
const { tag = "Resource", schemas = {}, permissions = {}, middlewares = {}, routeGuards = [],
|
|
485
|
+
const { tag = "Resource", schemas = {}, permissions = {}, middlewares = {}, routeGuards = [], routes: customRoutes = [], disableDefaultRoutes = false, disabledRoutes = [], resourceName = "unknown", schemaOptions, rateLimit, pipe: pipeline, fields: fieldPermissions, updateMethod = DEFAULT_UPDATE_METHOD } = options;
|
|
484
486
|
const rateLimitConfig = buildRateLimitConfig(rateLimit);
|
|
485
487
|
const cacheMw = !(fastify.hasDecorator("queryCache") && controller && typeof controller._cacheConfig !== "undefined" && controller._cacheConfig !== void 0) && fastify.hasDecorator("responseCache") ? fastify.responseCache.middleware : null;
|
|
486
488
|
const idempotencyMw = fastify.hasDecorator("idempotency") ? fastify.idempotency.middleware : null;
|
|
@@ -646,7 +648,7 @@ function createCrudRouter(fastify, controller, options = {}) {
|
|
|
646
648
|
});
|
|
647
649
|
}
|
|
648
650
|
}
|
|
649
|
-
if (
|
|
651
|
+
if (customRoutes.length > 0) createCustomRoutes(fastify, customRoutes, controller, {
|
|
650
652
|
tag,
|
|
651
653
|
resourceName,
|
|
652
654
|
arcDecorator,
|
|
@@ -941,6 +943,7 @@ function defineResource(config) {
|
|
|
941
943
|
idField: resolvedConfig.idField,
|
|
942
944
|
matchesFilter: config.adapter?.matchesFilter,
|
|
943
945
|
cache: resolvedConfig.cache,
|
|
946
|
+
onFieldWriteDenied: resolvedConfig.onFieldWriteDenied,
|
|
944
947
|
presetFields: resolvedConfig._controllerOptions ? {
|
|
945
948
|
slugField: resolvedConfig._controllerOptions.slugField,
|
|
946
949
|
parentField: resolvedConfig._controllerOptions.parentField
|
|
@@ -1088,16 +1091,6 @@ var ResourceDefinition = class {
|
|
|
1088
1091
|
schemaOptions;
|
|
1089
1092
|
customSchemas;
|
|
1090
1093
|
permissions;
|
|
1091
|
-
additionalRoutes;
|
|
1092
|
-
/**
|
|
1093
|
-
* Original v2.8 `routes` declaration — retained for downstream consumers
|
|
1094
|
-
* (OpenAPI, MCP, registry, CLI introspect). Preserves fields dropped during
|
|
1095
|
-
* normalization to `additionalRoutes` (notably `mcp`, `description`,
|
|
1096
|
-
* `annotations`). Undefined when the resource was defined with the legacy
|
|
1097
|
-
* `additionalRoutes` shape.
|
|
1098
|
-
*
|
|
1099
|
-
* Added in 2.8.1 — the source-of-truth fix for "canonical resource manifest".
|
|
1100
|
-
*/
|
|
1101
1094
|
routes;
|
|
1102
1095
|
middlewares;
|
|
1103
1096
|
routeGuards;
|
|
@@ -1130,8 +1123,7 @@ var ResourceDefinition = class {
|
|
|
1130
1123
|
this.schemaOptions = config.schemaOptions ?? {};
|
|
1131
1124
|
this.customSchemas = config.customSchemas ?? {};
|
|
1132
1125
|
this.permissions = config.permissions ?? {};
|
|
1133
|
-
this.routes = config.routes;
|
|
1134
|
-
this.additionalRoutes = config.routes ? convertRoutesToAdditionalRoutes(config.routes) : [];
|
|
1126
|
+
this.routes = config.routes ?? [];
|
|
1135
1127
|
this.middlewares = config.middlewares ?? {};
|
|
1136
1128
|
this.routeGuards = config.routeGuards;
|
|
1137
1129
|
this.disableDefaultRoutes = config.disableDefaultRoutes ?? false;
|
|
@@ -1150,7 +1142,6 @@ var ResourceDefinition = class {
|
|
|
1150
1142
|
this.queryParser = config.queryParser;
|
|
1151
1143
|
this._appliedPresets = config._appliedPresets ?? [];
|
|
1152
1144
|
this._pendingHooks = config._pendingHooks ?? [];
|
|
1153
|
-
if (config.onRegister) this._onRegister = config.onRegister;
|
|
1154
1145
|
}
|
|
1155
1146
|
/** Get repository from adapter (if available) */
|
|
1156
1147
|
get repository() {
|
|
@@ -1166,7 +1157,7 @@ var ResourceDefinition = class {
|
|
|
1166
1157
|
const ctrl = this.controller;
|
|
1167
1158
|
for (const method of enabledCrudRoutes) if (typeof ctrl[method] !== "function") errors.push(`CRUD method '${method}' not found on controller`);
|
|
1168
1159
|
}
|
|
1169
|
-
for (const route of this.
|
|
1160
|
+
for (const route of this.routes) if (typeof route.handler === "string") {
|
|
1170
1161
|
if (!this.controller) errors.push(`Route ${route.method} ${route.path}: string handler '${route.handler}' requires a controller`);
|
|
1171
1162
|
else if (typeof this.controller[route.handler] !== "function") errors.push(`Route ${route.method} ${route.path}: handler '${route.handler}' not found`);
|
|
1172
1163
|
}
|
|
@@ -1207,8 +1198,6 @@ var ResourceDefinition = class {
|
|
|
1207
1198
|
});
|
|
1208
1199
|
await fastify.register(async (instance) => {
|
|
1209
1200
|
const typedInstance = instance;
|
|
1210
|
-
const onRegister = self._onRegister;
|
|
1211
|
-
if (onRegister) await onRegister(instance);
|
|
1212
1201
|
let schemas = null;
|
|
1213
1202
|
const openApi = self._registryMeta?.openApiSchemas;
|
|
1214
1203
|
if (openApi && (!self.customSchemas || Object.keys(self.customSchemas).length === 0)) {
|
|
@@ -1281,14 +1270,13 @@ var ResourceDefinition = class {
|
|
|
1281
1270
|
schemas = schemas ?? {};
|
|
1282
1271
|
schemas.list = schemas.list ? deepMergeSchemas({ querystring: normalizedSchema }, schemas.list) : { querystring: normalizedSchema };
|
|
1283
1272
|
}
|
|
1284
|
-
const resolvedRoutes = self.additionalRoutes;
|
|
1285
1273
|
createCrudRouter(typedInstance, self.controller, {
|
|
1286
1274
|
tag: self.tag,
|
|
1287
1275
|
schemas: schemas ?? void 0,
|
|
1288
1276
|
permissions: self.permissions,
|
|
1289
1277
|
middlewares: self.middlewares,
|
|
1290
1278
|
routeGuards: self.routeGuards,
|
|
1291
|
-
|
|
1279
|
+
routes: self.routes,
|
|
1292
1280
|
disableDefaultRoutes: self.disableDefaultRoutes,
|
|
1293
1281
|
disabledRoutes: self.disabledRoutes,
|
|
1294
1282
|
resourceName: self.name,
|
|
@@ -1299,7 +1287,7 @@ var ResourceDefinition = class {
|
|
|
1299
1287
|
fields: self.fields
|
|
1300
1288
|
});
|
|
1301
1289
|
if (self.actions && Object.keys(self.actions).length > 0) {
|
|
1302
|
-
const { createActionRouter } = await import("./createActionRouter-
|
|
1290
|
+
const { createActionRouter } = await import("./createActionRouter-DH1YFL9m.mjs").then((n) => n.n);
|
|
1303
1291
|
createActionRouter(instance, normalizeActionsToRouterConfig(self.actions, self.actionPermissions, self.tag));
|
|
1304
1292
|
}
|
|
1305
1293
|
if (self.events && Object.keys(self.events).length > 0) typedInstance.log?.debug?.(`Resource '${self.name}' defined ${Object.keys(self.events).length} events`);
|
|
@@ -1366,29 +1354,6 @@ function capitalize(str) {
|
|
|
1366
1354
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1367
1355
|
}
|
|
1368
1356
|
/**
|
|
1369
|
-
* Convert v2.8 RouteDefinition[] to internal AdditionalRoute[] format.
|
|
1370
|
-
* The internal format is what createCrudRouter understands.
|
|
1371
|
-
*/
|
|
1372
|
-
function convertRoutesToAdditionalRoutes(routes) {
|
|
1373
|
-
return routes.map((route) => ({
|
|
1374
|
-
method: route.method,
|
|
1375
|
-
path: route.path,
|
|
1376
|
-
handler: route.handler,
|
|
1377
|
-
permissions: route.permissions,
|
|
1378
|
-
wrapHandler: !route.raw,
|
|
1379
|
-
operation: route.operation,
|
|
1380
|
-
summary: route.summary,
|
|
1381
|
-
description: route.description,
|
|
1382
|
-
tags: route.tags,
|
|
1383
|
-
preHandler: route.preHandler,
|
|
1384
|
-
preAuth: route.preAuth,
|
|
1385
|
-
streamResponse: route.streamResponse,
|
|
1386
|
-
schema: route.schema,
|
|
1387
|
-
mcpHandler: route.mcpHandler,
|
|
1388
|
-
mcp: route.mcp
|
|
1389
|
-
}));
|
|
1390
|
-
}
|
|
1391
|
-
/**
|
|
1392
1357
|
* Normalize ActionsMap into the ActionRouterConfig shape that createActionRouter expects.
|
|
1393
1358
|
*/
|
|
1394
1359
|
function normalizeActionsToRouterConfig(actions, globalAuth, tag) {
|
package/dist/docs/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as ExternalOpenApiPaths } from "../externalPaths-
|
|
1
|
+
import { rt as RegistryEntry } from "../interface-YrWsmKqE.mjs";
|
|
2
|
+
import { t as ExternalOpenApiPaths } from "../externalPaths-Bapitwvd.mjs";
|
|
3
3
|
import { FastifyPluginAsync } from "fastify";
|
|
4
4
|
|
|
5
5
|
//#region src/docs/openapi.d.ts
|
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as getUserRoles } from "../types-ZUu_h0jp.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-CXuTG1M9.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/docs/scalar.ts
|
|
5
5
|
const scalarPlugin = async (fastify, opts = {}) => {
|
package/dist/dynamic/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Kt as ResourceDefinition, r as DataAdapter } from "../interface-YrWsmKqE.mjs";
|
|
2
2
|
import { t as PermissionCheck } from "../types-DZi1aYhm.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/dynamic/ArcDynamicLoader.d.ts
|
package/dist/dynamic/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as ArcQueryParser } from "../queryParser-
|
|
2
|
-
import { n as defineResource } from "../defineResource-
|
|
3
|
-
import { C as publicRead, T as readOnly, b as fullPublic, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "../permissions-
|
|
1
|
+
import { t as ArcQueryParser } from "../queryParser-Cs-6SHQK.mjs";
|
|
2
|
+
import { n as defineResource } from "../defineResource-C__jkwvs.mjs";
|
|
3
|
+
import { C as publicRead, T as readOnly, b as fullPublic, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "../permissions-oNZawnkR.mjs";
|
|
4
4
|
//#region src/dynamic/ArcDynamicLoader.ts
|
|
5
5
|
const VALID_FIELD_TYPES = new Set([
|
|
6
6
|
"string",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
2
|
import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
|
|
3
|
-
import { t as arcLog } from "./logger-
|
|
3
|
+
import { t as arcLog } from "./logger-CDjpjySd.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/scope/elevation.ts
|
|
6
6
|
var elevation_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -57,13 +57,27 @@ const elevationPlugin = async (fastify, opts = {}) => {
|
|
|
57
57
|
userId,
|
|
58
58
|
organizationId: orgId
|
|
59
59
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
const event = {
|
|
61
|
+
userId,
|
|
62
|
+
organizationId: orgId || void 0,
|
|
63
|
+
request,
|
|
64
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
65
|
+
};
|
|
66
|
+
const publish = fastify.events?.publish;
|
|
67
|
+
if (publish) try {
|
|
68
|
+
await publish("arc.scope.elevated", {
|
|
69
|
+
userId: event.userId,
|
|
70
|
+
organizationId: event.organizationId,
|
|
71
|
+
route: request.routeOptions?.url ?? request.url,
|
|
72
|
+
method: request.method,
|
|
73
|
+
requestId: request.id,
|
|
74
|
+
timestamp: event.timestamp.toISOString()
|
|
66
75
|
});
|
|
76
|
+
} catch (err) {
|
|
77
|
+
log.warn("Failed to publish arc.scope.elevated event", { error: err instanceof Error ? err.message : String(err) });
|
|
78
|
+
}
|
|
79
|
+
if (onElevation) try {
|
|
80
|
+
await onElevation(event);
|
|
67
81
|
} catch {
|
|
68
82
|
log.warn("onElevation callback threw — continuing request");
|
|
69
83
|
}
|
|
@@ -1,11 +1,61 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { p as isArcError } from "./errors-
|
|
2
|
+
import { p as isArcError } from "./errors-CqWnSqM-.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/plugins/errorHandler.ts
|
|
5
|
-
var errorHandler_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
var errorHandler_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
defaultIsDuplicateKeyError: () => defaultIsDuplicateKeyError,
|
|
7
|
+
errorHandlerPlugin: () => errorHandlerPlugin
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Default duplicate-key detector covering the mainstream drivers arc sees
|
|
11
|
+
* most. Detection is strictly by known driver codes — never by message
|
|
12
|
+
* string matching — because false positives on dup-key silently mask real
|
|
13
|
+
* errors (WriteConflict, NotWritablePrimary, etc.) as 409s. For long-tail
|
|
14
|
+
* drivers (Neo4j, MSSQL, DynamoDB, custom kits), compose rather than
|
|
15
|
+
* replace:
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { defaultIsDuplicateKeyError } from '@classytic/arc/plugins';
|
|
19
|
+
*
|
|
20
|
+
* errorHandler: {
|
|
21
|
+
* isDuplicateKeyError: (err) =>
|
|
22
|
+
* defaultIsDuplicateKeyError(err) || isNeo4jDupKey(err),
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Drizzle apps get coverage transitively (Drizzle doesn't wrap driver
|
|
27
|
+
* errors — pg/mysql2/better-sqlite3 codes propagate as-is). Neon is
|
|
28
|
+
* Postgres-wire-compatible → `23505` covers `@neondatabase/serverless`.
|
|
29
|
+
*/
|
|
30
|
+
function defaultIsDuplicateKeyError(err) {
|
|
31
|
+
if (!err || typeof err !== "object") return false;
|
|
32
|
+
const e = err;
|
|
33
|
+
if (e.code === 11e3 || e.codeName === "DuplicateKey") return true;
|
|
34
|
+
if (e.code === "P2002") return true;
|
|
35
|
+
if (e.code === "23505") return true;
|
|
36
|
+
if (e.code === "ER_DUP_ENTRY" || e.errno === 1062) return true;
|
|
37
|
+
if (e.code === "SQLITE_CONSTRAINT_UNIQUE" || e.code === "SQLITE_CONSTRAINT_PRIMARYKEY") return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Extract the duplicate-field names for the `details.duplicateFields`
|
|
42
|
+
* response. Only called when the caller has opted into detail exposure
|
|
43
|
+
* (`includeStack: true`) — shape differs per driver.
|
|
44
|
+
*/
|
|
45
|
+
function extractDuplicateFields(err) {
|
|
46
|
+
if (!err || typeof err !== "object") return null;
|
|
47
|
+
const e = err;
|
|
48
|
+
if (e.keyValue && typeof e.keyValue === "object") return Object.keys(e.keyValue);
|
|
49
|
+
if (e.meta?.target) {
|
|
50
|
+
if (Array.isArray(e.meta.target)) return e.meta.target.map(String);
|
|
51
|
+
if (typeof e.meta.target === "string") return [e.meta.target];
|
|
52
|
+
}
|
|
53
|
+
if (typeof e.constraint === "string") return [e.constraint];
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
6
56
|
async function errorHandlerPluginFn(fastify, options = {}) {
|
|
7
57
|
const isProduction = process.env.NODE_ENV === "production";
|
|
8
|
-
const { includeStack = !isProduction, onError, errorMap = {}, errorMappers = [] } = options;
|
|
58
|
+
const { includeStack = !isProduction, onError, errorMap = {}, errorMappers = [], isDuplicateKeyError = defaultIsDuplicateKeyError } = options;
|
|
9
59
|
fastify.setErrorHandler(async (error, request, reply) => {
|
|
10
60
|
if (onError) try {
|
|
11
61
|
await onError(error, request);
|
|
@@ -75,12 +125,14 @@ async function errorHandlerPluginFn(fastify, options = {}) {
|
|
|
75
125
|
statusCode = 400;
|
|
76
126
|
response.code = "INVALID_ID";
|
|
77
127
|
response.error = "Invalid identifier format";
|
|
78
|
-
} else if (error
|
|
128
|
+
} else if (isDuplicateKeyError(error)) {
|
|
79
129
|
statusCode = 409;
|
|
80
130
|
response.code = "DUPLICATE_KEY";
|
|
81
131
|
response.error = "Resource already exists";
|
|
82
|
-
|
|
83
|
-
|
|
132
|
+
if (includeStack) {
|
|
133
|
+
const duplicateFields = extractDuplicateFields(error);
|
|
134
|
+
if (duplicateFields && duplicateFields.length > 0) response.details = { duplicateFields };
|
|
135
|
+
}
|
|
84
136
|
}
|
|
85
137
|
if (includeStack && error.stack) response.stack = error.stack;
|
|
86
138
|
if (statusCode >= 500) request.log.error({
|
|
@@ -118,4 +170,4 @@ const errorHandlerPlugin = fp(errorHandlerPluginFn, {
|
|
|
118
170
|
fastify: "5.x"
|
|
119
171
|
});
|
|
120
172
|
//#endregion
|
|
121
|
-
export {
|
|
173
|
+
export { errorHandlerPlugin as n, errorHandler_exports as r, defaultIsDuplicateKeyError as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as DomainEvent } from "./EventTransport-CqZ8FyM_.mjs";
|
|
2
2
|
import { FastifyInstance, FastifyPluginAsync, FastifyRequest } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/plugins/caching.d.ts
|
|
@@ -176,8 +176,43 @@ interface ErrorHandlerOptions {
|
|
|
176
176
|
* ```
|
|
177
177
|
*/
|
|
178
178
|
errorMappers?: ErrorMapper[];
|
|
179
|
+
/**
|
|
180
|
+
* Classify an error as a duplicate-key / unique-constraint violation →
|
|
181
|
+
* mapped to `409 Conflict` with `code: "DUPLICATE_KEY"`.
|
|
182
|
+
*
|
|
183
|
+
* Mirrors `RepositoryLike.isDuplicateKeyError` for the Fastify layer: errors
|
|
184
|
+
* that escape a controller (custom routes, user hooks, raw driver calls)
|
|
185
|
+
* still land here, so the classifier is duplicated at the edge. Defaults
|
|
186
|
+
* cover MongoDB (`code 11000` / `codeName "DuplicateKey"`), Prisma
|
|
187
|
+
* (`code "P2002"`), and Postgres (`code "23505"`). Override to add other
|
|
188
|
+
* backends (DynamoDB `ConditionalCheckFailedException`, etc.) or to disable
|
|
189
|
+
* the built-in detection.
|
|
190
|
+
*/
|
|
191
|
+
isDuplicateKeyError?: (err: unknown) => boolean;
|
|
179
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Default duplicate-key detector covering the mainstream drivers arc sees
|
|
195
|
+
* most. Detection is strictly by known driver codes — never by message
|
|
196
|
+
* string matching — because false positives on dup-key silently mask real
|
|
197
|
+
* errors (WriteConflict, NotWritablePrimary, etc.) as 409s. For long-tail
|
|
198
|
+
* drivers (Neo4j, MSSQL, DynamoDB, custom kits), compose rather than
|
|
199
|
+
* replace:
|
|
200
|
+
*
|
|
201
|
+
* ```ts
|
|
202
|
+
* import { defaultIsDuplicateKeyError } from '@classytic/arc/plugins';
|
|
203
|
+
*
|
|
204
|
+
* errorHandler: {
|
|
205
|
+
* isDuplicateKeyError: (err) =>
|
|
206
|
+
* defaultIsDuplicateKeyError(err) || isNeo4jDupKey(err),
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* Drizzle apps get coverage transitively (Drizzle doesn't wrap driver
|
|
211
|
+
* errors — pg/mysql2/better-sqlite3 codes propagate as-is). Neon is
|
|
212
|
+
* Postgres-wire-compatible → `23505` covers `@neondatabase/serverless`.
|
|
213
|
+
*/
|
|
214
|
+
declare function defaultIsDuplicateKeyError(err: unknown): boolean;
|
|
180
215
|
declare function errorHandlerPluginFn(fastify: FastifyInstance, options?: ErrorHandlerOptions): Promise<void>;
|
|
181
216
|
declare const errorHandlerPlugin: typeof errorHandlerPluginFn;
|
|
182
217
|
//#endregion
|
|
183
|
-
export {
|
|
218
|
+
export { CachingRule as _, VersioningOptions as a, MetricEntry as c, _default$1 as d, metricsPlugin as f, CachingOptions as g, ssePlugin as h, errorHandlerPlugin as i, MetricsCollector as l, _default$2 as m, ErrorMapper as n, _default as o, SSEOptions as p, defaultIsDuplicateKeyError as r, versioningPlugin as s, ErrorHandlerOptions as t, MetricsOptions as u, _default$3 as v, cachingPlugin as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as
|
|
1
|
+
import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CqZ8FyM_.mjs";
|
|
2
2
|
import { FastifyPluginAsync } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/events/defineEvent.d.ts
|
|
@@ -123,13 +123,25 @@ interface RetryOptions {
|
|
|
123
123
|
* @default 0.1
|
|
124
124
|
*/
|
|
125
125
|
jitter?: number;
|
|
126
|
+
/**
|
|
127
|
+
* Transport to route dead-lettered events to. When set and the transport
|
|
128
|
+
* implements {@link EventTransport.deadLetter}, exhausted events are
|
|
129
|
+
* auto-wrapped in a {@link DeadLetteredEvent} envelope and routed to the
|
|
130
|
+
* transport's native DLQ (Kafka DLQ topic, SQS DLQ, etc.). No custom
|
|
131
|
+
* plumbing needed for Kafka/SQS/Streams users.
|
|
132
|
+
*
|
|
133
|
+
* Works alongside {@link onDead} — both fire if both are set.
|
|
134
|
+
*/
|
|
135
|
+
transport?: Pick<EventTransport, "deadLetter">;
|
|
126
136
|
/**
|
|
127
137
|
* Callback when all retries are exhausted. The event is "dead".
|
|
128
138
|
* Use this to publish to a `$deadLetter` channel, log, alert, etc.
|
|
139
|
+
*
|
|
140
|
+
* Fires in addition to {@link transport} routing if both are set.
|
|
129
141
|
*/
|
|
130
142
|
onDead?: (event: DomainEvent, errors: Error[]) => void | Promise<void>;
|
|
131
143
|
/**
|
|
132
|
-
* Optional name for logging
|
|
144
|
+
* Optional name for logging + written into `DeadLetteredEvent.handlerName`.
|
|
133
145
|
*/
|
|
134
146
|
name?: string;
|
|
135
147
|
/**
|