@classytic/arc 2.41.1 → 2.44.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/{EventTransport-CbUKDzZZ.d.mts → EventTransport-CiicKz2Z.d.mts} +1 -1
- package/dist/{EventTransport-DSqD_Xsg.mjs → EventTransport-DZWDsaPa.mjs} +22 -17
- package/dist/{HookSystem-CMF94SEA.mjs → HookSystem-yjEgn7Cm.mjs} +2 -2
- package/dist/{QueryCache-DFA-QrU9.d.mts → QueryCache--5uAuYPW.d.mts} +7 -3
- package/dist/{ResourceRegistry-MGpXoxHZ.mjs → ResourceRegistry-DJxHUpE4.mjs} +44 -13
- package/dist/acquire-BozJ-9yt.mjs +35 -0
- package/dist/actionPermissions-5N04zBL4.mjs +772 -0
- package/dist/audit/index.d.mts +46 -8
- package/dist/audit/index.mjs +48 -26
- package/dist/auth/audit.d.mts +8 -8
- package/dist/auth/audit.mjs +1 -1
- package/dist/auth/index.d.mts +46 -16
- package/dist/auth/index.mjs +134 -156
- package/dist/auth/redis-session.d.mts +4 -5
- package/dist/auth/redis-session.mjs +1 -1
- package/dist/{authorizationDecision-DawKGoXb.mjs → authorizationDecision-wX3SA9w_.mjs} +7 -102
- package/dist/{base-CxrV1LmG.d.mts → base-CZyixEQR.d.mts} +27 -5
- package/dist/boundedMap-DWiKW7lP.mjs +57 -0
- package/dist/{buildHandler-CvxKOc0m.mjs → buildHandler-Bswu_vNb.mjs} +4 -4
- package/dist/cache/index.d.mts +31 -43
- package/dist/cache/index.mjs +4 -4
- package/dist/{caching-DbCBxlgw.mjs → caching-Drp68DIS.mjs} +3 -3
- package/dist/claimed-DYvQoZLv.mjs +8 -0
- package/dist/cleanup/index.d.mts +18 -22
- package/dist/cleanup/index.mjs +27 -73
- package/dist/cli/commands/describe.d.mts +7 -5
- package/dist/cli/commands/describe.mjs +7 -4
- package/dist/cli/commands/docs.d.mts +2 -3
- package/dist/cli/commands/docs.mjs +3 -3
- package/dist/cli/commands/doctor.d.mts +2 -3
- package/dist/cli/commands/doctor.mjs +1 -1
- package/dist/cli/commands/generate.mjs +2 -3
- package/dist/cli/commands/init.mjs +2 -3
- package/dist/cli/commands/introspect.d.mts +2 -3
- package/dist/cli/commands/introspect.mjs +2 -2
- package/dist/cli/index.mjs +3 -3
- package/dist/{constants-D5Ubn1fe.mjs → constants-B2QHb6u6.mjs} +4 -2
- package/dist/context/index.d.mts +11 -14
- package/dist/context/index.mjs +18 -38
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +8 -8
- package/dist/{core-5lazhva9.mjs → core-COcqo0Cp.mjs} +15 -5
- package/dist/{createActionRouter-DNqoaK81.mjs → createActionRouter-zG13rpPJ.mjs} +97 -39
- package/dist/{createAggregationRouter-BcbQJf10.mjs → createAggregationRouter-CWRz96Vr.mjs} +11 -8
- package/dist/{preloadResources-f3boenVZ.mjs → createApp-BGLYtErt.mjs} +305 -394
- package/dist/{createMcpServer-CbDWkZ1T.d.mts → createMcpServer-DSztofa9.d.mts} +1 -1
- package/dist/{defineAggregation-D_eJjm5A.mjs → defineAggregation--3xguLkk.mjs} +1 -1
- package/dist/{defineResource-DxkMTjRn.mjs → defineResource-gUp9ug66.mjs} +118 -1024
- package/dist/discovery/index.d.mts +6 -7
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.d.mts +11 -5
- package/dist/docs/index.mjs +4 -4
- package/dist/{elevation-CkvG0LG2.mjs → elevation-BG4gnMsJ.mjs} +41 -12
- package/dist/{elevation-BXCfVcNG.d.mts → elevation-BW2J3tNj.d.mts} +1 -2
- package/dist/encryption/index.d.mts +5 -5
- package/dist/encryption/index.mjs +3 -3
- package/dist/{errorHandler-D1GHKGlV.mjs → errorHandler-COHw3N1b.mjs} +26 -5
- package/dist/{errors-BH7YU_9O.mjs → errors-CW4anJBy.mjs} +58 -23
- package/dist/{errors-BGdVwP25.d.mts → errors-JYc9vwqE.d.mts} +9 -0
- package/dist/{eventPlugin-B52abJ8W.d.mts → eventPlugin-BtmA4-3P.d.mts} +65 -9
- package/dist/{eventPlugin-zZY-unhr.mjs → eventPlugin-BweHAVws.mjs} +82 -21
- package/dist/{subscribe-helpers-DatDkcuG.mjs → eventTypes-N4-omQFR.mjs} +151 -17
- package/dist/events/index.d.mts +43 -18
- package/dist/events/index.mjs +49 -53
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +139 -157
- package/dist/events/transports/redis.d.mts +5 -6
- package/dist/events/transports/redis.mjs +2 -2
- package/dist/factory/index.d.mts +42 -27
- package/dist/factory/index.mjs +213 -32
- package/dist/{fastify-augmentation-Cq2nHVaW.d.mts → fastify-augmentation-DRlCIWE9.d.mts} +11 -25
- package/dist/{fields-BHrkoF5y.mjs → fields-A5crhsJb.mjs} +1 -1
- package/dist/{fields-I_EeRWND.d.mts → fields-BBSpf8pS.d.mts} +1 -1
- package/dist/filter-merge-DGM-GQ1J.mjs +99 -0
- package/dist/{generate-BLRf2m3y.mjs → generate-BXKo2Gc8.mjs} +2 -2
- package/dist/{headers-BIXWKrzQ.mjs → headers-DKZQKL-Z.mjs} +2 -2
- package/dist/health-BYAwA6YS.mjs +22 -0
- package/dist/{health-ZRHeDHXH.mjs → health-CrqUp3sz.mjs} +115 -55
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.mjs +2 -3
- package/dist/idempotency/index.d.mts +36 -10
- package/dist/idempotency/index.mjs +230 -111
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +77 -12
- package/dist/{index-D4u76eQW.d.mts → index-Beg3aNnK.d.mts} +23 -101
- package/dist/{preloadResources-CjS2OfpU.d.mts → index-BkV55WlV.d.mts} +37 -38
- package/dist/{index-BHdZD8zK.d.mts → index-Bxriq3so.d.mts} +84 -21
- package/dist/index-CUJvoyw3.d.mts +510 -0
- package/dist/{index-CbJiYrfv.d.mts → index-Chgz3d0i.d.mts} +1 -1
- package/dist/{index-DHbyPo5j.d.mts → index-WH7xgvxS.d.mts} +304 -254
- package/dist/index.d.mts +9 -9
- package/dist/index.mjs +11 -11
- package/dist/{init-CpLkjU18.mjs → init-BPzK5Lnr.mjs} +1 -1
- package/dist/integrations/event-gateway.d.mts +11 -7
- package/dist/integrations/event-gateway.mjs +4 -4
- package/dist/integrations/index.d.mts +3 -3
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs/index.d.mts +1 -1
- package/dist/integrations/jobs/index.mjs +18 -5
- package/dist/integrations/mcp/index.d.mts +102 -89
- package/dist/integrations/mcp/index.mjs +19 -4
- package/dist/integrations/mcp/testing.d.mts +8 -9
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.d.mts +85 -144
- package/dist/integrations/streamline.mjs +131 -55
- package/dist/integrations/webhooks.d.mts +83 -143
- package/dist/integrations/webhooks.mjs +36 -80
- package/dist/integrations/websocket-pushref-redis.d.mts +5 -6
- package/dist/integrations/websocket-pushref-redis.mjs +1 -1
- package/dist/integrations/websocket-redis.d.mts +5 -6
- package/dist/integrations/websocket-redis.mjs +1 -1
- package/dist/integrations/websocket.d.mts +3 -3
- package/dist/integrations/websocket.mjs +2 -2
- package/dist/{interface-DEWNOMza.d.mts → interface-JJzwH4Ro.d.mts} +34 -2
- package/dist/{jsonBody-ELR9lfeU.mjs → jsonBody-YIq-vGLv.mjs} +2 -2
- package/dist/{keys-cpZCtcIE.mjs → keys-CpoiZ8hU.mjs} +7 -18
- package/dist/{loadResources-BPfWiI5s.mjs → loadResources-6jO52-RR.mjs} +3 -3
- package/dist/{loadResourcesFromEntry-ixtfL3J2.mjs → loadResourcesFromEntry-MP8xEppu.mjs} +2 -2
- package/dist/logger/index.d.mts +9 -17
- package/dist/logger/index.mjs +2 -153
- package/dist/logger-D4V1zGLI.mjs +160 -0
- package/dist/{mcpPlugin-BX5PujI0.mjs → mcpPlugin-srPc7ItN.mjs} +446 -170
- package/dist/{memory-Iotz0cCx.mjs → memory-CTa5pOCW.mjs} +36 -34
- package/dist/{metrics-NMsmpRmY.mjs → metrics-DsZrvnpB.mjs} +39 -72
- package/dist/middleware/index.d.mts +5 -5
- package/dist/middleware/index.mjs +3 -3
- package/dist/migrations/index.d.mts +13 -13
- package/dist/migrations/index.mjs +2 -2
- package/dist/{module-DpLJG2_N.mjs → module--L0iBIZz.mjs} +8 -8
- package/dist/mongodb-memory-server-CHhYSq5y.mjs +35539 -0
- package/dist/mongoose-CYJCLyi-.mjs +67451 -0
- package/dist/multiTenant-CAtYlW6H.d.mts +104 -0
- package/dist/{multipartBody-DtRWM6_U.mjs → multipartBody-Cc7eZ9cq.mjs} +46 -7
- package/dist/node-D8UZv_8c.mjs +41236 -0
- package/dist/{openapi-CmFf3yq_.mjs → openapi-CMegfsm8.mjs} +48 -10
- package/dist/outbox-admin/index.d.mts +5 -5
- package/dist/outbox-admin/index.mjs +6 -18
- package/dist/{outbox-module-D2z5WkDY.mjs → outbox-module-Ryk270jd.mjs} +203 -33
- package/dist/{outbox-module-BHdUnuuK.d.mts → outbox-module-gZCHoE4H.d.mts} +79 -6
- package/dist/permissions/index.d.mts +5 -4
- package/dist/permissions/index.mjs +8 -6
- package/dist/{permissions-D8TBH44E.mjs → permissions-C5ijIz5Q.mjs} +149 -33
- package/dist/{pipe-FMWNheSO.mjs → pipe-D81zMtWs.mjs} +2 -2
- package/dist/pipeline/index.d.mts +7 -7
- package/dist/pipeline/index.mjs +2 -2
- package/dist/plan-CJGMKoui.mjs +565 -0
- package/dist/{BaseController-CYEwjyjN.mjs → plugin-DALd9dcF.mjs} +1269 -346
- package/dist/plugins/index.d.mts +17 -14
- package/dist/plugins/index.mjs +44 -22
- package/dist/plugins/response-cache.d.mts +5 -6
- package/dist/plugins/response-cache.mjs +8 -14
- package/dist/plugins/tracing-entry.mjs +2 -2
- package/dist/{pluralize-CXWZIzTv.mjs → pluralize-COUNYo3d.mjs} +1 -1
- package/dist/presets/filesUpload.d.mts +8 -8
- package/dist/presets/filesUpload.mjs +5 -5
- package/dist/presets/index.d.mts +35 -40
- package/dist/presets/index.mjs +4 -4
- package/dist/presets/multiTenant.d.mts +2 -107
- package/dist/presets/multiTenant.mjs +22 -162
- package/dist/presets/search.d.mts +9 -10
- package/dist/presets/search.mjs +2 -2
- package/dist/{presets-ZJSPgmT2.mjs → presets-CONf2Qem.mjs} +99 -107
- package/dist/{projection-BzIgzoKZ.mjs → projection-wFoLqdss.mjs} +2 -2
- package/dist/{pushref-registry-Dov9l4qE.d.mts → pushref-registry-UxCkoA4C.d.mts} +1 -1
- package/dist/{queryCachePlugin-DZHPOm9p.mjs → queryCachePlugin-BATECpyh.mjs} +12 -14
- package/dist/{queryCachePlugin-BzqxconG.d.mts → queryCachePlugin-C2lZjTxk.d.mts} +1 -1
- package/dist/{rateLimitKey-BvOvcBDi.mjs → rateLimitKey-DVEZ_UpV.mjs} +1 -1
- package/dist/{realtime-8tIQWZz4.mjs → realtime-xyubMKSB.mjs} +25 -21
- package/dist/{redis-Bzi1y3F9.d.mts → redis-BDgv9Glw.d.mts} +17 -24
- package/dist/redis-stream-BMk-bpQS.d.mts +219 -0
- package/dist/redisShapes-CQksY67q.d.mts +55 -0
- package/dist/registry/index.d.mts +15 -10
- package/dist/registry/index.mjs +4 -4
- package/dist/{registry-DNkgGQcK.mjs → registry-Bdzg-hdm.mjs} +13 -10
- package/dist/{renewingLease-yF8BdW4b.mjs → renewingLease-BFJxGPuh.mjs} +1 -1
- package/dist/{replyHelpers-CNdvMfM4.mjs → replyHelpers-Bnc6lJyy.mjs} +2 -2
- package/dist/{requestContext-cDkAUr-P.mjs → requestContext-C10UeFe5.mjs} +1 -1
- package/dist/requirement-Bu50QALH.mjs +35 -0
- package/dist/requirement-CbiLdQ1n.d.mts +22 -0
- package/dist/resourceRateLimit-Wf6d6FL9.d.mts +30 -0
- package/dist/resourceRateLimit-urWPJxrt.mjs +180 -0
- package/dist/rolldown-runtime-MYrLNGnq.mjs +45 -0
- package/dist/routeValidator-DHtpzrzk.mjs +70 -0
- package/dist/{runtimeCapabilities-CkhS6jn6.mjs → runtimeCapabilities-DIMKMV2G.mjs} +1 -1
- package/dist/{schedules-j6uXXAeJ.mjs → schedules-CKTs5ys8.mjs} +46 -37
- package/dist/{schemaConverter-BVA7cFRG.mjs → schemaConverter-BVjkQ5DD.mjs} +2 -2
- package/dist/{schemaIR-CTvPDoPB.mjs → schemaIR-BA0Hb21Y.mjs} +2 -2
- package/dist/schemas/index.d.mts +20 -10
- package/dist/schemas/index.mjs +8 -3
- package/dist/scim/index.d.mts +13 -13
- package/dist/scim/index.mjs +2 -2
- package/dist/scope/index.d.mts +4 -4
- package/dist/scope/index.mjs +6 -6
- package/dist/{scope-BUi1xV1I.mjs → scope-DINaj7Ax.mjs} +4 -4
- package/dist/shutdown-LpLMH8T1.mjs +59 -0
- package/dist/{simpleEqualityMatcher-C9bzq2gO.mjs → simpleEqualityMatcher-DbwIM1f1.mjs} +1 -1
- package/dist/{sse-BeqVKQKu.mjs → sse-BzJFPX_1.mjs} +11 -15
- package/dist/{sseStream-Ppzo-WUH.mjs → sseStream-DQChzGTs.mjs} +2 -2
- package/dist/{store-helpers-dW71XVWL.mjs → store-helpers-Coj9RhOZ.mjs} +1 -1
- package/dist/{streaming-IcRFjWQU.mjs → streaming-JzB5CAga.mjs} +1 -1
- package/dist/subscriberIdentity-DeyppIif.mjs +28 -0
- package/dist/tenancy-DxV8OuX2.mjs +43 -0
- package/dist/tenantPreparation-CBvvAcAj.mjs +67 -0
- package/dist/testing/cleanupStoreContract.d.mts +4 -5
- package/dist/testing/cleanupStoreContract.mjs +1 -1
- package/dist/testing/index.d.mts +215 -197
- package/dist/testing/index.mjs +289 -214
- package/dist/testing/outboxStoreContract.d.mts +4 -5
- package/dist/testing/outboxStoreContract.mjs +137 -2
- package/dist/testing/requiredPorts.d.mts +16 -0
- package/dist/testing/requiredPorts.mjs +65 -0
- package/dist/testing/storageContract.d.mts +4 -5
- package/dist/testing/storageContract.mjs +1 -1
- package/dist/timing-CntavTlR.mjs +46 -0
- package/dist/{transactionContext-CPbdlnVw.mjs → transactionContext-orvnGu4F.mjs} +1 -1
- package/dist/{typeGuards-BLjPgVBm.mjs → typeGuards-kEaP_WmO.mjs} +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.mjs +1 -1
- package/dist/{types-DfVDvkdP.d.mts → types-BJ-2XqVF.d.mts} +189 -204
- package/dist/{types-CWQn9-IC.d.mts → types-D3Ixsh00.d.mts} +22 -9
- package/dist/{types-CgenB1gv.mjs → types-fvO6Ovzx.mjs} +4 -4
- package/dist/usage/index.d.mts +5 -6
- package/dist/usage/index.mjs +5 -5
- package/dist/{userHelpers-ChRvkuSZ.mjs → userHelpers-C76zD5pa.mjs} +1 -1
- package/dist/utils/index.d.mts +125 -264
- package/dist/utils/index.mjs +13 -12
- package/dist/{utils-CxcctrAh.mjs → utils-BpkVZ8rB.mjs} +315 -404
- package/dist/{validate-DrYWnOzI.mjs → validate-CWp-lsrm.mjs} +6 -14
- package/dist/{versioning-D6JIK8Tk.d.mts → versioning-Bsb51gGT.d.mts} +28 -13
- package/dist/{versioning-DKkT4hNJ.mjs → versioning-CHhL9P3o.mjs} +4 -4
- package/dist/{websocket-BOXVggMf.d.mts → websocket-Cs4awVyD.d.mts} +1 -1
- package/dist/{workScope-CxKqoIFn.mjs → workScope-n9a7d_lZ.mjs} +2 -2
- package/package.json +57 -59
- package/skills/arc/SKILL.md +13 -4
- package/skills/arc/references/auth.md +8 -5
- package/skills/arc/references/integrations.md +1 -1
- package/skills/arc/references/mcp.md +8 -6
- package/skills/arc/references/multi-tenancy.md +19 -14
- package/skills/arc/references/production.md +27 -10
- package/dist/actionPermissions-BoPGQ5-4.mjs +0 -350
- package/dist/index-CFfLKMH4.d.mts +0 -290
- package/dist/interface-YzIbF7Ii.mjs +0 -17
- package/dist/redis-stream-BPKscsTB.d.mts +0 -260
- package/dist/registerRoute-Bsnk6NiZ.mjs +0 -364
- package/dist/rolldown-runtime-eysyzFAF.mjs +0 -15
- package/dist/sync/changelog.d.mts +0 -3
- package/dist/sync/changelog.mjs +0 -3
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { _ as HealthCheck, a as ModuleContribution, f as ScheduleDefinition, n as ArcModuleInput, r as ArcModuleRegistry, s as ModuleSetupContext, t as ArcModule } from "./types-DfVDvkdP.mjs";
|
|
3
|
-
import { FastifyInstance } from "fastify";
|
|
4
|
-
//#region src/factory/module/contributions.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* Collect every module's `healthChecks` in the caller's order. Fails at boot
|
|
7
|
-
* on a duplicate check `name` across modules, naming BOTH owning modules.
|
|
8
|
-
* The host's app-level checks are appended AFTER this (modules-first,
|
|
9
|
-
* host-last) by the caller.
|
|
10
|
-
*/
|
|
11
|
-
declare function collectModuleHealthChecks(modules: readonly ArcModule[]): HealthCheck[];
|
|
12
|
-
/**
|
|
13
|
-
* Collect every module's `workflows`. Resolves factory contributions (so a
|
|
14
|
-
* factory can close over a container the caller has already decorated on
|
|
15
|
-
* `fastify`) and flattens to a single opaque array. Arc core deliberately
|
|
16
|
-
* does NOT validate or interpret the values — the streamline integration
|
|
17
|
-
* owns name/shape checks and registration. Called by the integration at init
|
|
18
|
-
* time, not by arc's boot pipeline (workflows depend on the integration's
|
|
19
|
-
* container).
|
|
20
|
-
*/
|
|
21
|
-
declare function collectModuleWorkflows(fastify: FastifyInstance, modules: readonly ArcModule[]): Promise<unknown[]>;
|
|
22
|
-
/**
|
|
23
|
-
* Collect every module's `scheduledJobs`. Resolves factory contributions
|
|
24
|
-
* (after bootstraps) and fails at boot on a duplicate job `name` across
|
|
25
|
-
* modules. The caller passes the returned definitions to the canonical
|
|
26
|
-
* schedules plugin; factories must therefore be resolved only once.
|
|
27
|
-
*/
|
|
28
|
-
declare function collectModuleScheduledJobs(fastify: FastifyInstance, modules: readonly ArcModule[],
|
|
29
|
-
/**
|
|
30
|
-
* Optional sink for per-module counts, filled as each arm resolves.
|
|
31
|
-
*
|
|
32
|
-
* Exists so `arc.moduleDescriptors` can report real numbers without
|
|
33
|
-
* resolving the factories a SECOND time — a contribution factory closes over
|
|
34
|
-
* booted engines and may register or allocate, so running it twice is not a
|
|
35
|
-
* free read. One resolution feeds both activation and introspection.
|
|
36
|
-
*/
|
|
37
|
-
countsByModule?: Map<string, number>): Promise<ScheduleDefinition[]>;
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region src/factory/module/extend.d.ts
|
|
40
|
-
/**
|
|
41
|
-
* What a caller may add. Every mergeable arm of `ArcModule`, plus `bootstrap`
|
|
42
|
-
* in wrapper form only.
|
|
43
|
-
*
|
|
44
|
-
* `name` is absent on purpose: renaming a module mid-composition breaks the
|
|
45
|
-
* `dependsOn` graph and the registry key its consumers read, and it is the one
|
|
46
|
-
* "extension" that is never additive.
|
|
47
|
-
*/
|
|
48
|
-
interface ModuleExtension<TExports = unknown> {
|
|
49
|
-
dependsOn?: readonly string[];
|
|
50
|
-
owns?: readonly string[] | "provided";
|
|
51
|
-
resources?: ArcModule<TExports>["resources"];
|
|
52
|
-
eventHandlers?: ArcModule<TExports>["eventHandlers"];
|
|
53
|
-
scheduledJobs?: ArcModule<TExports>["scheduledJobs"];
|
|
54
|
-
workflows?: ArcModule<TExports>["workflows"];
|
|
55
|
-
healthChecks?: ArcModule<TExports>["healthChecks"];
|
|
56
|
-
errorMappers?: ArcModule<TExports>["errorMappers"];
|
|
57
|
-
plugins?: ArcModule<TExports>["plugins"];
|
|
58
|
-
afterResources?: ArcModule<TExports>["afterResources"];
|
|
59
|
-
onClose?: ArcModule<TExports>["onClose"];
|
|
60
|
-
/**
|
|
61
|
-
* WRAP the module's bootstrap — it is never replaced.
|
|
62
|
-
*
|
|
63
|
-
* Bootstrap returns the module's exports, so two of them cannot be
|
|
64
|
-
* concatenated: one value has to win, and a host silently winning is the gym
|
|
65
|
-
* failure (`{ ...mod, bootstrap }` overwrote the factory's own, so the engine
|
|
66
|
-
* the module published was never created). The wrapper form makes the
|
|
67
|
-
* relationship explicit — call `inner` and decorate its result, or
|
|
68
|
-
* deliberately do not.
|
|
69
|
-
*
|
|
70
|
-
* `inner` is `undefined` when the module has no bootstrap of its own.
|
|
71
|
-
*/
|
|
72
|
-
bootstrap?: (inner: ((f: FastifyInstance, c: ModuleSetupContext) => TExports | Promise<TExports>) | undefined) => (f: FastifyInstance, c: ModuleSetupContext) => TExports | Promise<TExports>;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Merge a host's additions onto a module. Nothing the module declared is lost.
|
|
76
|
-
*
|
|
77
|
-
* ```ts
|
|
78
|
-
* return extendModule(createOrderModule({ … }), {
|
|
79
|
-
* eventHandlers: () => hostHandlers(), // appended after the module's
|
|
80
|
-
* dependsOn: ["outbox"], // unioned
|
|
81
|
-
* bootstrap: (inner) => async (f, c) => { // wraps, never replaces
|
|
82
|
-
* const exports = await inner?.(f, c);
|
|
83
|
-
* return decorate(exports);
|
|
84
|
-
* },
|
|
85
|
-
* });
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
declare function extendModule<TExports = unknown>(mod: ArcModule<TExports>, extension: ModuleExtension<TExports>): ArcModule<TExports>;
|
|
89
|
-
//#endregion
|
|
90
|
-
//#region src/factory/module/lifecycle.d.ts
|
|
91
|
-
/**
|
|
92
|
-
* Subscribe every module's `eventHandlers` in dependency order (pass the
|
|
93
|
-
* `orderModules`-sorted list). Returns the ordered list of unsubscribe
|
|
94
|
-
* functions so the caller can tear them down at shutdown BEFORE module
|
|
95
|
-
* `onClose` (while module deps are still alive). Fails at boot on:
|
|
96
|
-
* - a duplicate NAMED handler across modules (attributing both owners);
|
|
97
|
-
* - a module declaring handlers while the event subsystem is unavailable.
|
|
98
|
-
* Resolves factory contributions (after bootstraps) so a handler can close over
|
|
99
|
-
* booted engines rather than a global getter.
|
|
100
|
-
*/
|
|
101
|
-
declare function subscribeModuleEventHandlers(fastify: FastifyInstance, modules: readonly ArcModule[],
|
|
102
|
-
/**
|
|
103
|
-
* Optional sink for per-module handler counts, filled as each arm resolves.
|
|
104
|
-
* Lets `arc.moduleDescriptors` report real numbers without resolving the
|
|
105
|
-
* factories a SECOND time — see the note on `collectModuleScheduledJobs`.
|
|
106
|
-
*/
|
|
107
|
-
countsByModule?: Map<string, number>): Promise<Array<() => void | Promise<void>>>;
|
|
108
|
-
//#endregion
|
|
109
|
-
//#region src/factory/module/order.d.ts
|
|
110
|
-
/**
|
|
111
|
-
* Order modules for composition by their `dependsOn` edges — a STABLE
|
|
112
|
-
* topological sort. Called once at the start of the bootstrap phase; every
|
|
113
|
-
* subsequent phase (bootstrap, resources, afterResources, and reverse-order
|
|
114
|
-
* onClose) iterates the returned list, so a module's declared dependencies are
|
|
115
|
-
* always composed before it.
|
|
116
|
-
*
|
|
117
|
-
* "Stable" = modules with no edge between them keep their original list order,
|
|
118
|
-
* so declaring `dependsOn` on one module never silently reorders an unrelated
|
|
119
|
-
* one. Backward compatible: a `modules` array with NO `dependsOn` anywhere is
|
|
120
|
-
* returned unchanged.
|
|
121
|
-
*
|
|
122
|
-
* Fail-fast — throws (never reorders past a broken contract) on:
|
|
123
|
-
* - duplicate module names (the name is the graph key)
|
|
124
|
-
* - a `dependsOn` name not present in the composed set
|
|
125
|
-
* - a self-reference (`dependsOn` includes the module's own name)
|
|
126
|
-
* - a dependency cycle (reports the concrete `a → b → … → a` path)
|
|
127
|
-
*/
|
|
128
|
-
declare function orderModules(modules: readonly ArcModule[]): ArcModule[];
|
|
129
|
-
//#endregion
|
|
130
|
-
//#region src/factory/module/resolve.d.ts
|
|
131
|
-
/**
|
|
132
|
-
* Resolve any module-input form to a concrete `ArcModule`. A thunk is invoked
|
|
133
|
-
* (this is where a dynamic `import()` fires); a promise (or plain module) is
|
|
134
|
-
* awaited. Called once per module at the start of the bootstrap phase.
|
|
135
|
-
*/
|
|
136
|
-
declare function resolveModule(input: ArcModuleInput): Promise<ArcModule>;
|
|
137
|
-
/** Resolve a `ModuleContribution` to a concrete array (array passthrough or factory call). */
|
|
138
|
-
declare function resolveContribution<T>(contribution: ModuleContribution<T> | undefined, fastify: FastifyInstance): Promise<readonly T[]>;
|
|
139
|
-
//#endregion
|
|
140
|
-
//#region src/factory/module/state.d.ts
|
|
141
|
-
type ModuleState = "resolved" | "bootstrapping" | "ready" | "closing" | "closed" | "failed";
|
|
142
|
-
/**
|
|
143
|
-
* Is `name` in the composed module graph? TRUE for resource-only modules and
|
|
144
|
-
* modules that exported nothing — the question `hasModuleExports()` cannot
|
|
145
|
-
* answer. FALSE before registerResources runs (no graph yet) and for
|
|
146
|
-
* uncomposed names.
|
|
147
|
-
*/
|
|
148
|
-
declare function hasModule(fastify: FastifyInstance, name: string): boolean;
|
|
149
|
-
/**
|
|
150
|
-
* The module's current lifecycle state, or `undefined` when the module is not
|
|
151
|
-
* composed (or no graph has been composed on this instance). See the state
|
|
152
|
-
* machine in the file header.
|
|
153
|
-
*/
|
|
154
|
-
declare function getModuleState(fastify: FastifyInstance, name: string): ModuleState | undefined;
|
|
155
|
-
//#endregion
|
|
156
|
-
//#region src/factory/module/index.d.ts
|
|
157
|
-
/**
|
|
158
|
-
* Identity helper for authoring a typed module — mirrors `defineResource`.
|
|
159
|
-
* Gives inference + a single obvious construction site; does no work.
|
|
160
|
-
*
|
|
161
|
-
* `TExports` is inferred from the `bootstrap` return value, so a module
|
|
162
|
-
* author gets a typed public export for free:
|
|
163
|
-
*
|
|
164
|
-
* ```ts
|
|
165
|
-
* export const accountingModule = (deps: Deps) =>
|
|
166
|
-
* defineModule({
|
|
167
|
-
* name: "accounting",
|
|
168
|
-
* bootstrap: async () => createAccountingEngine(deps), // TExports inferred
|
|
169
|
-
* });
|
|
170
|
-
* ```
|
|
171
|
-
*/
|
|
172
|
-
declare function defineModule<TExports = unknown>(module: ArcModule<TExports>): ArcModule<TExports>;
|
|
173
|
-
/**
|
|
174
|
-
* Typed accessor for a module's public export (its `bootstrap` return value),
|
|
175
|
-
* recorded at `fastify.arc.modules[name]`.
|
|
176
|
-
*
|
|
177
|
-
* Throwing, in line with the fail-fast contract (and `requireOrgId`-style
|
|
178
|
-
* accessors): a missing entry means the module either isn't composed, is
|
|
179
|
-
* composed AFTER the caller (list order = init order), or returned nothing —
|
|
180
|
-
* all wiring bugs that must surface at boot, not as `undefined` downstream.
|
|
181
|
-
*
|
|
182
|
-
* The type parameter is an assertion, not a proof. Two ways to type it:
|
|
183
|
-
* - augment `ArcModuleRegistry` once — then the name alone infers the type:
|
|
184
|
-
* `getModuleExports(f, "accounting")` → `AccountingEngine`.
|
|
185
|
-
* - or pass it inline: `getModuleExports<AccountingEngine>(f, "accounting")`.
|
|
186
|
-
*
|
|
187
|
-
* Siblings, for the two shapes this one is wrong for:
|
|
188
|
-
* - `getOptionalModuleExports` — the module is genuinely OPTIONAL.
|
|
189
|
-
* - `lazyModuleExports` / `lazyRequiredModuleExports` — the read happens at
|
|
190
|
-
* composition time, where boot order decides the answer.
|
|
191
|
-
*/
|
|
192
|
-
declare function getModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K];
|
|
193
|
-
declare function getModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports;
|
|
194
|
-
/**
|
|
195
|
-
* Non-throwing sibling of `getModuleExports`: `undefined` when the module is
|
|
196
|
-
* not composed (or has not bootstrapped yet).
|
|
197
|
-
*
|
|
198
|
-
* Exists because OPTIONAL sibling modules are a first-class composition shape —
|
|
199
|
-
* a deployment that turns `inventory` off still sells services, so its POS
|
|
200
|
-
* module must ask "is inventory here?" rather than fail-fast. Hosts were
|
|
201
|
-
* spelling that question as
|
|
202
|
-
*
|
|
203
|
-
* ```ts
|
|
204
|
-
* (fastify as { arc?: { modules?: Record<string, unknown> } })
|
|
205
|
-
* .arc?.modules?.inventory;
|
|
206
|
-
* ```
|
|
207
|
-
*
|
|
208
|
-
* — a double cast that (a) defeats `ArcModuleRegistry` inference, (b) silently
|
|
209
|
-
* survives a typo in the module name, and (c) is impossible to grep for. Use
|
|
210
|
-
* `getModuleExports` when the dependency is REQUIRED (boot must fail), this
|
|
211
|
-
* when it is genuinely optional.
|
|
212
|
-
*
|
|
213
|
-
* Prefer `lazyModuleExports` whenever the read happens at COMPOSITION time —
|
|
214
|
-
* see its doc for why a value read once can latch `undefined` forever.
|
|
215
|
-
*/
|
|
216
|
-
declare function getOptionalModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K] | undefined;
|
|
217
|
-
declare function getOptionalModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports | undefined;
|
|
218
|
-
/**
|
|
219
|
-
* Is a module's public export recorded yet? The predicate form of
|
|
220
|
-
* `getOptionalModuleExports`, for readiness gates (`ready: () => ...`) that
|
|
221
|
-
* should not have to reason about falsy-but-present exports.
|
|
222
|
-
*/
|
|
223
|
-
declare function hasModuleExports(fastify: FastifyInstance, name: string): boolean;
|
|
224
|
-
/**
|
|
225
|
-
* A DEFERRED reader of a sibling module's export: returns a getter that reads
|
|
226
|
-
* the registry at CALL time, not now.
|
|
227
|
-
*
|
|
228
|
-
* ── Why this exists (the bug it removes) ─────────────────────────────────────
|
|
229
|
-
*
|
|
230
|
-
* Module composition runs bootstraps in dependency/list order, but a lot of
|
|
231
|
-
* wiring is *registered* earlier than it *runs*: an `eventHandlers` factory, a
|
|
232
|
-
* bridge accessor handed to another module, a hook added during bootstrap and
|
|
233
|
-
* fired per request. Such a factory can execute BEFORE the sibling it needs has
|
|
234
|
-
* bootstrapped — so a sibling engine captured into a local at that moment is
|
|
235
|
-
* `undefined`, and stays `undefined` for the life of the process even though the
|
|
236
|
-
* sibling came up milliseconds later.
|
|
237
|
-
*
|
|
238
|
-
* That failure is SILENT by construction: the consumer sees a null bridge and
|
|
239
|
-
* treats it as "this deployment has no inventory / no revenue engine", which is
|
|
240
|
-
* a legitimate configuration. Real cost in this codebase: orders were created
|
|
241
|
-
* and never payment-confirmed (no entitlement, no card, no door) and nothing
|
|
242
|
-
* errored anywhere.
|
|
243
|
-
*
|
|
244
|
-
* The getter therefore:
|
|
245
|
-
* - re-reads while the module is ABSENT, so boot order cannot matter;
|
|
246
|
-
* - memoizes the FIRST resolved value, so the steady-state read is a closure
|
|
247
|
-
* variable rather than a registry lookup per request;
|
|
248
|
-
* - never memoizes absence — that is precisely the latch this replaces.
|
|
249
|
-
*
|
|
250
|
-
* ```ts
|
|
251
|
-
* const inventory = lazyModuleExports<FlowEngine>(fastify, "inventory");
|
|
252
|
-
* return {
|
|
253
|
-
* flowBridge: () => (inventory() ? createFlowEngineBridge({ getFlowEngine: () => inventory()! }) : null),
|
|
254
|
-
* ready: () => inventory() !== undefined,
|
|
255
|
-
* };
|
|
256
|
-
* ```
|
|
257
|
-
*/
|
|
258
|
-
declare function lazyModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): () => ArcModuleRegistry[K] | undefined;
|
|
259
|
-
declare function lazyModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): () => TExports | undefined;
|
|
260
|
-
/**
|
|
261
|
-
* Required counterpart of `lazyModuleExports`: defers the read, then throws
|
|
262
|
-
* `getModuleExports`' error if the module is still absent at first use.
|
|
263
|
-
*
|
|
264
|
-
* The pair matters because "required" and "readable now" are different
|
|
265
|
-
* questions. A hook registered at bootstrap that needs the `order` engine at
|
|
266
|
-
* REQUEST time is a hard dependency, but reading it eagerly turns a correct
|
|
267
|
-
* composition into a boot crash purely because of list order. Deferring keeps
|
|
268
|
-
* the fail-fast guarantee and moves it to the first moment the answer is
|
|
269
|
-
* actually needed.
|
|
270
|
-
*
|
|
271
|
-
* Deferred does NOT mean unvalidated: a lazily-required module is still a
|
|
272
|
-
* HARD dependency, so PRESENCE is checked eagerly. When the composed module
|
|
273
|
-
* graph is known (any `createApp`/`registerResources` boot — the normal
|
|
274
|
-
* case), a name that is not in the graph throws HERE, at composition time,
|
|
275
|
-
* instead of surviving startup and failing on the first request or event.
|
|
276
|
-
* Only the EXPORT read (does bootstrap's return value exist yet?) is
|
|
277
|
-
* deferred to first call.
|
|
278
|
-
*
|
|
279
|
-
* Convention for hard sibling access: also declare the target in the
|
|
280
|
-
* consumer's `dependsOn`. That orders composition (the sibling's bootstrap
|
|
281
|
-
* runs first), while this accessor merely defers the read — the two are
|
|
282
|
-
* complementary, not alternatives:
|
|
283
|
-
* - hard dependency, read during bootstrap → `dependsOn` + `getModuleExports`
|
|
284
|
-
* - hard dependency, read at request/event time → `dependsOn` + this
|
|
285
|
-
* - optional integration → `lazyModuleExports` (no `dependsOn` needed)
|
|
286
|
-
*/
|
|
287
|
-
declare function lazyRequiredModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): () => ArcModuleRegistry[K];
|
|
288
|
-
declare function lazyRequiredModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): () => TExports;
|
|
289
|
-
//#endregion
|
|
290
|
-
export { collectModuleScheduledJobs as _, lazyModuleExports as a, getModuleState as c, resolveModule as d, orderModules as f, collectModuleHealthChecks as g, extendModule as h, hasModuleExports as i, hasModule as l, ModuleExtension as m, getModuleExports as n, lazyRequiredModuleExports as o, subscribeModuleEventHandlers as p, getOptionalModuleExports as r, ModuleState as s, defineModule as t, resolveContribution as u, collectModuleWorkflows as v };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
|
|
2
|
-
//#region src/idempotency/stores/interface.ts
|
|
3
|
-
/**
|
|
4
|
-
* Helper to create a result object
|
|
5
|
-
*/
|
|
6
|
-
function createIdempotencyResult(statusCode, body, headers, ttlMs) {
|
|
7
|
-
const now = /* @__PURE__ */ new Date();
|
|
8
|
-
return {
|
|
9
|
-
statusCode,
|
|
10
|
-
headers,
|
|
11
|
-
body,
|
|
12
|
-
createdAt: now,
|
|
13
|
-
expiresAt: new Date(now.getTime() + ttlMs)
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
//#endregion
|
|
17
|
-
export { createIdempotencyResult as t };
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "./EventTransport-CbUKDzZZ.mjs";
|
|
3
|
-
//#region src/events/transports/redis-stream.d.ts
|
|
4
|
-
interface RedisStreamLike {
|
|
5
|
-
xadd(key: string, id: string, ...fieldValues: string[]): Promise<string | null>;
|
|
6
|
-
xreadgroup(command: "GROUP", group: string, consumer: string, ...args: unknown[]): Promise<Array<[string, Array<[string, string[] | null]>]> | null>;
|
|
7
|
-
xack(key: string, group: string, ...ids: unknown[]): Promise<number>;
|
|
8
|
-
xgroup(command: string, key: string, group: string, ...args: unknown[]): Promise<unknown>;
|
|
9
|
-
xpending(key: string, group: string, ...args: unknown[]): Promise<unknown[]>;
|
|
10
|
-
xclaim(key: string, group: string, consumer: string, minIdleTime: number, ...ids: unknown[]): Promise<unknown[]>;
|
|
11
|
-
xlen(key: string): Promise<number>;
|
|
12
|
-
/**
|
|
13
|
-
* Read a range of entries by id. When present, the DLQ writer uses this
|
|
14
|
-
* to fetch the original message payload so dead-lettered events are
|
|
15
|
-
* **fully replayable** (a re-publish of `envelope.event` is sufficient).
|
|
16
|
-
*
|
|
17
|
-
* Optional to preserve back-compat with custom Redis wrappers that
|
|
18
|
-
* satisfied the pre-2.11.3 shape. When missing, the DLQ envelope still
|
|
19
|
-
* carries the **error reason + attempt accounting** (operator-grade
|
|
20
|
-
* triage info survives), but `envelope.event.payload` is `null` and
|
|
21
|
-
* `envelope.event.type` is `<unknown>` — replay is NOT possible without
|
|
22
|
-
* upgrading the client. A one-shot warning fires per process so this
|
|
23
|
-
* isn't silent.
|
|
24
|
-
*/
|
|
25
|
-
xrange?(key: string, start: string, end: string): Promise<Array<[string, string[]]>>;
|
|
26
|
-
/** Graceful close — flushes queued commands then closes. ioredis-style. */
|
|
27
|
-
quit(): Promise<unknown>;
|
|
28
|
-
/**
|
|
29
|
-
* Force-disconnect — closes the socket immediately, abandoning any
|
|
30
|
-
* pending command (including a live `XREADGROUP BLOCK`). Optional because
|
|
31
|
-
* non-ioredis clients may not expose a force path; `close()` falls back
|
|
32
|
-
* to `quit()` when this is missing, accepting a longer shutdown wait.
|
|
33
|
-
*/
|
|
34
|
-
disconnect?(): void;
|
|
35
|
-
}
|
|
36
|
-
interface RedisStreamTransportOptions {
|
|
37
|
-
/**
|
|
38
|
-
* Redis stream key name.
|
|
39
|
-
* @default 'arc:events'
|
|
40
|
-
*/
|
|
41
|
-
stream?: string;
|
|
42
|
-
/**
|
|
43
|
-
* Consumer group name. Each group receives every event independently.
|
|
44
|
-
* Multiple instances of the same service should share a group name.
|
|
45
|
-
* @default 'default'
|
|
46
|
-
*/
|
|
47
|
-
group?: string;
|
|
48
|
-
/**
|
|
49
|
-
* Consumer name within the group. Must be unique per instance.
|
|
50
|
-
* @default 'consumer-<random>'
|
|
51
|
-
*/
|
|
52
|
-
consumer?: string;
|
|
53
|
-
/**
|
|
54
|
-
* Block time in ms when waiting for new events.
|
|
55
|
-
* @default 5000
|
|
56
|
-
*/
|
|
57
|
-
blockTimeMs?: number;
|
|
58
|
-
/**
|
|
59
|
-
* Max events to read per batch.
|
|
60
|
-
* @default 10
|
|
61
|
-
*/
|
|
62
|
-
batchSize?: number;
|
|
63
|
-
/**
|
|
64
|
-
* Bounded concurrency for processing a batch's ENTRIES (default: 1 —
|
|
65
|
-
* strict stream order, the safe default). With one slow handler,
|
|
66
|
-
* throughput per consumer is ~`1 / total handler latency`; raising this
|
|
67
|
-
* processes up to N entries of a batch concurrently.
|
|
68
|
-
*
|
|
69
|
-
* Trade-off: entries within a batch may complete OUT OF ORDER — only
|
|
70
|
-
* raise it when handlers are order-independent (idempotent, keyed
|
|
71
|
-
* upserts). Handlers on this transport should be short and I/O-bound
|
|
72
|
-
* regardless; heavy work belongs in jobs. Matching handlers for a single
|
|
73
|
-
* event always run sequentially.
|
|
74
|
-
* @default 1
|
|
75
|
-
*/
|
|
76
|
-
processingConcurrency?: number;
|
|
77
|
-
/**
|
|
78
|
-
* Max delivery attempts before moving to dead letter stream.
|
|
79
|
-
* @default 5
|
|
80
|
-
*/
|
|
81
|
-
maxRetries?: number;
|
|
82
|
-
/**
|
|
83
|
-
* Idle time in ms before pending entries are claimed by this consumer.
|
|
84
|
-
* Handles crash recovery — if a consumer dies mid-processing, another
|
|
85
|
-
* consumer will claim its pending entries after this timeout.
|
|
86
|
-
* @default 30000
|
|
87
|
-
*/
|
|
88
|
-
claimTimeoutMs?: number;
|
|
89
|
-
/**
|
|
90
|
-
* Dead letter stream name. Failed events are moved here after maxRetries.
|
|
91
|
-
* Set to `false` to disable DLQ (failed events are acked and dropped).
|
|
92
|
-
* @default 'arc:events:dlq'
|
|
93
|
-
*/
|
|
94
|
-
deadLetterStream?: string | false;
|
|
95
|
-
/**
|
|
96
|
-
* Max stream length (approximate). Uses XADD MAXLEN ~ to trim old entries.
|
|
97
|
-
* Set to 0 to disable trimming.
|
|
98
|
-
* @default 10000
|
|
99
|
-
*/
|
|
100
|
-
maxLen?: number;
|
|
101
|
-
/**
|
|
102
|
-
* Max event payload size in bytes. Publish rejects events exceeding this limit
|
|
103
|
-
* to prevent Redis memory exhaustion from oversized payloads.
|
|
104
|
-
* @default 1_000_000 (1 MB)
|
|
105
|
-
*/
|
|
106
|
-
maxPayloadBytes?: number;
|
|
107
|
-
/**
|
|
108
|
-
* If `true`, `close()` does NOT call `redis.quit()` — useful when the host
|
|
109
|
-
* manages the Redis connection lifecycle externally (shared client across
|
|
110
|
-
* multiple transports / cache stores). Without this, every transport
|
|
111
|
-
* `close()` would tear down a shared client and break siblings.
|
|
112
|
-
*
|
|
113
|
-
* Mirror of `RedisEventTransportOptions.externalLifecycle`.
|
|
114
|
-
* @default false
|
|
115
|
-
*/
|
|
116
|
-
externalLifecycle?: boolean;
|
|
117
|
-
/**
|
|
118
|
-
* Hard cap on how long `close()` waits for the in-flight `XREADGROUP BLOCK`
|
|
119
|
-
* iteration to drain. Tests and serverless shutdowns would otherwise hang
|
|
120
|
-
* up to `blockTimeMs` (default 5s) per close.
|
|
121
|
-
*
|
|
122
|
-
* Behaviour after timeout:
|
|
123
|
-
* - `externalLifecycle: false` (default) — `redis.disconnect()` (or
|
|
124
|
-
* `quit()` if the client lacks `disconnect`) breaks the BLOCK
|
|
125
|
-
* immediately. Strict bounded close.
|
|
126
|
-
* - `externalLifecycle: true` — arc CANNOT touch the host's connection,
|
|
127
|
-
* so the poll loop is left to drain in the background when its
|
|
128
|
-
* XREADGROUP returns. `close()` returns within `closeTimeoutMs` but
|
|
129
|
-
* the loop's eventual completion is silently absorbed (no log spam,
|
|
130
|
-
* no unhandled rejection). The contract here is "bounded return,
|
|
131
|
-
* background drain" — set `blockTimeMs` low (e.g. 500ms) under
|
|
132
|
-
* externalLifecycle to keep the drain window short.
|
|
133
|
-
*
|
|
134
|
-
* @default 1000
|
|
135
|
-
*/
|
|
136
|
-
closeTimeoutMs?: number;
|
|
137
|
-
/**
|
|
138
|
-
* Logger for error messages (default: console).
|
|
139
|
-
* Pass `fastify.log` to integrate with your application logger.
|
|
140
|
-
*/
|
|
141
|
-
logger?: EventLogger;
|
|
142
|
-
}
|
|
143
|
-
declare class RedisStreamTransport implements EventTransport {
|
|
144
|
-
readonly name = "redis-stream";
|
|
145
|
-
private redis;
|
|
146
|
-
private stream;
|
|
147
|
-
private group;
|
|
148
|
-
private consumer;
|
|
149
|
-
private blockTimeMs;
|
|
150
|
-
private batchSize;
|
|
151
|
-
private processingConcurrency;
|
|
152
|
-
private maxRetries;
|
|
153
|
-
private claimTimeoutMs;
|
|
154
|
-
private deadLetterStream;
|
|
155
|
-
private maxLen;
|
|
156
|
-
private maxPayloadBytes;
|
|
157
|
-
private logger;
|
|
158
|
-
/** Tracks the lifecycle policy — set in constructor, read in close(). */
|
|
159
|
-
private externalLifecycle;
|
|
160
|
-
private closeTimeoutMs;
|
|
161
|
-
private handlers;
|
|
162
|
-
private running;
|
|
163
|
-
private pollPromise;
|
|
164
|
-
/**
|
|
165
|
-
* Monotonic counter bumped every time the poll loop should stop —
|
|
166
|
-
* `unsubscribe` (last handler removed) and `close()` increment it. Each
|
|
167
|
-
* `pollLoop` instance captures its generation at start and exits when
|
|
168
|
-
* `this.generation` no longer matches. Prevents the
|
|
169
|
-
* subscribe → unsubscribe → fast-resubscribe race where the old loop
|
|
170
|
-
* would still be in `XREADGROUP BLOCK` while a new loop started, leading
|
|
171
|
-
* to two concurrent poll loops on the same consumer name.
|
|
172
|
-
*/
|
|
173
|
-
private generation;
|
|
174
|
-
private groupCreated;
|
|
175
|
-
/**
|
|
176
|
-
* Last-seen failure context per message id, populated when an in-process
|
|
177
|
-
* handler throws in {@link processEntry}. Consumed (and cleared) by
|
|
178
|
-
* {@link moveToDlq} so the dead-letter envelope carries the actual error
|
|
179
|
-
* message instead of opaque "reclaimed without context". Entries are
|
|
180
|
-
* deleted on ack and on DLQ write; messages resolved by ANOTHER consumer
|
|
181
|
-
* never drain locally, so the map is additionally hard-capped at
|
|
182
|
-
* {@link MAX_FAILURE_CONTEXT_ENTRIES} with oldest-first eviction.
|
|
183
|
-
*/
|
|
184
|
-
private failureContext;
|
|
185
|
-
/** One-shot guard so the "client lacks xrange" warning fires once per process. */
|
|
186
|
-
private xrangeWarningEmitted;
|
|
187
|
-
constructor(redis: RedisStreamLike, options?: RedisStreamTransportOptions);
|
|
188
|
-
publish(event: DomainEvent): Promise<void>;
|
|
189
|
-
subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
|
|
190
|
-
/**
|
|
191
|
-
* Stop polling and release transport state.
|
|
192
|
-
*
|
|
193
|
-
* **Two close contracts** — pick the one that matches your deployment:
|
|
194
|
-
*
|
|
195
|
-
* 1. **Default (`externalLifecycle: false`) — strict bounded close.**
|
|
196
|
-
* `close()` waits up to `closeTimeoutMs` for the in-flight
|
|
197
|
-
* `XREADGROUP BLOCK` to drain. On timeout it calls `redis.disconnect()`
|
|
198
|
-
* (or `quit()` if the client lacks `disconnect`) to break the BLOCK
|
|
199
|
-
* immediately, then awaits the loop's exit. After `close()` returns
|
|
200
|
-
* the transport is fully closed and the connection is released.
|
|
201
|
-
*
|
|
202
|
-
* 2. **`externalLifecycle: true` — bounded RETURN, background drain.**
|
|
203
|
-
* Arc must NOT touch a connection it doesn't own. `close()` returns
|
|
204
|
-
* within `closeTimeoutMs`, but the poll loop is left to drain on its
|
|
205
|
-
* own when its outstanding `XREADGROUP BLOCK` returns (up to
|
|
206
|
-
* `blockTimeMs`). Arc silently absorbs the loop's eventual completion
|
|
207
|
-
* so the host doesn't see unhandled rejections / log spam against a
|
|
208
|
-
* transport it considers closed. The host's own `redis.quit()` /
|
|
209
|
-
* process exit is what ultimately tears the connection down.
|
|
210
|
-
*
|
|
211
|
-
* Practical implication: under `externalLifecycle: true`, set
|
|
212
|
-
* `blockTimeMs` low (e.g. 500ms) so the background drain window is
|
|
213
|
-
* short. The transport is "closed enough" to stop dispatching to
|
|
214
|
-
* handlers (handlers map is cleared and generation is bumped) but is
|
|
215
|
-
* not "fully closed" in the connection-lifecycle sense until the host
|
|
216
|
-
* closes the underlying client.
|
|
217
|
-
*
|
|
218
|
-
* In both modes the generation counter is bumped, so a follow-up
|
|
219
|
-
* `subscribe()` spawns a fresh poll loop with a new generation — the
|
|
220
|
-
* stale loop exits on its next iteration and never overlaps the new one.
|
|
221
|
-
*/
|
|
222
|
-
close(): Promise<void>;
|
|
223
|
-
private ensureGroup;
|
|
224
|
-
private pollLoop;
|
|
225
|
-
private readNewMessages;
|
|
226
|
-
/**
|
|
227
|
-
* Process a batch's entries with bounded concurrency
|
|
228
|
-
* (`processingConcurrency`, default 1 = strict order). Worker-pool over a
|
|
229
|
-
* shared index — at most N entries in flight, each entry's own handlers
|
|
230
|
-
* still sequential inside `processEntry`.
|
|
231
|
-
*/
|
|
232
|
-
private processEntries;
|
|
233
|
-
private claimPending;
|
|
234
|
-
private processEntry;
|
|
235
|
-
/**
|
|
236
|
-
* The canonical matcher from primitives — the SAME glob rules the memory
|
|
237
|
-
* transport speaks. A private matcher here once accepted `prefix.*` but not
|
|
238
|
-
* `prefix:*`, so an `order:*` subscription that worked in-process received
|
|
239
|
-
* nothing after a move to the stream, with no error.
|
|
240
|
-
*/
|
|
241
|
-
private getMatchingHandlers;
|
|
242
|
-
private moveToDlq;
|
|
243
|
-
/**
|
|
244
|
-
* Reconstruct a `DeadLetteredEvent` for a message id. Reads the original
|
|
245
|
-
* entry via `xrange` (when the client supports it) and merges in any
|
|
246
|
-
* in-process failure context. Returns `null` only when BOTH sources are
|
|
247
|
-
* missing — callers ack-and-drop rather than re-queuing a ghost.
|
|
248
|
-
*
|
|
249
|
-
* Graceful degradation paths:
|
|
250
|
-
* - Client lacks `xrange` (older custom wrappers) → log once, build the
|
|
251
|
-
* envelope from `failureContext` alone. Payload is absent but the
|
|
252
|
-
* error reason + attempt accounting still survive.
|
|
253
|
-
* - `xrange` throws (network blip, ACL) → same fallback.
|
|
254
|
-
* - Source entry trimmed before DLQ write → same fallback.
|
|
255
|
-
*/
|
|
256
|
-
private buildDlqEnvelope;
|
|
257
|
-
private sleep;
|
|
258
|
-
}
|
|
259
|
-
//#endregion
|
|
260
|
-
export { RedisStreamTransport as n, RedisStreamTransportOptions as r, RedisStreamLike as t };
|