@classytic/arc 2.10.3 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{BaseController-CbKKIflT.mjs → BaseController-JNV08qOT.mjs} +595 -537
- package/dist/{queryCachePlugin-BKbWjgDG.d.mts → QueryCache-DOBNHBE0.d.mts} +2 -32
- package/dist/actionPermissions-C8YYU92K.mjs +22 -0
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-BXY4i-hw.mjs → adapters-D0tT2Tyo.mjs} +54 -0
- package/dist/audit/index.d.mts +2 -2
- package/dist/audit/index.mjs +15 -17
- 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-BBRVhjQN.mjs → betterAuthOpenApi-DwxtK3uG.mjs} +1 -1
- package/dist/cache/index.d.mts +3 -2
- package/dist/cache/index.mjs +3 -3
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +37 -27
- package/dist/cli/commands/init.mjs +47 -34
- 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 +3 -3
- package/dist/core/index.mjs +4 -3
- package/dist/core-DXdSSFW-.mjs +1037 -0
- package/dist/createActionRouter-BwaSM0No.mjs +166 -0
- package/dist/{createApp-BuvPma24.mjs → createApp-DvNYEhpb.mjs} +118 -36
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{elevation-C7hgL_aI.mjs → elevation-DOFoxoDs.mjs} +1 -1
- package/dist/errorHandler-Co3lnVmJ.d.mts +114 -0
- package/dist/{eventPlugin-DCUjuiQT.mjs → eventPlugin--5HIkdPU.mjs} +1 -1
- package/dist/{eventPlugin-CxWgpd6K.d.mts → eventPlugin-CUNjYYRY.d.mts} +1 -1
- package/dist/events/index.d.mts +4 -4
- package/dist/events/index.mjs +69 -51
- 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-Lo1VUDpt.d.mts → fields-C8Y0XLAu.d.mts} +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/index.mjs +38 -27
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-ChIw3776.d.mts → index-BYCqHCVu.d.mts} +4 -4
- package/dist/{index-Cl0uoKd5.d.mts → index-Cm0vUrr_.d.mts} +2100 -1688
- package/dist/{index-DStwgFUK.d.mts → index-DAushRTt.d.mts} +29 -10
- package/dist/index-DsJ1MNfC.d.mts +1179 -0
- package/dist/{index-8qw4y6ff.d.mts → index-t8pLpPFW.d.mts} +13 -10
- package/dist/index.d.mts +7 -251
- package/dist/index.mjs +8 -128
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/streamline.d.mts +46 -5
- package/dist/integrations/streamline.mjs +50 -21
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +2 -154
- package/dist/integrations/websocket.mjs +292 -224
- package/dist/{keys-qcD-TVJl.mjs → keys-CARyUjiR.mjs} +2 -0
- package/dist/{loadResources-BAzJItAJ.mjs → loadResources-YNwKHvRA.mjs} +3 -1
- package/dist/logger/index.d.mts +81 -0
- package/dist/{logger-DLg8-Ueg.mjs → logger/index.mjs} +1 -6
- package/dist/middleware/index.d.mts +109 -0
- package/dist/middleware/index.mjs +70 -0
- package/dist/multipartBody-CvTR1Un6.mjs +123 -0
- package/dist/{openapi-B5F8AddX.mjs → openapi-C0L9ar7m.mjs} +9 -7
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +1 -3
- package/dist/{permissions-Dk6mshja.mjs → permissions-B4vU9L0Q.mjs} +220 -2
- package/dist/pipe-DVoIheVC.mjs +62 -0
- package/dist/pipeline/index.d.mts +62 -0
- package/dist/pipeline/index.mjs +53 -0
- package/dist/plugins/index.d.mts +25 -5
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +42 -24
- package/dist/presets/filesUpload.d.mts +4 -4
- 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 +48 -8
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-fLJVXdVn.mjs → presets-k604Lj99.mjs} +1 -1
- package/dist/queryCachePlugin-BUXBSm4F.d.mts +34 -0
- package/dist/{queryCachePlugin-DQCEfJis.mjs → queryCachePlugin-Bq6bO6vc.mjs} +3 -3
- package/dist/{redis-DqyeggCa.d.mts → redis-Cm1gnRDf.d.mts} +1 -1
- package/dist/{redis-stream-CakIQmwR.d.mts → redis-stream-CM8TXTix.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{requestContext-xHIKedG6.mjs → requestContext-CfRkaxwf.mjs} +1 -1
- package/dist/{resourceToTools-BElv3xPT.mjs → resourceToTools--okX6QBr.mjs} +534 -415
- package/dist/routerShared-DeESFp4a.mjs +515 -0
- package/dist/schemaIR-BlG9bY7v.mjs +137 -0
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +1 -1
- package/dist/{sse-yBCgOLGu.mjs → sse-V7aXc3bW.mjs} +1 -1
- package/dist/{store-helpers-ZCSMJJAX.mjs → store-helpers-BhrzxvyQ.mjs} +4 -0
- package/dist/testing/index.d.mts +367 -711
- package/dist/testing/index.mjs +646 -1434
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/{tracing-65B51Dw3.d.mts → tracing-DokiEsuz.d.mts} +9 -4
- package/dist/types/index.d.mts +5 -5
- package/dist/types/index.mjs +1 -3
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-Co8k3NyS.d.mts → types-CgikqKAj.d.mts} +133 -21
- package/dist/{types-Btdda02s.d.mts → types-D9NqiYIw.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -898
- package/dist/utils/index.mjs +4 -5
- package/dist/utils-D3Yxnrwr.mjs +1639 -0
- package/dist/versioning-M9lNLhO8.d.mts +117 -0
- package/dist/websocket-CyJ1VIFI.d.mts +186 -0
- package/package.json +26 -8
- package/skills/arc/SKILL.md +124 -39
- package/skills/arc/references/testing.md +212 -183
- package/dist/applyPermissionResult-QhV1Pa-g.mjs +0 -37
- package/dist/core-CcR01lup.mjs +0 -1411
- package/dist/createActionRouter-Bp_5c_2b.mjs +0 -249
- package/dist/errorHandler-DRQ3EqfL.d.mts +0 -218
- package/dist/errors-CCSsMpXE.d.mts +0 -140
- package/dist/fields-bxkeltzz.mjs +0 -126
- package/dist/filesUpload-t21LS-py.mjs +0 -377
- package/dist/queryParser-DBqBB6AC.mjs +0 -352
- package/dist/types-Csi3FLfq.mjs +0 -27
- package/dist/utils-B2fNOD_i.mjs +0 -929
- /package/dist/{EventTransport-CUw5NNWe.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
- /package/dist/{HookSystem-BNYKnrXF.mjs → HookSystem-CGsMd6oK.mjs} +0 -0
- /package/dist/{ResourceRegistry-BPd6NQDm.mjs → ResourceRegistry-DkAeAuTX.mjs} +0 -0
- /package/dist/{caching-CBpK_SCM.mjs → caching-CheW3m-S.mjs} +0 -0
- /package/dist/{elevation-C5SwtkAn.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
- /package/dist/{errorHandler-Bb49BvPD.mjs → errorHandler-BQm8ZxTK.mjs} +0 -0
- /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
- /package/dist/{interface-CSbZdv_3.d.mts → interface-CkkWm5uR.d.mts} +0 -0
- /package/dist/{interface-D218ikEo.d.mts → interface-Da0r7Lna.d.mts} +0 -0
- /package/dist/{memory-B5Amv9A1.mjs → memory-DikHSvWa.mjs} +0 -0
- /package/dist/{metrics-DuhiSEZI.mjs → metrics-Csh4nsvv.mjs} +0 -0
- /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-BneOJkpi.mjs} +0 -0
- /package/dist/{registry-B3lRFBWo.mjs → registry-D63ee7fl.mjs} +0 -0
- /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-ByllIXXV.mjs} +0 -0
- /package/dist/{schemaConverter-BxFDdtXu.mjs → schemaConverter-B0oKLuqI.mjs} +0 -0
- /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
- /package/dist/{storage-CVk_SEn2.d.mts → storage-BwGQXUpd.d.mts} +0 -0
- /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
- /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
- /package/dist/{versioning-C2U_bLY0.mjs → versioning-CGPjkqAg.mjs} +0 -0
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--5HIkdPU.mjs";
|
|
2
|
+
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-BhrzxvyQ.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;
|
|
@@ -351,6 +377,7 @@ function repositoryAsOutboxStore(repository) {
|
|
|
351
377
|
if (typeof repository.findOneAndUpdate !== "function") missing.push("findOneAndUpdate");
|
|
352
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";
|
|
354
381
|
/**
|
|
355
382
|
* Unwrap mongokit's pagination envelope ({ docs, total, ... }) — some
|
|
356
383
|
* kits may return a bare array when pagination is disabled. Handle both.
|
|
@@ -362,13 +389,20 @@ function repositoryAsOutboxStore(repository) {
|
|
|
362
389
|
const isDuplicateKeyError = createIsDuplicateKeyError(repository);
|
|
363
390
|
const safeGetOne = createSafeGetOne(repository);
|
|
364
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)));
|
|
365
399
|
return {
|
|
366
400
|
async save(event, options) {
|
|
367
401
|
if (!event?.type || typeof event.type !== "string") throw new InvalidOutboxEventError("event.type is required");
|
|
368
402
|
if (!event.meta?.id || typeof event.meta.id !== "string") throw new InvalidOutboxEventError("event.meta.id is required");
|
|
369
403
|
const now = /* @__PURE__ */ new Date();
|
|
370
404
|
const doc = {
|
|
371
|
-
|
|
405
|
+
[idField]: event.meta.id,
|
|
372
406
|
event,
|
|
373
407
|
type: event.type,
|
|
374
408
|
status: "pending",
|
|
@@ -395,11 +429,7 @@ function repositoryAsOutboxStore(repository) {
|
|
|
395
429
|
async getPending(limit) {
|
|
396
430
|
const now = /* @__PURE__ */ new Date();
|
|
397
431
|
return unwrapDocs(await r.getAll({
|
|
398
|
-
filters:
|
|
399
|
-
status: "pending",
|
|
400
|
-
visibleAt: { $lte: now },
|
|
401
|
-
$or: [{ leaseOwner: null }, { leaseExpiresAt: { $lte: now } }]
|
|
402
|
-
},
|
|
432
|
+
filters: claimableFilter(now),
|
|
403
433
|
sort: { createdAt: 1 },
|
|
404
434
|
page: 1,
|
|
405
435
|
limit
|
|
@@ -409,23 +439,19 @@ function repositoryAsOutboxStore(repository) {
|
|
|
409
439
|
const limit = options?.limit ?? DEFAULT_CLAIM_LIMIT;
|
|
410
440
|
const leaseMs = options?.leaseMs ?? DEFAULT_LEASE_MS$1;
|
|
411
441
|
const consumerId = options?.consumerId ?? "anonymous";
|
|
412
|
-
const typeFilter = options?.types?.length ?
|
|
442
|
+
const typeFilter = options?.types?.length ? anyOf("type", options.types) : null;
|
|
413
443
|
const claimed = [];
|
|
414
444
|
for (let i = 0; i < limit; i++) {
|
|
415
445
|
const now = /* @__PURE__ */ new Date();
|
|
416
446
|
const leaseExpiresAt = new Date(now.getTime() + leaseMs);
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
$or: [{ leaseOwner: null }, { leaseExpiresAt: { $lte: now } }],
|
|
421
|
-
...typeFilter
|
|
422
|
-
}, {
|
|
423
|
-
$set: {
|
|
447
|
+
const filter = typeFilter ? and(claimableFilter(now), typeFilter) : claimableFilter(now);
|
|
448
|
+
const doc = await r.findOneAndUpdate(filter, update({
|
|
449
|
+
set: {
|
|
424
450
|
leaseOwner: consumerId,
|
|
425
451
|
leaseExpiresAt
|
|
426
452
|
},
|
|
427
|
-
|
|
428
|
-
}, {
|
|
453
|
+
inc: { attempts: 1 }
|
|
454
|
+
}), {
|
|
429
455
|
sort: { createdAt: 1 },
|
|
430
456
|
returnDocument: "after"
|
|
431
457
|
});
|
|
@@ -436,18 +462,15 @@ function repositoryAsOutboxStore(repository) {
|
|
|
436
462
|
},
|
|
437
463
|
async acknowledge(eventId, options) {
|
|
438
464
|
const now = /* @__PURE__ */ new Date();
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
};
|
|
443
|
-
if (options?.consumerId) filter.leaseOwner = options.consumerId;
|
|
444
|
-
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: {
|
|
445
468
|
status: "delivered",
|
|
446
469
|
deliveredAt: now,
|
|
447
470
|
leaseOwner: null,
|
|
448
471
|
leaseExpiresAt: null
|
|
449
|
-
} }, { returnDocument: "after" })) return;
|
|
450
|
-
const current = await safeGetOne(
|
|
472
|
+
} }), { returnDocument: "after" })) return;
|
|
473
|
+
const current = await safeGetOne(eq(idField, eventId));
|
|
451
474
|
if (!current) return;
|
|
452
475
|
if (current.status === "delivered") return;
|
|
453
476
|
if (options?.consumerId && current.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, current.leaseOwner);
|
|
@@ -456,32 +479,30 @@ function repositoryAsOutboxStore(repository) {
|
|
|
456
479
|
const now = /* @__PURE__ */ new Date();
|
|
457
480
|
const targetStatus = options?.deadLetter ? "dead_letter" : "pending";
|
|
458
481
|
const visibleAt = options?.retryAt ?? now;
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
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: {
|
|
462
493
|
status: targetStatus,
|
|
463
494
|
visibleAt,
|
|
464
495
|
leaseOwner: null,
|
|
465
496
|
leaseExpiresAt: null,
|
|
466
497
|
lastFailedAt: now,
|
|
467
|
-
lastError:
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
},
|
|
471
|
-
firstFailedAt: { $ifNull: ["$firstFailedAt", now] }
|
|
472
|
-
} }];
|
|
473
|
-
if (await r.findOneAndUpdate(filter, pipeline, {
|
|
474
|
-
returnDocument: "after",
|
|
475
|
-
updatePipeline: true
|
|
476
|
-
})) return;
|
|
477
|
-
const current = await safeGetOne({ _id: eventId });
|
|
478
|
-
if (!current) return;
|
|
479
|
-
if (options?.consumerId && current.leaseOwner !== options.consumerId) throw new OutboxOwnershipError(eventId, options.consumerId, current.leaseOwner);
|
|
498
|
+
lastError: errorInfo,
|
|
499
|
+
firstFailedAt
|
|
500
|
+
} }), { returnDocument: "after" });
|
|
480
501
|
},
|
|
481
502
|
async getDeadLettered(limit) {
|
|
482
503
|
return unwrapDocs(await r.getAll({
|
|
483
|
-
filters:
|
|
484
|
-
sort: {
|
|
504
|
+
filters: eq("status", "dead_letter"),
|
|
505
|
+
sort: { [idField]: 1 },
|
|
485
506
|
page: 1,
|
|
486
507
|
limit
|
|
487
508
|
})).filter((d) => isWellFormed(d.event)).map((d) => ({
|
|
@@ -500,18 +521,15 @@ function repositoryAsOutboxStore(repository) {
|
|
|
500
521
|
let totalDeleted = 0;
|
|
501
522
|
for (;;) {
|
|
502
523
|
const batch = unwrapDocs(await r.getAll({
|
|
503
|
-
filters:
|
|
504
|
-
status: "delivered",
|
|
505
|
-
deliveredAt: { $lte: cutoff }
|
|
506
|
-
},
|
|
524
|
+
filters: and(eq("status", "delivered"), lte("deliveredAt", cutoff)),
|
|
507
525
|
sort: { deliveredAt: 1 },
|
|
508
526
|
page: 1,
|
|
509
527
|
limit: DEFAULT_PURGE_BATCH,
|
|
510
|
-
select:
|
|
528
|
+
select: idField
|
|
511
529
|
}));
|
|
512
530
|
if (batch.length === 0) break;
|
|
513
|
-
const ids = batch.map((d) => d
|
|
514
|
-
const res = await r.deleteMany(
|
|
531
|
+
const ids = batch.map((d) => d[idField]);
|
|
532
|
+
const res = await r.deleteMany(anyOf(idField, ids));
|
|
515
533
|
totalDeleted += res.deletedCount ?? 0;
|
|
516
534
|
if (batch.length < DEFAULT_PURGE_BATCH) break;
|
|
517
535
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-
|
|
1
|
+
import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-CM8TXTix.mjs";
|
|
2
2
|
export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
|
|
@@ -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-CgikqKAj.mjs";
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/factory/createApp.d.ts
|
package/dist/factory/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-
|
|
2
|
-
import { t as loadResources } from "../loadResources-
|
|
1
|
+
import { a as edgePreset, c as testingPreset, i as developmentPreset, n as createApp, o as getPreset, s as productionPreset, t as ArcFactory } from "../createApp-DvNYEhpb.mjs";
|
|
2
|
+
import { t as loadResources } from "../loadResources-YNwKHvRA.mjs";
|
|
3
3
|
//#region src/factory/edge.ts
|
|
4
4
|
/**
|
|
5
5
|
* Convert a Fastify app into a Web Standards fetch handler.
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cn as beforeUpdate, Sn as beforeDelete, Tn as defineHook, _n as HookSystemOptions, bn as afterUpdate, dn as HookContext, fn as HookHandler, gn as HookSystem, hn as HookRegistration, mn as HookPhase, pn as HookOperation, un as DefineHookOptions, vn as afterCreate, wn as createHookSystem, xn as beforeCreate, yn as afterDelete } from "../index-Cm0vUrr_.mjs";
|
|
2
2
|
export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
package/dist/hooks/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-
|
|
1
|
+
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-CGsMd6oK.mjs";
|
|
2
2
|
export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-
|
|
3
|
-
import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-
|
|
1
|
+
import { jn as RepositoryLike } from "../index-Cm0vUrr_.mjs";
|
|
2
|
+
import { i as createIdempotencyResult, n as IdempotencyResult, r as IdempotencyStore, t as IdempotencyLock } from "../interface-CkkWm5uR.mjs";
|
|
3
|
+
import { i as RedisIdempotencyStoreOptions, n as RedisClient } from "../redis-Cm1gnRDf.mjs";
|
|
4
4
|
import { FastifyPluginAsync } from "fastify";
|
|
5
5
|
|
|
6
6
|
//#region src/idempotency/idempotencyPlugin.d.ts
|
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-
|
|
1
|
+
import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-BhrzxvyQ.mjs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
|
+
import { and, eq, exists, gt, lt, or, startsWith } from "@classytic/repo-core/filter";
|
|
5
|
+
import { update } from "@classytic/repo-core/update";
|
|
4
6
|
//#region src/idempotency/repository-idempotency-adapter.ts
|
|
7
|
+
/**
|
|
8
|
+
* RepositoryLike → IdempotencyStore adapter.
|
|
9
|
+
*
|
|
10
|
+
* Maps the idempotency store's verbs (get / set / tryLock / unlock / delete /
|
|
11
|
+
* deleteByPrefix / findByPrefix) onto arc's canonical repository primitives
|
|
12
|
+
* (`getOne` / `deleteMany` / `findOneAndUpdate`). `idempotencyPlugin` wraps
|
|
13
|
+
* a passed repository with this helper when you use the `{ repository }`
|
|
14
|
+
* option; the function is also re-exported from `@classytic/arc/idempotency`
|
|
15
|
+
* so consumers can build and decorate the store (metrics, tracing, key
|
|
16
|
+
* namespacing) before passing it via `store:`.
|
|
17
|
+
*
|
|
18
|
+
* Portability: filters compose via `@classytic/repo-core/filter` builders
|
|
19
|
+
* (`and` / `or` / `eq` / `gt` / `lt` / `exists` / `startsWith`) and updates
|
|
20
|
+
* via `@classytic/repo-core/update` (`update({ set, unset, setOnInsert })`).
|
|
21
|
+
* Both IRs compile to Mongo operators on mongokit, SQL predicates on
|
|
22
|
+
* sqlitekit / pgkit, and `WhereInput` / `update` on prismakit. The store
|
|
23
|
+
* therefore runs identically on every backend that implements the
|
|
24
|
+
* `StandardRepo.findOneAndUpdate` + `getOne` + `deleteMany` surface.
|
|
25
|
+
*/
|
|
5
26
|
function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
|
|
6
27
|
const missing = [];
|
|
7
28
|
if (typeof repository.getOne !== "function") missing.push("getOne");
|
|
@@ -9,13 +30,13 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
|
|
|
9
30
|
if (typeof repository.findOneAndUpdate !== "function") missing.push("findOneAndUpdate");
|
|
10
31
|
if (missing.length > 0) throw new Error(`idempotencyPlugin: repository is missing required methods: ${missing.join(", ")}. mongokit ≥3.8 satisfies these; other kits must implement them to back idempotency via a repository.`);
|
|
11
32
|
const r = repository;
|
|
33
|
+
const idField = repository.idField ?? "_id";
|
|
12
34
|
const isDuplicateKeyError = createIsDuplicateKeyError(repository);
|
|
13
35
|
const safeGetOne = createSafeGetOne(repository);
|
|
14
|
-
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15
36
|
return {
|
|
16
37
|
name: "repository",
|
|
17
38
|
async get(key) {
|
|
18
|
-
const doc = await safeGetOne(
|
|
39
|
+
const doc = await safeGetOne(eq(idField, key));
|
|
19
40
|
if (!doc?.result) return void 0;
|
|
20
41
|
if (new Date(doc.expiresAt) < /* @__PURE__ */ new Date()) return void 0;
|
|
21
42
|
return {
|
|
@@ -28,8 +49,8 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
|
|
|
28
49
|
};
|
|
29
50
|
},
|
|
30
51
|
async set(key, result) {
|
|
31
|
-
await r.findOneAndUpdate(
|
|
32
|
-
|
|
52
|
+
await r.findOneAndUpdate(eq(idField, key), update({
|
|
53
|
+
set: {
|
|
33
54
|
result: {
|
|
34
55
|
statusCode: result.statusCode,
|
|
35
56
|
headers: result.headers,
|
|
@@ -38,8 +59,8 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
|
|
|
38
59
|
createdAt: result.createdAt,
|
|
39
60
|
expiresAt: result.expiresAt
|
|
40
61
|
},
|
|
41
|
-
|
|
42
|
-
}, {
|
|
62
|
+
unset: ["lock"]
|
|
63
|
+
}), {
|
|
43
64
|
upsert: true,
|
|
44
65
|
returnDocument: "after"
|
|
45
66
|
});
|
|
@@ -49,19 +70,16 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
|
|
|
49
70
|
const lockExpiresAt = new Date(now.getTime() + ttlMs);
|
|
50
71
|
const docExpiresAt = new Date(now.getTime() + defaultTtlMs);
|
|
51
72
|
try {
|
|
52
|
-
const doc = await r.findOneAndUpdate({
|
|
53
|
-
|
|
54
|
-
$or: [{ lock: { $exists: false } }, { "lock.expiresAt": { $lt: now } }]
|
|
55
|
-
}, {
|
|
56
|
-
$set: { lock: {
|
|
73
|
+
const doc = await r.findOneAndUpdate(and(eq(idField, key), or(exists("lock", false), lt("lock.expiresAt", now))), update({
|
|
74
|
+
set: { lock: {
|
|
57
75
|
requestId,
|
|
58
76
|
expiresAt: lockExpiresAt
|
|
59
77
|
} },
|
|
60
|
-
|
|
78
|
+
setOnInsert: {
|
|
61
79
|
createdAt: now,
|
|
62
80
|
expiresAt: docExpiresAt
|
|
63
81
|
}
|
|
64
|
-
}, {
|
|
82
|
+
}), {
|
|
65
83
|
upsert: true,
|
|
66
84
|
returnDocument: "after"
|
|
67
85
|
});
|
|
@@ -72,31 +90,24 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
|
|
|
72
90
|
}
|
|
73
91
|
},
|
|
74
92
|
async unlock(key, requestId) {
|
|
75
|
-
await r.findOneAndUpdate({
|
|
76
|
-
_id: key,
|
|
77
|
-
"lock.requestId": requestId
|
|
78
|
-
}, { $unset: { lock: "" } });
|
|
93
|
+
await r.findOneAndUpdate(and(eq(idField, key), eq("lock.requestId", requestId)), update({ unset: ["lock"] }));
|
|
79
94
|
},
|
|
80
95
|
async isLocked(key) {
|
|
81
|
-
const doc = await safeGetOne(
|
|
96
|
+
const doc = await safeGetOne(eq(idField, key));
|
|
82
97
|
if (!doc?.lock) return false;
|
|
83
98
|
return new Date(doc.lock.expiresAt) > /* @__PURE__ */ new Date();
|
|
84
99
|
},
|
|
85
100
|
async delete(key) {
|
|
86
|
-
await r.deleteMany(
|
|
101
|
+
await r.deleteMany(eq(idField, key));
|
|
87
102
|
},
|
|
88
103
|
async deleteByPrefix(prefix) {
|
|
89
|
-
return (await r.deleteMany(
|
|
104
|
+
return (await r.deleteMany(startsWith(idField, prefix, "sensitive"))).deletedCount ?? 0;
|
|
90
105
|
},
|
|
91
106
|
async findByPrefix(prefix) {
|
|
92
|
-
const doc = await safeGetOne(
|
|
93
|
-
_id: { $regex: `^${escapeRegex(prefix)}` },
|
|
94
|
-
result: { $exists: true },
|
|
95
|
-
expiresAt: { $gt: /* @__PURE__ */ new Date() }
|
|
96
|
-
});
|
|
107
|
+
const doc = await safeGetOne(and(startsWith(idField, prefix, "sensitive"), exists("result", true), gt("expiresAt", /* @__PURE__ */ new Date())));
|
|
97
108
|
if (!doc?.result) return void 0;
|
|
98
109
|
return {
|
|
99
|
-
key: doc
|
|
110
|
+
key: String(doc[idField] ?? prefix),
|
|
100
111
|
statusCode: doc.result.statusCode,
|
|
101
112
|
headers: doc.result.headers,
|
|
102
113
|
body: doc.result.body,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-
|
|
1
|
+
import { a as UpstashRedisLike, i as RedisIdempotencyStoreOptions, n as RedisClient, o as ioredisAsIdempotencyClient, r as RedisIdempotencyStore, s as upstashAsIdempotencyClient, t as IoredisLike } from "../redis-Cm1gnRDf.mjs";
|
|
2
2
|
export { type IoredisLike, type RedisClient, RedisIdempotencyStore, type RedisIdempotencyStoreOptions, type UpstashRedisLike, ioredisAsIdempotencyClient, upstashAsIdempotencyClient };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { FastifyRequest } from "fastify";
|
|
1
|
+
import { r as CacheStore, t as CacheLogger } from "./interface-Da0r7Lna.mjs";
|
|
2
|
+
import { r as RequestScope } from "./types-tgR4Pt8F.mjs";
|
|
3
|
+
import { c as PermissionCheck, l as PermissionContext, u as PermissionResult } from "./fields-C8Y0XLAu.mjs";
|
|
4
|
+
import { FastifyReply, FastifyRequest } from "fastify";
|
|
5
5
|
|
|
6
6
|
//#region src/permissions/applyPermissionResult.d.ts
|
|
7
7
|
/**
|