@blokjs/runner 0.6.21 → 0.7.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.
Files changed (167) hide show
  1. package/dist/Blok.d.ts +2 -0
  2. package/dist/Blok.js +42 -110
  3. package/dist/Blok.js.map +1 -1
  4. package/dist/DefaultLogger.d.ts +13 -0
  5. package/dist/DefaultLogger.js +25 -0
  6. package/dist/DefaultLogger.js.map +1 -1
  7. package/dist/RunnerSteps.d.ts +23 -0
  8. package/dist/RunnerSteps.js +128 -87
  9. package/dist/RunnerSteps.js.map +1 -1
  10. package/dist/SubworkflowNode.js +19 -0
  11. package/dist/SubworkflowNode.js.map +1 -1
  12. package/dist/TriggerBase.d.ts +12 -0
  13. package/dist/TriggerBase.js +216 -181
  14. package/dist/TriggerBase.js.map +1 -1
  15. package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +9 -0
  16. package/dist/adapters/grpc/GrpcRuntimeAdapter.js +76 -6
  17. package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -1
  18. package/dist/index.d.ts +4 -39
  19. package/dist/index.js +7 -32
  20. package/dist/index.js.map +1 -1
  21. package/dist/monitoring/JanitorMetrics.d.ts +3 -0
  22. package/dist/monitoring/JanitorMetrics.js +11 -0
  23. package/dist/monitoring/JanitorMetrics.js.map +1 -1
  24. package/dist/monitoring/ProcessErrorMetrics.d.ts +32 -0
  25. package/dist/monitoring/ProcessErrorMetrics.js +43 -0
  26. package/dist/monitoring/ProcessErrorMetrics.js.map +1 -0
  27. package/dist/monitoring/PrometheusMetricsBridge.d.ts +7 -0
  28. package/dist/monitoring/PrometheusMetricsBridge.js +8 -2
  29. package/dist/monitoring/PrometheusMetricsBridge.js.map +1 -1
  30. package/dist/monitoring/SubworkflowMetrics.d.ts +25 -0
  31. package/dist/monitoring/SubworkflowMetrics.js +38 -0
  32. package/dist/monitoring/SubworkflowMetrics.js.map +1 -0
  33. package/dist/observability/ErrorSink.d.ts +23 -0
  34. package/dist/observability/ErrorSink.js +32 -0
  35. package/dist/observability/ErrorSink.js.map +1 -0
  36. package/dist/observability/SentryIntegration.d.ts +9 -0
  37. package/dist/observability/SentryIntegration.js +31 -0
  38. package/dist/observability/SentryIntegration.js.map +1 -0
  39. package/dist/scheduling/DebounceCoordinator.d.ts +7 -53
  40. package/dist/scheduling/DebounceCoordinator.js +8 -207
  41. package/dist/scheduling/DebounceCoordinator.js.map +1 -1
  42. package/dist/tracing/InMemoryRunStore.d.ts +5 -1
  43. package/dist/tracing/InMemoryRunStore.js +14 -0
  44. package/dist/tracing/InMemoryRunStore.js.map +1 -1
  45. package/dist/tracing/Janitor.js +3 -0
  46. package/dist/tracing/Janitor.js.map +1 -1
  47. package/dist/tracing/PostgresRunStore.d.ts +4 -1
  48. package/dist/tracing/PostgresRunStore.js +73 -3
  49. package/dist/tracing/PostgresRunStore.js.map +1 -1
  50. package/dist/tracing/RunStore.d.ts +17 -1
  51. package/dist/tracing/RunTracker.d.ts +13 -34
  52. package/dist/tracing/RunTracker.js +62 -32
  53. package/dist/tracing/RunTracker.js.map +1 -1
  54. package/dist/tracing/SqliteRunStore.d.ts +4 -1
  55. package/dist/tracing/SqliteRunStore.js +60 -0
  56. package/dist/tracing/SqliteRunStore.js.map +1 -1
  57. package/dist/tracing/TraceRouter.d.ts +13 -0
  58. package/dist/tracing/TraceRouter.js +43 -11
  59. package/dist/tracing/TraceRouter.js.map +1 -1
  60. package/dist/tracing/TracingLogger.js +22 -0
  61. package/dist/tracing/TracingLogger.js.map +1 -1
  62. package/dist/tracing/createStore.js +51 -22
  63. package/dist/tracing/createStore.js.map +1 -1
  64. package/dist/tracing/types.d.ts +22 -0
  65. package/dist/types/GlobalOptions.d.ts +5 -7
  66. package/dist/workflow/WorkflowNormalizer.js +63 -0
  67. package/dist/workflow/WorkflowNormalizer.js.map +1 -1
  68. package/package.json +7 -4
  69. package/dist/cache/NodeResultCache.d.ts +0 -286
  70. package/dist/cache/NodeResultCache.js +0 -506
  71. package/dist/cache/NodeResultCache.js.map +0 -1
  72. package/dist/cache/index.d.ts +0 -1
  73. package/dist/cache/index.js +0 -2
  74. package/dist/cache/index.js.map +0 -1
  75. package/dist/concurrency/ConcurrencyBackend.d.ts +0 -61
  76. package/dist/concurrency/ConcurrencyBackend.js +0 -20
  77. package/dist/concurrency/ConcurrencyBackend.js.map +0 -1
  78. package/dist/concurrency/NatsKvConcurrencyBackend.d.ts +0 -64
  79. package/dist/concurrency/NatsKvConcurrencyBackend.js +0 -310
  80. package/dist/concurrency/NatsKvConcurrencyBackend.js.map +0 -1
  81. package/dist/concurrency/RedisConcurrencyBackend.d.ts +0 -64
  82. package/dist/concurrency/RedisConcurrencyBackend.js +0 -374
  83. package/dist/concurrency/RedisConcurrencyBackend.js.map +0 -1
  84. package/dist/concurrency/createConcurrencyBackend.d.ts +0 -24
  85. package/dist/concurrency/createConcurrencyBackend.js +0 -38
  86. package/dist/concurrency/createConcurrencyBackend.js.map +0 -1
  87. package/dist/graphql/GraphQLSchemaGenerator.d.ts +0 -129
  88. package/dist/graphql/GraphQLSchemaGenerator.js +0 -425
  89. package/dist/graphql/GraphQLSchemaGenerator.js.map +0 -1
  90. package/dist/integrations/APMIntegration.d.ts +0 -141
  91. package/dist/integrations/APMIntegration.js +0 -212
  92. package/dist/integrations/APMIntegration.js.map +0 -1
  93. package/dist/integrations/AzureMonitorIntegration.d.ts +0 -118
  94. package/dist/integrations/AzureMonitorIntegration.js +0 -254
  95. package/dist/integrations/AzureMonitorIntegration.js.map +0 -1
  96. package/dist/integrations/CloudWatchIntegration.d.ts +0 -135
  97. package/dist/integrations/CloudWatchIntegration.js +0 -293
  98. package/dist/integrations/CloudWatchIntegration.js.map +0 -1
  99. package/dist/integrations/SentryIntegration.d.ts +0 -153
  100. package/dist/integrations/SentryIntegration.js +0 -200
  101. package/dist/integrations/SentryIntegration.js.map +0 -1
  102. package/dist/integrations/index.d.ts +0 -19
  103. package/dist/integrations/index.js +0 -16
  104. package/dist/integrations/index.js.map +0 -1
  105. package/dist/marketplace/RuntimeAutoScaler.d.ts +0 -148
  106. package/dist/marketplace/RuntimeAutoScaler.js +0 -366
  107. package/dist/marketplace/RuntimeAutoScaler.js.map +0 -1
  108. package/dist/marketplace/RuntimeCatalog.d.ts +0 -180
  109. package/dist/marketplace/RuntimeCatalog.js +0 -339
  110. package/dist/marketplace/RuntimeCatalog.js.map +0 -1
  111. package/dist/marketplace/RuntimeDiscovery.d.ts +0 -86
  112. package/dist/marketplace/RuntimeDiscovery.js +0 -231
  113. package/dist/marketplace/RuntimeDiscovery.js.map +0 -1
  114. package/dist/marketplace/RuntimeHealthMonitor.d.ts +0 -100
  115. package/dist/marketplace/RuntimeHealthMonitor.js +0 -241
  116. package/dist/marketplace/RuntimeHealthMonitor.js.map +0 -1
  117. package/dist/marketplace/RuntimeMetricsDashboard.d.ts +0 -113
  118. package/dist/marketplace/RuntimeMetricsDashboard.js +0 -293
  119. package/dist/marketplace/RuntimeMetricsDashboard.js.map +0 -1
  120. package/dist/openapi/OpenAPIGenerator.d.ts +0 -192
  121. package/dist/openapi/OpenAPIGenerator.js +0 -378
  122. package/dist/openapi/OpenAPIGenerator.js.map +0 -1
  123. package/dist/openapi/index.d.ts +0 -20
  124. package/dist/openapi/index.js +0 -20
  125. package/dist/openapi/index.js.map +0 -1
  126. package/dist/scheduling/DebounceBackend.d.ts +0 -108
  127. package/dist/scheduling/DebounceBackend.js +0 -23
  128. package/dist/scheduling/DebounceBackend.js.map +0 -1
  129. package/dist/scheduling/NatsKvDebounceBackend.d.ts +0 -53
  130. package/dist/scheduling/NatsKvDebounceBackend.js +0 -334
  131. package/dist/scheduling/NatsKvDebounceBackend.js.map +0 -1
  132. package/dist/scheduling/RedisDebounceBackend.d.ts +0 -49
  133. package/dist/scheduling/RedisDebounceBackend.js +0 -356
  134. package/dist/scheduling/RedisDebounceBackend.js.map +0 -1
  135. package/dist/scheduling/createDebounceBackend.d.ts +0 -25
  136. package/dist/scheduling/createDebounceBackend.js +0 -39
  137. package/dist/scheduling/createDebounceBackend.js.map +0 -1
  138. package/dist/security/ABAC.d.ts +0 -224
  139. package/dist/security/ABAC.js +0 -380
  140. package/dist/security/ABAC.js.map +0 -1
  141. package/dist/security/AuditLogger.d.ts +0 -242
  142. package/dist/security/AuditLogger.js +0 -317
  143. package/dist/security/AuditLogger.js.map +0 -1
  144. package/dist/security/AuthMiddleware.d.ts +0 -162
  145. package/dist/security/AuthMiddleware.js +0 -289
  146. package/dist/security/AuthMiddleware.js.map +0 -1
  147. package/dist/security/EncryptionAtRest.d.ts +0 -206
  148. package/dist/security/EncryptionAtRest.js +0 -236
  149. package/dist/security/EncryptionAtRest.js.map +0 -1
  150. package/dist/security/OAuthProvider.d.ts +0 -334
  151. package/dist/security/OAuthProvider.js +0 -719
  152. package/dist/security/OAuthProvider.js.map +0 -1
  153. package/dist/security/PIIDetector.d.ts +0 -233
  154. package/dist/security/PIIDetector.js +0 -354
  155. package/dist/security/PIIDetector.js.map +0 -1
  156. package/dist/security/RBAC.d.ts +0 -143
  157. package/dist/security/RBAC.js +0 -285
  158. package/dist/security/RBAC.js.map +0 -1
  159. package/dist/security/SecretManager.d.ts +0 -652
  160. package/dist/security/SecretManager.js +0 -1147
  161. package/dist/security/SecretManager.js.map +0 -1
  162. package/dist/security/TLSConfig.d.ts +0 -305
  163. package/dist/security/TLSConfig.js +0 -550
  164. package/dist/security/TLSConfig.js.map +0 -1
  165. package/dist/security/index.d.ts +0 -81
  166. package/dist/security/index.js +0 -82
  167. package/dist/security/index.js.map +0 -1
@@ -1,374 +0,0 @@
1
- /**
2
- * Tier C #4 follow-up · Redis-backed concurrency backend.
3
- *
4
- * Coordinates per-(workflow, concurrencyKey) lease state across processes
5
- * via a single Redis key per bucket. Atomicity comes from server-side Lua
6
- * scripts — `EVAL` runs single-threaded against the keyspace, so the
7
- * read → filter → check-limit → write sequence is a single round-trip
8
- * with no OCC retry loop (the headline win over the NATS KV backend's
9
- * `WATCH`/`MULTI`/`EXEC`-style optimistic concurrency).
10
- *
11
- * Storage model: one Redis string key per `(workflowName, concurrencyKey)`
12
- * bucket. Value is a JSON-encoded `{leases: [{runId, expiresAt}]}`
13
- * document. Bounded-cardinality assumption identical to NATS KV — typical
14
- * concurrency keys hold 1-50 active leases.
15
- *
16
- * Lease leak: each lease carries an `expiresAt`. Expired leases are
17
- * lazy-purged inside the Lua script that observes them; an explicit
18
- * `purgeExpired` SCAN sweep is also exposed for janitor use.
19
- *
20
- * Connection: ioredis is loaded via dynamic `import("ioredis")` so the
21
- * dependency stays optional. Matches the existing pattern used by
22
- * `triggers/worker`'s `RedisStreamsAdapter` and
23
- * `triggers/pubsub`'s `RedisStreamsPubSubAdapter`.
24
- */
25
- import { ConcurrencyMetrics } from "../monitoring/ConcurrencyMetrics";
26
- const DEFAULT_KEY_PREFIX = "blok-concurrency";
27
- /**
28
- * Read configuration from environment variables. Used by
29
- * {@link createConcurrencyBackend} when the operator opts into Redis.
30
- */
31
- export function readRedisConfigFromEnv() {
32
- const url = process.env.BLOK_CONCURRENCY_REDIS_URL?.trim() || undefined;
33
- const host = process.env.BLOK_CONCURRENCY_REDIS_HOST?.trim() || undefined;
34
- const portRaw = process.env.BLOK_CONCURRENCY_REDIS_PORT?.trim();
35
- const port = portRaw && /^\d+$/.test(portRaw) ? Number(portRaw) : undefined;
36
- const dbRaw = process.env.BLOK_CONCURRENCY_REDIS_DB?.trim();
37
- const db = dbRaw && /^\d+$/.test(dbRaw) ? Number(dbRaw) : undefined;
38
- const tls = process.env.BLOK_CONCURRENCY_REDIS_TLS === "1" || process.env.BLOK_CONCURRENCY_REDIS_TLS === "true";
39
- return {
40
- url,
41
- host,
42
- port,
43
- password: process.env.BLOK_CONCURRENCY_REDIS_PASSWORD,
44
- username: process.env.BLOK_CONCURRENCY_REDIS_USERNAME,
45
- db,
46
- tls,
47
- keyPrefix: process.env.BLOK_CONCURRENCY_REDIS_KEY_PREFIX?.trim() || DEFAULT_KEY_PREFIX,
48
- };
49
- }
50
- /**
51
- * Atomic acquire. Returns `{acquired, currentInFlight}` as a 2-element array.
52
- *
53
- * Storage shape: the bucket is either MISSING (no active leases) or a
54
- * JSON string `{"leases":[{"runId":"...","expiresAt":<ms>}, ...]}`.
55
- * When the leases array would become empty we DEL the key — we never
56
- * encode the empty array (sidesteps the cjson empty-table-as-object trap).
57
- *
58
- * KEYS[1] = bucket key
59
- * ARGV[1] = limit (int as string)
60
- * ARGV[2] = runId
61
- * ARGV[3] = leaseExpiresAt (ms as string)
62
- * ARGV[4] = now (ms as string)
63
- *
64
- * Returns: {acquired, currentInFlight}
65
- * - acquired: 1 = granted, 0 = denied
66
- * - currentInFlight: in-flight count INCLUDING the granted slot on success,
67
- * count at denial on rejection.
68
- */
69
- const ACQUIRE_LUA = `
70
- local raw = redis.call('GET', KEYS[1])
71
- local leases = {}
72
- if raw and raw ~= '' then
73
- local ok, parsed = pcall(cjson.decode, raw)
74
- if ok and type(parsed) == 'table' and type(parsed.leases) == 'table' then
75
- leases = parsed.leases
76
- end
77
- end
78
-
79
- local now = tonumber(ARGV[4])
80
- local active = {}
81
- for i = 1, #leases do
82
- local l = leases[i]
83
- if type(l) == 'table' and tonumber(l.expiresAt) and tonumber(l.expiresAt) > now then
84
- active[#active + 1] = { runId = tostring(l.runId), expiresAt = tonumber(l.expiresAt) }
85
- end
86
- end
87
-
88
- local runId = ARGV[2]
89
- local newExpires = tonumber(ARGV[3])
90
-
91
- -- Idempotent re-acquire: refresh lease, don't grow count.
92
- for i = 1, #active do
93
- if active[i].runId == runId then
94
- active[i] = { runId = runId, expiresAt = newExpires }
95
- redis.call('SET', KEYS[1], cjson.encode({ leases = active }))
96
- return { 1, #active }
97
- end
98
- end
99
-
100
- local limit = tonumber(ARGV[1])
101
- if #active >= limit then
102
- -- Persist the purge of expired entries (if any) so the bucket stays clean.
103
- if #active < #leases then
104
- if #active == 0 then
105
- redis.call('DEL', KEYS[1])
106
- else
107
- redis.call('SET', KEYS[1], cjson.encode({ leases = active }))
108
- end
109
- end
110
- return { 0, #active }
111
- end
112
-
113
- active[#active + 1] = { runId = runId, expiresAt = newExpires }
114
- redis.call('SET', KEYS[1], cjson.encode({ leases = active }))
115
- return { 1, #active }
116
- `;
117
- /**
118
- * Atomic release. Removes a lease by runId. DELs the bucket when empty.
119
- *
120
- * KEYS[1] = bucket key
121
- * ARGV[1] = runId
122
- *
123
- * Returns: 1 if a lease was removed, 0 if no-op (bucket missing or runId not present).
124
- */
125
- const RELEASE_LUA = `
126
- local raw = redis.call('GET', KEYS[1])
127
- if not raw or raw == '' then return 0 end
128
-
129
- local ok, parsed = pcall(cjson.decode, raw)
130
- if not ok or type(parsed) ~= 'table' or type(parsed.leases) ~= 'table' then return 0 end
131
-
132
- local target = ARGV[1]
133
- local next_leases = {}
134
- local removed = 0
135
- for i = 1, #parsed.leases do
136
- local l = parsed.leases[i]
137
- if type(l) == 'table' and tostring(l.runId) == target then
138
- removed = 1
139
- else
140
- next_leases[#next_leases + 1] = { runId = tostring(l.runId), expiresAt = tonumber(l.expiresAt) }
141
- end
142
- end
143
-
144
- if removed == 0 then return 0 end
145
-
146
- if #next_leases == 0 then
147
- redis.call('DEL', KEYS[1])
148
- else
149
- redis.call('SET', KEYS[1], cjson.encode({ leases = next_leases }))
150
- end
151
- return 1
152
- `;
153
- /**
154
- * Purge expired leases from a single bucket. Atomic.
155
- *
156
- * KEYS[1] = bucket key
157
- * ARGV[1] = now (ms as string)
158
- *
159
- * Returns: number of leases purged.
160
- */
161
- const PURGE_BUCKET_LUA = `
162
- local raw = redis.call('GET', KEYS[1])
163
- if not raw or raw == '' then return 0 end
164
-
165
- local ok, parsed = pcall(cjson.decode, raw)
166
- if not ok or type(parsed) ~= 'table' or type(parsed.leases) ~= 'table' then return 0 end
167
-
168
- local now = tonumber(ARGV[1])
169
- local active = {}
170
- for i = 1, #parsed.leases do
171
- local l = parsed.leases[i]
172
- if type(l) == 'table' and tonumber(l.expiresAt) and tonumber(l.expiresAt) > now then
173
- active[#active + 1] = { runId = tostring(l.runId), expiresAt = tonumber(l.expiresAt) }
174
- end
175
- end
176
-
177
- local purged = #parsed.leases - #active
178
- if purged == 0 then return 0 end
179
-
180
- if #active == 0 then
181
- redis.call('DEL', KEYS[1])
182
- else
183
- redis.call('SET', KEYS[1], cjson.encode({ leases = active }))
184
- end
185
- return purged
186
- `;
187
- export class RedisConcurrencyBackend {
188
- name = "redis";
189
- client = null;
190
- config;
191
- connected = false;
192
- constructor(config) {
193
- const env = readRedisConfigFromEnv();
194
- this.config = {
195
- url: config?.url ?? env.url,
196
- host: config?.host ?? env.host,
197
- port: config?.port ?? env.port,
198
- password: config?.password ?? env.password,
199
- username: config?.username ?? env.username,
200
- db: config?.db ?? env.db,
201
- tls: config?.tls ?? env.tls,
202
- keyPrefix: config?.keyPrefix ?? env.keyPrefix,
203
- };
204
- }
205
- async connect() {
206
- if (this.connected)
207
- return;
208
- // Security review FW-5 parity — refuse to start in production with
209
- // the default key prefix. Two deployments sharing a Redis instance
210
- // would silently contend on the same `(workflow, key)` buckets,
211
- // corrupting concurrency state across tenants.
212
- const blokEnv = process.env.BLOK_ENV;
213
- const nodeEnv = process.env.NODE_ENV;
214
- const isProd = blokEnv === "production" || nodeEnv === "production";
215
- if (isProd && this.config.keyPrefix === DEFAULT_KEY_PREFIX) {
216
- throw new Error(`[blok] Redis concurrency backend refuses to start in production with the default key prefix ('${DEFAULT_KEY_PREFIX}'). Set BLOK_CONCURRENCY_REDIS_KEY_PREFIX to a deployment-unique value (e.g. 'blok-concurrency-acme-prod') to prevent cross-deployment collision on a shared Redis instance.`);
217
- }
218
- let ioredisModule;
219
- try {
220
- ioredisModule = (await import("ioredis"));
221
- }
222
- catch (err) {
223
- throw new Error(`RedisConcurrencyBackend requires the 'ioredis' package. Install it: \`bun add ioredis\` or \`npm install ioredis\`. Underlying error: ${err instanceof Error ? err.message : String(err)}`);
224
- }
225
- const IORedisCtor = ioredisModule.default ?? ioredisModule.Redis;
226
- if (!IORedisCtor) {
227
- throw new Error("RedisConcurrencyBackend could not locate the ioredis constructor on the imported module. Reinstall ioredis or report this issue.");
228
- }
229
- // Production-friendly defaults: fail fast on connection trouble
230
- // rather than hanging triggers on broker outage. Operators who
231
- // want different semantics can layer a wrapper or fork the
232
- // backend — these are intentional opinions matching the "trigger
233
- // startup should not block indefinitely on broker reachability"
234
- // posture of the rest of the runner.
235
- const failFastDefaults = {
236
- connectTimeout: 5_000,
237
- maxRetriesPerRequest: 0,
238
- enableOfflineQueue: false,
239
- lazyConnect: true,
240
- };
241
- if (this.config.url) {
242
- this.client = new IORedisCtor(this.config.url);
243
- }
244
- else {
245
- const opts = { ...failFastDefaults };
246
- if (this.config.host)
247
- opts.host = this.config.host;
248
- if (this.config.port)
249
- opts.port = this.config.port;
250
- if (this.config.username)
251
- opts.username = this.config.username;
252
- if (this.config.password)
253
- opts.password = this.config.password;
254
- if (typeof this.config.db === "number")
255
- opts.db = this.config.db;
256
- if (this.config.tls)
257
- opts.tls = {};
258
- this.client = new IORedisCtor(opts);
259
- }
260
- // Surface async errors instead of crashing the process.
261
- this.client.on("error", (err) => {
262
- console.warn(`[blok][concurrency][redis] client error: ${err.message}`);
263
- });
264
- await this.client.ping();
265
- this.connected = true;
266
- }
267
- async disconnect() {
268
- if (!this.connected)
269
- return;
270
- try {
271
- await this.client?.quit();
272
- }
273
- catch {
274
- // quit() can reject if the connection is already torn down; ignore.
275
- }
276
- finally {
277
- this.client = null;
278
- this.connected = false;
279
- }
280
- }
281
- bucketKey(workflowName, concurrencyKey) {
282
- // Mirror NATS KV's hex-escape scheme so workflow/key strings with
283
- // special characters (`:`, `>`, etc.) round-trip without collision.
284
- // Cross-backend portability matters when operators migrate between
285
- // backends: the same `(workflow, key)` pair maps to the same bucket
286
- // identity modulo the prefix.
287
- return `${this.config.keyPrefix}:${this.encodeSegment(workflowName)}__${this.encodeSegment(concurrencyKey)}`;
288
- }
289
- encodeSegment(s) {
290
- // Same regex as NATS KV — replace anything outside the safe set
291
- // with hex escape `_HHHH_` so the encoding is lossless and matches
292
- // the NATS backend byte-for-byte modulo prefix.
293
- return s.replace(/[^-_=.a-zA-Z0-9]/g, (ch) => `_${ch.codePointAt(0)?.toString(16)}_`);
294
- }
295
- requireClient() {
296
- if (!this.client) {
297
- throw new Error("RedisConcurrencyBackend not connected — call connect() first.");
298
- }
299
- return this.client;
300
- }
301
- async acquireSlot(workflowName, concurrencyKey, concurrencyLimit, runId, leaseExpiresAt) {
302
- const client = this.requireClient();
303
- const key = this.bucketKey(workflowName, concurrencyKey);
304
- const metricAttrs = { workflow_name: workflowName, concurrency_key: concurrencyKey };
305
- try {
306
- const raw = await client.eval(ACQUIRE_LUA, 1, key, String(concurrencyLimit), runId, String(leaseExpiresAt), String(Date.now()));
307
- const [acquiredFlag, currentInFlight] = this.parsePair(raw);
308
- const outcome = acquiredFlag === 1 ? "success" : "denied";
309
- // Lua is single-shot — attempt depth is always 0.
310
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome }, 0);
311
- return { acquired: acquiredFlag === 1, currentInFlight };
312
- }
313
- catch (err) {
314
- console.warn(`[blok][concurrency][redis] acquireSlot eval failed for ${workflowName}:${concurrencyKey}: ${err instanceof Error ? err.message : String(err)}; failing closed`);
315
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome: "fail-closed" }, 0);
316
- return { acquired: false, currentInFlight: -1 };
317
- }
318
- }
319
- async releaseSlot(workflowName, concurrencyKey, runId) {
320
- const client = this.requireClient();
321
- const key = this.bucketKey(workflowName, concurrencyKey);
322
- try {
323
- await client.eval(RELEASE_LUA, 1, key, runId);
324
- }
325
- catch (err) {
326
- // Lease will expire via TTL — release is best-effort. Surface
327
- // the error so operators can see broker outages.
328
- console.warn(`[blok][concurrency][redis] releaseSlot eval failed for ${workflowName}:${concurrencyKey} runId=${runId}: ${err instanceof Error ? err.message : String(err)}; lease will expire via TTL`);
329
- }
330
- }
331
- async purgeExpired(now) {
332
- const client = this.requireClient();
333
- const pattern = `${this.config.keyPrefix}:*`;
334
- let cursor = "0";
335
- let purged = 0;
336
- do {
337
- let res;
338
- try {
339
- res = await client.scan(cursor, "MATCH", pattern, "COUNT", 100);
340
- }
341
- catch (err) {
342
- console.warn(`[blok][concurrency][redis] purgeExpired SCAN failed: ${err instanceof Error ? err.message : String(err)}; aborting sweep`);
343
- return purged;
344
- }
345
- const [nextCursor, keys] = res;
346
- cursor = nextCursor;
347
- for (const key of keys) {
348
- try {
349
- const raw = await client.eval(PURGE_BUCKET_LUA, 1, key, String(now));
350
- const count = typeof raw === "number" ? raw : Number(raw);
351
- if (!Number.isNaN(count))
352
- purged += count;
353
- }
354
- catch {
355
- // Best-effort — skip this bucket; janitor will retry on next sweep.
356
- }
357
- }
358
- } while (cursor !== "0");
359
- return purged;
360
- }
361
- /**
362
- * Decode the `{acquired, currentInFlight}` pair from a Lua eval result.
363
- * ioredis returns Redis arrays as plain JS arrays of (string | number)
364
- * — the script returns integers, so both elements should be numbers.
365
- */
366
- parsePair(raw) {
367
- if (!Array.isArray(raw) || raw.length < 2)
368
- return [0, -1];
369
- const acquired = typeof raw[0] === "number" ? raw[0] : Number(raw[0]);
370
- const current = typeof raw[1] === "number" ? raw[1] : Number(raw[1]);
371
- return [Number.isFinite(acquired) ? acquired : 0, Number.isFinite(current) ? current : -1];
372
- }
373
- }
374
- //# sourceMappingURL=RedisConcurrencyBackend.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RedisConcurrencyBackend.js","sourceRoot":"","sources":["../../src/concurrency/RedisConcurrencyBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAiBtE,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAwB9C;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACrC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IACxE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAC1E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,EAAE,CAAC;IAChE,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,IAAI,EAAE,CAAC;IAC5D,MAAM,EAAE,GAAG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,MAAM,CAAC;IAChH,OAAO;QACN,GAAG;QACH,IAAI;QACJ,IAAI;QACJ,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,+BAA+B;QACrD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,+BAA+B;QACrD,EAAE;QACF,GAAG;QACH,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,iCAAiC,EAAE,IAAI,EAAE,IAAI,kBAAkB;KACtF,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CnB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BnB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyBxB,CAAC;AAEF,MAAM,OAAO,uBAAuB;IAC1B,IAAI,GAAG,OAAO,CAAC;IAEhB,MAAM,GAAuB,IAAI,CAAC;IACzB,MAAM,CAAyB;IACxC,SAAS,GAAG,KAAK,CAAC;IAE1B,YAAY,MAAwC;QACnD,MAAM,GAAG,GAAG,sBAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG;YACb,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG;YAC3B,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI;YAC9B,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI;YAC9B,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,GAAG,CAAC,QAAQ;YAC1C,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,GAAG,CAAC,QAAQ;YAC1C,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,GAAG,CAAC,EAAE;YACxB,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG;YAC3B,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,GAAG,CAAC,SAAS;SAC7C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAE3B,mEAAmE;QACnE,mEAAmE;QACnE,gEAAgE;QAChE,+CAA+C;QAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;QACrC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;QACrC,MAAM,MAAM,GAAG,OAAO,KAAK,YAAY,IAAI,OAAO,KAAK,YAAY,CAAC;QACpE,IAAI,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,kBAAkB,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CACd,iGAAiG,kBAAkB,8KAA8K,CACjS,CAAC;QACH,CAAC;QAED,IAAI,aAA4B,CAAC;QACjC,IAAI,CAAC;YACJ,aAAa,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAA6B,CAAC;QACvE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACd,yIAAyI,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC3L,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,KAAK,CAAC;QACjE,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACd,kIAAkI,CAClI,CAAC;QACH,CAAC;QAED,gEAAgE;QAChE,+DAA+D;QAC/D,2DAA2D;QAC3D,iEAAiE;QACjE,gEAAgE;QAChE,qCAAqC;QACrC,MAAM,gBAAgB,GAA4B;YACjD,cAAc,EAAE,KAAK;YACrB,oBAAoB,EAAE,CAAC;YACvB,kBAAkB,EAAE,KAAK;YACzB,WAAW,EAAE,IAAI;SACjB,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACP,MAAM,IAAI,GAA4B,EAAE,GAAG,gBAAgB,EAAE,CAAC;YAC9D,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YACnD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YACnD,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;YAC/D,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;YAC/D,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ;gBAAE,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACjE,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG;gBAAE,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QAED,wDAAwD;QACxD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YACtC,OAAO,CAAC,IAAI,CAAC,4CAA4C,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,UAAU;QACf,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACR,oEAAoE;QACrE,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACxB,CAAC;IACF,CAAC;IAEO,SAAS,CAAC,YAAoB,EAAE,cAAsB;QAC7D,kEAAkE;QAClE,oEAAoE;QACpE,mEAAmE;QACnE,oEAAoE;QACpE,8BAA8B;QAC9B,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC;IAC9G,CAAC;IAEO,aAAa,CAAC,CAAS;QAC9B,gEAAgE;QAChE,mEAAmE;QACnE,gDAAgD;QAChD,OAAO,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACvF,CAAC;IAEO,aAAa;QACpB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,WAAW,CAChB,YAAoB,EACpB,cAAsB,EACtB,gBAAwB,EACxB,KAAa,EACb,cAAsB;QAEtB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC;QAErF,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC5B,WAAW,EACX,CAAC,EACD,GAAG,EACH,MAAM,CAAC,gBAAgB,CAAC,EACxB,KAAK,EACL,MAAM,CAAC,cAAc,CAAC,EACtB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAClB,CAAC;YACF,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC5D,MAAM,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC1D,kDAAkD;YAClD,kBAAkB,CAAC,WAAW,EAAE,CAAC,gBAAgB,CAAC,EAAE,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;YAClF,OAAO,EAAE,QAAQ,EAAE,YAAY,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;QAC1D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CACX,0DAA0D,YAAY,IAAI,cAAc,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAC/J,CAAC;YACF,kBAAkB,CAAC,WAAW,EAAE,CAAC,gBAAgB,CAAC,EAAE,GAAG,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC;YACjG,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC,EAAE,CAAC;QACjD,CAAC;IACF,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,YAAoB,EAAE,cAAsB,EAAE,KAAa;QAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QACzD,IAAI,CAAC;YACJ,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,8DAA8D;YAC9D,iDAAiD;YACjD,OAAO,CAAC,IAAI,CACX,0DAA0D,YAAY,IAAI,cAAc,UAAU,KAAK,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,6BAA6B,CACzL,CAAC;QACH,CAAC;IACF,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAW;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC;QAC7C,IAAI,MAAM,GAAG,GAAG,CAAC;QACjB,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,GAAG,CAAC;YACH,IAAI,GAAuB,CAAC;YAC5B,IAAI,CAAC;gBACJ,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YACjE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CACX,wDAAwD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAC1H,CAAC;gBACF,OAAO,MAAM,CAAC;YACf,CAAC;YACD,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC;YAC/B,MAAM,GAAG,UAAU,CAAC;YACpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACxB,IAAI,CAAC;oBACJ,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;oBACrE,MAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC1D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;wBAAE,MAAM,IAAI,KAAK,CAAC;gBAC3C,CAAC;gBAAC,MAAM,CAAC;oBACR,oEAAoE;gBACrE,CAAC;YACF,CAAC;QACF,CAAC,QAAQ,MAAM,KAAK,GAAG,EAAE;QAEzB,OAAO,MAAM,CAAC;IACf,CAAC;IAED;;;;OAIG;IACK,SAAS,CAAC,GAAY;QAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5F,CAAC;CACD"}
@@ -1,24 +0,0 @@
1
- /**
2
- * Tier 2 #6 follow-up · concurrency backend factory.
3
- *
4
- * Reads `BLOK_CONCURRENCY_BACKEND` and returns the matching backend
5
- * instance, or `null` when the user wants the default in-process behavior.
6
- *
7
- * Trigger packages call this in `listen()` and pass the result to
8
- * `RunTracker.getInstance().setConcurrencyBackend(backend)`.
9
- */
10
- import type { ConcurrencyBackend } from "./ConcurrencyBackend";
11
- /**
12
- * Returns a configured `ConcurrencyBackend` based on
13
- * `BLOK_CONCURRENCY_BACKEND`, or `null` for the default in-process backend.
14
- *
15
- * Recognized values:
16
- * - unset / `""` / `"memory"` — null (use default in-process via RunStore)
17
- * - `"nats-kv"` — NATS KV backend (requires `nats` package + reachable NATS server)
18
- * - `"redis"` — Redis backend (requires `ioredis` package + reachable Redis server)
19
- *
20
- * Unknown values throw at startup with a clear error message — silently
21
- * falling back would be dangerous (operator thinks they configured cross-
22
- * process coordination but they didn't).
23
- */
24
- export declare function createConcurrencyBackend(): ConcurrencyBackend | null;
@@ -1,38 +0,0 @@
1
- /**
2
- * Tier 2 #6 follow-up · concurrency backend factory.
3
- *
4
- * Reads `BLOK_CONCURRENCY_BACKEND` and returns the matching backend
5
- * instance, or `null` when the user wants the default in-process behavior.
6
- *
7
- * Trigger packages call this in `listen()` and pass the result to
8
- * `RunTracker.getInstance().setConcurrencyBackend(backend)`.
9
- */
10
- import { NatsKvConcurrencyBackend } from "./NatsKvConcurrencyBackend";
11
- import { RedisConcurrencyBackend } from "./RedisConcurrencyBackend";
12
- /**
13
- * Returns a configured `ConcurrencyBackend` based on
14
- * `BLOK_CONCURRENCY_BACKEND`, or `null` for the default in-process backend.
15
- *
16
- * Recognized values:
17
- * - unset / `""` / `"memory"` — null (use default in-process via RunStore)
18
- * - `"nats-kv"` — NATS KV backend (requires `nats` package + reachable NATS server)
19
- * - `"redis"` — Redis backend (requires `ioredis` package + reachable Redis server)
20
- *
21
- * Unknown values throw at startup with a clear error message — silently
22
- * falling back would be dangerous (operator thinks they configured cross-
23
- * process coordination but they didn't).
24
- */
25
- export function createConcurrencyBackend() {
26
- const kind = (process.env.BLOK_CONCURRENCY_BACKEND ?? "").trim().toLowerCase();
27
- if (!kind || kind === "memory" || kind === "in-process")
28
- return null;
29
- switch (kind) {
30
- case "nats-kv":
31
- return new NatsKvConcurrencyBackend();
32
- case "redis":
33
- return new RedisConcurrencyBackend();
34
- default:
35
- throw new Error(`Unknown BLOK_CONCURRENCY_BACKEND='${kind}'. Expected one of: 'memory' (default), 'nats-kv', 'redis'.`);
36
- }
37
- }
38
- //# sourceMappingURL=createConcurrencyBackend.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createConcurrencyBackend.js","sourceRoot":"","sources":["../../src/concurrency/createConcurrencyBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB;IACvC,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/E,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IAErE,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,SAAS;YACb,OAAO,IAAI,wBAAwB,EAAE,CAAC;QACvC,KAAK,OAAO;YACX,OAAO,IAAI,uBAAuB,EAAE,CAAC;QACtC;YACC,MAAM,IAAI,KAAK,CACd,qCAAqC,IAAI,6DAA6D,CACtG,CAAC;IACJ,CAAC;AACF,CAAC"}
@@ -1,129 +0,0 @@
1
- /**
2
- * GraphQL Schema Generator for Blok Workflows
3
- *
4
- * Automatically generates GraphQL schema definitions (SDL) from workflow definitions.
5
- * Introspects HTTP trigger configurations and node structures to produce
6
- * Query/Mutation types with appropriate input/output types.
7
- *
8
- * @example
9
- * ```typescript
10
- * const generator = new GraphQLSchemaGenerator({
11
- * schemaName: "BlokAPI",
12
- * includeSubscriptions: true,
13
- * });
14
- *
15
- * generator.addWorkflow({
16
- * name: "get-user",
17
- * version: "1.0.0",
18
- * trigger: { http: { method: "GET", path: "/users/:id" } },
19
- * steps: [{ name: "fetch", node: "db-query", type: "local" }],
20
- * nodes: { "db-query": {} },
21
- * });
22
- *
23
- * console.log(generator.generate());
24
- * ```
25
- */
26
- export interface GraphQLGeneratorConfig {
27
- /** Schema name used in documentation */
28
- schemaName?: string;
29
- /** Description for the schema */
30
- description?: string;
31
- /** Include subscription types for WebSocket/SSE workflows */
32
- includeSubscriptions?: boolean;
33
- /** Include workflow metadata in type descriptions */
34
- includeMetadata?: boolean;
35
- /** Custom scalar definitions */
36
- customScalars?: Array<{
37
- name: string;
38
- description: string;
39
- }>;
40
- }
41
- export interface GqlWorkflowDefinition {
42
- name: string;
43
- version: string;
44
- description?: string;
45
- trigger: {
46
- http?: {
47
- method: string;
48
- path: string;
49
- };
50
- grpc?: {
51
- service: string;
52
- method: string;
53
- };
54
- websocket?: {
55
- path?: string;
56
- };
57
- sse?: {
58
- path?: string;
59
- };
60
- [key: string]: unknown;
61
- };
62
- steps: Array<{
63
- name: string;
64
- node: string;
65
- type?: string;
66
- runtime?: string;
67
- }>;
68
- nodes: Record<string, unknown>;
69
- inputs?: Record<string, GqlFieldDef>;
70
- outputs?: Record<string, GqlFieldDef>;
71
- }
72
- export interface GqlFieldDef {
73
- type: string;
74
- required?: boolean;
75
- description?: string;
76
- items?: GqlFieldDef;
77
- fields?: Record<string, GqlFieldDef>;
78
- }
79
- export declare class GraphQLSchemaGenerator {
80
- private config;
81
- private workflows;
82
- private customTypes;
83
- constructor(config?: GraphQLGeneratorConfig);
84
- addWorkflow(workflow: GqlWorkflowDefinition): void;
85
- addWorkflows(workflows: GqlWorkflowDefinition[]): void;
86
- addCustomType(name: string, definition: string): void;
87
- /**
88
- * Generate GraphQL Schema Definition Language (SDL)
89
- */
90
- generate(): string;
91
- /**
92
- * Generate an introspection-friendly JSON representation
93
- */
94
- toJSON(): GraphQLSchemaJSON;
95
- private resolveWorkflow;
96
- private generateInputType;
97
- private generateOutputType;
98
- private generateFieldDefinition;
99
- private generateSubscriptionField;
100
- private inferOutputFields;
101
- private inferInputFields;
102
- private fieldDefToGraphQLType;
103
- private getTriggerType;
104
- private extractPathParams;
105
- private toPascalCase;
106
- private toFieldName;
107
- private emptySchema;
108
- }
109
- export interface GraphQLSchemaJSON {
110
- schemaName: string;
111
- types: GraphQLTypeInfo[];
112
- queries: GraphQLFieldInfo[];
113
- mutations: GraphQLFieldInfo[];
114
- subscriptions: GraphQLFieldInfo[];
115
- }
116
- export interface GraphQLTypeInfo {
117
- name: string;
118
- kind: "OBJECT" | "INPUT_OBJECT" | "ENUM" | "SCALAR";
119
- fields: GraphQLFieldInfo[];
120
- }
121
- export interface GraphQLFieldInfo {
122
- name: string;
123
- type: string;
124
- description?: string;
125
- args?: Array<{
126
- name: string;
127
- type: string;
128
- }>;
129
- }