@classytic/arc 2.9.1 → 2.10.8
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 +20 -91
- package/dist/{BaseController-Vu2yc56T.mjs → BaseController-DVNKvoX4.mjs} +154 -170
- package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-CcN2LVrc.mjs} +1 -1
- package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.mjs +2 -2
- package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
- package/dist/audit/index.d.mts +38 -3
- package/dist/audit/index.mjs +54 -22
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.mjs +3 -3
- package/dist/cache/index.d.mts +17 -15
- package/dist/cache/index.mjs +16 -15
- package/dist/{caching-CjybdRwx.mjs → caching-3h93rkJM.mjs} +8 -3
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/context/index.d.mts +58 -0
- package/dist/context/index.mjs +2 -0
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +3 -4
- package/dist/{defineResource-C__jkwvs.mjs → core-3MWJosCH.mjs} +174 -94
- package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-C8UUB3Px.mjs} +1 -1
- package/dist/{createApp-CBJUJKGP.mjs → createApp-BwnEAO2h.mjs} +53 -19
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DxQ6ACbt.mjs → elevation-Dci0AYLT.mjs} +2 -2
- package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
- package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
- package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
- package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
- package/dist/events/index.d.mts +8 -5
- package/dist/events/index.mjs +87 -52
- 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 +1 -1
- package/dist/{types-DZi1aYhm.d.mts → fields-C8Y0XLAu.d.mts} +122 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +5 -2
- package/dist/idempotency/index.mjs +46 -37
- package/dist/{interface-YrWsmKqE.d.mts → index-BGbpGVyM.d.mts} +2107 -2756
- package/dist/{index-CtGKT0lf.d.mts → index-BziRPS4H.d.mts} +81 -7
- package/dist/{index-C-xjcA6F.d.mts → index-C_Noptz-.d.mts} +284 -409
- package/dist/{index-Cibkchnx.d.mts → index-EqQN6p0W.d.mts} +3 -3
- package/dist/index.d.mts +6 -219
- package/dist/index.mjs +10 -131
- 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 +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/interface-yhyb_pLY.d.mts +77 -0
- package/dist/logger/index.d.mts +81 -0
- package/dist/{logger-CDjpjySd.mjs → logger/index.mjs} +1 -6
- package/dist/{memory-BFAYkf8H.mjs → memory-DqI-449b.mjs} +23 -8
- package/dist/middleware/index.d.mts +109 -0
- package/dist/middleware/index.mjs +70 -0
- package/dist/multipartBody-CUQGVlM_.mjs +123 -0
- package/dist/{openapi-CXuTG1M9.mjs → openapi-DpNpqBmo.mjs} +9 -7
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -4
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-oNZawnkR.mjs → permissions-wkqRwicB.mjs} +315 -397
- package/dist/pipe-CGJxqDGx.mjs +62 -0
- package/dist/pipeline/index.d.mts +62 -0
- package/dist/pipeline/index.mjs +53 -0
- package/dist/plugins/index.d.mts +23 -3
- package/dist/plugins/index.mjs +9 -11
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +3 -3
- package/dist/presets/filesUpload.mjs +255 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +2 -2
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +43 -9
- package/dist/presets/search.d.mts +91 -4
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-hM4WhNWY.mjs → presets-CrwOvuXI.mjs} +1 -1
- package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-ChLNZvFT.mjs} +9 -9
- package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
- package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-NR__Qiju.mjs} +69 -2
- package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/{requestContext-DYtmNpm5.mjs → requestContext-C38GskNt.mjs} +1 -1
- package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-CJpt7LGI.mjs → sse-D8UeDwis.mjs} +1 -1
- package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
- package/dist/testing/index.d.mts +6 -5
- package/dist/testing/index.mjs +17 -10
- package/dist/types/index.d.mts +5 -5
- package/dist/types/index.mjs +1 -31
- package/dist/types-CDnTEpga.mjs +27 -0
- package/dist/{types-CoSzA-s-.d.mts → types-CVKBssX5.d.mts} +1 -1
- package/dist/{types-CunEX4UX.d.mts → types-CVdgPXBW.d.mts} +20 -7
- package/dist/utils/index.d.mts +277 -3
- package/dist/utils/index.mjs +4 -5
- package/dist/{utils-B7FuRr9w.mjs → utils-LMwVidKy.mjs} +303 -2
- package/dist/{versioning-Cm8qoFDg.mjs → versioning-B6mimogM.mjs} +3 -5
- package/dist/versioning-CeUXHfjw.d.mts +117 -0
- package/package.json +31 -18
- package/skills/arc/SKILL.md +8 -12
- package/skills/arc/references/production.md +0 -41
- package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
- package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
- package/dist/core-DNncu0xF.mjs +0 -34
- package/dist/dynamic/index.d.mts +0 -93
- package/dist/dynamic/index.mjs +0 -122
- package/dist/errorHandler-DixGcttC.d.mts +0 -218
- package/dist/fields-BC7zcmI9.d.mts +0 -121
- package/dist/filesUpload-q8oHt--L.mjs +0 -377
- package/dist/interface-DplgQO2e.d.mts +0 -54
- package/dist/policies/index.d.mts +0 -425
- package/dist/policies/index.mjs +0 -318
- package/dist/rpc/index.d.mts +0 -90
- package/dist/rpc/index.mjs +0 -248
- /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
- /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
- /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
- /package/dist/{elevation-B6S5csVA.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
- /package/dist/{errors-CqWnSqM-.mjs → errors-BqdUDja_.mjs} +0 -0
- /package/dist/{fields-CU6FlaDV.mjs → fields-CTMWOUDt.mjs} +0 -0
- /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
- /package/dist/{types-ZUu_h0jp.mjs → types-D57iXYb8.mjs} +0 -0
- /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
|
@@ -116,10 +116,7 @@ const developmentPreset = {
|
|
|
116
116
|
"x-request-id"
|
|
117
117
|
]
|
|
118
118
|
},
|
|
119
|
-
rateLimit:
|
|
120
|
-
max: 1e3,
|
|
121
|
-
timeWindow: "1 minute"
|
|
122
|
-
},
|
|
119
|
+
rateLimit: false,
|
|
123
120
|
underPressure: {
|
|
124
121
|
exposeStatusRoute: true,
|
|
125
122
|
maxEventLoopDelay: 5e3
|
|
@@ -207,7 +204,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
|
|
|
207
204
|
await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
|
|
208
205
|
trackPlugin("arc-core");
|
|
209
206
|
if (config.arcPlugins?.events !== false) {
|
|
210
|
-
const { default: eventPlugin } = await import("./eventPlugin-
|
|
207
|
+
const { default: eventPlugin } = await import("./eventPlugin-ByU4Cv0e.mjs").then((n) => n.n);
|
|
211
208
|
const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
|
|
212
209
|
await fastify.register(eventPlugin, {
|
|
213
210
|
...eventOpts,
|
|
@@ -243,15 +240,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
243
240
|
trackPlugin("arc-graceful-shutdown");
|
|
244
241
|
}
|
|
245
242
|
if (config.arcPlugins?.caching) {
|
|
246
|
-
const { default: cachingPlugin } = await import("./caching-
|
|
243
|
+
const { default: cachingPlugin } = await import("./caching-3h93rkJM.mjs").then((n) => n.r);
|
|
247
244
|
const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
|
|
248
245
|
await fastify.register(cachingPlugin, opts);
|
|
249
246
|
trackPlugin("arc-caching", opts);
|
|
250
247
|
}
|
|
251
248
|
if (config.arcPlugins?.queryCache) {
|
|
252
|
-
const { queryCachePlugin } = await import("./queryCachePlugin-
|
|
249
|
+
const { queryCachePlugin } = await import("./queryCachePlugin-ChLNZvFT.mjs").then((n) => n.n);
|
|
253
250
|
const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
|
|
254
|
-
const store = config.stores?.queryCache ?? new (await (import("./memory-
|
|
251
|
+
const store = config.stores?.queryCache ?? new (await (import("./memory-DqI-449b.mjs").then((n) => n.n))).MemoryCacheStore();
|
|
255
252
|
await fastify.register(queryCachePlugin, {
|
|
256
253
|
store,
|
|
257
254
|
...opts
|
|
@@ -260,7 +257,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
260
257
|
}
|
|
261
258
|
if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
|
|
262
259
|
else {
|
|
263
|
-
const { default: ssePlugin } = await import("./sse-
|
|
260
|
+
const { default: ssePlugin } = await import("./sse-D8UeDwis.mjs").then((n) => n.r);
|
|
264
261
|
const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
|
|
265
262
|
await fastify.register(ssePlugin, opts);
|
|
266
263
|
trackPlugin("arc-sse", opts);
|
|
@@ -272,7 +269,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
|
|
|
272
269
|
trackPlugin("arc-metrics", opts);
|
|
273
270
|
}
|
|
274
271
|
if (config.arcPlugins?.versioning) {
|
|
275
|
-
const { default: versioningPlugin } = await import("./versioning-
|
|
272
|
+
const { default: versioningPlugin } = await import("./versioning-B6mimogM.mjs").then((n) => n.r);
|
|
276
273
|
await fastify.register(versioningPlugin, config.arcPlugins.versioning);
|
|
277
274
|
trackPlugin("arc-versioning", config.arcPlugins.versioning);
|
|
278
275
|
}
|
|
@@ -303,7 +300,8 @@ async function registerAuth(fastify, config, trackPlugin) {
|
|
|
303
300
|
const { plugin, openapi } = authConfig.betterAuth;
|
|
304
301
|
await fastify.register(plugin);
|
|
305
302
|
trackPlugin("auth-better-auth");
|
|
306
|
-
|
|
303
|
+
const arc = fastify.arc;
|
|
304
|
+
if (arc && openapi && !arc.externalOpenApiPaths.includes(openapi)) arc.externalOpenApiPaths.push(openapi);
|
|
307
305
|
fastify.log.debug("Better Auth authentication enabled");
|
|
308
306
|
break;
|
|
309
307
|
}
|
|
@@ -340,7 +338,7 @@ async function registerAuth(fastify, config, trackPlugin) {
|
|
|
340
338
|
*/
|
|
341
339
|
async function registerElevation(fastify, config, trackPlugin) {
|
|
342
340
|
if (!config.elevation) return;
|
|
343
|
-
const { elevationPlugin } = await import("./elevation-
|
|
341
|
+
const { elevationPlugin } = await import("./elevation-Dci0AYLT.mjs").then((n) => n.r);
|
|
344
342
|
await fastify.register(elevationPlugin, config.elevation);
|
|
345
343
|
trackPlugin("arc-elevation", config.elevation);
|
|
346
344
|
fastify.log.debug("Elevation plugin enabled");
|
|
@@ -350,7 +348,7 @@ async function registerElevation(fastify, config, trackPlugin) {
|
|
|
350
348
|
*/
|
|
351
349
|
async function registerErrorHandler(fastify, config, trackPlugin) {
|
|
352
350
|
if (config.errorHandler === false) return;
|
|
353
|
-
const { errorHandlerPlugin } = await import("./errorHandler-
|
|
351
|
+
const { errorHandlerPlugin } = await import("./errorHandler-CSxe7KIM.mjs").then((n) => n.r);
|
|
354
352
|
const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
|
|
355
353
|
await fastify.register(errorHandlerPlugin, errorOpts);
|
|
356
354
|
trackPlugin("arc-error-handler", errorOpts);
|
|
@@ -463,6 +461,40 @@ async function registerResources(fastify, config) {
|
|
|
463
461
|
}
|
|
464
462
|
//#endregion
|
|
465
463
|
//#region src/factory/registerSecurity.ts
|
|
464
|
+
/**
|
|
465
|
+
* Translate `skipPaths` sugar into a `@fastify/rate-limit` `allowList`
|
|
466
|
+
* function. A user-supplied `allowList` (array of IPs or function) is
|
|
467
|
+
* preserved and OR-ed with the path match.
|
|
468
|
+
*/
|
|
469
|
+
function buildRateLimitOpts(input) {
|
|
470
|
+
const { skipPaths, allowList, ...rest } = input;
|
|
471
|
+
if (!skipPaths || skipPaths.length === 0) return allowList === void 0 ? rest : {
|
|
472
|
+
...rest,
|
|
473
|
+
allowList
|
|
474
|
+
};
|
|
475
|
+
const matchesPath = compilePathMatcher(skipPaths);
|
|
476
|
+
const combined = async (req, key) => {
|
|
477
|
+
if (matchesPath((req.url ?? "").split("?", 1)[0] ?? "")) return true;
|
|
478
|
+
if (typeof allowList === "function") return await allowList(req, key);
|
|
479
|
+
if (Array.isArray(allowList)) return allowList.includes(key);
|
|
480
|
+
return false;
|
|
481
|
+
};
|
|
482
|
+
return {
|
|
483
|
+
...rest,
|
|
484
|
+
allowList: combined
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
function compilePathMatcher(patterns) {
|
|
488
|
+
const prefixes = [];
|
|
489
|
+
const exact = /* @__PURE__ */ new Set();
|
|
490
|
+
for (const p of patterns) if (p.endsWith("*")) prefixes.push(p.slice(0, -1));
|
|
491
|
+
else exact.add(p);
|
|
492
|
+
return (path) => {
|
|
493
|
+
if (exact.has(path)) return true;
|
|
494
|
+
for (const pre of prefixes) if (path.startsWith(pre)) return true;
|
|
495
|
+
return false;
|
|
496
|
+
};
|
|
497
|
+
}
|
|
466
498
|
const PLUGIN_REGISTRY = {
|
|
467
499
|
cors: {
|
|
468
500
|
package: "@fastify/cors",
|
|
@@ -532,10 +564,10 @@ async function registerSecurityPlugins(fastify, config) {
|
|
|
532
564
|
} else fastify.log.warn("CORS disabled");
|
|
533
565
|
if (config.rateLimit !== false) {
|
|
534
566
|
const rateLimit = await loadPlugin("rateLimit");
|
|
535
|
-
const rateLimitOpts = config.rateLimit ?? {
|
|
567
|
+
const rateLimitOpts = buildRateLimitOpts(config.rateLimit ?? {
|
|
536
568
|
max: 100,
|
|
537
569
|
timeWindow: "1 minute"
|
|
538
|
-
};
|
|
570
|
+
});
|
|
539
571
|
await fastify.register(rateLimit, rateLimitOpts);
|
|
540
572
|
if (!(typeof rateLimitOpts === "object" && "store" in rateLimitOpts)) {
|
|
541
573
|
if (config.runtime === "distributed") throw new Error("[Arc] runtime: 'distributed' with rate limiting requires a shared store.\nProvide rateLimit: { store: new RedisStore({ ... }) } or disable rate limiting: rateLimit: false");
|
|
@@ -643,14 +675,14 @@ function validateDistributedRuntime(options) {
|
|
|
643
675
|
if (!events || MEMORY_STORE_NAMES.has(events.name)) missing.push("events transport");
|
|
644
676
|
if (options.arcPlugins?.caching) {
|
|
645
677
|
const cache = options.stores?.cache;
|
|
646
|
-
if (!cache || MEMORY_STORE_NAMES.has(cache.name)) missing.push("cache store");
|
|
678
|
+
if (!cache || cache.name !== void 0 && MEMORY_STORE_NAMES.has(cache.name)) missing.push("cache store");
|
|
647
679
|
}
|
|
648
680
|
const idempotency = options.stores?.idempotency;
|
|
649
681
|
if (idempotency && MEMORY_STORE_NAMES.has(idempotency.name)) missing.push("idempotency store (memory-backed in distributed mode)");
|
|
650
682
|
else if (!idempotency) deferredWarnings.push("runtime: 'distributed' — no idempotency store configured. Write-path deduplication will be instance-local. If resources use the idempotency plugin, provide stores.idempotency with a Redis/MongoDB store.");
|
|
651
683
|
if (options.arcPlugins?.queryCache) {
|
|
652
684
|
const qc = options.stores?.queryCache;
|
|
653
|
-
if (!qc || MEMORY_STORE_NAMES.has(qc.name)) missing.push("queryCache store");
|
|
685
|
+
if (!qc || qc.name !== void 0 && MEMORY_STORE_NAMES.has(qc.name)) missing.push("queryCache store");
|
|
654
686
|
}
|
|
655
687
|
if (missing.length > 0) throw new Error(`[Arc] runtime: 'distributed' requires Redis/durable adapters.\nMissing: ${missing.join(", ")}.\nProvide Redis-backed stores or use runtime: 'memory' for development.`);
|
|
656
688
|
return deferredWarnings;
|
|
@@ -676,7 +708,7 @@ function validateDistributedRuntime(options) {
|
|
|
676
708
|
*/
|
|
677
709
|
async function createApp(options) {
|
|
678
710
|
if (options.debug !== void 0 && options.debug !== false) {
|
|
679
|
-
const { configureArcLogger } = await import("./logger
|
|
711
|
+
const { configureArcLogger } = await import("./logger/index.mjs");
|
|
680
712
|
configureArcLogger({ debug: options.debug });
|
|
681
713
|
}
|
|
682
714
|
validateAuthOptions(options);
|
|
@@ -717,7 +749,9 @@ async function createApp(options) {
|
|
|
717
749
|
await registerSecurityPlugins(fastify, config);
|
|
718
750
|
await registerUtilityPlugins(fastify, config);
|
|
719
751
|
const trackPlugin = (name, opts) => {
|
|
720
|
-
fastify.arc
|
|
752
|
+
const arc = fastify.arc;
|
|
753
|
+
if (!arc) return;
|
|
754
|
+
arc.plugins.set(name, {
|
|
721
755
|
name,
|
|
722
756
|
options: opts,
|
|
723
757
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
package/dist/docs/index.d.mts
CHANGED
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as getUserRoles } from "../types-
|
|
2
|
-
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-
|
|
1
|
+
import { t as getUserRoles } from "../types-D57iXYb8.mjs";
|
|
2
|
+
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-DpNpqBmo.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/docs/scalar.ts
|
|
5
5
|
const scalarPlugin = async (fastify, opts = {}) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
2
|
+
import { arcLog } from "./logger/index.mjs";
|
|
3
|
+
import { t as getUserRoles } from "./types-D57iXYb8.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/scope/elevation.ts
|
|
6
6
|
var elevation_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { FastifyInstance, FastifyRequest } from "fastify";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/errorHandler.d.ts
|
|
4
|
+
/** Class-based error mapper — maps thrown error instances to HTTP responses */
|
|
5
|
+
interface ErrorMapper<T extends Error = Error> {
|
|
6
|
+
/**
|
|
7
|
+
* Error class to match. Checked at runtime via `instanceof` — the constructor
|
|
8
|
+
* arity/signature is not called by the plugin, so the signature is typed
|
|
9
|
+
* permissively to accept real-world error classes:
|
|
10
|
+
*
|
|
11
|
+
* - **Abstract classes** (e.g. base domain errors) — `abstract new` is accepted.
|
|
12
|
+
* - **Specific constructor signatures** (e.g. `new InvalidTransitionError(from, to, id?)`)
|
|
13
|
+
* — `any[]` avoids forcing consumers to widen to `unknown[]` or cast.
|
|
14
|
+
*
|
|
15
|
+
* What matters for dispatch is the `instanceof` check, not the ctor shape.
|
|
16
|
+
*/
|
|
17
|
+
type: abstract new (...args: any[]) => T;
|
|
18
|
+
/** Convert the error to an HTTP response shape */
|
|
19
|
+
toResponse: (error: T) => {
|
|
20
|
+
status: number;
|
|
21
|
+
code?: string;
|
|
22
|
+
message?: string;
|
|
23
|
+
details?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
interface ErrorHandlerOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Include stack trace in error responses (default: false in production)
|
|
29
|
+
*/
|
|
30
|
+
includeStack?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Custom error callback for logging to external services
|
|
33
|
+
*/
|
|
34
|
+
onError?: (error: Error, request: FastifyRequest) => void | Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Map specific error types to custom responses (by error.name string)
|
|
37
|
+
*/
|
|
38
|
+
errorMap?: Record<string, {
|
|
39
|
+
statusCode: number;
|
|
40
|
+
code: string;
|
|
41
|
+
message?: string;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Class-based error mappers — checked via `instanceof`, highest priority.
|
|
45
|
+
*
|
|
46
|
+
* Register your domain error classes once; Arc auto-catches and maps them
|
|
47
|
+
* in every handler. Handlers just `throw` — no try/catch needed.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* class AccountingError extends Error {
|
|
52
|
+
* constructor(message: string, public status: number, public code: string) {
|
|
53
|
+
* super(message);
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
*
|
|
57
|
+
* const app = await createApp({
|
|
58
|
+
* errorHandler: {
|
|
59
|
+
* errorMappers: [
|
|
60
|
+
* {
|
|
61
|
+
* type: AccountingError,
|
|
62
|
+
* toResponse: (err) => ({ status: err.status, code: err.code, message: err.message }),
|
|
63
|
+
* },
|
|
64
|
+
* ],
|
|
65
|
+
* },
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // Now handlers just throw:
|
|
69
|
+
* handler: async (req) => {
|
|
70
|
+
* await ledger.post(id); // throws AccountingError → Arc maps to proper HTTP response
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
errorMappers?: ErrorMapper[];
|
|
75
|
+
/**
|
|
76
|
+
* Classify an error as a duplicate-key / unique-constraint violation →
|
|
77
|
+
* mapped to `409 Conflict` with `code: "DUPLICATE_KEY"`.
|
|
78
|
+
*
|
|
79
|
+
* Mirrors `RepositoryLike.isDuplicateKeyError` for the Fastify layer: errors
|
|
80
|
+
* that escape a controller (custom routes, user hooks, raw driver calls)
|
|
81
|
+
* still land here, so the classifier is duplicated at the edge. Defaults
|
|
82
|
+
* cover MongoDB (`code 11000` / `codeName "DuplicateKey"`), Prisma
|
|
83
|
+
* (`code "P2002"`), and Postgres (`code "23505"`). Override to add other
|
|
84
|
+
* backends (DynamoDB `ConditionalCheckFailedException`, etc.) or to disable
|
|
85
|
+
* the built-in detection.
|
|
86
|
+
*/
|
|
87
|
+
isDuplicateKeyError?: (err: unknown) => boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Default duplicate-key detector covering the mainstream drivers arc sees
|
|
91
|
+
* most. Detection is strictly by known driver codes — never by message
|
|
92
|
+
* string matching — because false positives on dup-key silently mask real
|
|
93
|
+
* errors (WriteConflict, NotWritablePrimary, etc.) as 409s. For long-tail
|
|
94
|
+
* drivers (Neo4j, MSSQL, DynamoDB, custom kits), compose rather than
|
|
95
|
+
* replace:
|
|
96
|
+
*
|
|
97
|
+
* ```ts
|
|
98
|
+
* import { defaultIsDuplicateKeyError } from '@classytic/arc/plugins';
|
|
99
|
+
*
|
|
100
|
+
* errorHandler: {
|
|
101
|
+
* isDuplicateKeyError: (err) =>
|
|
102
|
+
* defaultIsDuplicateKeyError(err) || isNeo4jDupKey(err),
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* Drizzle apps get coverage transitively (Drizzle doesn't wrap driver
|
|
107
|
+
* errors — pg/mysql2/better-sqlite3 codes propagate as-is). Neon is
|
|
108
|
+
* Postgres-wire-compatible → `23505` covers `@neondatabase/serverless`.
|
|
109
|
+
*/
|
|
110
|
+
declare function defaultIsDuplicateKeyError(err: unknown): boolean;
|
|
111
|
+
declare function errorHandlerPluginFn(fastify: FastifyInstance, options?: ErrorHandlerOptions): Promise<void>;
|
|
112
|
+
declare const errorHandlerPlugin: typeof errorHandlerPluginFn;
|
|
113
|
+
//#endregion
|
|
114
|
+
export { errorHandlerPlugin as i, ErrorMapper as n, defaultIsDuplicateKeyError as r, ErrorHandlerOptions as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { p as isArcError } from "./errors-
|
|
2
|
+
import { p as isArcError } from "./errors-BqdUDja_.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/plugins/errorHandler.ts
|
|
5
5
|
var errorHandler_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { t as requestContext } from "./requestContext-
|
|
2
|
+
import { t as requestContext } from "./requestContext-C38GskNt.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/events/EventTransport.ts
|
|
5
5
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-
|
|
1
|
+
import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CfVEGaEl.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,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as EventMeta, c as MemoryEventTransportOptions, d as createEvent, i as EventLogger, l as PublishManyResult, n as DomainEvent, o as EventTransport, r as EventHandler, s as MemoryEventTransport, t as DeadLetteredEvent, u as createChildEvent } from "../EventTransport-
|
|
3
|
-
import { a as withRetry, c as EventDefinitionOutput, d as EventSchema, f as ValidationResult, i as createDeadLetterPublisher, l as EventRegistry, m as defineEvent, n as eventPlugin, o as CustomValidator, p as createEventRegistry, r as RetryOptions, s as EventDefinitionInput, t as EventPluginOptions, u as EventRegistryOptions } from "../eventPlugin-
|
|
1
|
+
import { _n as RepositoryLike } from "../index-BGbpGVyM.mjs";
|
|
2
|
+
import { a as EventMeta, c as MemoryEventTransportOptions, d as createEvent, i as EventLogger, l as PublishManyResult, n as DomainEvent, o as EventTransport, r as EventHandler, s as MemoryEventTransport, t as DeadLetteredEvent, u as createChildEvent } from "../EventTransport-CfVEGaEl.mjs";
|
|
3
|
+
import { a as withRetry, c as EventDefinitionOutput, d as EventSchema, f as ValidationResult, i as createDeadLetterPublisher, l as EventRegistry, m as defineEvent, n as eventPlugin, o as CustomValidator, p as createEventRegistry, r as RetryOptions, s as EventDefinitionInput, t as EventPluginOptions, u as EventRegistryOptions } from "../eventPlugin-D1ThQ1Pp.mjs";
|
|
4
4
|
import { RedisEventTransportOptions, RedisLike } from "./transports/redis.mjs";
|
|
5
|
-
import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-
|
|
5
|
+
import { r as RedisStreamTransportOptions, t as RedisStreamLike } from "../redis-stream-bkO88VHx.mjs";
|
|
6
6
|
|
|
7
7
|
//#region src/events/eventTypes.d.ts
|
|
8
8
|
/**
|
|
@@ -597,4 +597,7 @@ interface ExponentialBackoffOptions {
|
|
|
597
597
|
*/
|
|
598
598
|
declare function exponentialBackoff(options: ExponentialBackoffOptions): Date;
|
|
599
599
|
//#endregion
|
|
600
|
-
|
|
600
|
+
//#region src/events/repository-outbox-adapter.d.ts
|
|
601
|
+
declare function repositoryAsOutboxStore(repository: RepositoryLike): OutboxStore;
|
|
602
|
+
//#endregion
|
|
603
|
+
export { ARC_LIFECYCLE_EVENTS, type ArcLifecycleEvent, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, type CacheEvent, type CrudEventSuffix, type CustomValidator, type DeadLetteredEvent, type DomainEvent, type EventDefinitionInput, type EventDefinitionOutput, type EventHandler, type EventLogger, type EventMeta, EventOutbox, type EventOutboxOptions, type EventPluginOptions, type EventRegistry, type EventRegistryOptions, type EventSchema, type EventTransport, type ExponentialBackoffOptions, InvalidOutboxEventError, MemoryEventTransport, type MemoryEventTransportOptions, MemoryOutboxStore, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, type OutboxFailureContext, type OutboxFailureDecision, type OutboxFailurePolicy, OutboxOwnershipError, type OutboxRelayErrorHandler, type OutboxRelayErrorKind, type OutboxStore, type OutboxWriteOptions, type PublishManyResult, type RedisEventTransportOptions, type RedisLike, type RedisStreamLike, type RedisStreamTransportOptions, type RelayResult, type RetryOptions, type ValidationResult, createChildEvent, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, repositoryAsOutboxStore, withRetry };
|
package/dist/events/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { a as MemoryEventTransport, i as withRetry, o as createChildEvent, r as createDeadLetterPublisher, s as createEvent, t as eventPlugin } from "../eventPlugin-
|
|
2
|
-
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-
|
|
1
|
+
import { a as MemoryEventTransport, i as withRetry, o as createChildEvent, r as createDeadLetterPublisher, s as createEvent, t as eventPlugin } from "../eventPlugin-ByU4Cv0e.mjs";
|
|
2
|
+
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-DYYUQbQN.mjs";
|
|
3
|
+
import { and, anyOf, eq, lte, ne, or } from "@classytic/repo-core/filter";
|
|
4
|
+
import { update } from "@classytic/repo-core/update";
|
|
3
5
|
//#region src/events/defineEvent.ts
|
|
4
6
|
/**
|
|
5
7
|
* defineEvent — Typed Event Definitions with Optional Schema Validation
|
|
@@ -339,6 +341,30 @@ var MemoryOutboxStore = class {
|
|
|
339
341
|
};
|
|
340
342
|
//#endregion
|
|
341
343
|
//#region src/events/repository-outbox-adapter.ts
|
|
344
|
+
/**
|
|
345
|
+
* RepositoryLike → OutboxStore adapter.
|
|
346
|
+
*
|
|
347
|
+
* Maps the `OutboxStore` vocabulary (save / claimPending / acknowledge /
|
|
348
|
+
* fail / getDeadLettered / purge) onto arc's own `RepositoryLike` primitives
|
|
349
|
+
* (create / getOne / findAll / deleteMany / findOneAndUpdate). `EventOutbox`
|
|
350
|
+
* wraps a passed repository with this helper when you use the
|
|
351
|
+
* `{ repository }` option; the function is also re-exported from
|
|
352
|
+
* `@classytic/arc/events` so consumers can build and decorate the store
|
|
353
|
+
* manually (metrics, tracing, multi-transport fan-out).
|
|
354
|
+
*
|
|
355
|
+
* Portability: filters compose via `@classytic/repo-core/filter` and
|
|
356
|
+
* updates via `@classytic/repo-core/update`. The primary-key column name
|
|
357
|
+
* is read from `repository.idField` — mongokit defaults to `_id`,
|
|
358
|
+
* sqlitekit / pgkit / prismakit to the schema's declared PK. The adapter
|
|
359
|
+
* therefore runs on any kit that implements `StandardRepo.findOneAndUpdate`
|
|
360
|
+
* + `getOne` + `getAll` + `deleteMany` + `create`.
|
|
361
|
+
*
|
|
362
|
+
* `fail()` uses a lease-gated read-then-write pair to preserve
|
|
363
|
+
* `firstFailedAt` across retries without relying on Mongo's aggregation-
|
|
364
|
+
* pipeline `$ifNull`. Leases guarantee single-writer during the failure
|
|
365
|
+
* window (`claimPending` filters out non-owned rows), so the two calls are
|
|
366
|
+
* safe under concurrent relayers.
|
|
367
|
+
*/
|
|
342
368
|
const DEFAULT_LEASE_MS$1 = 3e4;
|
|
343
369
|
const DEFAULT_CLAIM_LIMIT = 100;
|
|
344
370
|
const DEFAULT_PURGE_BATCH = 500;
|
|
@@ -346,21 +372,37 @@ function repositoryAsOutboxStore(repository) {
|
|
|
346
372
|
const missing = [];
|
|
347
373
|
if (typeof repository.create !== "function") missing.push("create");
|
|
348
374
|
if (typeof repository.getOne !== "function") missing.push("getOne");
|
|
349
|
-
if (typeof repository.
|
|
375
|
+
if (typeof repository.getAll !== "function") missing.push("getAll");
|
|
350
376
|
if (typeof repository.deleteMany !== "function") missing.push("deleteMany");
|
|
351
377
|
if (typeof repository.findOneAndUpdate !== "function") missing.push("findOneAndUpdate");
|
|
352
|
-
if (missing.length > 0) throw new Error(`EventOutbox: repository is missing required methods: ${missing.join(", ")}. mongokit ≥3.
|
|
378
|
+
if (missing.length > 0) throw new Error(`EventOutbox: repository is missing required methods: ${missing.join(", ")}. mongokit ≥3.10.2 satisfies all five; other kits must implement them to back the outbox.`);
|
|
353
379
|
const r = repository;
|
|
380
|
+
const idField = repository.idField ?? "_id";
|
|
381
|
+
/**
|
|
382
|
+
* Unwrap mongokit's pagination envelope ({ docs, total, ... }) — some
|
|
383
|
+
* kits may return a bare array when pagination is disabled. Handle both.
|
|
384
|
+
*/
|
|
385
|
+
const unwrapDocs = (result) => {
|
|
386
|
+
if (Array.isArray(result)) return result;
|
|
387
|
+
return result?.docs ?? [];
|
|
388
|
+
};
|
|
354
389
|
const isDuplicateKeyError = createIsDuplicateKeyError(repository);
|
|
355
390
|
const safeGetOne = createSafeGetOne(repository);
|
|
356
391
|
const isWellFormed = (event) => !!event && typeof event.type === "string" && !!event.meta?.id;
|
|
392
|
+
/**
|
|
393
|
+
* Filter matching every row that's eligible to be claimed by a relayer:
|
|
394
|
+
* status=pending, visible now, and either unleased or under an expired
|
|
395
|
+
* lease. Used by `getPending` and `claimPending` — defined once so the
|
|
396
|
+
* two code paths stay in lockstep.
|
|
397
|
+
*/
|
|
398
|
+
const claimableFilter = (now) => and(eq("status", "pending"), lte("visibleAt", now), or(eq("leaseOwner", null), lte("leaseExpiresAt", now)));
|
|
357
399
|
return {
|
|
358
400
|
async save(event, options) {
|
|
359
401
|
if (!event?.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
|
|
360
402
|
if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
|
|
361
403
|
const now = /* @__PURE__ */ new Date();
|
|
362
404
|
const doc = {
|
|
363
|
-
|
|
405
|
+
[idField]: event.meta.id,
|
|
364
406
|
event,
|
|
365
407
|
type: event.type,
|
|
366
408
|
status: "pending",
|
|
@@ -386,12 +428,10 @@ function repositoryAsOutboxStore(repository) {
|
|
|
386
428
|
},
|
|
387
429
|
async getPending(limit) {
|
|
388
430
|
const now = /* @__PURE__ */ new Date();
|
|
389
|
-
return (await r.
|
|
390
|
-
|
|
391
|
-
visibleAt: { $lte: now },
|
|
392
|
-
$or: [{ leaseOwner: null }, { leaseExpiresAt: { $lte: now } }]
|
|
393
|
-
}, {
|
|
431
|
+
return unwrapDocs(await r.getAll({
|
|
432
|
+
filters: claimableFilter(now),
|
|
394
433
|
sort: { createdAt: 1 },
|
|
434
|
+
page: 1,
|
|
395
435
|
limit
|
|
396
436
|
})).map((d) => d.event).filter(isWellFormed);
|
|
397
437
|
},
|
|
@@ -399,23 +439,19 @@ function repositoryAsOutboxStore(repository) {
|
|
|
399
439
|
const limit = options?.limit ?? DEFAULT_CLAIM_LIMIT;
|
|
400
440
|
const leaseMs = options?.leaseMs ?? DEFAULT_LEASE_MS$1;
|
|
401
441
|
const consumerId = options?.consumerId ?? "anonymous";
|
|
402
|
-
const typeFilter = options?.types?.length ?
|
|
442
|
+
const typeFilter = options?.types?.length ? anyOf("type", options.types) : null;
|
|
403
443
|
const claimed = [];
|
|
404
444
|
for (let i = 0; i < limit; i++) {
|
|
405
445
|
const now = /* @__PURE__ */ new Date();
|
|
406
446
|
const leaseExpiresAt = new Date(now.getTime() + leaseMs);
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
$or: [{ leaseOwner: null }, { leaseExpiresAt: { $lte: now } }],
|
|
411
|
-
...typeFilter
|
|
412
|
-
}, {
|
|
413
|
-
$set: {
|
|
447
|
+
const filter = typeFilter ? and(claimableFilter(now), typeFilter) : claimableFilter(now);
|
|
448
|
+
const doc = await r.findOneAndUpdate(filter, update({
|
|
449
|
+
set: {
|
|
414
450
|
leaseOwner: consumerId,
|
|
415
451
|
leaseExpiresAt
|
|
416
452
|
},
|
|
417
|
-
|
|
418
|
-
}, {
|
|
453
|
+
inc: { attempts: 1 }
|
|
454
|
+
}), {
|
|
419
455
|
sort: { createdAt: 1 },
|
|
420
456
|
returnDocument: "after"
|
|
421
457
|
});
|
|
@@ -426,18 +462,15 @@ function repositoryAsOutboxStore(repository) {
|
|
|
426
462
|
},
|
|
427
463
|
async acknowledge(eventId, options) {
|
|
428
464
|
const now = /* @__PURE__ */ new Date();
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
};
|
|
433
|
-
if (options?.consumerId) filter.leaseOwner = options.consumerId;
|
|
434
|
-
if (await r.findOneAndUpdate(filter, { $set: {
|
|
465
|
+
const baseFilter = and(eq(idField, eventId), ne("status", "delivered"));
|
|
466
|
+
const filter = options?.consumerId ? and(baseFilter, eq("leaseOwner", options.consumerId)) : baseFilter;
|
|
467
|
+
if (await r.findOneAndUpdate(filter, update({ set: {
|
|
435
468
|
status: "delivered",
|
|
436
469
|
deliveredAt: now,
|
|
437
470
|
leaseOwner: null,
|
|
438
471
|
leaseExpiresAt: null
|
|
439
|
-
} }, { returnDocument: "after" })) return;
|
|
440
|
-
const current = await safeGetOne(
|
|
472
|
+
} }), { returnDocument: "after" })) return;
|
|
473
|
+
const current = await safeGetOne(eq(idField, eventId));
|
|
441
474
|
if (!current) return;
|
|
442
475
|
if (current.status === "delivered") return;
|
|
443
476
|
if (options?.consumerId && current.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, current.leaseOwner);
|
|
@@ -446,28 +479,31 @@ function repositoryAsOutboxStore(repository) {
|
|
|
446
479
|
const now = /* @__PURE__ */ new Date();
|
|
447
480
|
const targetStatus = options?.deadLetter ? "dead_letter" : "pending";
|
|
448
481
|
const visibleAt = options?.retryAt ?? now;
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
const
|
|
482
|
+
const baseFilter = eq(idField, eventId);
|
|
483
|
+
const filter = options?.consumerId ? and(baseFilter, eq("leaseOwner", options.consumerId)) : baseFilter;
|
|
484
|
+
const current = await safeGetOne(baseFilter);
|
|
485
|
+
if (!current) return;
|
|
486
|
+
if (options?.consumerId && current.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, current.leaseOwner);
|
|
487
|
+
const errorInfo = error.code ? {
|
|
488
|
+
message: error.message,
|
|
489
|
+
code: error.code
|
|
490
|
+
} : { message: error.message };
|
|
491
|
+
const firstFailedAt = current.firstFailedAt ?? now;
|
|
492
|
+
await r.findOneAndUpdate(filter, update({ set: {
|
|
452
493
|
status: targetStatus,
|
|
453
494
|
visibleAt,
|
|
454
495
|
leaseOwner: null,
|
|
455
496
|
leaseExpiresAt: null,
|
|
456
497
|
lastFailedAt: now,
|
|
457
|
-
lastError:
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
},
|
|
461
|
-
firstFailedAt: { $ifNull: ["$firstFailedAt", now] }
|
|
462
|
-
} }];
|
|
463
|
-
if (await r.findOneAndUpdate(filter, pipeline, { returnDocument: "after" })) return;
|
|
464
|
-
const current = await safeGetOne({ _id: eventId });
|
|
465
|
-
if (!current) return;
|
|
466
|
-
if (options?.consumerId && current.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, current.leaseOwner);
|
|
498
|
+
lastError: errorInfo,
|
|
499
|
+
firstFailedAt
|
|
500
|
+
} }), { returnDocument: "after" });
|
|
467
501
|
},
|
|
468
502
|
async getDeadLettered(limit) {
|
|
469
|
-
return (await r.
|
|
470
|
-
|
|
503
|
+
return unwrapDocs(await r.getAll({
|
|
504
|
+
filters: eq("status", "dead_letter"),
|
|
505
|
+
sort: { [idField]: 1 },
|
|
506
|
+
page: 1,
|
|
471
507
|
limit
|
|
472
508
|
})).filter((d) => isWellFormed(d.event)).map((d) => ({
|
|
473
509
|
event: d.event,
|
|
@@ -484,17 +520,16 @@ function repositoryAsOutboxStore(repository) {
|
|
|
484
520
|
const cutoff = new Date(Date.now() - olderThanMs);
|
|
485
521
|
let totalDeleted = 0;
|
|
486
522
|
for (;;) {
|
|
487
|
-
const batch = await r.
|
|
488
|
-
|
|
489
|
-
deliveredAt: { $lte: cutoff }
|
|
490
|
-
}, {
|
|
523
|
+
const batch = unwrapDocs(await r.getAll({
|
|
524
|
+
filters: and(eq("status", "delivered"), lte("deliveredAt", cutoff)),
|
|
491
525
|
sort: { deliveredAt: 1 },
|
|
526
|
+
page: 1,
|
|
492
527
|
limit: DEFAULT_PURGE_BATCH,
|
|
493
|
-
select:
|
|
494
|
-
});
|
|
528
|
+
select: idField
|
|
529
|
+
}));
|
|
495
530
|
if (batch.length === 0) break;
|
|
496
|
-
const ids = batch.map((d) => d
|
|
497
|
-
const res = await r.deleteMany(
|
|
531
|
+
const ids = batch.map((d) => d[idField]);
|
|
532
|
+
const res = await r.deleteMany(anyOf(idField, ids));
|
|
498
533
|
totalDeleted += res.deletedCount ?? 0;
|
|
499
534
|
if (batch.length < DEFAULT_PURGE_BATCH) break;
|
|
500
535
|
}
|
|
@@ -843,4 +878,4 @@ function exponentialBackoff(options) {
|
|
|
843
878
|
return new Date(now + jittered);
|
|
844
879
|
}
|
|
845
880
|
//#endregion
|
|
846
|
-
export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, InvalidOutboxEventError, MemoryEventTransport, MemoryOutboxStore, OutboxOwnershipError, createChildEvent, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, withRetry };
|
|
881
|
+
export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, InvalidOutboxEventError, MemoryEventTransport, MemoryOutboxStore, OutboxOwnershipError, createChildEvent, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, repositoryAsOutboxStore, withRetry };
|
|
@@ -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-bkO88VHx.mjs";
|
|
2
2
|
export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "../../EventTransport-
|
|
1
|
+
import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "../../EventTransport-CfVEGaEl.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 loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, 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 loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-CVdgPXBW.mjs";
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/factory/createApp.d.ts
|
package/dist/factory/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-
|
|
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-BwnEAO2h.mjs";
|
|
2
2
|
import { t as loadResources } from "../loadResources-Bksk8ydA.mjs";
|
|
3
3
|
//#region src/factory/edge.ts
|
|
4
4
|
/**
|