@classytic/arc 2.8.0 → 2.8.3
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 +10 -1
- package/dist/{BaseController-CpMfCXdn.mjs → BaseController-DAGGc5Xn.mjs} +76 -25
- package/dist/{EventTransport-n1KBxC_N.d.mts → EventTransport-CinyO7zQ.d.mts} +37 -1
- package/dist/{ResourceRegistry-BOtJuRCs.mjs → ResourceRegistry-Dq3_zBQP.mjs} +17 -5
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-BxGgSHjj.mjs → adapters-BBqAVvPK.mjs} +11 -0
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +1 -1
- package/dist/audit/mongodb.d.mts +1 -1
- package/dist/audit/mongodb.mjs +1 -1
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +3 -3
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-CHCIuA-p.mjs → betterAuthOpenApi-C5lDyRH2.mjs} +1 -1
- package/dist/cache/index.d.mts +2 -2
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.mjs +10 -10
- package/dist/cli/commands/introspect.mjs +3 -3
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/{core-BfrfxNqO.mjs → core-DKSwNSXf.mjs} +1 -1
- package/dist/{createActionRouter-CbkIAaGh.mjs → createActionRouter-Df1BuawX.mjs} +87 -21
- package/dist/{createApp-Cy8eUNKQ.mjs → createApp-BOYjBgdI.mjs} +16 -7
- package/dist/{defineResource-CovBXvTB.mjs → defineResource-Bb_Bdhtw.mjs} +60 -33
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.d.mts +2 -2
- package/dist/dynamic/index.mjs +1 -1
- package/dist/{errorHandler-BeN-ERN7.d.mts → errorHandler-CdZDavNH.d.mts} +2 -2
- package/dist/{errorHandler-BW08lEiy.mjs → errorHandler-mzqk4cGl.mjs} +1 -1
- package/dist/{eventPlugin-CAOWMQS8.d.mts → eventPlugin-CVxlE6De.d.mts} +1 -1
- package/dist/{eventPlugin-x4jo3sG0.mjs → eventPlugin-D91S2YF4.mjs} +19 -1
- package/dist/events/index.d.mts +399 -28
- package/dist/events/index.mjs +345 -29
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +3 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +2 -152
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/mongodb.mjs +18 -6
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +10 -1
- package/dist/{index-BpMhrFgn.d.mts → index-BgmMdpm8.d.mts} +1 -1
- package/dist/{index-CBru2y5Y.d.mts → index-CSkeivBx.d.mts} +3 -3
- package/dist/{index-qct60lnl.d.mts → index-CpTSDqmD.d.mts} +60 -6
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +7 -7
- 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-IJqN3pXK.d.mts → interface-BVuMfeVv.d.mts} +596 -125
- package/dist/loadResources-Bksk8ydA.mjs +154 -0
- package/dist/{mongodb-B1eVtFhw.d.mts → mongodb-B8U2xaLj.d.mts} +1 -1
- package/dist/{mongodb-NShVZDMr.d.mts → mongodb-X7LbEjTN.d.mts} +10 -1
- package/dist/{openapi-AYLVjqVe.mjs → openapi-CYCuekCn.mjs} +50 -3
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -3
- package/dist/plugins/index.d.mts +5 -5
- package/dist/plugins/index.mjs +8 -8
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/presets/index.d.mts +3 -3
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/{presets-BFrGvvjL.mjs → presets-C2xgzW6x.mjs} +10 -18
- package/dist/{queryCachePlugin-BCFVXnxK.d.mts → queryCachePlugin-CnTZZTC5.d.mts} +1 -1
- package/dist/{redis-stream-CF1lrKVk.d.mts → redis-stream-D54N5oXs.d.mts} +1 -1
- package/dist/{redis-Bunu3qWg.d.mts → redis-z3sFr1UP.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +1 -1
- package/dist/{resourceToTools-C_1SMiCz.mjs → resourceToTools-O_HwWXFa.mjs} +194 -64
- package/dist/rpc/index.d.mts +1 -1
- package/dist/rpc/index.mjs +1 -1
- package/dist/scope/index.d.mts +2 -2
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/{types-gUxAIZHp.d.mts → types-Bg2X42_m.d.mts} +30 -9
- package/dist/{types-BoaZHr-2.d.mts → types-CVC4HOKi.d.mts} +1 -1
- package/dist/{types-Ct0PUUSp.d.mts → types-CcG4avic.d.mts} +1 -1
- package/dist/utils/index.d.mts +43 -17
- package/dist/utils/index.mjs +5 -5
- package/dist/{utils-B-l6410F.mjs → utils-yYT3HDXt.mjs} +65 -13
- package/package.json +10 -9
- package/skills/arc/SKILL.md +79 -6
- /package/dist/{caching-CHH-iHs3.mjs → caching-CjybdRwx.mjs} +0 -0
- /package/dist/{circuitBreaker-BGVoB1hD.d.mts → circuitBreaker-CvXkjfrW.d.mts} +0 -0
- /package/dist/{circuitBreaker-l18oRgL5.mjs → circuitBreaker-cmi5XDv5.mjs} +0 -0
- /package/dist/{elevation-UJO3-NvX.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
- /package/dist/{errors-Cg58SLNi.mjs → errors-BF2bIOIS.mjs} +0 -0
- /package/dist/{errors-BI8kEKsO.d.mts → errors-Bmn3eZT6.d.mts} +0 -0
- /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
- /package/dist/{fields-DoeDgh2b.d.mts → fields-DC4So2M2.d.mts} +0 -0
- /package/dist/{interface-CkkWm5uR.d.mts → interface-B-pe8fhj.d.mts} +0 -0
- /package/dist/{interface-bpoLKKqx.d.mts → interface-DplgQO2e.d.mts} +0 -0
- /package/dist/{metrics-DuhiSEZI.mjs → metrics-TuOmguhi.mjs} +0 -0
- /package/dist/{mongodb-5Ff3w8jy.mjs → mongodb-B5O6xaW1.mjs} +0 -0
- /package/dist/{pluralize-BneOJkpi.mjs → pluralize-A0tWEl1K.mjs} +0 -0
- /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-BLojtuvR.mjs} +0 -0
- /package/dist/{requestContext-xHIKedG6.mjs → requestContext-DYvHl113.mjs} +0 -0
- /package/dist/{schemaConverter-Y5EejTnJ.mjs → schemaConverter-OxfCshus.mjs} +0 -0
- /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
- /package/dist/{sse-CD5Hghpu.mjs → sse-CJpt7LGI.mjs} +0 -0
- /package/dist/{tracing-xqXzWeaf.d.mts → tracing-DxjKk7eW.d.mts} +0 -0
- /package/dist/{types-CN6JvmYz.d.mts → types-C72d3NDn.d.mts} +0 -0
- /package/dist/{versioning-CPU_5Xfs.mjs → versioning-Cm8qoFDg.mjs} +0 -0
package/dist/events/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as MemoryEventTransport, i as withRetry, o as createEvent, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-
|
|
1
|
+
import { a as MemoryEventTransport, i as withRetry, o as createEvent, r as createDeadLetterPublisher, t as eventPlugin } from "../eventPlugin-D91S2YF4.mjs";
|
|
2
2
|
//#region src/events/defineEvent.ts
|
|
3
3
|
/**
|
|
4
4
|
* defineEvent — Typed Event Definitions with Optional Schema Validation
|
|
@@ -224,52 +224,235 @@ const CACHE_EVENTS = Object.freeze({
|
|
|
224
224
|
});
|
|
225
225
|
//#endregion
|
|
226
226
|
//#region src/events/outbox.ts
|
|
227
|
-
/** Default outbox retention —
|
|
227
|
+
/** Default outbox retention — delivered events older than this are eligible for purge */
|
|
228
228
|
const DEFAULT_OUTBOX_RETENTION_MS = 10080 * 60 * 1e3;
|
|
229
|
+
const DEFAULT_LEASE_MS = 3e4;
|
|
230
|
+
/**
|
|
231
|
+
* Thrown by a store when `acknowledge` / `fail` is called by a consumer that
|
|
232
|
+
* does not own the event's current lease.
|
|
233
|
+
*
|
|
234
|
+
* Stores that enforce lease ownership MUST throw this (not silently return)
|
|
235
|
+
* so {@link EventOutbox} can detect the mismatch and avoid over-counting
|
|
236
|
+
* successful deliveries. {@link EventOutbox.relay} catches it and reports
|
|
237
|
+
* via {@link EventOutboxOptions.onError} instead of counting as relayed.
|
|
238
|
+
*/
|
|
239
|
+
var OutboxOwnershipError = class extends Error {
|
|
240
|
+
eventId;
|
|
241
|
+
attemptedBy;
|
|
242
|
+
currentOwner;
|
|
243
|
+
constructor(eventId, attemptedBy, currentOwner) {
|
|
244
|
+
super(`Outbox ownership mismatch for event "${eventId}": attempted by "${attemptedBy}", current owner is "${currentOwner ?? "none"}". The lease may have expired and been reclaimed by another worker.`);
|
|
245
|
+
this.name = "OutboxOwnershipError";
|
|
246
|
+
this.eventId = eventId;
|
|
247
|
+
this.attemptedBy = attemptedBy;
|
|
248
|
+
this.currentOwner = currentOwner;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
/** Thrown by {@link EventOutbox.store} when an event is missing `type` or `meta.id`. */
|
|
252
|
+
var InvalidOutboxEventError = class extends Error {
|
|
253
|
+
constructor(reason) {
|
|
254
|
+
super(`Invalid outbox event: ${reason}`);
|
|
255
|
+
this.name = "InvalidOutboxEventError";
|
|
256
|
+
}
|
|
257
|
+
};
|
|
229
258
|
var EventOutbox = class {
|
|
230
259
|
_store;
|
|
231
260
|
_transport;
|
|
232
261
|
_batchSize;
|
|
262
|
+
_consumerId;
|
|
263
|
+
_leaseMs;
|
|
264
|
+
_onError;
|
|
265
|
+
_usePublishMany;
|
|
233
266
|
constructor(opts) {
|
|
234
267
|
this._store = opts.store;
|
|
235
268
|
this._transport = opts.transport;
|
|
236
269
|
this._batchSize = opts.batchSize ?? 100;
|
|
270
|
+
this._consumerId = opts.consumerId ?? `relay-${Math.random().toString(36).slice(2, 10)}`;
|
|
271
|
+
this._leaseMs = opts.leaseMs ?? DEFAULT_LEASE_MS;
|
|
272
|
+
this._onError = opts.onError;
|
|
273
|
+
this._usePublishMany = opts.usePublishMany ?? true;
|
|
274
|
+
}
|
|
275
|
+
/** Unique consumer ID used for lease ownership when the store supports claims */
|
|
276
|
+
get consumerId() {
|
|
277
|
+
return this._consumerId;
|
|
237
278
|
}
|
|
238
|
-
/**
|
|
239
|
-
|
|
240
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Store event in outbox.
|
|
281
|
+
*
|
|
282
|
+
* Validates that `event.type` and `event.meta.id` are present — throws
|
|
283
|
+
* {@link InvalidOutboxEventError} otherwise, so corrupt rows can never
|
|
284
|
+
* be persisted via this API.
|
|
285
|
+
*
|
|
286
|
+
* Pass `options.session` to participate in a host-managed DB transaction
|
|
287
|
+
* (store must support session-aware writes). Other options (`visibleAt`,
|
|
288
|
+
* `dedupeKey`, `partitionKey`, `headers`) are forwarded to stores that
|
|
289
|
+
* implement them and ignored otherwise.
|
|
290
|
+
*/
|
|
291
|
+
async store(event, options) {
|
|
292
|
+
if (!event || typeof event !== "object") throw new InvalidOutboxEventError("event is not an object");
|
|
293
|
+
if (!event.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
|
|
294
|
+
if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
|
|
295
|
+
await this._store.save(event, options);
|
|
296
|
+
}
|
|
297
|
+
_reportError(kind, error, event) {
|
|
298
|
+
if (!this._onError) return;
|
|
299
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
300
|
+
try {
|
|
301
|
+
this._onError({
|
|
302
|
+
kind,
|
|
303
|
+
event,
|
|
304
|
+
error: err
|
|
305
|
+
});
|
|
306
|
+
} catch {}
|
|
241
307
|
}
|
|
242
308
|
/**
|
|
243
|
-
* Relay pending events to transport
|
|
309
|
+
* Relay pending events to transport and return the number of successful
|
|
310
|
+
* publish+acknowledge pairs.
|
|
244
311
|
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
312
|
+
* For richer observability (per-kind counts, publishMany detection, etc.)
|
|
313
|
+
* use {@link relayBatch} which returns a {@link RelayResult}. This method
|
|
314
|
+
* is the backward-compatible shortcut that returns just the count.
|
|
247
315
|
*
|
|
248
|
-
* @returns Number of successfully published
|
|
316
|
+
* @returns Number of successfully published AND acknowledged events
|
|
249
317
|
*/
|
|
250
318
|
async relay() {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
319
|
+
return (await this.relayBatch()).relayed;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Relay a batch of pending events to the transport and return a rich
|
|
323
|
+
* {@link RelayResult} describing the outcome of each event.
|
|
324
|
+
*
|
|
325
|
+
* Behavior summary:
|
|
326
|
+
*
|
|
327
|
+
* - **Claim path**: uses {@link OutboxStore.claimPending} when the store
|
|
328
|
+
* supports it (safe for multi-worker relay) or falls back to
|
|
329
|
+
* {@link OutboxStore.getPending} (single-worker only).
|
|
330
|
+
*
|
|
331
|
+
* - **Publish path**: if the transport implements
|
|
332
|
+
* {@link EventTransport.publishMany} and `usePublishMany` is not disabled,
|
|
333
|
+
* the entire batch is sent in one call. Otherwise each event is published
|
|
334
|
+
* individually. Either way, per-event outcomes are tracked.
|
|
335
|
+
*
|
|
336
|
+
* - **Failure path**: if the store implements `fail`, per-event failures
|
|
337
|
+
* are reported via `store.fail(...)` and the batch continues. Without
|
|
338
|
+
* `fail`, the batch stops on the first failure (legacy behavior).
|
|
339
|
+
*
|
|
340
|
+
* - **Malformed events**: events missing `type` or `meta.id` abort the
|
|
341
|
+
* batch — a well-behaved store must never return them (see
|
|
342
|
+
* {@link OutboxStore} semantics #6). The error is reported via `onError`.
|
|
343
|
+
*
|
|
344
|
+
* - **Ownership mismatches**: if `acknowledge`/`fail` throws
|
|
345
|
+
* {@link OutboxOwnershipError} (our lease expired and another worker
|
|
346
|
+
* claimed the event), the event is NOT counted as relayed. The other
|
|
347
|
+
* worker will re-publish — at-least-once semantics preserved.
|
|
348
|
+
*
|
|
349
|
+
* @returns Per-kind outcome counts for the batch
|
|
350
|
+
*/
|
|
351
|
+
async relayBatch() {
|
|
352
|
+
const empty = {
|
|
353
|
+
relayed: 0,
|
|
354
|
+
attempted: 0,
|
|
355
|
+
publishFailed: 0,
|
|
356
|
+
ackFailed: 0,
|
|
357
|
+
ownershipMismatches: 0,
|
|
358
|
+
malformed: 0,
|
|
359
|
+
failHookErrors: 0,
|
|
360
|
+
usedPublishMany: false
|
|
361
|
+
};
|
|
362
|
+
if (!this._transport) return empty;
|
|
363
|
+
const pending = this._store.claimPending ? await this._store.claimPending({
|
|
364
|
+
limit: this._batchSize,
|
|
365
|
+
consumerId: this._consumerId,
|
|
366
|
+
leaseMs: this._leaseMs
|
|
367
|
+
}) : await this._store.getPending(this._batchSize);
|
|
368
|
+
const valid = [];
|
|
369
|
+
let malformed = 0;
|
|
254
370
|
for (const event of pending) {
|
|
255
|
-
if (!event.type || !event.meta?.id) {
|
|
256
|
-
|
|
371
|
+
if (!event || !event.type || !event.meta?.id) {
|
|
372
|
+
this._reportError("malformed_event", new InvalidOutboxEventError("store returned event missing type or meta.id — batch aborted"), event);
|
|
373
|
+
malformed++;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
valid.push(event);
|
|
377
|
+
}
|
|
378
|
+
const counts = {
|
|
379
|
+
relayed: 0,
|
|
380
|
+
publishFailed: 0,
|
|
381
|
+
ackFailed: 0,
|
|
382
|
+
ownershipMismatches: 0,
|
|
383
|
+
failHookErrors: 0
|
|
384
|
+
};
|
|
385
|
+
const canPublishMany = this._usePublishMany && typeof this._transport.publishMany === "function";
|
|
386
|
+
const canFail = typeof this._store.fail === "function";
|
|
387
|
+
let publishOutcomes;
|
|
388
|
+
if (canPublishMany && valid.length > 0) try {
|
|
389
|
+
const result = await this._transport.publishMany(valid);
|
|
390
|
+
publishOutcomes = new Map(result);
|
|
391
|
+
} catch (batchErr) {
|
|
392
|
+
publishOutcomes = /* @__PURE__ */ new Map();
|
|
393
|
+
const err = batchErr instanceof Error ? batchErr : new Error(String(batchErr));
|
|
394
|
+
for (const ev of valid) publishOutcomes.set(ev.meta.id, err);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
publishOutcomes = /* @__PURE__ */ new Map();
|
|
398
|
+
for (const event of valid) try {
|
|
399
|
+
await this._transport.publish(event);
|
|
400
|
+
publishOutcomes.set(event.meta.id, null);
|
|
401
|
+
} catch (err) {
|
|
402
|
+
publishOutcomes.set(event.meta.id, err instanceof Error ? err : new Error(String(err)));
|
|
403
|
+
if (!canFail) break;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
let stopBatch = false;
|
|
407
|
+
for (const event of valid) {
|
|
408
|
+
if (stopBatch) break;
|
|
409
|
+
const publishErr = publishOutcomes.get(event.meta.id);
|
|
410
|
+
if (publishErr instanceof Error) {
|
|
411
|
+
counts.publishFailed++;
|
|
412
|
+
this._reportError("publish_failed", publishErr, event);
|
|
413
|
+
if (!canFail) {
|
|
414
|
+
stopBatch = true;
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
await this._store.fail(event.meta.id, normalizeError(publishErr), { consumerId: this._consumerId });
|
|
419
|
+
} catch (failErr) {
|
|
420
|
+
if (failErr instanceof OutboxOwnershipError) {
|
|
421
|
+
counts.ownershipMismatches++;
|
|
422
|
+
this._reportError("ownership_mismatch", failErr, event);
|
|
423
|
+
} else {
|
|
424
|
+
counts.failHookErrors++;
|
|
425
|
+
this._reportError("fail_failed", failErr, event);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
257
428
|
continue;
|
|
258
429
|
}
|
|
259
430
|
try {
|
|
260
|
-
await this.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
431
|
+
await this._store.acknowledge(event.meta.id, { consumerId: this._consumerId });
|
|
432
|
+
counts.relayed++;
|
|
433
|
+
} catch (ackErr) {
|
|
434
|
+
counts.ackFailed++;
|
|
435
|
+
if (ackErr instanceof OutboxOwnershipError) {
|
|
436
|
+
counts.ownershipMismatches++;
|
|
437
|
+
this._reportError("ownership_mismatch", ackErr, event);
|
|
438
|
+
} else this._reportError("acknowledge_failed", ackErr, event);
|
|
265
439
|
}
|
|
266
440
|
}
|
|
267
|
-
return
|
|
441
|
+
return {
|
|
442
|
+
relayed: counts.relayed,
|
|
443
|
+
attempted: valid.length,
|
|
444
|
+
publishFailed: counts.publishFailed,
|
|
445
|
+
ackFailed: counts.ackFailed,
|
|
446
|
+
ownershipMismatches: counts.ownershipMismatches,
|
|
447
|
+
malformed,
|
|
448
|
+
failHookErrors: counts.failHookErrors,
|
|
449
|
+
usedPublishMany: canPublishMany && valid.length > 0
|
|
450
|
+
};
|
|
268
451
|
}
|
|
269
452
|
/**
|
|
270
|
-
* Purge old
|
|
453
|
+
* Purge old **delivered** events from the outbox store.
|
|
271
454
|
* Delegates to `store.purge()` if implemented; no-op otherwise.
|
|
272
|
-
* @param olderThanMs - Remove events
|
|
455
|
+
* @param olderThanMs - Remove events delivered more than this many ms ago (default: 7 days)
|
|
273
456
|
* @returns Number of purged events, or 0 if store doesn't support purge
|
|
274
457
|
*/
|
|
275
458
|
async purge(olderThanMs = DEFAULT_OUTBOX_RETENTION_MS) {
|
|
@@ -277,17 +460,150 @@ var EventOutbox = class {
|
|
|
277
460
|
return this._store.purge(olderThanMs);
|
|
278
461
|
}
|
|
279
462
|
};
|
|
463
|
+
function normalizeError(err) {
|
|
464
|
+
if (err instanceof Error) return {
|
|
465
|
+
message: err.message,
|
|
466
|
+
code: err.code
|
|
467
|
+
};
|
|
468
|
+
return { message: String(err) };
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* In-memory outbox store — reference implementation supporting the full
|
|
472
|
+
* capability set (claim/lease, fail/retry, dedupe, visibleAt).
|
|
473
|
+
*
|
|
474
|
+
* For dev/testing only. Production deployments should use a durable store
|
|
475
|
+
* backed by the app's database.
|
|
476
|
+
*/
|
|
280
477
|
var MemoryOutboxStore = class {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
478
|
+
entries = [];
|
|
479
|
+
seenDedupeKeys = /* @__PURE__ */ new Set();
|
|
480
|
+
async save(event, options) {
|
|
481
|
+
if (!event?.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
|
|
482
|
+
if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
|
|
483
|
+
if (options?.dedupeKey) {
|
|
484
|
+
if (this.seenDedupeKeys.has(options.dedupeKey)) return;
|
|
485
|
+
this.seenDedupeKeys.add(options.dedupeKey);
|
|
486
|
+
}
|
|
487
|
+
this.entries.push({
|
|
488
|
+
event,
|
|
489
|
+
status: "pending",
|
|
490
|
+
attempts: 0,
|
|
491
|
+
visibleAt: options?.visibleAt?.getTime() ?? 0,
|
|
492
|
+
leaseOwner: null,
|
|
493
|
+
leaseExpiresAt: 0,
|
|
494
|
+
deliveredAt: null,
|
|
495
|
+
lastError: null,
|
|
496
|
+
dedupeKey: options?.dedupeKey
|
|
497
|
+
});
|
|
284
498
|
}
|
|
285
499
|
async getPending(limit) {
|
|
286
|
-
|
|
500
|
+
const now = Date.now();
|
|
501
|
+
return this.entries.filter((e) => e.status === "pending" && e.visibleAt <= now && (e.leaseOwner === null || e.leaseExpiresAt <= now)).slice(0, limit).map((e) => e.event);
|
|
287
502
|
}
|
|
288
|
-
async
|
|
289
|
-
|
|
503
|
+
async claimPending(options) {
|
|
504
|
+
const now = Date.now();
|
|
505
|
+
const limit = options?.limit ?? 100;
|
|
506
|
+
const leaseMs = options?.leaseMs ?? DEFAULT_LEASE_MS;
|
|
507
|
+
const consumerId = options?.consumerId ?? "anonymous";
|
|
508
|
+
const typeFilter = options?.types ? new Set(options.types) : null;
|
|
509
|
+
const claimed = [];
|
|
510
|
+
for (const entry of this.entries) {
|
|
511
|
+
if (claimed.length >= limit) break;
|
|
512
|
+
if (entry.status !== "pending") continue;
|
|
513
|
+
if (entry.visibleAt > now) continue;
|
|
514
|
+
if (entry.leaseOwner !== null && entry.leaseExpiresAt > now) continue;
|
|
515
|
+
if (typeFilter && !typeFilter.has(entry.event.type)) continue;
|
|
516
|
+
entry.leaseOwner = consumerId;
|
|
517
|
+
entry.leaseExpiresAt = now + leaseMs;
|
|
518
|
+
entry.attempts++;
|
|
519
|
+
claimed.push(entry.event);
|
|
520
|
+
}
|
|
521
|
+
return claimed;
|
|
522
|
+
}
|
|
523
|
+
async acknowledge(eventId, options) {
|
|
524
|
+
const entry = this.entries.find((e) => e.event.meta.id === eventId);
|
|
525
|
+
if (!entry) return;
|
|
526
|
+
if (entry.status === "delivered") return;
|
|
527
|
+
if (options?.consumerId && entry.leaseOwner && entry.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, entry.leaseOwner);
|
|
528
|
+
entry.status = "delivered";
|
|
529
|
+
entry.deliveredAt = Date.now();
|
|
530
|
+
entry.leaseOwner = null;
|
|
531
|
+
}
|
|
532
|
+
async fail(eventId, error, options) {
|
|
533
|
+
const entry = this.entries.find((e) => e.event.meta.id === eventId);
|
|
534
|
+
if (!entry) return;
|
|
535
|
+
if (options?.consumerId && entry.leaseOwner && entry.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, entry.leaseOwner);
|
|
536
|
+
entry.lastError = error;
|
|
537
|
+
entry.leaseOwner = null;
|
|
538
|
+
entry.leaseExpiresAt = 0;
|
|
539
|
+
if (options?.deadLetter) {
|
|
540
|
+
entry.status = "dead_letter";
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
entry.status = "pending";
|
|
544
|
+
entry.visibleAt = options?.retryAt ? options.retryAt.getTime() : 0;
|
|
545
|
+
}
|
|
546
|
+
async purge(olderThanMs) {
|
|
547
|
+
const cutoff = Date.now() - olderThanMs;
|
|
548
|
+
let purged = 0;
|
|
549
|
+
for (let i = this.entries.length - 1; i >= 0; i--) {
|
|
550
|
+
const entry = this.entries[i];
|
|
551
|
+
if (!entry) continue;
|
|
552
|
+
if (entry.status === "delivered" && entry.deliveredAt !== null && entry.deliveredAt < cutoff) {
|
|
553
|
+
if (entry.dedupeKey) this.seenDedupeKeys.delete(entry.dedupeKey);
|
|
554
|
+
this.entries.splice(i, 1);
|
|
555
|
+
purged++;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return purged;
|
|
559
|
+
}
|
|
560
|
+
/** Test helper: inspect entry by id */
|
|
561
|
+
_getEntry(eventId) {
|
|
562
|
+
return this.entries.find((e) => e.event.meta.id === eventId);
|
|
290
563
|
}
|
|
291
564
|
};
|
|
565
|
+
/**
|
|
566
|
+
* Compute a `retryAt` `Date` using exponential backoff with jitter.
|
|
567
|
+
*
|
|
568
|
+
* This is a convenience helper for store authors implementing
|
|
569
|
+
* {@link OutboxStore.fail}: call it to compute the retry visibility window
|
|
570
|
+
* based on the event's current attempt count.
|
|
571
|
+
*
|
|
572
|
+
* Formula: `delay = min(maxMs, baseMs * 2^(attempt - 1)) * (1 + random * jitter)`
|
|
573
|
+
*
|
|
574
|
+
* @example Basic usage inside a store's `fail()` method
|
|
575
|
+
* ```typescript
|
|
576
|
+
* async fail(eventId, error, options) {
|
|
577
|
+
* const entry = await this.findById(eventId);
|
|
578
|
+
* entry.attempts++;
|
|
579
|
+
* if (entry.attempts >= MAX_ATTEMPTS) {
|
|
580
|
+
* return this.deadLetter(eventId, error);
|
|
581
|
+
* }
|
|
582
|
+
* const retryAt = exponentialBackoff({ attempt: entry.attempts });
|
|
583
|
+
* entry.visibleAt = retryAt;
|
|
584
|
+
* await this.update(entry);
|
|
585
|
+
* }
|
|
586
|
+
* ```
|
|
587
|
+
*
|
|
588
|
+
* @example Tuning for a faster transport
|
|
589
|
+
* ```typescript
|
|
590
|
+
* exponentialBackoff({ attempt: 3, baseMs: 250, maxMs: 10_000, jitter: 0.3 });
|
|
591
|
+
* // attempt=1 → ~250ms ±30%
|
|
592
|
+
* // attempt=2 → ~500ms ±30%
|
|
593
|
+
* // attempt=3 → ~1000ms ±30%
|
|
594
|
+
* // attempt=10 → capped at 10_000ms
|
|
595
|
+
* ```
|
|
596
|
+
*/
|
|
597
|
+
function exponentialBackoff(options) {
|
|
598
|
+
const attempt = Math.max(1, Math.floor(options.attempt));
|
|
599
|
+
const baseMs = options.baseMs ?? 1e3;
|
|
600
|
+
const maxMs = options.maxMs ?? 6e4;
|
|
601
|
+
const jitter = Math.max(0, Math.min(1, options.jitter ?? .2));
|
|
602
|
+
const now = options.now ?? Date.now();
|
|
603
|
+
const exp = baseMs * 2 ** (attempt - 1);
|
|
604
|
+
const capped = Math.min(maxMs, exp);
|
|
605
|
+
const jittered = jitter > 0 ? capped * (1 + Math.random() * jitter) : capped;
|
|
606
|
+
return new Date(now + jittered);
|
|
607
|
+
}
|
|
292
608
|
//#endregion
|
|
293
|
-
export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, MemoryEventTransport, MemoryOutboxStore, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, withRetry };
|
|
609
|
+
export { ARC_LIFECYCLE_EVENTS, CACHE_EVENTS, CRUD_EVENT_SUFFIXES, EventOutbox, InvalidOutboxEventError, MemoryEventTransport, MemoryOutboxStore, OutboxOwnershipError, createDeadLetterPublisher, createEvent, createEventRegistry, crudEventType, defineEvent, eventPlugin, exponentialBackoff, 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-D54N5oXs.mjs";
|
|
2
2
|
export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
|
|
@@ -118,7 +118,9 @@ var RedisStreamTransport = class {
|
|
|
118
118
|
const claimed = await this.redis.xclaim(this.stream, this.group, this.consumer, this.claimTimeoutMs, ...staleIds);
|
|
119
119
|
for (const [messageId, fields] of claimed) await this.processEntry(messageId, fields);
|
|
120
120
|
}
|
|
121
|
-
} catch {
|
|
121
|
+
} catch (err) {
|
|
122
|
+
this.logger.error("[RedisStreamTransport] claimPending error:", err);
|
|
123
|
+
}
|
|
122
124
|
}
|
|
123
125
|
async processEntry(messageId, fields) {
|
|
124
126
|
const fieldMap = /* @__PURE__ */ new Map();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "../../EventTransport-
|
|
1
|
+
import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "../../EventTransport-CinyO7zQ.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-Bg2X42_m.mjs";
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/factory/createApp.d.ts
|
package/dist/factory/index.mjs
CHANGED
|
@@ -1,7 +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 {
|
|
3
|
-
import { dirname, join, resolve } from "node:path";
|
|
4
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
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-BOYjBgdI.mjs";
|
|
2
|
+
import { t as loadResources } from "../loadResources-Bksk8ydA.mjs";
|
|
5
3
|
//#region src/factory/edge.ts
|
|
6
4
|
/**
|
|
7
5
|
* Convert a Fastify app into a Web Standards fetch handler.
|
|
@@ -48,152 +46,4 @@ function toFetchHandler(app, options = {}) {
|
|
|
48
46
|
};
|
|
49
47
|
}
|
|
50
48
|
//#endregion
|
|
51
|
-
//#region src/factory/loadResources.ts
|
|
52
|
-
/**
|
|
53
|
-
* loadResources — Auto-discover resource files from a directory.
|
|
54
|
-
*
|
|
55
|
-
* Scans for `*.resource.{ts,js,mts,mjs}` files, imports each,
|
|
56
|
-
* and collects their default exports. No barrel file needed.
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```ts
|
|
60
|
-
* import { createApp, loadResources } from '@classytic/arc/factory';
|
|
61
|
-
*
|
|
62
|
-
* // Recommended: import.meta.url — works in both src/ (dev) and dist/ (prod)
|
|
63
|
-
* const app = await createApp({
|
|
64
|
-
* resources: await loadResources(import.meta.url),
|
|
65
|
-
* auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
|
|
66
|
-
* });
|
|
67
|
-
*
|
|
68
|
-
* // Or explicit path (must match runtime layout)
|
|
69
|
-
* const app2 = await createApp({
|
|
70
|
-
* resources: await loadResources('./src/resources'),
|
|
71
|
-
* });
|
|
72
|
-
* ```
|
|
73
|
-
*
|
|
74
|
-
* File convention:
|
|
75
|
-
* ```
|
|
76
|
-
* src/resources/
|
|
77
|
-
* product/product.resource.ts → export default defineResource({ name: 'product', ... })
|
|
78
|
-
* order/order.resource.ts → export default defineResource({ name: 'order', ... })
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
/**
|
|
82
|
-
* Scan a directory for resource files and import their default exports.
|
|
83
|
-
*
|
|
84
|
-
* Accepts a directory path OR `import.meta.url` (file:// URL).
|
|
85
|
-
* When given a URL, resolves to the directory containing that file —
|
|
86
|
-
* so `loadResources(import.meta.url)` works in both dev (`src/`) and
|
|
87
|
-
* production (`dist/`) without path gymnastics.
|
|
88
|
-
*
|
|
89
|
-
* @param dir - Directory path, or `import.meta.url` (file:// URL resolved to its dirname)
|
|
90
|
-
* @param options - Pattern and recursion options
|
|
91
|
-
* @returns Array of resource definitions (anything with `.toPlugin()`)
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```ts
|
|
95
|
-
* // Works from both src/ and dist/ — resolves relative to the calling file
|
|
96
|
-
* await loadResources(import.meta.url);
|
|
97
|
-
*
|
|
98
|
-
* // Subdirectory relative to the calling file
|
|
99
|
-
* await loadResources(import.meta.url, { suffix: '.resource' });
|
|
100
|
-
*
|
|
101
|
-
* // Explicit path (must match runtime layout)
|
|
102
|
-
* await loadResources('./src/resources');
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
105
|
-
async function loadResources(dir, options = {}) {
|
|
106
|
-
const { suffix = ".resource", recursive = true, exclude, include, silent = false } = options;
|
|
107
|
-
const files = await collectFiles(resolve(dir.startsWith("file://") ? dirname(fileURLToPath(dir)) : dir), new RegExp(`${escapeRegex(suffix)}\\.(ts|js|mts|mjs)$`), recursive);
|
|
108
|
-
files.sort();
|
|
109
|
-
const includeSet = include ? new Set(include) : null;
|
|
110
|
-
const excludeSet = exclude ? new Set(exclude) : null;
|
|
111
|
-
const skipped = [];
|
|
112
|
-
const failed = [];
|
|
113
|
-
const isWindowsPath = (p) => /^[a-z]:[\\/]/i.test(p);
|
|
114
|
-
const results = await Promise.all(files.map(async (file) => {
|
|
115
|
-
let mod;
|
|
116
|
-
let primaryError;
|
|
117
|
-
try {
|
|
118
|
-
mod = await import(pathToFileURL(file).href);
|
|
119
|
-
return {
|
|
120
|
-
file,
|
|
121
|
-
mod
|
|
122
|
-
};
|
|
123
|
-
} catch (err) {
|
|
124
|
-
primaryError = err;
|
|
125
|
-
}
|
|
126
|
-
if (!isWindowsPath(file)) try {
|
|
127
|
-
mod = await import(file);
|
|
128
|
-
return {
|
|
129
|
-
file,
|
|
130
|
-
mod
|
|
131
|
-
};
|
|
132
|
-
} catch {}
|
|
133
|
-
const err = primaryError;
|
|
134
|
-
const code = err.code;
|
|
135
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
136
|
-
if (code === "ERR_MODULE_NOT_FOUND" && msg.includes(".js")) failed.push(`${file}: ${msg}\n Hint: This file uses .js extension imports (TypeScript ESM convention).
|
|
137
|
-
• Production: ensure your build compiles .ts→.js before loadResources() runs.
|
|
138
|
-
• Node.js: use tsx, ts-node/esm, or a build step.
|
|
139
|
-
• Vitest: nested .js→.ts resolution may fail through dynamic imports.
|
|
140
|
-
Workaround: use import.meta.glob to preload resources statically.
|
|
141
|
-
See: https://github.com/classytic/arc/blob/main/docs/production-ops/factory.mdx#vitest-limitation`);
|
|
142
|
-
else failed.push(`${file}: ${msg}`);
|
|
143
|
-
return null;
|
|
144
|
-
}));
|
|
145
|
-
const resources = [];
|
|
146
|
-
for (const result of results) {
|
|
147
|
-
if (!result) continue;
|
|
148
|
-
let resource = result.mod.default ?? result.mod.resource;
|
|
149
|
-
if (!resource || typeof resource.toPlugin !== "function") {
|
|
150
|
-
for (const value of Object.values(result.mod)) if (value && typeof value === "object" && typeof value.toPlugin === "function") {
|
|
151
|
-
resource = value;
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (!resource || typeof resource.toPlugin !== "function") {
|
|
156
|
-
skipped.push(result.file);
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
const name = resource.name;
|
|
160
|
-
if (name) {
|
|
161
|
-
if (includeSet && !includeSet.has(name)) continue;
|
|
162
|
-
if (!includeSet && excludeSet?.has(name)) continue;
|
|
163
|
-
}
|
|
164
|
-
resources.push(resource);
|
|
165
|
-
}
|
|
166
|
-
const log = silent ? void 0 : options?.logger;
|
|
167
|
-
if (log) {
|
|
168
|
-
if (failed.length) {
|
|
169
|
-
log.warn(`[arc] loadResources: ${failed.length} file(s) failed to import:`);
|
|
170
|
-
for (const f of failed) log.warn(` - ${f}`);
|
|
171
|
-
}
|
|
172
|
-
if (skipped.length) {
|
|
173
|
-
log.warn(`[arc] loadResources: ${skipped.length} file(s) skipped (no default export with toPlugin):`);
|
|
174
|
-
for (const f of skipped) log.warn(` - ${f}`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return resources;
|
|
178
|
-
}
|
|
179
|
-
async function collectFiles(dir, pattern, recursive) {
|
|
180
|
-
const results = [];
|
|
181
|
-
let entries;
|
|
182
|
-
try {
|
|
183
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
184
|
-
} catch {
|
|
185
|
-
return results;
|
|
186
|
-
}
|
|
187
|
-
for (const entry of entries) {
|
|
188
|
-
const name = String(entry.name);
|
|
189
|
-
const fullPath = join(dir, name);
|
|
190
|
-
if (entry.isDirectory() && recursive) results.push(...await collectFiles(fullPath, pattern, recursive));
|
|
191
|
-
else if (entry.isFile() && pattern.test(name)) results.push(fullPath);
|
|
192
|
-
}
|
|
193
|
-
return results;
|
|
194
|
-
}
|
|
195
|
-
function escapeRegex(str) {
|
|
196
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
197
|
-
}
|
|
198
|
-
//#endregion
|
|
199
49
|
export { ArcFactory, createApp, developmentPreset, edgePreset, getPreset, loadResources, productionPreset, testingPreset, toFetchHandler };
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { An as beforeCreate, Cn as HookPhase, Dn as afterCreate, En as HookSystemOptions, Mn as beforeUpdate, Nn as createHookSystem, On as afterDelete, Pn as defineHook, Sn as HookOperation, Tn as HookSystem, bn as HookContext, jn as beforeDelete, kn as afterUpdate, wn as HookRegistration, xn as HookHandler, yn as DefineHookOptions } from "../interface-BVuMfeVv.mjs";
|
|
2
2
|
export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-
|
|
2
|
-
import { n as MongoIdempotencyStoreOptions } from "../mongodb-
|
|
3
|
-
import { r as RedisIdempotencyStoreOptions, t as RedisClient } from "../redis-
|
|
1
|
+
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-B-pe8fhj.mjs";
|
|
2
|
+
import { n as MongoIdempotencyStoreOptions } from "../mongodb-X7LbEjTN.mjs";
|
|
3
|
+
import { r as RedisIdempotencyStoreOptions, t as RedisClient } from "../redis-z3sFr1UP.mjs";
|
|
4
4
|
import { FastifyPluginAsync } from "fastify";
|
|
5
5
|
|
|
6
6
|
//#region src/idempotency/idempotencyPlugin.d.ts
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as MongoIdempotencyStoreOptions, t as MongoIdempotencyStore } from "../mongodb-
|
|
1
|
+
import { n as MongoIdempotencyStoreOptions, t as MongoIdempotencyStore } from "../mongodb-X7LbEjTN.mjs";
|
|
2
2
|
export { MongoIdempotencyStore, type MongoIdempotencyStoreOptions };
|