@classytic/arc 2.31.0 → 2.32.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/dist/{BaseController-De7GqHck.mjs → BaseController-Dk34dxhI.mjs} +16 -13
- package/dist/{EventTransport-9mlTgqzE.mjs → EventTransport-BV10D0oG.mjs} +1 -1
- package/dist/{HookSystem-BcmPyq5I.mjs → HookSystem-vimw5D7Z.mjs} +2 -2
- package/dist/{ResourceRegistry-qq0mn2s9.mjs → ResourceRegistry-BVr7PgA0.mjs} +17 -15
- package/dist/{actionPermissions-BE5NwaQk.mjs → actionPermissions-Dti7ebyv.mjs} +1 -1
- package/dist/audit/index.mjs +2 -2
- package/dist/auth/audit.mjs +1 -1
- package/dist/auth/index.mjs +11 -10
- package/dist/auth/redis-session.mjs +1 -1
- package/dist/{authorizationDecision-ChvUQGG1.mjs → authorizationDecision-__T3EJDA.mjs} +2 -2
- package/dist/{buildHandler-CDrCJzmB.mjs → buildHandler-Dn7rzUJo.mjs} +6 -5
- package/dist/cache/index.mjs +4 -4
- package/dist/{caching-BFHA6Scf.mjs → caching-DFJqHyFs.mjs} +2 -2
- package/dist/cleanup/index.d.mts +36 -14
- package/dist/cleanup/index.mjs +45 -29
- package/dist/cli/commands/describe.mjs +4 -6
- package/dist/cli/commands/docs.mjs +3 -3
- package/dist/cli/commands/doctor.mjs +1 -1
- package/dist/cli/commands/generate.mjs +2 -2
- package/dist/cli/commands/init.mjs +2 -2
- package/dist/cli/commands/introspect.mjs +2 -2
- package/dist/cli/index.mjs +3 -3
- package/dist/{constants-D3Dv4LAV.mjs → constants-J99LGTJI.mjs} +1 -1
- package/dist/context/index.mjs +3 -3
- package/dist/core/index.d.mts +1 -1
- package/dist/core/index.mjs +7 -7
- package/dist/{core-BGpIxINN.mjs → core-BwwmNSp7.mjs} +3 -3
- package/dist/{createActionRouter-CDXEdasl.mjs → createActionRouter-DkJZWo0m.mjs} +14 -11
- package/dist/{createAggregationRouter-KrQDzx-k.mjs → createAggregationRouter-B1exOVD8.mjs} +10 -8
- package/dist/{createApp-Df89BEni.mjs → createApp-Bv0m-Q6_.mjs} +182 -61
- package/dist/{defineAggregation-DbPPS8RI.mjs → defineAggregation-gX4No1gt.mjs} +1 -1
- package/dist/{defineResource-Bv6EtN1x.mjs → defineResource-XFPPUu2c.mjs} +41 -32
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.mjs +3 -3
- package/dist/{elevation-D2l1mh4g.mjs → elevation-DNXXxgjl.mjs} +4 -4
- package/dist/encryption/index.mjs +5 -4
- package/dist/{errorHandler-C5NeD6bT.mjs → errorHandler-B2AZUJUj.mjs} +3 -3
- package/dist/{errors-Cj42AntO.mjs → errors-Bh1KK5ps.mjs} +1 -1
- package/dist/{eventPlugin-CkffEihm.mjs → eventPlugin-Dk_TyXeE.mjs} +8 -7
- package/dist/events/index.d.mts +108 -41
- package/dist/events/index.mjs +166 -142
- package/dist/events/transports/redis-stream-entry.mjs +14 -10
- package/dist/events/transports/redis.mjs +1 -1
- package/dist/factory/index.d.mts +5 -5
- package/dist/factory/index.mjs +131 -8
- package/dist/fastify-augmentation-BppG5bMT.d.mts +179 -0
- package/dist/{fields-CB5Cuzk9.mjs → fields-DEi65pGj.mjs} +6 -11
- package/dist/{generate-EcA6ui4i.mjs → generate-CRSG0jTv.mjs} +2 -2
- package/dist/{headers-3zvE0rM3.mjs → headers-BXjQYbeC.mjs} +2 -2
- package/dist/{health-DjZYjM7H.mjs → health-5XnTa2uo.mjs} +1 -1
- package/dist/hooks/index.mjs +2 -2
- package/dist/idempotency/index.mjs +8 -6
- package/dist/idempotency/redis.mjs +1 -1
- package/dist/{index-Bc2ox8_U.d.mts → index-DXlHwvuE.d.mts} +1 -1
- package/dist/{index-CFThn1K9.d.mts → index-ZWhLTp_s.d.mts} +70 -4
- package/dist/{index-CEJNZFtX.d.mts → index-zq6VrjaB.d.mts} +70 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +11 -11
- package/dist/{init-BEiNZBsJ.mjs → init-BbfP8aky.mjs} +7 -5
- package/dist/integrations/event-gateway.mjs +2 -2
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs/index.mjs +3 -3
- package/dist/integrations/mcp/index.mjs +2 -2
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.mjs +3 -3
- package/dist/integrations/webhooks.mjs +1 -1
- package/dist/integrations/websocket-pushref-redis.mjs +1 -1
- package/dist/integrations/websocket-redis.mjs +1 -1
- package/dist/integrations/websocket.mjs +38 -35
- package/dist/{interface-DYzM0q-u.mjs → interface-BP4IJCBO.mjs} +1 -1
- package/dist/{jsonBody-BYbLDi5D.mjs → jsonBody-DDSR2HFl.mjs} +2 -2
- package/dist/{keys-C0_pa1tY.mjs → keys-B-HBTGXl.mjs} +1 -1
- package/dist/{loadResources-yawi9tAE.mjs → loadResources-DisEAmkm.mjs} +4 -3
- package/dist/{loadResourcesFromEntry-BAjYZonx.mjs → loadResourcesFromEntry-D1MJp13f.mjs} +2 -2
- package/dist/logger/index.mjs +1 -1
- package/dist/{mcpPlugin-B_es0hiF.mjs → mcpPlugin-CpfVpKHE.mjs} +32 -31
- package/dist/{memory-DR6wpa9F.mjs → memory-DsuWnj4T.mjs} +5 -5
- package/dist/{metrics-CUdw_wLB.mjs → metrics-DdQL8syd.mjs} +2 -2
- package/dist/middleware/index.mjs +3 -3
- package/dist/migrations/index.mjs +3 -3
- package/dist/{module-0pFJA6YW.mjs → module-Br81am6m.mjs} +1 -1
- package/dist/{multipartBody-wOgj_fnj.mjs → multipartBody-BnkBLN7v.mjs} +3 -3
- package/dist/{openapi-B2L4js1v.mjs → openapi-DIRzvxC0.mjs} +6 -6
- package/dist/outbox-admin/index.d.mts +85 -0
- package/dist/outbox-admin/index.mjs +115 -0
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +6 -6
- package/dist/{permissions-L--QDAir.mjs → permissions-Dl_m0NCe.mjs} +101 -8
- package/dist/{pipe-DRDNsI2T.mjs → pipe-ELHCP3zj.mjs} +3 -5
- package/dist/pipeline/index.mjs +2 -2
- package/dist/{pipeline-UPQFatit.mjs → pipeline-CPA-jx0M.mjs} +17 -15
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/index.mjs +16 -16
- package/dist/plugins/response-cache.mjs +2 -2
- package/dist/plugins/tracing-entry.mjs +2 -2
- package/dist/{pluralize-O0FZgESl.mjs → pluralize-C2ZkKbsn.mjs} +1 -1
- package/dist/{preloadResources-Dz6BjzM6.mjs → preloadResources-CDs87fTw.mjs} +1 -1
- package/dist/{preloadResources-CyoJMSiO.d.mts → preloadResources-T1hmlTEZ.d.mts} +2 -2
- package/dist/presets/filesUpload.mjs +6 -6
- package/dist/presets/index.mjs +2 -2
- package/dist/presets/multiTenant.mjs +3 -3
- package/dist/presets/search.mjs +2 -2
- package/dist/{presets-C4-g4_4P.mjs → presets-Dntd_pUO.mjs} +6 -5
- package/dist/{projection-BHw6xlOQ.mjs → projection-CjHhM5W1.mjs} +2 -2
- package/dist/{queryCachePlugin-BZr8v46E.mjs → queryCachePlugin-Dhps-Ldt.mjs} +6 -6
- package/dist/{rateLimit-CMPY5Qms.mjs → rateLimit-C7mmAGs3.mjs} +2 -2
- package/dist/{rateLimitKey-Dn5JNmkj.mjs → rateLimitKey-CccEFBfk.mjs} +1 -1
- package/dist/{realtime-C5NoxWFY.mjs → realtime-DVvVZZFz.mjs} +10 -10
- package/dist/{registerRoute-CBN84fc7.mjs → registerRoute-B_QrjYZS.mjs} +10 -8
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +3 -3
- package/dist/{registry-4213U4zb.mjs → registry-DqUmzA9W.mjs} +2 -2
- package/dist/{renewingLease-Dll8mGgc.mjs → renewingLease-BpP9wwj7.mjs} +1 -1
- package/dist/{replyHelpers-DIiZKGUt.mjs → replyHelpers-DS-P0b32.mjs} +2 -2
- package/dist/{repositoryFilter-f9eAfq_l.mjs → repositoryFilter-DotlxG3L.mjs} +1 -1
- package/dist/{requestContext-2TxXOJ7T.mjs → requestContext-B6vQF-sy.mjs} +1 -1
- package/dist/{rolldown-runtime-CUsjNX9R.mjs → rolldown-runtime-BhflRrBs.mjs} +1 -1
- package/dist/{schedules-DdtlICTf.mjs → schedules-C2Q3uv2d.mjs} +3 -3
- package/dist/{schemaConverter-D--wdJM-.mjs → schemaConverter-Crjvczi_.mjs} +1 -1
- package/dist/{schemaIR-Bm2enbnh.mjs → schemaIR-CnyKK_1j.mjs} +2 -2
- package/dist/schemas/index.mjs +1 -1
- package/dist/scim/index.mjs +2 -2
- package/dist/scope/index.mjs +5 -5
- package/dist/{scope-DHx5Fous.mjs → scope-afz_Ieek.mjs} +4 -4
- package/dist/{simpleEqualityMatcher-DjQJ7FKA.mjs → simpleEqualityMatcher-C4KiMWUa.mjs} +1 -1
- package/dist/{sse-CUTo9y0X.mjs → sse-B9P4Y-UI.mjs} +7 -6
- package/dist/{sseStream-B_5XcVVd.mjs → sseStream-B3zb_d1h.mjs} +2 -2
- package/dist/{store-helpers-D1MP_gRG.mjs → store-helpers-DmEMHlPQ.mjs} +1 -1
- package/dist/{streaming-PSZwi8JV.mjs → streaming-DPZdQmDz.mjs} +1 -1
- package/dist/{subscribe-helpers-C0Tb2aUp.mjs → subscribe-helpers-sp5xTDVA.mjs} +2 -2
- package/dist/sync/changelog.mjs +1 -1
- package/dist/testing/cleanupStoreContract.mjs +10 -6
- package/dist/testing/index.d.mts +31 -4
- package/dist/testing/index.mjs +97 -39
- package/dist/testing/outboxStoreContract.d.mts +11 -2
- package/dist/testing/outboxStoreContract.mjs +110 -21
- package/dist/testing/storageContract.mjs +11 -6
- package/dist/{transactionContext-dAfBVUrk.mjs → transactionContext-BvLKvOIL.mjs} +1 -1
- package/dist/{typeGuards-B0ryPo3I.mjs → typeGuards-B_5-hKjJ.mjs} +1 -1
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.mjs +1 -1
- package/dist/{types-CBgvkp8O.d.mts → types-CT5vu6M0.d.mts} +87 -11
- package/dist/{types-Cys0ko9Z.mjs → types-DXYX7dIR.mjs} +4 -4
- package/dist/usage/index.mjs +0 -0
- package/dist/{userHelpers-ChYJ6CdK.mjs → userHelpers-BNsOXzOd.mjs} +1 -1
- package/dist/utils/index.mjs +10 -10
- package/dist/{utils-vL8BrDE2.mjs → utils-BtOha_Sp.mjs} +3 -3
- package/dist/{validate-_KbifpHF.mjs → validate-PMCPR9El.mjs} +2 -2
- package/dist/{versioning-CHDTor3P.mjs → versioning-CKv2jz_U.mjs} +4 -4
- package/package.json +23 -13
- package/dist/fastify-augmentation-zh0_AYHa.d.mts +0 -85
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
2
|
import { OutboxOwnershipError } from "@classytic/primitives/outbox";
|
|
3
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
3
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
4
4
|
//#region src/testing/outboxStoreContract.ts
|
|
5
5
|
let seq = 0;
|
|
6
6
|
/** A minimal well-formed event. Ids are unique per call. */
|
|
@@ -30,9 +30,16 @@ function runOutboxStoreContract(name, setup) {
|
|
|
30
30
|
afterAll(async () => {
|
|
31
31
|
if (teardown) await teardown();
|
|
32
32
|
});
|
|
33
|
+
/**
|
|
34
|
+
* Isolation for EVERY test, not just the ones that call `seed()`. Resetting inside
|
|
35
|
+
* `seed()` left any test that asserts on an empty store — or that only reads —
|
|
36
|
+
* running against its predecessor's rows.
|
|
37
|
+
*/
|
|
38
|
+
beforeEach(async () => {
|
|
39
|
+
await reset();
|
|
40
|
+
});
|
|
33
41
|
/** Save n events, oldest first. */
|
|
34
42
|
async function seed(n, type) {
|
|
35
|
-
if (reset) await reset();
|
|
36
43
|
const events = [];
|
|
37
44
|
for (let i = 0; i < n; i++) {
|
|
38
45
|
const e = event(type);
|
|
@@ -44,10 +51,10 @@ function runOutboxStoreContract(name, setup) {
|
|
|
44
51
|
describe("save — rejects malformed events (invariant 1)", () => {
|
|
45
52
|
it("persists a well-formed event", async () => {
|
|
46
53
|
const [e] = await seed(1);
|
|
47
|
-
|
|
54
|
+
const pending = await store.getPending(10);
|
|
55
|
+
expect(pending.map(idOf)).toContain(idOf(e));
|
|
48
56
|
});
|
|
49
57
|
it("THROWS rather than persisting an event with no `type`", async () => {
|
|
50
|
-
if (reset) await reset();
|
|
51
58
|
await expect(store.save({
|
|
52
59
|
payload: {},
|
|
53
60
|
meta: { id: "no-type" }
|
|
@@ -55,7 +62,6 @@ function runOutboxStoreContract(name, setup) {
|
|
|
55
62
|
expect((await store.getPending(10)).length).toBe(0);
|
|
56
63
|
});
|
|
57
64
|
it("THROWS rather than persisting an event with no `meta.id`", async () => {
|
|
58
|
-
if (reset) await reset();
|
|
59
65
|
await expect(store.save({
|
|
60
66
|
type: "x",
|
|
61
67
|
payload: {},
|
|
@@ -67,7 +73,8 @@ function runOutboxStoreContract(name, setup) {
|
|
|
67
73
|
describe("getPending", () => {
|
|
68
74
|
it("returns events FIFO (oldest first)", async () => {
|
|
69
75
|
const saved = await seed(3);
|
|
70
|
-
|
|
76
|
+
const pending = await store.getPending(10);
|
|
77
|
+
expect(pending.slice(0, 3).map(idOf)).toEqual(saved.map(idOf));
|
|
71
78
|
});
|
|
72
79
|
it("honours the limit", async () => {
|
|
73
80
|
await seed(3);
|
|
@@ -86,10 +93,11 @@ function runOutboxStoreContract(name, setup) {
|
|
|
86
93
|
it("claims pending events", async ({ skip }) => {
|
|
87
94
|
if (!store.claimPending) return skip();
|
|
88
95
|
await seed(2);
|
|
89
|
-
|
|
96
|
+
const claimed = await store.claimPending({
|
|
90
97
|
consumerId: "c1",
|
|
91
98
|
limit: 10
|
|
92
|
-
})
|
|
99
|
+
});
|
|
100
|
+
expect(claimed.length).toBe(2);
|
|
93
101
|
});
|
|
94
102
|
it("two concurrent claimers NEVER receive the same event", async ({ skip }) => {
|
|
95
103
|
if (!store.claimPending) return skip();
|
|
@@ -103,7 +111,8 @@ function runOutboxStoreContract(name, setup) {
|
|
|
103
111
|
})]);
|
|
104
112
|
const idsA = a.map(idOf);
|
|
105
113
|
const idsB = b.map(idOf);
|
|
106
|
-
|
|
114
|
+
const overlap = idsA.filter((id) => idsB.includes(id));
|
|
115
|
+
expect(overlap).toEqual([]);
|
|
107
116
|
expect(idsA.length + idsB.length).toBeLessThanOrEqual(6);
|
|
108
117
|
});
|
|
109
118
|
it("does not re-claim an event whose lease is still live", async ({ skip }) => {
|
|
@@ -114,10 +123,11 @@ function runOutboxStoreContract(name, setup) {
|
|
|
114
123
|
limit: 10,
|
|
115
124
|
leaseMs: 6e4
|
|
116
125
|
});
|
|
117
|
-
|
|
126
|
+
const second = await store.claimPending({
|
|
118
127
|
consumerId: "c2",
|
|
119
128
|
limit: 10
|
|
120
|
-
})
|
|
129
|
+
});
|
|
130
|
+
expect(second).toEqual([]);
|
|
121
131
|
});
|
|
122
132
|
it("RECLAIMS an event whose lease expired (crashed worker)", async ({ skip }) => {
|
|
123
133
|
if (!store.claimPending) return skip();
|
|
@@ -127,18 +137,20 @@ function runOutboxStoreContract(name, setup) {
|
|
|
127
137
|
limit: 10,
|
|
128
138
|
leaseMs: 0
|
|
129
139
|
});
|
|
130
|
-
|
|
140
|
+
const reclaimed = await store.claimPending({
|
|
131
141
|
consumerId: "c2",
|
|
132
142
|
limit: 10
|
|
133
|
-
})
|
|
143
|
+
});
|
|
144
|
+
expect(reclaimed.length).toBe(1);
|
|
134
145
|
});
|
|
135
146
|
it("claims FIFO", async ({ skip }) => {
|
|
136
147
|
if (!store.claimPending) return skip();
|
|
137
148
|
const saved = await seed(3);
|
|
138
|
-
|
|
149
|
+
const claimed = await store.claimPending({
|
|
139
150
|
consumerId: "c1",
|
|
140
151
|
limit: 2
|
|
141
|
-
})
|
|
152
|
+
});
|
|
153
|
+
expect(claimed.map(idOf)).toEqual(saved.slice(0, 2).map(idOf));
|
|
142
154
|
});
|
|
143
155
|
});
|
|
144
156
|
describe("acknowledge", () => {
|
|
@@ -148,7 +160,6 @@ function runOutboxStoreContract(name, setup) {
|
|
|
148
160
|
expect((await store.getPending(10)).map(idOf)).not.toContain(idOf(e));
|
|
149
161
|
});
|
|
150
162
|
it("is a NO-OP for an unknown id — never an ownership error (invariant 4)", async () => {
|
|
151
|
-
if (reset) await reset();
|
|
152
163
|
await expect(store.acknowledge("does-not-exist")).resolves.not.toThrow();
|
|
153
164
|
});
|
|
154
165
|
it("THROWS OutboxOwnershipError when consumerId is not the lease owner (invariant 3)", async ({ skip }) => {
|
|
@@ -185,10 +196,11 @@ function runOutboxStoreContract(name, setup) {
|
|
|
185
196
|
});
|
|
186
197
|
if (!claimed) return skip();
|
|
187
198
|
await store.fail(idOf(claimed), { message: "boom" });
|
|
188
|
-
|
|
199
|
+
const again = await store.claimPending({
|
|
189
200
|
consumerId: "c2",
|
|
190
201
|
limit: 10
|
|
191
|
-
})
|
|
202
|
+
});
|
|
203
|
+
expect(again.map(idOf)).toContain(idOf(claimed));
|
|
192
204
|
});
|
|
193
205
|
it("THROWS OutboxOwnershipError on a consumerId mismatch (invariant 3)", async ({ skip }) => {
|
|
194
206
|
if (!store.fail || !store.claimPending) return skip();
|
|
@@ -211,10 +223,11 @@ function runOutboxStoreContract(name, setup) {
|
|
|
211
223
|
});
|
|
212
224
|
if (!claimed) return skip();
|
|
213
225
|
await store.fail(idOf(claimed), { message: "boom" }, { retryAt: new Date(Date.now() + 6e4) });
|
|
214
|
-
|
|
226
|
+
const again = await store.claimPending({
|
|
215
227
|
consumerId: "c2",
|
|
216
228
|
limit: 10
|
|
217
|
-
})
|
|
229
|
+
});
|
|
230
|
+
expect(again.map(idOf)).not.toContain(idOf(claimed));
|
|
218
231
|
});
|
|
219
232
|
it("`deadLetter: true` removes it from the pending stream", async ({ skip }) => {
|
|
220
233
|
if (!store.fail) return skip();
|
|
@@ -242,6 +255,82 @@ function runOutboxStoreContract(name, setup) {
|
|
|
242
255
|
expect((await store.getPending(10)).length).toBe(2);
|
|
243
256
|
});
|
|
244
257
|
});
|
|
258
|
+
/**
|
|
259
|
+
* `requeue`, `countByStatus` and `oldestPendingAgeMs` were a HOST's three extra
|
|
260
|
+
* methods before they were contract members — which is why they are pinned here.
|
|
261
|
+
* A dead-letter row an operator cannot re-drive, or a health number that lies, fails
|
|
262
|
+
* silently: the operator concludes the queue is fine, and the whole point of the
|
|
263
|
+
* table is that somebody eventually looks.
|
|
264
|
+
*/
|
|
265
|
+
describe("requeue", () => {
|
|
266
|
+
it("returns a dead-lettered event to pending and clears the attempt count", async ({ skip }) => {
|
|
267
|
+
if (!store.fail || !store.requeue) return skip();
|
|
268
|
+
const [e] = await seed(1);
|
|
269
|
+
const id = idOf(e);
|
|
270
|
+
await store.fail(id, { message: "fatal" }, { deadLetter: true });
|
|
271
|
+
expect((await store.getPending(10)).length).toBe(0);
|
|
272
|
+
expect(await store.requeue(id)).toBe(true);
|
|
273
|
+
const pending = await store.getPending(10);
|
|
274
|
+
expect(pending.length).toBe(1);
|
|
275
|
+
if (store.countByStatus) expect(await store.countByStatus("dead_letter")).toBe(0);
|
|
276
|
+
});
|
|
277
|
+
it("REFUSES a pending event — requeue is dead-letter-scoped", async ({ skip }) => {
|
|
278
|
+
if (!store.requeue) return skip();
|
|
279
|
+
const [e] = await seed(1);
|
|
280
|
+
expect(await store.requeue(idOf(e))).toBe(false);
|
|
281
|
+
});
|
|
282
|
+
it("is FALSE, not an error, for an unknown id", async ({ skip }) => {
|
|
283
|
+
if (!store.requeue) return skip();
|
|
284
|
+
expect(await store.requeue("no-such-event")).toBe(false);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
describe("countByStatus", () => {
|
|
288
|
+
it("counts pending, and moves the count as events are delivered", async ({ skip }) => {
|
|
289
|
+
if (!store.countByStatus) return skip();
|
|
290
|
+
await seed(3);
|
|
291
|
+
expect(await store.countByStatus("pending")).toBe(3);
|
|
292
|
+
if (!store.claimPending) return skip();
|
|
293
|
+
const [claimed] = await store.claimPending({
|
|
294
|
+
consumerId: "c",
|
|
295
|
+
limit: 1,
|
|
296
|
+
leaseMs: 6e4
|
|
297
|
+
});
|
|
298
|
+
if (!claimed) return skip();
|
|
299
|
+
await store.acknowledge(idOf(claimed), { consumerId: "c" });
|
|
300
|
+
expect(await store.countByStatus("pending")).toBe(2);
|
|
301
|
+
expect(await store.countByStatus("delivered")).toBe(1);
|
|
302
|
+
});
|
|
303
|
+
it("counts dead-lettered rows — the number an alert fires on", async ({ skip }) => {
|
|
304
|
+
if (!store.countByStatus || !store.fail) return skip();
|
|
305
|
+
expect(await store.countByStatus("dead_letter")).toBe(0);
|
|
306
|
+
const [e] = await seed(1);
|
|
307
|
+
await store.fail(idOf(e), { message: "fatal" }, { deadLetter: true });
|
|
308
|
+
expect(await store.countByStatus("dead_letter")).toBe(1);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
describe("oldestPendingAgeMs", () => {
|
|
312
|
+
it("is null on an empty queue, and a non-negative age once something pends", async ({ skip }) => {
|
|
313
|
+
if (!store.oldestPendingAgeMs) return skip();
|
|
314
|
+
expect(await store.oldestPendingAgeMs()).toBeNull();
|
|
315
|
+
await seed(1);
|
|
316
|
+
const age = await store.oldestPendingAgeMs();
|
|
317
|
+
expect(age).not.toBeNull();
|
|
318
|
+
expect(age ?? -1).toBeGreaterThanOrEqual(0);
|
|
319
|
+
});
|
|
320
|
+
it("ignores DELIVERED rows — it answers 'how long undelivered', not 'how old'", async ({ skip }) => {
|
|
321
|
+
if (!store.oldestPendingAgeMs) return skip();
|
|
322
|
+
if (!store.claimPending) return skip();
|
|
323
|
+
await seed(1);
|
|
324
|
+
const [claimed] = await store.claimPending({
|
|
325
|
+
consumerId: "c",
|
|
326
|
+
limit: 1,
|
|
327
|
+
leaseMs: 6e4
|
|
328
|
+
});
|
|
329
|
+
if (!claimed) return skip();
|
|
330
|
+
await store.acknowledge(idOf(claimed), { consumerId: "c" });
|
|
331
|
+
expect(await store.oldestPendingAgeMs()).toBeNull();
|
|
332
|
+
});
|
|
333
|
+
});
|
|
245
334
|
});
|
|
246
335
|
}
|
|
247
336
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
2
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
3
3
|
//#region src/testing/storageContract.ts
|
|
4
4
|
/**
|
|
@@ -89,7 +89,8 @@ function runStorageContract(name, setup) {
|
|
|
89
89
|
size: bytes.length
|
|
90
90
|
}, EMPTY_CTX);
|
|
91
91
|
const read = await storage.read(file.id, EMPTY_CTX);
|
|
92
|
-
|
|
92
|
+
const actual = await readAll(read);
|
|
93
|
+
expect(actual.equals(bytes)).toBe(true);
|
|
93
94
|
expect(read.contentType).toBe("application/octet-stream");
|
|
94
95
|
await storage.delete(file.id, EMPTY_CTX);
|
|
95
96
|
});
|
|
@@ -101,7 +102,8 @@ function runStorageContract(name, setup) {
|
|
|
101
102
|
mimeType: "application/octet-stream",
|
|
102
103
|
size: bytes.length
|
|
103
104
|
}, EMPTY_CTX);
|
|
104
|
-
|
|
105
|
+
const first = await storage.delete(file.id, EMPTY_CTX);
|
|
106
|
+
expect(first).toBe(true);
|
|
105
107
|
let second = "threw";
|
|
106
108
|
try {
|
|
107
109
|
second = await storage.delete(file.id, EMPTY_CTX);
|
|
@@ -169,8 +171,10 @@ function runStorageContract(name, setup) {
|
|
|
169
171
|
mimeType: "application/octet-stream",
|
|
170
172
|
size: bytes.length
|
|
171
173
|
}, EMPTY_CTX);
|
|
172
|
-
|
|
173
|
-
expect(
|
|
174
|
+
const before = await readAll(await storage.read(file.id, EMPTY_CTX));
|
|
175
|
+
expect(before.equals(bytes)).toBe(true);
|
|
176
|
+
const removed = await storage.delete(file.id, EMPTY_CTX);
|
|
177
|
+
expect(removed).toBe(true);
|
|
174
178
|
let rejected = false;
|
|
175
179
|
try {
|
|
176
180
|
if (!(await readAll(await storage.read(file.id, EMPTY_CTX))).equals(bytes)) rejected = true;
|
|
@@ -189,7 +193,8 @@ function runStorageContract(name, setup) {
|
|
|
189
193
|
}, EMPTY_CTX);
|
|
190
194
|
const result = await storage.read(file.id, EMPTY_CTX);
|
|
191
195
|
expect(result.kind === "stream" || result.kind === "buffer").toBe(true);
|
|
192
|
-
|
|
196
|
+
const actual = await readAll(result);
|
|
197
|
+
expect(actual.equals(bytes)).toBe(true);
|
|
193
198
|
await storage.delete(file.id, EMPTY_CTX);
|
|
194
199
|
});
|
|
195
200
|
it("read() with a mid-object range slices correctly (when adapter supports ranges)", async () => {
|
package/dist/types/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
2
|
export {};
|
package/dist/types/storage.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
2
|
export {};
|
|
@@ -320,6 +320,26 @@ interface LoadResourcesOptions<TContext = unknown> {
|
|
|
320
320
|
*/
|
|
321
321
|
declare function loadResources<TContext = unknown>(dir: string, options?: LoadResourcesOptions<TContext>): Promise<ResourceLike[]>;
|
|
322
322
|
//#endregion
|
|
323
|
+
//#region src/factory/module/disposers.d.ts
|
|
324
|
+
/** Teardown callback registered by a setup phase via `defer`. */
|
|
325
|
+
type ModuleDisposer = () => void | Promise<void>;
|
|
326
|
+
/**
|
|
327
|
+
* Second argument to a module's setup phases (`plugins`, `bootstrap`,
|
|
328
|
+
* `afterResources`).
|
|
329
|
+
*/
|
|
330
|
+
interface ModuleSetupContext {
|
|
331
|
+
/**
|
|
332
|
+
* Register a teardown callback for the resource just acquired. Call it
|
|
333
|
+
* IMMEDIATELY after acquisition — that is what makes partial-init teardown
|
|
334
|
+
* exact rather than defensive.
|
|
335
|
+
*
|
|
336
|
+
* Disposers run LIFO, after this module's `onClose`, on both the rollback
|
|
337
|
+
* and shutdown paths, and exactly once. A throwing disposer is logged and
|
|
338
|
+
* never blocks the ones behind it.
|
|
339
|
+
*/
|
|
340
|
+
defer(disposer: ModuleDisposer): void;
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
323
343
|
//#region src/factory/module/types.d.ts
|
|
324
344
|
/**
|
|
325
345
|
* A module's contribution of some arm (event handlers, scheduled jobs, …).
|
|
@@ -430,8 +450,18 @@ interface ArcModule<TExports = unknown> {
|
|
|
430
450
|
* published ecosystem packages: `plugins` = "register infra"; `bootstrap` =
|
|
431
451
|
* "initialise engines (and return the public export)". Registering a plugin
|
|
432
452
|
* inside `bootstrap` still works — this slot just makes the two distinct.
|
|
453
|
+
*
|
|
454
|
+
* Receives `{ defer }` to register teardown for anything it acquires, and
|
|
455
|
+
* may RETURN a single disposer as shorthand for the one-resource case:
|
|
456
|
+
*
|
|
457
|
+
* ```ts
|
|
458
|
+
* plugins: async (fastify) => {
|
|
459
|
+
* const conn = await connect();
|
|
460
|
+
* return () => conn.close(); // equivalent to defer(...)
|
|
461
|
+
* },
|
|
462
|
+
* ```
|
|
433
463
|
*/
|
|
434
|
-
plugins?: (fastify: FastifyInstance) =>
|
|
464
|
+
plugins?: (fastify: FastifyInstance, context: ModuleSetupContext) => ModuleDisposer | undefined | Promise<ModuleDisposer | undefined>;
|
|
435
465
|
/**
|
|
436
466
|
* Domain error mappers this module ships (see `defineErrorMapper`). Merged
|
|
437
467
|
* into the app's error handler at boot, AFTER any host-declared mappers —
|
|
@@ -468,8 +498,23 @@ interface ArcModule<TExports = unknown> {
|
|
|
468
498
|
* // arc-invoice bootstrap, composed AFTER arc-accounting:
|
|
469
499
|
* const acct = getModuleExports<AccountingEngine>(fastify, "accounting");
|
|
470
500
|
* ```
|
|
501
|
+
*
|
|
502
|
+
* The return value is the module's export, so teardown here goes through
|
|
503
|
+
* `defer` (the second argument) rather than a returned disposer — register
|
|
504
|
+
* each resource the moment it exists and partial-init cleanup becomes exact
|
|
505
|
+
* instead of a chain of `?.` guards:
|
|
506
|
+
*
|
|
507
|
+
* ```ts
|
|
508
|
+
* bootstrap: async (fastify, { defer }) => {
|
|
509
|
+
* const client = await openClient();
|
|
510
|
+
* defer(() => client.close());
|
|
511
|
+
* const engine = await createEngine(client); // if this throws, only
|
|
512
|
+
* defer(() => engine.stop()); // the client is released
|
|
513
|
+
* return engine;
|
|
514
|
+
* },
|
|
515
|
+
* ```
|
|
471
516
|
*/
|
|
472
|
-
bootstrap?: (fastify: FastifyInstance) => TExports | Promise<TExports>;
|
|
517
|
+
bootstrap?: (fastify: FastifyInstance, context: ModuleSetupContext) => TExports | Promise<TExports>;
|
|
473
518
|
/**
|
|
474
519
|
* App-level resource NAMES this module authoritatively SUPERSEDES. When the
|
|
475
520
|
* host also lists (or `resourceDir`-discovers) a resource of the same name,
|
|
@@ -489,18 +534,37 @@ interface ArcModule<TExports = unknown> {
|
|
|
489
534
|
* any fork exists.
|
|
490
535
|
* - Collected across ALL modules; the app-side supersession is their union.
|
|
491
536
|
*
|
|
492
|
-
* **
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
537
|
+
* **Prefer `owns: "provided"`** (2.32) — arc derives the list from the
|
|
538
|
+
* resources this module actually returned, so the claim and the reality
|
|
539
|
+
* cannot disagree:
|
|
540
|
+
*
|
|
541
|
+
* ```ts
|
|
542
|
+
* defineModule({ name: "order", owns: "provided", resources: () => [...] })
|
|
543
|
+
* ```
|
|
544
|
+
*
|
|
545
|
+
* That is the whole arm for most modules. Resources are resolved exactly
|
|
546
|
+
* once, names are validated (duplicates within a module are rejected), the
|
|
547
|
+
* effective `owns` is derived, and supersession runs afterward — one atomic
|
|
548
|
+
* phase arc owns, rather than a rule each module re-states.
|
|
549
|
+
*
|
|
550
|
+
* **The explicit-array form is ENFORCED at boot: if you `owns` a name,
|
|
551
|
+
* PROVIDE it** — in THIS module's own `resources`. Arc fails boot when a
|
|
552
|
+
* claimed name is not among them, naming the module, the unmet names, and
|
|
553
|
+
* what it did supply. Without that check, a typo or a resource deleted
|
|
554
|
+
* without updating the list booted "successfully" with the app's route
|
|
555
|
+
* silently removed and nothing serving it. Two real cases, both silent 404s:
|
|
556
|
+
* a POS module claiming a checkout resource it mounted only when the host
|
|
557
|
+
* supplied a pipeline, and a device gateway claiming a name it never
|
|
558
|
+
* provided at all.
|
|
559
|
+
*
|
|
560
|
+
* Keep the explicit array only when the list is genuinely NOT the module's
|
|
561
|
+
* own resource set — e.g. pre-declaring a name before the fork exists.
|
|
498
562
|
*
|
|
499
563
|
* A sibling module supplying the name does NOT satisfy the claim — ownership
|
|
500
564
|
* is local to the module that declares it, which is the colocation this arm
|
|
501
565
|
* exists for.
|
|
502
566
|
*/
|
|
503
|
-
readonly owns?: readonly string[];
|
|
567
|
+
readonly owns?: readonly string[] | "provided";
|
|
504
568
|
/**
|
|
505
569
|
* The module's resources. Array or factory — the factory form runs AFTER all
|
|
506
570
|
* bootstraps, so `defineResource(...)` receives fully-booted engines. Flows
|
|
@@ -512,8 +576,12 @@ interface ArcModule<TExports = unknown> {
|
|
|
512
576
|
* Post-registration wiring — runs in the `afterResources` phase, once this
|
|
513
577
|
* module's routes are mounted. Use for cross-resource event subscriptions the
|
|
514
578
|
* module owns.
|
|
579
|
+
*
|
|
580
|
+
* Receives `{ defer }`, and may return a disposer, on the same terms as
|
|
581
|
+
* `plugins` — handy for wiring that must be unwound (a subscription, a
|
|
582
|
+
* listener) without hoisting a handle into module scope.
|
|
515
583
|
*/
|
|
516
|
-
afterResources?: (fastify: FastifyInstance) =>
|
|
584
|
+
afterResources?: (fastify: FastifyInstance, context: ModuleSetupContext) => ModuleDisposer | undefined | Promise<ModuleDisposer | undefined>;
|
|
517
585
|
/**
|
|
518
586
|
* Readiness checks this module contributes to the app's
|
|
519
587
|
* `healthPlugin` (`/_health/ready`). Collected across ALL modules in
|
|
@@ -611,6 +679,14 @@ interface ArcModule<TExports = unknown> {
|
|
|
611
679
|
* onClose: async () => { await client?.close(); }, // still runs
|
|
612
680
|
* });
|
|
613
681
|
* ```
|
|
682
|
+
*
|
|
683
|
+
* Prefer `defer` (the setup phases' second argument) for anything acquired
|
|
684
|
+
* step-by-step: it registers each teardown at the point of acquisition, so
|
|
685
|
+
* the runtime knows exactly what was reached and the `?.` guards above
|
|
686
|
+
* disappear. `onClose` remains the right slot for tearing down what
|
|
687
|
+
* `bootstrap` RETURNED — the module's engine — and runs FIRST, ahead of the
|
|
688
|
+
* module's deferred disposers (see `disposers.ts` for the ordering rule).
|
|
689
|
+
* The two compose; either alone is complete.
|
|
614
690
|
*/
|
|
615
691
|
onClose?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
616
692
|
}
|
|
@@ -657,4 +733,4 @@ type ArcModuleInput<TExports = unknown> = ArcModule<TExports> | Promise<ArcModul
|
|
|
657
733
|
*/
|
|
658
734
|
interface ArcModuleRegistry {}
|
|
659
735
|
//#endregion
|
|
660
|
-
export {
|
|
736
|
+
export { HealthCheck as _, ModuleContribution as a, healthPlugin as b, LoadResourcesOptions as c, loadResources as d, ScheduleDefinition as f, schedulesPlugin as g, _default as h, EventHandlerDefinition as i, ResourceLike as l, SchedulesPluginOptions as m, ArcModuleInput as n, ModuleDisposer as o, ScheduleStats as p, ArcModuleRegistry as r, ModuleSetupContext as s, ArcModule as t, ResourceModule as u, HealthOptions as v, _default$1 as y };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { l as UnauthorizedError, o as OrgRequiredError } from "./errors-
|
|
3
|
-
import { n as requireSingleHeaderValue } from "./headers-
|
|
4
|
-
import { t as getUserId$1 } from "./userHelpers-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { l as UnauthorizedError, o as OrgRequiredError } from "./errors-Bh1KK5ps.mjs";
|
|
3
|
+
import { n as requireSingleHeaderValue } from "./headers-BXjQYbeC.mjs";
|
|
4
|
+
import { t as getUserId$1 } from "./userHelpers-BNsOXzOd.mjs";
|
|
5
5
|
//#region src/scope/types.ts
|
|
6
6
|
/**
|
|
7
7
|
* Request Scope — The One Standard
|
package/dist/usage/index.mjs
CHANGED
|
Binary file
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { a as OrgAccessDeniedError, c as ServiceUnavailableError, d as createDomainError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-
|
|
3
|
-
import { n as requireSingleHeaderValue, t as getHeader } from "../headers-
|
|
4
|
-
import { n as getUserRoles, r as normalizeRoles, t as getUserId } from "../userHelpers-
|
|
5
|
-
import { t as simpleEqualityMatcher } from "../simpleEqualityMatcher-
|
|
6
|
-
import { A as createCircuitBreakerRegistry, C as defineCompensation, D as CircuitBreakerRegistry, E as CircuitBreakerError, O as CircuitState, S as defineErrorMapper, T as CircuitBreaker, _ as createQueryParser, a as deleteResponse, b as NEUTRAL_DIALECT, c as getDefaultCrudSchemas, d as listResponse, f as offsetListResponse, g as ArcQueryParser, h as responses, i as bareListResponse, k as createCircuitBreaker, l as getListQueryParams, m as queryParams, n as scheduleBackground, o as errorContractSchema, p as paginationSchema, r as aggregateListResponse, s as errorDetailSchema, t as createStateMachine, u as keysetListResponse, v as handleRaw, w as withCompensation, x as defineGuard, y as MONGO_DIALECT } from "../utils-
|
|
7
|
-
import { a as isZodSchema, i as isJsonSchema, n as convertRouteSchema, o as toJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-
|
|
8
|
-
import { a as promoteStreamTokenToHeader, i as pipeUIMessageStreamToReply, n as forwardedStreamHeaders, r as isReadableStream, t as UI_MESSAGE_STREAM_HEADERS } from "../streaming-
|
|
9
|
-
import { t as openSseStream } from "../sseStream-
|
|
10
|
-
import { t as hasEvents } from "../typeGuards-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { a as OrgAccessDeniedError, c as ServiceUnavailableError, d as createDomainError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-Bh1KK5ps.mjs";
|
|
3
|
+
import { n as requireSingleHeaderValue, t as getHeader } from "../headers-BXjQYbeC.mjs";
|
|
4
|
+
import { n as getUserRoles, r as normalizeRoles, t as getUserId } from "../userHelpers-BNsOXzOd.mjs";
|
|
5
|
+
import { t as simpleEqualityMatcher } from "../simpleEqualityMatcher-C4KiMWUa.mjs";
|
|
6
|
+
import { A as createCircuitBreakerRegistry, C as defineCompensation, D as CircuitBreakerRegistry, E as CircuitBreakerError, O as CircuitState, S as defineErrorMapper, T as CircuitBreaker, _ as createQueryParser, a as deleteResponse, b as NEUTRAL_DIALECT, c as getDefaultCrudSchemas, d as listResponse, f as offsetListResponse, g as ArcQueryParser, h as responses, i as bareListResponse, k as createCircuitBreaker, l as getListQueryParams, m as queryParams, n as scheduleBackground, o as errorContractSchema, p as paginationSchema, r as aggregateListResponse, s as errorDetailSchema, t as createStateMachine, u as keysetListResponse, v as handleRaw, w as withCompensation, x as defineGuard, y as MONGO_DIALECT } from "../utils-BtOha_Sp.mjs";
|
|
7
|
+
import { a as isZodSchema, i as isJsonSchema, n as convertRouteSchema, o as toJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-Crjvczi_.mjs";
|
|
8
|
+
import { a as promoteStreamTokenToHeader, i as pipeUIMessageStreamToReply, n as forwardedStreamHeaders, r as isReadableStream, t as UI_MESSAGE_STREAM_HEADERS } from "../streaming-DPZdQmDz.mjs";
|
|
9
|
+
import { t as openSseStream } from "../sseStream-B3zb_d1h.mjs";
|
|
10
|
+
import { t as hasEvents } from "../typeGuards-B_5-hKjJ.mjs";
|
|
11
11
|
export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, MONGO_DIALECT, NEUTRAL_DIALECT, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, UI_MESSAGE_STREAM_HEADERS, UnauthorizedError, ValidationError, aggregateListResponse, bareListResponse, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineErrorMapper, defineGuard, deleteResponse, errorContractSchema, errorDetailSchema, forwardedStreamHeaders, getDefaultCrudSchemas, getHeader, getListQueryParams, getUserId, getUserRoles, handleRaw, hasEvents, isArcError, isJsonSchema, isReadableStream, isZodSchema, keysetListResponse, listResponse, normalizeRoles, offsetListResponse, openSseStream, paginationSchema, pipeUIMessageStreamToReply, promoteStreamTokenToHeader, queryParams, requireSingleHeaderValue, responses, scheduleBackground, simpleEqualityMatcher, toJsonSchema, withCompensation };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { m as RESERVED_QUERY_PARAMS } from "./constants-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { m as RESERVED_QUERY_PARAMS } from "./constants-J99LGTJI.mjs";
|
|
3
3
|
import { arcLog } from "./logger/index.mjs";
|
|
4
|
-
import { t as ArcError } from "./errors-
|
|
4
|
+
import { t as ArcError } from "./errors-Bh1KK5ps.mjs";
|
|
5
5
|
import { errorContractSchema as errorContractSchema$1, errorDetailSchema as errorDetailSchema$1 } from "@classytic/repo-core/errors";
|
|
6
6
|
import { scheduleBackground } from "@classytic/repo-core/cache";
|
|
7
7
|
//#region src/utils/circuitBreaker.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-BhflRrBs.mjs";
|
|
3
3
|
//#region src/core/aggregation/normalize.ts
|
|
4
4
|
/**
|
|
5
5
|
* Framework cap on URL-driven aggregation limits when the host opts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
3
|
-
import { d as createDomainError } from "./errors-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-BhflRrBs.mjs";
|
|
3
|
+
import { d as createDomainError } from "./errors-Bh1KK5ps.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/plugins/versioning.ts
|
|
6
6
|
var versioning_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -31,7 +31,7 @@ const versioningPlugin = async (fastify, opts) => {
|
|
|
31
31
|
reply.header(responseHeader, version);
|
|
32
32
|
if (deprecatedSet.has(version)) {
|
|
33
33
|
reply.header("deprecation", "true");
|
|
34
|
-
reply.header("sunset", sunset ?? new Date(Date.now() +
|
|
34
|
+
reply.header("sunset", sunset ?? new Date(Date.now() + 7776e6).toISOString());
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
};
|