@blokjs/runner 0.4.0 → 0.6.1

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.
Files changed (163) hide show
  1. package/dist/Blok.js +32 -3
  2. package/dist/Blok.js.map +1 -1
  3. package/dist/Configuration.d.ts +41 -5
  4. package/dist/Configuration.js +215 -92
  5. package/dist/Configuration.js.map +1 -1
  6. package/dist/ForEachNode.d.ts +59 -0
  7. package/dist/ForEachNode.js +522 -0
  8. package/dist/ForEachNode.js.map +1 -0
  9. package/dist/LoopMaxIterationsError.d.ts +11 -0
  10. package/dist/LoopMaxIterationsError.js +18 -0
  11. package/dist/LoopMaxIterationsError.js.map +1 -0
  12. package/dist/LoopNode.d.ts +36 -0
  13. package/dist/LoopNode.js +182 -0
  14. package/dist/LoopNode.js.map +1 -0
  15. package/dist/Runner.d.ts +11 -1
  16. package/dist/Runner.js +9 -2
  17. package/dist/Runner.js.map +1 -1
  18. package/dist/RunnerSteps.js +419 -112
  19. package/dist/RunnerSteps.js.map +1 -1
  20. package/dist/RuntimeAdapterNode.d.ts +2 -1
  21. package/dist/RuntimeAdapterNode.js +2 -2
  22. package/dist/RuntimeAdapterNode.js.map +1 -1
  23. package/dist/RuntimeRegistry.d.ts +23 -2
  24. package/dist/RuntimeRegistry.js +31 -2
  25. package/dist/RuntimeRegistry.js.map +1 -1
  26. package/dist/SubworkflowNode.d.ts +106 -0
  27. package/dist/SubworkflowNode.js +261 -3
  28. package/dist/SubworkflowNode.js.map +1 -1
  29. package/dist/SwitchNode.d.ts +37 -0
  30. package/dist/SwitchNode.js +153 -0
  31. package/dist/SwitchNode.js.map +1 -0
  32. package/dist/TriggerBase.d.ts +50 -0
  33. package/dist/TriggerBase.js +262 -4
  34. package/dist/TriggerBase.js.map +1 -1
  35. package/dist/TryCatchNode.d.ts +32 -0
  36. package/dist/TryCatchNode.js +207 -0
  37. package/dist/TryCatchNode.js.map +1 -0
  38. package/dist/adapters/grpc/GrpcCodec.js +2 -2
  39. package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +6 -4
  40. package/dist/adapters/grpc/GrpcRuntimeAdapter.js +6 -4
  41. package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -1
  42. package/dist/adapters/grpc/types.d.ts +7 -5
  43. package/dist/adapters/grpc/types.js.map +1 -1
  44. package/dist/adapters/transport.d.ts +12 -41
  45. package/dist/adapters/transport.js +21 -70
  46. package/dist/adapters/transport.js.map +1 -1
  47. package/dist/cache/NodeResultCache.js +7 -0
  48. package/dist/cache/NodeResultCache.js.map +1 -1
  49. package/dist/concurrency/NatsKvConcurrencyBackend.js +18 -5
  50. package/dist/concurrency/NatsKvConcurrencyBackend.js.map +1 -1
  51. package/dist/concurrency/RedisConcurrencyBackend.d.ts +64 -0
  52. package/dist/concurrency/RedisConcurrencyBackend.js +374 -0
  53. package/dist/concurrency/RedisConcurrencyBackend.js.map +1 -0
  54. package/dist/concurrency/createConcurrencyBackend.d.ts +1 -0
  55. package/dist/concurrency/createConcurrencyBackend.js +5 -1
  56. package/dist/concurrency/createConcurrencyBackend.js.map +1 -1
  57. package/dist/defineNode.d.ts +8 -0
  58. package/dist/defineNode.js +25 -5
  59. package/dist/defineNode.js.map +1 -1
  60. package/dist/graphql/GraphQLSchemaGenerator.js +1 -1
  61. package/dist/graphql/GraphQLSchemaGenerator.js.map +1 -1
  62. package/dist/index.d.ts +10 -6
  63. package/dist/index.js +13 -9
  64. package/dist/index.js.map +1 -1
  65. package/dist/marketplace/RuntimeCatalog.d.ts +6 -0
  66. package/dist/marketplace/RuntimeCatalog.js.map +1 -1
  67. package/dist/marketplace/RuntimeDiscovery.d.ts +2 -2
  68. package/dist/marketplace/RuntimeDiscovery.js +18 -6
  69. package/dist/marketplace/RuntimeDiscovery.js.map +1 -1
  70. package/dist/monitoring/ConcurrencyMetrics.d.ts +26 -0
  71. package/dist/monitoring/ConcurrencyMetrics.js +36 -4
  72. package/dist/monitoring/ConcurrencyMetrics.js.map +1 -1
  73. package/dist/monitoring/ForEachWaitMetrics.d.ts +22 -0
  74. package/dist/monitoring/ForEachWaitMetrics.js +36 -0
  75. package/dist/monitoring/ForEachWaitMetrics.js.map +1 -0
  76. package/dist/openapi/OpenAPIGenerator.js +7 -2
  77. package/dist/openapi/OpenAPIGenerator.js.map +1 -1
  78. package/dist/runtime/PrimitiveStack.d.ts +64 -0
  79. package/dist/runtime/PrimitiveStack.js +92 -0
  80. package/dist/runtime/PrimitiveStack.js.map +1 -0
  81. package/dist/scheduling/DebounceBackend.d.ts +108 -0
  82. package/dist/scheduling/DebounceBackend.js +23 -0
  83. package/dist/scheduling/DebounceBackend.js.map +1 -0
  84. package/dist/scheduling/DebounceCoordinator.d.ts +65 -12
  85. package/dist/scheduling/DebounceCoordinator.js +234 -13
  86. package/dist/scheduling/DebounceCoordinator.js.map +1 -1
  87. package/dist/scheduling/DeferredRunScheduler.d.ts +28 -0
  88. package/dist/scheduling/DeferredRunScheduler.js +105 -3
  89. package/dist/scheduling/DeferredRunScheduler.js.map +1 -1
  90. package/dist/scheduling/NatsKvDebounceBackend.d.ts +53 -0
  91. package/dist/scheduling/NatsKvDebounceBackend.js +334 -0
  92. package/dist/scheduling/NatsKvDebounceBackend.js.map +1 -0
  93. package/dist/scheduling/RedisDebounceBackend.d.ts +49 -0
  94. package/dist/scheduling/RedisDebounceBackend.js +356 -0
  95. package/dist/scheduling/RedisDebounceBackend.js.map +1 -0
  96. package/dist/scheduling/createDebounceBackend.d.ts +25 -0
  97. package/dist/scheduling/createDebounceBackend.js +39 -0
  98. package/dist/scheduling/createDebounceBackend.js.map +1 -0
  99. package/dist/security/AuditLogger.js +1 -1
  100. package/dist/security/AuditLogger.js.map +1 -1
  101. package/dist/security/AuthMiddleware.d.ts +19 -20
  102. package/dist/security/AuthMiddleware.js +35 -20
  103. package/dist/security/AuthMiddleware.js.map +1 -1
  104. package/dist/security/OAuthProvider.js +2 -2
  105. package/dist/security/OAuthProvider.js.map +1 -1
  106. package/dist/security/SecretManager.js +14 -13
  107. package/dist/security/SecretManager.js.map +1 -1
  108. package/dist/security/index.d.ts +3 -1
  109. package/dist/security/index.js +3 -1
  110. package/dist/security/index.js.map +1 -1
  111. package/dist/testing/TestHarness.d.ts +27 -12
  112. package/dist/testing/TestHarness.js +19 -3
  113. package/dist/testing/TestHarness.js.map +1 -1
  114. package/dist/testing/WorkflowTestRunner.js +0 -7
  115. package/dist/testing/WorkflowTestRunner.js.map +1 -1
  116. package/dist/tracing/InMemoryRunStore.d.ts +14 -1
  117. package/dist/tracing/InMemoryRunStore.js +95 -6
  118. package/dist/tracing/InMemoryRunStore.js.map +1 -1
  119. package/dist/tracing/PostgresRunStore.d.ts +28 -2
  120. package/dist/tracing/PostgresRunStore.js +276 -3
  121. package/dist/tracing/PostgresRunStore.js.map +1 -1
  122. package/dist/tracing/RoutingDiagnostics.d.ts +55 -0
  123. package/dist/tracing/RoutingDiagnostics.js +50 -0
  124. package/dist/tracing/RoutingDiagnostics.js.map +1 -0
  125. package/dist/tracing/RunStore.d.ts +82 -1
  126. package/dist/tracing/RunTracker.d.ts +7 -1
  127. package/dist/tracing/RunTracker.js +23 -0
  128. package/dist/tracing/RunTracker.js.map +1 -1
  129. package/dist/tracing/SqliteRunStore.d.ts +57 -2
  130. package/dist/tracing/SqliteRunStore.js +408 -48
  131. package/dist/tracing/SqliteRunStore.js.map +1 -1
  132. package/dist/tracing/TraceRouter.js +380 -18
  133. package/dist/tracing/TraceRouter.js.map +1 -1
  134. package/dist/tracing/createStore.js +14 -3
  135. package/dist/tracing/createStore.js.map +1 -1
  136. package/dist/tracing/metadataFilter.d.ts +63 -0
  137. package/dist/tracing/metadataFilter.js +224 -0
  138. package/dist/tracing/metadataFilter.js.map +1 -0
  139. package/dist/tracing/types.d.ts +331 -7
  140. package/dist/utils/envAllowlist.d.ts +35 -0
  141. package/dist/utils/envAllowlist.js +113 -0
  142. package/dist/utils/envAllowlist.js.map +1 -0
  143. package/dist/version/RuntimeVersionValidator.d.ts +38 -0
  144. package/dist/version/RuntimeVersionValidator.js +121 -0
  145. package/dist/version/RuntimeVersionValidator.js.map +1 -0
  146. package/dist/visualization/WorkflowVisualizer.js +4 -4
  147. package/dist/visualization/WorkflowVisualizer.js.map +1 -1
  148. package/dist/workflow/PersistenceHelper.d.ts +18 -10
  149. package/dist/workflow/PersistenceHelper.js +35 -9
  150. package/dist/workflow/PersistenceHelper.js.map +1 -1
  151. package/dist/workflow/WorkflowNormalizer.d.ts +19 -1
  152. package/dist/workflow/WorkflowNormalizer.js +469 -19
  153. package/dist/workflow/WorkflowNormalizer.js.map +1 -1
  154. package/dist/workflow/WorkflowRegistry.d.ts +122 -0
  155. package/dist/workflow/WorkflowRegistry.js +121 -0
  156. package/dist/workflow/WorkflowRegistry.js.map +1 -1
  157. package/dist/workflow/sampleBody.d.ts +54 -0
  158. package/dist/workflow/sampleBody.js +320 -0
  159. package/dist/workflow/sampleBody.js.map +1 -0
  160. package/package.json +3 -8
  161. package/dist/adapters/HttpRuntimeAdapter.d.ts +0 -79
  162. package/dist/adapters/HttpRuntimeAdapter.js +0 -233
  163. package/dist/adapters/HttpRuntimeAdapter.js.map +0 -1
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Tier C #1 · NATS KV-backed debounce backend.
3
+ *
4
+ * Coordinates per-(workflow, debounceKey) window state across processes
5
+ * via a single NATS JetStream KV value per bucket with revision-based
6
+ * compare-and-swap (OCC). Mirrors the storage model of
7
+ * `NatsKvConcurrencyBackend` but with a different document shape (one
8
+ * window per bucket, not a leases array).
9
+ *
10
+ * Acquire / extend / coalesce: a bounded CAS loop (10 retries) that
11
+ * reads → decides ownership → atomically writes. On retry exhaustion,
12
+ * fall back to admitting the ping as a `coalesce` against the current
13
+ * owner — debounce is not a safety gate, so we'd rather over-coalesce
14
+ * than drop pings on a contention spike.
15
+ *
16
+ * Finalize: same OCC pattern. The owning process atomically reads the
17
+ * doc, confirms it still owns AND `now >= scheduledAt`, and atomically
18
+ * deletes. On lease handoff, the owner discovers it no longer owns and
19
+ * abandons silently.
20
+ *
21
+ * **Owner-local payload**: this backend tracks `pingCount`,
22
+ * `lastPingAt`, and `scheduledAt` only — not the payload. Cross-process
23
+ * latest-payload-wins is a deferred follow-up.
24
+ */
25
+ const DEFAULT_BUCKET_NAME = "blok-debounce";
26
+ const MAX_CAS_RETRIES = 10;
27
+ export function readNatsKvDebounceConfigFromEnv() {
28
+ const serversRaw = process.env.BLOK_DEBOUNCE_NATS_SERVERS ?? "nats://localhost:4222";
29
+ const servers = serversRaw
30
+ .split(",")
31
+ .map((s) => s.trim())
32
+ .filter(Boolean);
33
+ return {
34
+ servers,
35
+ token: process.env.BLOK_DEBOUNCE_NATS_TOKEN,
36
+ user: process.env.BLOK_DEBOUNCE_NATS_USER,
37
+ pass: process.env.BLOK_DEBOUNCE_NATS_PASS,
38
+ bucketName: process.env.BLOK_DEBOUNCE_NATS_KV_BUCKET ?? DEFAULT_BUCKET_NAME,
39
+ };
40
+ }
41
+ export class NatsKvDebounceBackend {
42
+ name = "nats-kv";
43
+ nc = null;
44
+ kv = null;
45
+ config;
46
+ connected = false;
47
+ constructor(config) {
48
+ const env = readNatsKvDebounceConfigFromEnv();
49
+ this.config = {
50
+ servers: config?.servers ?? env.servers,
51
+ token: config?.token ?? env.token,
52
+ user: config?.user ?? env.user,
53
+ pass: config?.pass ?? env.pass,
54
+ bucketName: config?.bucketName ?? env.bucketName,
55
+ };
56
+ }
57
+ async connect() {
58
+ if (this.connected)
59
+ return;
60
+ // Security review FW-5 parity — refuse to start in production with
61
+ // the default bucket name (same risk as the concurrency NATS KV
62
+ // bucket).
63
+ const blokEnv = process.env.BLOK_ENV;
64
+ const nodeEnv = process.env.NODE_ENV;
65
+ const isProd = blokEnv === "production" || nodeEnv === "production";
66
+ if (isProd && this.config.bucketName === DEFAULT_BUCKET_NAME) {
67
+ throw new Error(`[blok] NATS KV debounce backend refuses to start in production with the default bucket name ('${DEFAULT_BUCKET_NAME}'). Set BLOK_DEBOUNCE_NATS_KV_BUCKET to a deployment-unique value (e.g. 'blok-debounce-acme-prod') to prevent cross-deployment collision on a shared NATS server.`);
68
+ }
69
+ let natsModule;
70
+ try {
71
+ natsModule = (await import("nats"));
72
+ }
73
+ catch (err) {
74
+ throw new Error(`NatsKvDebounceBackend requires the 'nats' package. Install it: \`bun add nats\` or \`npm install nats\`. Underlying error: ${err instanceof Error ? err.message : String(err)}`);
75
+ }
76
+ const connectOpts = { servers: this.config.servers };
77
+ if (this.config.token)
78
+ connectOpts.token = this.config.token;
79
+ if (this.config.user)
80
+ connectOpts.user = this.config.user;
81
+ if (this.config.pass)
82
+ connectOpts.pass = this.config.pass;
83
+ this.nc = await natsModule.connect(connectOpts);
84
+ // nats.js v2.x — KV lives at `nc.jetstream().views.kv(name)`.
85
+ const js = this.nc.jetstream();
86
+ this.kv = await js.views.kv(this.config.bucketName);
87
+ this.connected = true;
88
+ }
89
+ async disconnect() {
90
+ if (!this.connected)
91
+ return;
92
+ try {
93
+ await this.nc?.drain();
94
+ }
95
+ finally {
96
+ this.nc = null;
97
+ this.kv = null;
98
+ this.connected = false;
99
+ }
100
+ }
101
+ bucketKey(workflowName, debounceKey) {
102
+ return `${this.encodeSegment(workflowName)}__${this.encodeSegment(debounceKey)}`;
103
+ }
104
+ encodeSegment(s) {
105
+ return s.replace(/[^-_=.a-zA-Z0-9]/g, (ch) => `_${ch.codePointAt(0)?.toString(16)}_`);
106
+ }
107
+ requireKv() {
108
+ if (!this.kv) {
109
+ throw new Error("NatsKvDebounceBackend not connected — call connect() first.");
110
+ }
111
+ return this.kv;
112
+ }
113
+ computeScheduledAt(opts, existing) {
114
+ const naive = opts.now + opts.delayMs;
115
+ const deadline = existing?.maxDelayDeadline ?? (opts.maxDelayMs !== undefined ? opts.now + opts.maxDelayMs : undefined);
116
+ return deadline !== undefined ? Math.min(naive, deadline) : naive;
117
+ }
118
+ async registerPing(opts) {
119
+ const kv = this.requireKv();
120
+ const key = this.bucketKey(opts.workflowName, opts.debounceKey);
121
+ for (let attempt = 0; attempt < MAX_CAS_RETRIES; attempt++) {
122
+ const entry = await this.safeGet(kv, key);
123
+ if (entry === "fetch-failed") {
124
+ // Surface but don't retry on broker outage — debounce is
125
+ // fail-open per the coordinator wrapper.
126
+ throw new Error(`registerPing fetch-failed for ${key} (attempt ${attempt + 1})`);
127
+ }
128
+ const existing = entry ? this.parseDoc(entry) : null;
129
+ // Owner-lease expired → treat as no existing window.
130
+ const ownerActive = existing !== null && existing.ownerLeaseExpiresAt > opts.now;
131
+ if (!existing || !ownerActive) {
132
+ // Take ownership — new doc or owner-lease handoff.
133
+ const doc = {
134
+ mode: opts.mode,
135
+ delayMs: opts.delayMs,
136
+ maxDelayMs: opts.maxDelayMs,
137
+ maxDelayDeadline: existing?.maxDelayDeadline ?? (opts.maxDelayMs !== undefined ? opts.now + opts.maxDelayMs : undefined),
138
+ firstPingAt: existing?.firstPingAt ?? opts.now,
139
+ lastPingAt: opts.now,
140
+ pingCount: (existing?.pingCount ?? 0) + 1,
141
+ activeRunId: opts.runId,
142
+ ownerProcessId: opts.processId,
143
+ ownerLeaseExpiresAt: opts.now + opts.ownerLeaseMs,
144
+ scheduledAt: this.computeScheduledAt(opts, existing),
145
+ };
146
+ try {
147
+ if (entry) {
148
+ await kv.update(key, JSON.stringify(doc), entry.revision);
149
+ }
150
+ else {
151
+ await kv.create(key, JSON.stringify(doc));
152
+ }
153
+ return {
154
+ outcome: "owner-new",
155
+ activeRunId: doc.activeRunId,
156
+ scheduledAt: doc.scheduledAt,
157
+ pingCount: doc.pingCount,
158
+ };
159
+ }
160
+ catch {
161
+ continue; // CAS conflict — retry.
162
+ }
163
+ }
164
+ // existing && ownerActive
165
+ if (existing.ownerProcessId === opts.processId) {
166
+ // We still own — extend the window.
167
+ const next = {
168
+ ...existing,
169
+ lastPingAt: opts.now,
170
+ pingCount: existing.pingCount + 1,
171
+ ownerLeaseExpiresAt: opts.now + opts.ownerLeaseMs,
172
+ scheduledAt: this.computeScheduledAt(opts, existing),
173
+ // activeRunId stays — owner's run id from owner-new is the source of truth.
174
+ };
175
+ try {
176
+ await kv.update(key, JSON.stringify(next), entry?.revision ?? 0);
177
+ return {
178
+ outcome: "owner-extend",
179
+ activeRunId: existing.activeRunId,
180
+ scheduledAt: next.scheduledAt,
181
+ pingCount: next.pingCount,
182
+ };
183
+ }
184
+ catch {
185
+ continue;
186
+ }
187
+ }
188
+ // Different process owns. Coalesce — bump pingCount + push scheduledAt only.
189
+ const next = {
190
+ ...existing,
191
+ lastPingAt: opts.now,
192
+ pingCount: existing.pingCount + 1,
193
+ scheduledAt: this.computeScheduledAt(opts, existing),
194
+ };
195
+ try {
196
+ await kv.update(key, JSON.stringify(next), entry?.revision ?? 0);
197
+ return {
198
+ outcome: "coalesce",
199
+ activeRunId: existing.activeRunId,
200
+ scheduledAt: next.scheduledAt,
201
+ pingCount: next.pingCount,
202
+ };
203
+ }
204
+ catch {
205
+ // CAS conflict — fall through to the next loop iteration.
206
+ }
207
+ }
208
+ // CAS retries exhausted — over-coalesce: read the current owner and
209
+ // return coalesce. Last-resort fallback that prefers admitting a
210
+ // ping (with attribution to whoever currently owns) over dropping it.
211
+ const entry = await this.safeGet(kv, key);
212
+ if (entry && entry !== "fetch-failed") {
213
+ const existing = this.parseDoc(entry);
214
+ if (existing) {
215
+ return {
216
+ outcome: "coalesce",
217
+ activeRunId: existing.activeRunId,
218
+ scheduledAt: existing.scheduledAt,
219
+ pingCount: existing.pingCount,
220
+ };
221
+ }
222
+ }
223
+ // No doc readable — best-effort owner-new with caller's runId so
224
+ // the coordinator drives a local timer; the next ping will resolve
225
+ // the race.
226
+ return {
227
+ outcome: "owner-new",
228
+ activeRunId: opts.runId,
229
+ scheduledAt: opts.now + opts.delayMs,
230
+ pingCount: 1,
231
+ };
232
+ }
233
+ async finalize(workflowName, debounceKey, runId, now) {
234
+ const kv = this.requireKv();
235
+ const key = this.bucketKey(workflowName, debounceKey);
236
+ for (let attempt = 0; attempt < MAX_CAS_RETRIES; attempt++) {
237
+ const entry = await this.safeGet(kv, key);
238
+ if (entry === "fetch-failed") {
239
+ return { finalize: "abandoned" };
240
+ }
241
+ if (!entry)
242
+ return { finalize: "abandoned" };
243
+ const doc = this.parseDoc(entry);
244
+ if (!doc)
245
+ return { finalize: "abandoned" };
246
+ // Different runId now owns → abandoned (owner lease handed off).
247
+ if (doc.activeRunId !== runId)
248
+ return { finalize: "abandoned" };
249
+ // Coalesce pings pushed scheduledAt forward → reschedule.
250
+ if (now < doc.scheduledAt) {
251
+ return { finalize: "reschedule", scheduledAt: doc.scheduledAt };
252
+ }
253
+ // Same owner + scheduledAt elapsed → try to fire (DELETE).
254
+ try {
255
+ await kv.delete(key);
256
+ return { finalize: "fire" };
257
+ }
258
+ catch {
259
+ // Race — another op modified the bucket; fall through to retry.
260
+ }
261
+ }
262
+ return { finalize: "abandoned" };
263
+ }
264
+ async cancel(workflowName, debounceKey) {
265
+ const kv = this.requireKv();
266
+ const key = this.bucketKey(workflowName, debounceKey);
267
+ const entry = await this.safeGet(kv, key);
268
+ if (!entry || entry === "fetch-failed")
269
+ return false;
270
+ try {
271
+ await kv.delete(key);
272
+ return true;
273
+ }
274
+ catch {
275
+ return false;
276
+ }
277
+ }
278
+ async purgeExpired(now) {
279
+ const kv = this.requireKv();
280
+ let purged = 0;
281
+ // Drain `kv.keys()` to an array BEFORE doing per-key reads.
282
+ // nats.js v2.x's `QueuedIterator` silently drops yields when
283
+ // `kv.get()` is interleaved with the iteration (the watch's
284
+ // internal consumer gets confused). Collect first, then operate.
285
+ const allKeys = [];
286
+ for await (const key of await kv.keys()) {
287
+ allKeys.push(key);
288
+ }
289
+ for (const key of allKeys) {
290
+ const entry = await this.safeGet(kv, key);
291
+ if (!entry || entry === "fetch-failed")
292
+ continue;
293
+ const doc = this.parseDoc(entry);
294
+ if (!doc)
295
+ continue;
296
+ // Bucket is purgeable when both: owner-lease expired AND
297
+ // scheduledAt elapsed (no active owner with a pending fire).
298
+ if (doc.ownerLeaseExpiresAt <= now && doc.scheduledAt <= now) {
299
+ try {
300
+ await kv.delete(key);
301
+ purged += 1;
302
+ }
303
+ catch {
304
+ // CAS conflict — leave for next sweep.
305
+ }
306
+ }
307
+ }
308
+ return purged;
309
+ }
310
+ async safeGet(kv, key) {
311
+ try {
312
+ const e = await kv.get(key);
313
+ return e ?? null;
314
+ }
315
+ catch (err) {
316
+ const code = err.code;
317
+ if (code === "NotFound" || code === "404")
318
+ return null;
319
+ return "fetch-failed";
320
+ }
321
+ }
322
+ parseDoc(entry) {
323
+ try {
324
+ const parsed = JSON.parse(entry.string());
325
+ if (!parsed || typeof parsed.activeRunId !== "string")
326
+ return null;
327
+ return parsed;
328
+ }
329
+ catch {
330
+ return null;
331
+ }
332
+ }
333
+ }
334
+ //# sourceMappingURL=NatsKvDebounceBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NatsKvDebounceBackend.js","sourceRoot":"","sources":["../../src/scheduling/NatsKvDebounceBackend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Tier C #1 · Redis-backed debounce backend.
3
+ *
4
+ * Coordinates per-(workflow, debounceKey) window state across processes
5
+ * via a single Redis string key per bucket. Atomicity comes from
6
+ * server-side **Lua scripts** — `registerPing` / `finalize` /
7
+ * `cancel` / `purgeExpired` each run as a single `EVAL` with no OCC
8
+ * retry loop (Lua runs single-threaded against the keyspace).
9
+ *
10
+ * Storage shape: one JSON document per `(workflowName, debounceKey)`
11
+ * bucket. Owner identity is encoded in the doc itself as
12
+ * `(activeRunId, ownerProcessId, ownerLeaseExpiresAt)`; lease handoff
13
+ * happens atomically when a ping arrives after the lease expired.
14
+ *
15
+ * **Owner-local payload**: this backend tracks `pingCount`,
16
+ * `lastPingAt`, and `scheduledAt` only — payloads do NOT travel across
17
+ * processes. The owning process's local `onFire` closure fires when
18
+ * its timer elapses.
19
+ */
20
+ import type { DebounceBackend, DebounceFinalizeResult, DebounceRegisterBackendOpts, DebounceRegisterBackendResult } from "./DebounceBackend";
21
+ export interface RedisDebounceConfig {
22
+ url?: string;
23
+ host?: string;
24
+ port?: number;
25
+ username?: string;
26
+ password?: string;
27
+ db?: number;
28
+ tls?: boolean;
29
+ keyPrefix: string;
30
+ }
31
+ export declare function readRedisDebounceConfigFromEnv(): RedisDebounceConfig;
32
+ export declare class RedisDebounceBackend implements DebounceBackend {
33
+ readonly name = "redis";
34
+ private client;
35
+ private readonly config;
36
+ private connected;
37
+ constructor(config?: Partial<RedisDebounceConfig>);
38
+ connect(): Promise<void>;
39
+ disconnect(): Promise<void>;
40
+ private bucketKey;
41
+ private encodeSegment;
42
+ private requireClient;
43
+ registerPing(opts: DebounceRegisterBackendOpts): Promise<DebounceRegisterBackendResult>;
44
+ finalize(workflowName: string, debounceKey: string, runId: string, now: number): Promise<DebounceFinalizeResult>;
45
+ cancel(workflowName: string, debounceKey: string): Promise<boolean>;
46
+ purgeExpired(now: number): Promise<number>;
47
+ private parseRegisterResult;
48
+ private parseFinalizeResult;
49
+ }