@nanobpm/nano-sdk 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -6
- package/dist/index.cjs +237 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +121 -10
- package/dist/index.d.ts +121 -10
- package/dist/index.js +234 -29
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @nanobpm/nano-sdk
|
|
2
2
|
|
|
3
|
-
A **drop-in replacement** for [`@camunda8/orchestration-cluster-api`](https://www.npmjs.com/package/@camunda8/orchestration-cluster-api) that transparently upgrades to Nano's **
|
|
3
|
+
A **drop-in replacement** for [`@camunda8/orchestration-cluster-api`](https://www.npmjs.com/package/@camunda8/orchestration-cluster-api) that transparently upgrades to Nano's **falcon** protocol when connected to a [Nano](../nanobpmn) server. Against stock Camunda 8 it behaves exactly like the upstream SDK.
|
|
4
4
|
|
|
5
5
|
```diff
|
|
6
6
|
- import { createCamundaClient } from "@camunda8/orchestration-cluster-api";
|
|
@@ -11,21 +11,21 @@ Everything else is re-exported unchanged — same types, same client, same API.
|
|
|
11
11
|
|
|
12
12
|
## What gets upgraded
|
|
13
13
|
|
|
14
|
-
When the client detects a Nano server, two hot paths move from REST onto a single persistent WebSocket (`/
|
|
14
|
+
When the client detects a Nano server, two hot paths move from REST onto a single persistent WebSocket (`/falcon`):
|
|
15
15
|
|
|
16
|
-
- **`createProcessInstance`** → `createInstance` frame (with `awaitCompletion` resolved via `instanceCompleted`).
|
|
16
|
+
- **`createProcessInstance`** → `createInstance` frame, gated on the server's submission-credit window (with `awaitCompletion` resolved via `instanceCompleted`).
|
|
17
17
|
- **`createJobWorker`** → `subscribe` + pushed `job` frames, acked with `completeJob`/`failJob`/`throwError` and credit-replenished.
|
|
18
18
|
|
|
19
19
|
This avoids the ~125 creates/s/conn ceiling of the REST long-poll path.
|
|
20
20
|
|
|
21
21
|
## Detection & override
|
|
22
22
|
|
|
23
|
-
Detection is automatic: the SDK probes `GET /v2/topology` once and looks for the Nano `
|
|
23
|
+
Detection is automatic: the SDK probes `GET /v2/topology` once and looks for the Nano `falconPath` advertisement. Control it via the `CAMUNDA_TRANSPORT` config (or env var):
|
|
24
24
|
|
|
25
25
|
| value | behaviour |
|
|
26
26
|
| ---------------- | ------------------------------------------- |
|
|
27
|
-
| `auto` (default) |
|
|
28
|
-
| `
|
|
27
|
+
| `auto` (default) | falcon on Nano, REST elsewhere |
|
|
28
|
+
| `falcon` | force the stream (assume Nano) |
|
|
29
29
|
| `rest` | never upgrade — pure upstream behaviour |
|
|
30
30
|
|
|
31
31
|
```ts
|
|
@@ -34,6 +34,37 @@ const client = createCamundaClient({
|
|
|
34
34
|
});
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
## Failing fast under backpressure (`submitTimeoutMs`)
|
|
38
|
+
|
|
39
|
+
On the Falcon protocol, admission backpressure is expressed by the server
|
|
40
|
+
withholding submission credits (no `503`, no retry), so a `createProcessInstance`
|
|
41
|
+
otherwise waits indefinitely for the gateway to ack. To fail fast instead, set a
|
|
42
|
+
submit timeout — per call, or client-wide via config/env:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// Client-wide default (ms); per-call submitTimeoutMs wins when both are set.
|
|
46
|
+
const client = createCamundaClient({
|
|
47
|
+
config: { CAMUNDA_REST_ADDRESS: "http://localhost:8080", CAMUNDA_NANO_SUBMIT_TIMEOUT_MS: 2000 },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
import { SubmissionTimeoutError } from "@nanobpm/nano-sdk";
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
await client.createProcessInstance({ processDefinitionId: "order", submitTimeoutMs: 500 });
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (err instanceof SubmissionTimeoutError) {
|
|
56
|
+
// Server is applying admission backpressure — back off, do NOT tight-loop retry.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`submitTimeoutMs` is a **client-side** guard: the SDK gates each create on the
|
|
62
|
+
server's submission-credit window (queuing client-side under backpressure rather
|
|
63
|
+
than flooding the gateway), and this bounds how long it waits for a credit before
|
|
64
|
+
rejecting with `SubmissionTimeoutError`. It is never sent on the wire. On timeout
|
|
65
|
+
the queued create is dropped so no credit slot leaks. Omit it (the default) to
|
|
66
|
+
wait indefinitely.
|
|
67
|
+
|
|
37
68
|
## Build & verify
|
|
38
69
|
|
|
39
70
|
```sh
|
package/dist/index.cjs
CHANGED
|
@@ -31,8 +31,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
|
-
|
|
34
|
+
EmbeddedTransport: () => EmbeddedTransport,
|
|
35
|
+
FalconTransport: () => FalconTransport,
|
|
35
36
|
NanoJobWorker: () => NanoJobWorker,
|
|
37
|
+
SubmissionTimeoutError: () => SubmissionTimeoutError,
|
|
36
38
|
createCamundaClient: () => createCamundaClient,
|
|
37
39
|
default: () => index_default,
|
|
38
40
|
detectNano: () => detectNano
|
|
@@ -56,11 +58,11 @@ async function detectNano(restAddress, fetchImpl = fetch) {
|
|
|
56
58
|
if (res.ok) {
|
|
57
59
|
const body = await res.json().catch(() => ({}));
|
|
58
60
|
const nano = body?.nano;
|
|
59
|
-
if (nano && typeof nano.
|
|
61
|
+
if (nano && typeof nano.falconPath === "string") {
|
|
60
62
|
info = {
|
|
61
63
|
engine: String(nano.engine ?? "nanobpmn"),
|
|
62
64
|
version: nano.version ? String(nano.version) : void 0,
|
|
63
|
-
|
|
65
|
+
falconPath: nano.falconPath
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
68
|
}
|
|
@@ -70,7 +72,7 @@ async function detectNano(restAddress, fetchImpl = fetch) {
|
|
|
70
72
|
cache.set(base, info);
|
|
71
73
|
return info;
|
|
72
74
|
}
|
|
73
|
-
function
|
|
75
|
+
function falconUrl(restAddress, path) {
|
|
74
76
|
let base = normalizeBase(restAddress);
|
|
75
77
|
if (base.startsWith("https://")) base = "wss://" + base.slice("https://".length);
|
|
76
78
|
else if (base.startsWith("http://")) base = "ws://" + base.slice("http://".length);
|
|
@@ -92,7 +94,17 @@ async function getWebSocket() {
|
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
// src/transport.ts
|
|
95
|
-
var
|
|
97
|
+
var SubmissionTimeoutError = class extends Error {
|
|
98
|
+
constructor(timeoutMs) {
|
|
99
|
+
super(
|
|
100
|
+
`create submission stalled: no gateway ack within ${timeoutMs}ms (server is applying admission backpressure)`
|
|
101
|
+
);
|
|
102
|
+
this.timeoutMs = timeoutMs;
|
|
103
|
+
this.name = "SubmissionTimeoutError";
|
|
104
|
+
}
|
|
105
|
+
timeoutMs;
|
|
106
|
+
};
|
|
107
|
+
var FalconTransport = class {
|
|
96
108
|
url;
|
|
97
109
|
ws = null;
|
|
98
110
|
open = false;
|
|
@@ -103,8 +115,17 @@ var CommandStreamTransport = class {
|
|
|
103
115
|
heartbeat = null;
|
|
104
116
|
connectPromise = null;
|
|
105
117
|
closed = false;
|
|
106
|
-
|
|
107
|
-
|
|
118
|
+
defaultSubmitTimeoutMs;
|
|
119
|
+
/**
|
|
120
|
+
* Server-granted submission-credit window (seeded by `welcome`, topped up by
|
|
121
|
+
* `submissionCredits`). Mirrors the engine's intake metering so creates queue
|
|
122
|
+
* client-side under admission backpressure instead of flooding the gateway.
|
|
123
|
+
*/
|
|
124
|
+
credits = 0;
|
|
125
|
+
creditWaiters = [];
|
|
126
|
+
constructor(restAddress, path, defaultSubmitTimeoutMs) {
|
|
127
|
+
this.url = falconUrl(restAddress, path);
|
|
128
|
+
this.defaultSubmitTimeoutMs = defaultSubmitTimeoutMs !== void 0 && defaultSubmitTimeoutMs > 0 ? defaultSubmitTimeoutMs : void 0;
|
|
108
129
|
}
|
|
109
130
|
nextCorr() {
|
|
110
131
|
this.corr += 1;
|
|
@@ -132,12 +153,16 @@ var CommandStreamTransport = class {
|
|
|
132
153
|
this.handle(f, resolve);
|
|
133
154
|
};
|
|
134
155
|
ws.onerror = () => {
|
|
135
|
-
if (!this.open) reject(new Error(`
|
|
156
|
+
if (!this.open) reject(new Error(`falcon connect failed: ${this.url}`));
|
|
136
157
|
};
|
|
137
158
|
ws.onclose = () => {
|
|
138
159
|
this.open = false;
|
|
160
|
+
this.credits = 0;
|
|
161
|
+
const waiters = this.creditWaiters;
|
|
162
|
+
this.creditWaiters = [];
|
|
163
|
+
for (const w of waiters) w.fail(new Error("falcon closed"));
|
|
139
164
|
if (this.heartbeat) clearInterval(this.heartbeat);
|
|
140
|
-
for (const p of this.pending.values()) p.reject(new Error("
|
|
165
|
+
for (const p of this.pending.values()) p.reject(new Error("falcon closed"));
|
|
141
166
|
this.pending.clear();
|
|
142
167
|
if (!this.closed) setTimeout(() => void this.reconnect(), 1e3);
|
|
143
168
|
};
|
|
@@ -155,12 +180,14 @@ var CommandStreamTransport = class {
|
|
|
155
180
|
switch (f.type) {
|
|
156
181
|
case "welcome": {
|
|
157
182
|
this.open = true;
|
|
183
|
+
this.credits = Number(f.submissionCredits ?? 0);
|
|
158
184
|
const hb = Number(f.heartbeatMs ?? 0);
|
|
159
185
|
if (hb > 0) {
|
|
160
186
|
if (this.heartbeat) clearInterval(this.heartbeat);
|
|
161
187
|
this.heartbeat = setInterval(() => this.send({ type: "heartbeat" }), hb);
|
|
162
188
|
}
|
|
163
189
|
for (const sub of this.subs.values()) this.sendSubscribe(sub);
|
|
190
|
+
this.releaseCreditWaiters();
|
|
164
191
|
resolveConnect();
|
|
165
192
|
break;
|
|
166
193
|
}
|
|
@@ -192,6 +219,11 @@ var CommandStreamTransport = class {
|
|
|
192
219
|
}
|
|
193
220
|
break;
|
|
194
221
|
}
|
|
222
|
+
case "submissionCredits": {
|
|
223
|
+
this.credits += Number(f.n ?? 0);
|
|
224
|
+
this.releaseCreditWaiters();
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
195
227
|
}
|
|
196
228
|
}
|
|
197
229
|
sendSubscribe(sub) {
|
|
@@ -204,9 +236,51 @@ var CommandStreamTransport = class {
|
|
|
204
236
|
fetchVariable: sub.fetchVariables
|
|
205
237
|
});
|
|
206
238
|
}
|
|
239
|
+
// ----- submission-credit gating ------------------------------------------
|
|
240
|
+
/**
|
|
241
|
+
* Take one submission credit, waiting for the gateway to replenish when the
|
|
242
|
+
* window is exhausted (admission backpressure — no 503, no retry). When
|
|
243
|
+
* `timeoutMs` elapses first, rejects with {@link SubmissionTimeoutError} and
|
|
244
|
+
* removes the queued waiter so no credit slot leaks.
|
|
245
|
+
*/
|
|
246
|
+
acquireCredit(timeoutMs) {
|
|
247
|
+
if (this.credits > 0) {
|
|
248
|
+
this.credits -= 1;
|
|
249
|
+
return Promise.resolve();
|
|
250
|
+
}
|
|
251
|
+
return new Promise((resolve, reject) => {
|
|
252
|
+
let timer;
|
|
253
|
+
const waiter = {
|
|
254
|
+
grant: () => {
|
|
255
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
256
|
+
this.credits -= 1;
|
|
257
|
+
resolve();
|
|
258
|
+
},
|
|
259
|
+
fail: (e) => {
|
|
260
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
261
|
+
reject(e);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
this.creditWaiters.push(waiter);
|
|
265
|
+
if (timeoutMs !== void 0 && timeoutMs > 0) {
|
|
266
|
+
timer = setTimeout(() => {
|
|
267
|
+
const i = this.creditWaiters.indexOf(waiter);
|
|
268
|
+
if (i >= 0) this.creditWaiters.splice(i, 1);
|
|
269
|
+
reject(new SubmissionTimeoutError(timeoutMs));
|
|
270
|
+
}, timeoutMs);
|
|
271
|
+
timer.unref?.();
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
releaseCreditWaiters() {
|
|
276
|
+
while (this.credits > 0 && this.creditWaiters.length > 0) {
|
|
277
|
+
this.creditWaiters.shift().grant();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
207
280
|
/** Create a process instance over the stream. */
|
|
208
281
|
async createInstance(input) {
|
|
209
282
|
await this.connect();
|
|
283
|
+
await this.acquireCredit(input.submitTimeoutMs ?? this.defaultSubmitTimeoutMs);
|
|
210
284
|
const corr = this.nextCorr();
|
|
211
285
|
let completionResolve = null;
|
|
212
286
|
const completion = input.awaitCompletion ? new Promise((r) => completionResolve = r) : null;
|
|
@@ -258,6 +332,68 @@ var CommandStreamTransport = class {
|
|
|
258
332
|
}
|
|
259
333
|
};
|
|
260
334
|
|
|
335
|
+
// src/embedded.ts
|
|
336
|
+
var EmbeddedTransport = class {
|
|
337
|
+
constructor(host, pollMs = 25) {
|
|
338
|
+
this.host = host;
|
|
339
|
+
this.pollMs = pollMs;
|
|
340
|
+
}
|
|
341
|
+
host;
|
|
342
|
+
pollMs;
|
|
343
|
+
subs = /* @__PURE__ */ new Map();
|
|
344
|
+
timer = null;
|
|
345
|
+
closed = false;
|
|
346
|
+
async createInstance(input) {
|
|
347
|
+
const { processInstanceKey } = await this.host.createInstance(input);
|
|
348
|
+
this.host.tick();
|
|
349
|
+
if (!input.awaitCompletion) return { status: 200, body: { processInstanceKey } };
|
|
350
|
+
while (!this.host.instanceCompleted(processInstanceKey)) {
|
|
351
|
+
this.host.tick();
|
|
352
|
+
await new Promise((r) => setTimeout(r, this.pollMs));
|
|
353
|
+
}
|
|
354
|
+
const variables = this.host.instanceVariables(processInstanceKey);
|
|
355
|
+
return { status: 200, body: { processInstanceKey, variables }, completion: { processCompleted: true, variables, processInstanceKey } };
|
|
356
|
+
}
|
|
357
|
+
async subscribe(sub) {
|
|
358
|
+
this.subs.set(sub.jobType, { worker: sub.worker, credits: sub.credits, timeoutMs: sub.timeoutMs, onJob: sub.onJob });
|
|
359
|
+
if (!this.timer) this.timer = setInterval(() => this.pump(), this.pollMs);
|
|
360
|
+
}
|
|
361
|
+
unsubscribe(jobType) {
|
|
362
|
+
this.subs.delete(jobType);
|
|
363
|
+
}
|
|
364
|
+
completeJob(jobKey, variables) {
|
|
365
|
+
void this.host.completeJob(jobKey, variables);
|
|
366
|
+
}
|
|
367
|
+
failJob(jobKey, retries, errorMessage) {
|
|
368
|
+
void this.host.failJob(jobKey, retries ?? 0, errorMessage);
|
|
369
|
+
}
|
|
370
|
+
throwError(jobKey, _errorCode, errorMessage) {
|
|
371
|
+
void this.host.failJob(jobKey, 0, errorMessage);
|
|
372
|
+
}
|
|
373
|
+
grantCredits(jobType, n) {
|
|
374
|
+
const s = this.subs.get(jobType);
|
|
375
|
+
if (s) s.credits += n;
|
|
376
|
+
}
|
|
377
|
+
pump() {
|
|
378
|
+
if (this.closed) return;
|
|
379
|
+
this.host.tick();
|
|
380
|
+
for (const [type, s] of this.subs) {
|
|
381
|
+
if (s.credits <= 0) continue;
|
|
382
|
+
void this.host.activateJobs(type, s.credits, s.timeoutMs, s.worker).then((jobs) => {
|
|
383
|
+
for (const j of jobs) {
|
|
384
|
+
if (s.credits <= 0) break;
|
|
385
|
+
s.credits--;
|
|
386
|
+
s.onJob(j);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
close() {
|
|
392
|
+
this.closed = true;
|
|
393
|
+
if (this.timer) clearInterval(this.timer);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
|
|
261
397
|
// src/nanoWorker.ts
|
|
262
398
|
var import_orchestration_cluster_api = require("@camunda8/orchestration-cluster-api");
|
|
263
399
|
var NanoJobWorker = class {
|
|
@@ -345,11 +481,27 @@ var NanoJobWorker = class {
|
|
|
345
481
|
|
|
346
482
|
// src/index.ts
|
|
347
483
|
__reExport(index_exports, require("@camunda8/orchestration-cluster-api"), module.exports);
|
|
484
|
+
function isTruthyEnv(v) {
|
|
485
|
+
if (v === void 0 || v === null) return false;
|
|
486
|
+
const s = String(v).trim().toLowerCase();
|
|
487
|
+
return s !== "" && s !== "0" && s !== "off" && s !== "false" && s !== "no";
|
|
488
|
+
}
|
|
489
|
+
function forceRest(opts) {
|
|
490
|
+
const fromOpts = opts?.config?.CAMUNDA_FORCE_REST;
|
|
491
|
+
const fromEnv = typeof process !== "undefined" ? process.env?.CAMUNDA_FORCE_REST : void 0;
|
|
492
|
+
return isTruthyEnv(fromOpts) || isTruthyEnv(fromEnv);
|
|
493
|
+
}
|
|
348
494
|
function resolveMode(opts) {
|
|
495
|
+
if (forceRest(opts)) return "rest";
|
|
349
496
|
const fromOpts = opts?.config?.CAMUNDA_TRANSPORT;
|
|
350
497
|
const fromEnv = typeof process !== "undefined" ? process.env?.CAMUNDA_TRANSPORT : void 0;
|
|
351
498
|
return fromOpts ?? fromEnv ?? "auto";
|
|
352
499
|
}
|
|
500
|
+
function resolveSubmitTimeoutMs(opts) {
|
|
501
|
+
const raw = opts?.config?.CAMUNDA_NANO_SUBMIT_TIMEOUT_MS ?? (typeof process !== "undefined" ? process.env?.CAMUNDA_NANO_SUBMIT_TIMEOUT_MS : void 0);
|
|
502
|
+
const n = typeof raw === "string" ? Number(raw) : raw;
|
|
503
|
+
return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
|
|
504
|
+
}
|
|
353
505
|
function baseFrom(restAddress) {
|
|
354
506
|
return normalizeBase(restAddress).replace(/\/v2$/, "");
|
|
355
507
|
}
|
|
@@ -357,53 +509,106 @@ function createCamundaClient(opts) {
|
|
|
357
509
|
const client = (0, import_orchestration_cluster_api2.createCamundaClient)(opts);
|
|
358
510
|
const mode = resolveMode(opts);
|
|
359
511
|
if (mode === "rest") return client;
|
|
512
|
+
if (mode === "embedded") {
|
|
513
|
+
if (!opts?.embeddedHost) throw new Error("transport 'embedded' requires opts.embeddedHost");
|
|
514
|
+
const transport2 = new EmbeddedTransport(opts.embeddedHost);
|
|
515
|
+
return wrapClient(client, async () => transport2, () => transport2.close());
|
|
516
|
+
}
|
|
360
517
|
const restAddress = client.getConfig().restAddress;
|
|
361
518
|
const base = baseFrom(restAddress);
|
|
519
|
+
const submitTimeoutMs = resolveSubmitTimeoutMs(opts);
|
|
362
520
|
let transport = null;
|
|
363
521
|
let nano;
|
|
522
|
+
let falconDead = false;
|
|
523
|
+
let warnedDead = false;
|
|
524
|
+
const markDead = (err) => {
|
|
525
|
+
falconDead = true;
|
|
526
|
+
transport = null;
|
|
527
|
+
if (!warnedDead) {
|
|
528
|
+
warnedDead = true;
|
|
529
|
+
console.warn(
|
|
530
|
+
`[@nanobpm/sdk] Falcon transport unavailable (${err?.message ?? err}); falling back to REST. Set CAMUNDA_FORCE_REST=1 to skip Falcon detection.`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
364
534
|
const ensure = async () => {
|
|
535
|
+
if (falconDead) return null;
|
|
365
536
|
if (nano === void 0) {
|
|
366
|
-
nano = mode === "
|
|
537
|
+
nano = mode === "falcon" ? { engine: "nanobpmn", falconPath: "/falcon" } : await detectNano(base);
|
|
367
538
|
}
|
|
368
539
|
if (!nano) return null;
|
|
369
|
-
if (!transport)
|
|
540
|
+
if (!transport) {
|
|
541
|
+
const t = new FalconTransport(base, nano.falconPath, submitTimeoutMs);
|
|
542
|
+
try {
|
|
543
|
+
await t.connect();
|
|
544
|
+
transport = t;
|
|
545
|
+
} catch (e) {
|
|
546
|
+
try {
|
|
547
|
+
t.close();
|
|
548
|
+
} catch {
|
|
549
|
+
}
|
|
550
|
+
markDead(e);
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
370
554
|
return transport;
|
|
371
555
|
};
|
|
556
|
+
return wrapClient(client, ensure, () => transport?.close());
|
|
557
|
+
}
|
|
558
|
+
function wrapClient(client, ensure, onStop) {
|
|
372
559
|
return new Proxy(client, {
|
|
373
560
|
get(target, prop, receiver) {
|
|
374
561
|
if (prop === "createProcessInstance") {
|
|
375
562
|
return (input, options) => {
|
|
376
|
-
|
|
377
|
-
return useStream.then(async (t) => {
|
|
563
|
+
return ensure().then(async (t) => {
|
|
378
564
|
if (!t) return target.createProcessInstance(input, options);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
565
|
+
try {
|
|
566
|
+
const r = await t.createInstance({
|
|
567
|
+
processDefinitionId: input?.processDefinitionId,
|
|
568
|
+
processDefinitionKey: input?.processDefinitionKey,
|
|
569
|
+
variables: input?.variables,
|
|
570
|
+
awaitCompletion: input?.awaitCompletion ?? false,
|
|
571
|
+
fetchVariables: input?.fetchVariables,
|
|
572
|
+
submitTimeoutMs: input?.submitTimeoutMs
|
|
573
|
+
});
|
|
574
|
+
if (r.status >= 400) throw new Error(`createInstance failed: ${r.status} ${JSON.stringify(r.body)}`);
|
|
575
|
+
const body = r.body ?? {};
|
|
576
|
+
return r.completion ? { ...body, variables: r.completion.variables, processInstanceKey: r.completion.processInstanceKey } : body;
|
|
577
|
+
} catch (e) {
|
|
578
|
+
const msg = String(e?.message ?? e);
|
|
579
|
+
if (msg.includes("falcon closed") || msg.includes("falcon connect failed")) {
|
|
580
|
+
console.warn(`[@nanobpm/sdk] Falcon call failed (${msg}); retrying via REST.`);
|
|
581
|
+
return target.createProcessInstance(input, options);
|
|
582
|
+
}
|
|
583
|
+
throw e;
|
|
584
|
+
}
|
|
389
585
|
});
|
|
390
586
|
};
|
|
391
587
|
}
|
|
392
588
|
if (prop === "createJobWorker") {
|
|
393
589
|
return (cfg) => {
|
|
394
590
|
const w = new NanoJobWorker(null, { ...cfg, autoStart: false });
|
|
395
|
-
void ensure().then((t) => {
|
|
396
|
-
if (t) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
591
|
+
void ensure().then(async (t) => {
|
|
592
|
+
if (!t) {
|
|
593
|
+
target.createJobWorker(cfg);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
w.bindTransport(t);
|
|
597
|
+
try {
|
|
598
|
+
await w.start();
|
|
599
|
+
} catch (e) {
|
|
600
|
+
console.warn(
|
|
601
|
+
`[@nanobpm/sdk] Falcon subscribe failed (${e?.message ?? e}); falling back to REST job worker.`
|
|
602
|
+
);
|
|
603
|
+
target.createJobWorker(cfg);
|
|
604
|
+
}
|
|
400
605
|
});
|
|
401
606
|
return w;
|
|
402
607
|
};
|
|
403
608
|
}
|
|
404
609
|
if (prop === "stopAllWorkers") {
|
|
405
610
|
return () => {
|
|
406
|
-
|
|
611
|
+
onStop?.();
|
|
407
612
|
return target.stopAllWorkers();
|
|
408
613
|
};
|
|
409
614
|
}
|
|
@@ -414,8 +619,10 @@ function createCamundaClient(opts) {
|
|
|
414
619
|
var index_default = createCamundaClient;
|
|
415
620
|
// Annotate the CommonJS export names for ESM import in node:
|
|
416
621
|
0 && (module.exports = {
|
|
417
|
-
|
|
622
|
+
EmbeddedTransport,
|
|
623
|
+
FalconTransport,
|
|
418
624
|
NanoJobWorker,
|
|
625
|
+
SubmissionTimeoutError,
|
|
419
626
|
createCamundaClient,
|
|
420
627
|
detectNano,
|
|
421
628
|
...require("@camunda8/orchestration-cluster-api")
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/detect.ts","../src/ws.ts","../src/transport.ts","../src/nanoWorker.ts"],"sourcesContent":["// @nanobpm/nano-sdk — a drop-in replacement for @camunda8/orchestration-cluster-api.\n//\n// It re-exports the entire upstream SDK surface, then overrides\n// `createCamundaClient` (and the default export) so that, when connected to a\n// Nano server, process-instance creation and job workers transparently upgrade\n// to Nano's command-stream protocol. Against stock Camunda 8 it is a no-op: the\n// upstream REST behaviour is used unchanged.\nimport {\n createCamundaClient as createCamundaClientBase,\n} from \"@camunda8/orchestration-cluster-api\";\nimport { detectNano, normalizeBase, type NanoInfo } from \"./detect.js\";\nimport { CommandStreamTransport } from \"./transport.js\";\nimport { NanoJobWorker } from \"./nanoWorker.js\";\n\n// Re-export everything else so consumers can swap the import path and nothing\n// breaks.\nexport * from \"@camunda8/orchestration-cluster-api\";\nexport { detectNano, type NanoInfo } from \"./detect.js\";\nexport { CommandStreamTransport } from \"./transport.js\";\nexport { NanoJobWorker } from \"./nanoWorker.js\";\n\n/** auto: upgrade only on Nano. command-stream: force. rest: never upgrade. */\nexport type NanoTransport = \"auto\" | \"command-stream\" | \"rest\";\n\ntype AnyOpts = Parameters<typeof createCamundaClientBase>[0] & {\n config?: Record<string, unknown> & { CAMUNDA_TRANSPORT?: NanoTransport; CAMUNDA_REST_ADDRESS?: string };\n};\n\nfunction resolveMode(opts?: AnyOpts): NanoTransport {\n const fromOpts = opts?.config?.CAMUNDA_TRANSPORT as NanoTransport | undefined;\n const fromEnv = (typeof process !== \"undefined\" ? process.env?.CAMUNDA_TRANSPORT : undefined) as NanoTransport | undefined;\n return fromOpts ?? fromEnv ?? \"auto\";\n}\n\n/** restAddress is normalized by the SDK to end with /v2; strip it for base. */\nfunction baseFrom(restAddress: string): string {\n return normalizeBase(restAddress).replace(/\\/v2$/, \"\");\n}\n\n/**\n * Drop-in replacement for the upstream createCamundaClient. Returns the upstream\n * client wrapped in a Proxy that upgrades createProcessInstance + createJobWorker\n * to the command stream when connected to a Nano server (overridable via the\n * CAMUNDA_TRANSPORT config: \"auto\" | \"command-stream\" | \"rest\").\n */\nexport function createCamundaClient(opts?: AnyOpts): ReturnType<typeof createCamundaClientBase> {\n const client = createCamundaClientBase(opts as any);\n const mode = resolveMode(opts);\n if (mode === \"rest\") return client;\n\n const restAddress = client.getConfig().restAddress;\n const base = baseFrom(restAddress);\n\n let transport: CommandStreamTransport | null = null;\n let nano: NanoInfo | null | undefined; // undefined = not yet probed\n\n const ensure = async (): Promise<CommandStreamTransport | null> => {\n if (nano === undefined) {\n nano = mode === \"command-stream\"\n ? { engine: \"nanobpmn\", commandStreamPath: \"/command-stream\" }\n : await detectNano(base);\n }\n if (!nano) return null;\n if (!transport) transport = new CommandStreamTransport(base, nano.commandStreamPath);\n return transport;\n };\n\n return new Proxy(client, {\n get(target, prop, receiver) {\n if (prop === \"createProcessInstance\") {\n return (input: any, options?: any) => {\n const useStream = ensure();\n return useStream.then(async (t) => {\n if (!t) return (target as any).createProcessInstance(input, options);\n const r = await t.createInstance({\n processDefinitionId: input?.processDefinitionId,\n processDefinitionKey: input?.processDefinitionKey,\n variables: input?.variables,\n awaitCompletion: input?.awaitCompletion ?? false,\n fetchVariables: input?.fetchVariables,\n });\n if (r.status >= 400) throw new Error(`createInstance failed: ${r.status} ${JSON.stringify(r.body)}`);\n const body: any = r.body ?? {};\n return r.completion ? { ...body, variables: r.completion.variables, processInstanceKey: r.completion.processInstanceKey } : body;\n });\n };\n }\n if (prop === \"createJobWorker\") {\n return (cfg: any) => {\n const w = new NanoJobWorker(null as any, { ...cfg, autoStart: false });\n void ensure().then((t) => {\n if (t) { w.bindTransport(t); void w.start(); }\n else (target as any).createJobWorker(cfg);\n });\n return w as any;\n };\n }\n if (prop === \"stopAllWorkers\") {\n return () => {\n transport?.close();\n return (target as any).stopAllWorkers();\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n\nexport default createCamundaClient;\n","// Nano server detection. A nanobpmn gateway advertises itself on GET /v2/topology\n// via a `nano` block carrying `commandStreamPath`. Detecting it lets the SDK\n// upgrade to the command-stream protocol transparently.\n\nexport interface NanoInfo {\n engine: string;\n version?: string;\n commandStreamPath: string;\n}\n\nconst cache = new Map<string, NanoInfo | null>();\n\n/** Strip trailing slashes for a tidy REST base. */\nexport function normalizeBase(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Probes a REST address once (cached) and returns the Nano engine info if the\n * server is a nanobpmn gateway, or null for stock Camunda 8.\n */\nexport async function detectNano(\n restAddress: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<NanoInfo | null> {\n const base = normalizeBase(restAddress);\n if (cache.has(base)) return cache.get(base) ?? null;\n let info: NanoInfo | null = null;\n try {\n const res = await fetchImpl(`${base}/v2/topology`, {\n headers: { accept: \"application/json\" },\n });\n if (res.ok) {\n const body: any = await res.json().catch(() => ({}));\n const nano = body?.nano;\n if (nano && typeof nano.commandStreamPath === \"string\") {\n info = {\n engine: String(nano.engine ?? \"nanobpmn\"),\n version: nano.version ? String(nano.version) : undefined,\n commandStreamPath: nano.commandStreamPath,\n };\n }\n }\n } catch {\n info = null; // unreachable or non-Nano: stay on REST\n }\n cache.set(base, info);\n return info;\n}\n\n/** Test seam: clear the detection cache. */\nexport function _clearDetectionCache(): void {\n cache.clear();\n}\n\n/** Build the ws:// or wss:// command-stream URL from a REST base + path. */\nexport function commandStreamUrl(restAddress: string, path: string): string {\n let base = normalizeBase(restAddress);\n if (base.startsWith(\"https://\")) base = \"wss://\" + base.slice(\"https://\".length);\n else if (base.startsWith(\"http://\")) base = \"ws://\" + base.slice(\"http://\".length);\n return base + path;\n}\n","// Picks a WebSocket implementation: native global (browser/Deno/Node>=22) or the\n// `ws` package (Node). Kept tiny so the transport stays runtime-agnostic.\nexport type WSImpl = new (url: string) => WebSocket;\n\nlet cached: WSImpl | null = null;\n\nexport async function getWebSocket(): Promise<WSImpl> {\n if (cached) return cached;\n const g = globalThis as { WebSocket?: WSImpl };\n if (typeof g.WebSocket === \"function\") {\n cached = g.WebSocket;\n return cached;\n }\n const mod = await import(\"ws\");\n cached = (mod.default ?? mod.WebSocket) as unknown as WSImpl;\n return cached;\n}\n","// Command-stream transport. One persistent WebSocket per client multiplexes:\n// * createInstance (corr-correlated CommandResult, awaitCompletion via\n// InstanceCompleted), and\n// * job subscriptions (welcome -> subscribe -> job push, replenished by\n// jobCredits; completeJob/failJob/throwError as unmetered drains).\n// Mirrors the protocol implemented by the engine (server/src/command_stream.rs)\n// and the embedded worker SDK (server/src/console/worker_sdk.ts).\nimport { commandStreamUrl } from \"./detect.js\";\nimport { getWebSocket } from \"./ws.js\";\n\ntype Json = Record<string, unknown>;\n\nexport interface JobFrame {\n jobKey: string;\n type: string;\n processInstanceKey: string;\n variables?: Record<string, unknown>;\n customHeaders?: Record<string, unknown>;\n retries?: number;\n [k: string]: unknown;\n}\n\nexport interface Subscription {\n jobType: string;\n worker: string;\n credits: number;\n timeoutMs: number;\n fetchVariables: string[] | null;\n onJob: (job: JobFrame) => void;\n}\n\ninterface Pending {\n resolve: (v: { status: number; body: unknown }) => void;\n reject: (e: unknown) => void;\n}\n\nexport class CommandStreamTransport {\n private url: string;\n private ws: WebSocket | null = null;\n private open = false;\n private corr = 0;\n private pending = new Map<number, Pending>();\n private awaits = new Map<number, (v: { processCompleted: boolean; variables: unknown; processInstanceKey: string }) => void>();\n private subs = new Map<string, Subscription>();\n private heartbeat: ReturnType<typeof setInterval> | null = null;\n private connectPromise: Promise<void> | null = null;\n private closed = false;\n\n constructor(restAddress: string, path: string) {\n this.url = commandStreamUrl(restAddress, path);\n }\n\n private nextCorr(): number {\n this.corr += 1;\n return this.corr;\n }\n\n private send(frame: Json): void {\n if (this.ws && this.open) this.ws.send(JSON.stringify(frame));\n }\n\n async connect(): Promise<void> {\n if (this.open) return;\n if (this.connectPromise) return this.connectPromise;\n this.connectPromise = new Promise<void>((resolve, reject) => {\n void getWebSocket().then((WS) => {\n const ws = new WS(this.url);\n this.ws = ws;\n ws.onopen = () => {};\n ws.onmessage = (ev: MessageEvent) => {\n let f: Json;\n try {\n f = JSON.parse(typeof ev.data === \"string\" ? ev.data : String(ev.data));\n } catch {\n return;\n }\n this.handle(f, resolve);\n };\n ws.onerror = () => {\n if (!this.open) reject(new Error(`command-stream connect failed: ${this.url}`));\n };\n ws.onclose = () => {\n this.open = false;\n if (this.heartbeat) clearInterval(this.heartbeat);\n // Reject in-flight commands; resubscribe on reconnect.\n for (const p of this.pending.values()) p.reject(new Error(\"command-stream closed\"));\n this.pending.clear();\n if (!this.closed) setTimeout(() => void this.reconnect(), 1000);\n };\n });\n });\n return this.connectPromise;\n }\n\n private async reconnect(): Promise<void> {\n this.connectPromise = null;\n this.open = false;\n await this.connect();\n for (const sub of this.subs.values()) this.sendSubscribe(sub);\n }\n\n private handle(f: Json, resolveConnect: () => void): void {\n switch (f.type) {\n case \"welcome\": {\n this.open = true;\n const hb = Number(f.heartbeatMs ?? 0);\n if (hb > 0) {\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = setInterval(() => this.send({ type: \"heartbeat\" }), hb);\n }\n for (const sub of this.subs.values()) this.sendSubscribe(sub);\n resolveConnect();\n break;\n }\n case \"job\": {\n const job = (f.job as JobFrame) ?? ({} as JobFrame);\n const sub = this.subs.get(job.type);\n if (sub) sub.onJob(job);\n break;\n }\n case \"commandResult\": {\n const corr = Number(f.corr ?? 0);\n const p = this.pending.get(corr);\n if (p) {\n this.pending.delete(corr);\n p.resolve({ status: Number(f.status ?? 0), body: f.body ?? null });\n }\n break;\n }\n case \"instanceCompleted\": {\n const corr = Number(f.corr ?? 0);\n const cb = this.awaits.get(corr);\n if (cb) {\n this.awaits.delete(corr);\n cb({\n processCompleted: Boolean(f.processCompleted),\n variables: f.variables ?? {},\n processInstanceKey: String(f.processInstanceKey ?? \"\"),\n });\n }\n break;\n }\n // submissionCredits / pressure / heartbeat: no client action needed yet.\n }\n }\n\n private sendSubscribe(sub: Subscription): void {\n this.send({\n type: \"subscribe\",\n jobType: sub.jobType,\n jobCredits: sub.credits,\n worker: sub.worker,\n timeout: sub.timeoutMs,\n fetchVariable: sub.fetchVariables,\n });\n }\n\n /** Create a process instance over the stream. */\n async createInstance(input: {\n processDefinitionId?: string;\n processDefinitionKey?: string;\n variables?: Record<string, unknown>;\n awaitCompletion?: boolean;\n fetchVariables?: string[];\n requestTimeoutMs?: number;\n }): Promise<{ status: number; body: unknown; completion?: { processCompleted: boolean; variables: unknown; processInstanceKey: string } }> {\n await this.connect();\n const corr = this.nextCorr();\n let completionResolve: ((v: { processCompleted: boolean; variables: unknown; processInstanceKey: string }) => void) | null = null;\n const completion = input.awaitCompletion\n ? new Promise<{ processCompleted: boolean; variables: unknown; processInstanceKey: string }>((r) => (completionResolve = r))\n : null;\n if (completionResolve) this.awaits.set(corr, completionResolve);\n const result = await new Promise<{ status: number; body: unknown }>((resolve, reject) => {\n this.pending.set(corr, { resolve, reject });\n this.send({\n type: \"createInstance\",\n corr,\n processDefinitionId: input.processDefinitionId ?? null,\n processDefinitionKey: input.processDefinitionKey ?? null,\n variables: input.variables ?? null,\n awaitCompletion: input.awaitCompletion ?? false,\n fetchVariables: input.fetchVariables ?? null,\n requestTimeout: input.requestTimeoutMs ?? null,\n });\n });\n const done = completion ? await completion : undefined;\n return { ...result, completion: done };\n }\n\n /** Subscribe a worker; jobs arrive via sub.onJob, credits replenished by ack helpers. */\n async subscribe(sub: Subscription): Promise<void> {\n this.subs.set(sub.jobType, sub);\n await this.connect();\n this.sendSubscribe(sub);\n }\n\n unsubscribe(jobType: string): void {\n this.subs.delete(jobType);\n }\n\n completeJob(jobKey: string, variables?: Record<string, unknown>): void {\n this.send({ type: \"completeJob\", corr: this.nextCorr(), jobKey, variables: variables ?? null });\n }\n failJob(jobKey: string, retries?: number, errorMessage?: string): void {\n this.send({ type: \"failJob\", corr: this.nextCorr(), jobKey, retries: retries ?? 0, errorMessage: errorMessage ?? null });\n }\n throwError(jobKey: string, errorCode: string, errorMessage?: string): void {\n this.send({ type: \"throwError\", corr: this.nextCorr(), jobKey, errorCode, errorMessage: errorMessage ?? null });\n }\n grantCredits(jobType: string, n: number): void {\n this.send({ type: \"jobCredits\", jobType, n });\n }\n\n close(): void {\n this.closed = true;\n if (this.heartbeat) clearInterval(this.heartbeat);\n try {\n this.ws?.close(1000, \"shutdown\");\n } catch {\n /* ignore */\n }\n }\n}\n","// A drop-in JobWorker that drains jobs over the command stream. Mirrors the\n// upstream JobWorker surface (close/stop/start) but receives pushed jobs instead\n// of long-polling. Each handled job replenishes one credit, keeping demand at\n// maxParallelJobs.\nimport { JobActionReceiptSymbol as JobActionReceipt } from \"@camunda8/orchestration-cluster-api\";\nimport type { CommandStreamTransport, JobFrame } from \"./transport.js\";\n\nexport interface NanoJobWorkerConfig {\n jobType: string;\n workerName?: string;\n maxParallelJobs?: number;\n jobTimeoutMs?: number;\n fetchVariables?: string[];\n jobHandler: (job: any) => Promise<typeof JobActionReceipt> | typeof JobActionReceipt;\n autoStart?: boolean;\n}\n\nexport class NanoJobWorker {\n private transport: CommandStreamTransport;\n private cfg: NanoJobWorkerConfig;\n private credits: number;\n private stopped = false;\n readonly jobType: string;\n readonly name: string;\n\n constructor(transport: CommandStreamTransport, cfg: NanoJobWorkerConfig) {\n this.transport = transport;\n this.cfg = cfg;\n this.jobType = cfg.jobType;\n this.credits = cfg.maxParallelJobs ?? 10;\n this.name = cfg.workerName || `worker-${cfg.jobType}`;\n if (cfg.autoStart !== false) void this.start();\n }\n\n /** Bind the transport after async Nano detection. */\n bindTransport(transport: CommandStreamTransport): void {\n this.transport = transport;\n }\n\n async start(): Promise<void> {\n this.stopped = false;\n await this.transport.subscribe({\n jobType: this.jobType,\n worker: this.name,\n credits: this.credits,\n timeoutMs: this.cfg.jobTimeoutMs ?? 60_000,\n fetchVariables: this.cfg.fetchVariables ?? null,\n onJob: (raw) => void this.dispatch(raw),\n });\n }\n\n private enrich(raw: JobFrame) {\n let acted = false;\n const ack = (replenish = true) => {\n if (!acted) {\n acted = true;\n if (replenish) this.transport.grantCredits(this.jobType, 1);\n }\n };\n return {\n ...raw,\n complete: async (variables: Record<string, unknown> = {}) => {\n this.transport.completeJob(raw.jobKey, variables);\n ack();\n return JobActionReceipt;\n },\n fail: async (reason: { errorMessage?: string; retries?: number } = {}) => {\n this.transport.failJob(raw.jobKey, reason.retries, reason.errorMessage);\n ack();\n return JobActionReceipt;\n },\n error: async (e: { errorCode: string; errorMessage?: string }) => {\n this.transport.throwError(raw.jobKey, e.errorCode, e.errorMessage);\n ack();\n return JobActionReceipt;\n },\n ignore: async () => {\n ack();\n return JobActionReceipt;\n },\n };\n }\n\n private async dispatch(raw: JobFrame): Promise<void> {\n if (this.stopped) return;\n const job = this.enrich(raw);\n try {\n await this.cfg.jobHandler(job);\n } catch (err) {\n try {\n this.transport.failJob(raw.jobKey, 0, String(err));\n } finally {\n this.transport.grantCredits(this.jobType, 1);\n }\n }\n }\n\n stop(): void {\n this.stopped = true;\n this.transport.unsubscribe(this.jobType);\n }\n close(): void {\n this.stop();\n }\n}\n"],"mappings":"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","names":["import_orchestration_cluster_api","JobActionReceipt","createCamundaClientBase"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/detect.ts","../src/ws.ts","../src/transport.ts","../src/embedded.ts","../src/nanoWorker.ts"],"sourcesContent":["// @nanobpm/nano-sdk — a drop-in replacement for @camunda8/orchestration-cluster-api.\n//\n// It re-exports the entire upstream SDK surface, then overrides\n// `createCamundaClient` (and the default export) so that, when connected to a\n// Nano server, process-instance creation and job workers transparently upgrade\n// to Nano's Falcon protocol. Against stock Camunda 8 it is a no-op: the\n// upstream REST behaviour is used unchanged.\nimport {\n createCamundaClient as createCamundaClientBase,\n} from \"@camunda8/orchestration-cluster-api\";\nimport { detectNano, normalizeBase, type NanoInfo } from \"./detect.js\";\nimport { FalconTransport } from \"./transport.js\";\nimport { EmbeddedTransport, type EmbeddedHost } from \"./embedded.js\";\nimport { NanoJobWorker } from \"./nanoWorker.js\";\n\n// Re-export everything else so consumers can swap the import path and nothing\n// breaks.\nexport * from \"@camunda8/orchestration-cluster-api\";\nexport { detectNano, type NanoInfo } from \"./detect.js\";\nexport { FalconTransport, SubmissionTimeoutError } from \"./transport.js\";\nexport { EmbeddedTransport, type EmbeddedHost, type EmbeddedJob } from \"./embedded.js\";\nexport { NanoJobWorker } from \"./nanoWorker.js\";\n\n/** auto: upgrade only on Nano. falcon: force. rest: never upgrade. embedded: in-process μ-nano. */\nexport type NanoTransport = \"auto\" | \"falcon\" | \"rest\" | \"embedded\";\n\ntype AnyOpts = Parameters<typeof createCamundaClientBase>[0] & {\n config?: Record<string, unknown> & {\n CAMUNDA_TRANSPORT?: NanoTransport;\n CAMUNDA_REST_ADDRESS?: string;\n CAMUNDA_NANO_SUBMIT_TIMEOUT_MS?: string | number;\n /**\n * Force plain REST even when the gateway advertises Falcon. Useful for\n * environments where WebSockets are blocked (corporate proxies etc.).\n * Accepts any truthy string (`1`, `true`, `yes`, `on`).\n */\n CAMUNDA_FORCE_REST?: string | boolean | number;\n };\n /** Embedded (ADR 0005) in-process engine host; required when transport is \"embedded\". */\n embeddedHost?: EmbeddedHost;\n};\n\nfunction isTruthyEnv(v: unknown): boolean {\n if (v === undefined || v === null) return false;\n const s = String(v).trim().toLowerCase();\n return s !== \"\" && s !== \"0\" && s !== \"off\" && s !== \"false\" && s !== \"no\";\n}\n\nfunction forceRest(opts?: AnyOpts): boolean {\n const fromOpts = (opts?.config as any)?.CAMUNDA_FORCE_REST;\n const fromEnv =\n typeof process !== \"undefined\" ? process.env?.CAMUNDA_FORCE_REST : undefined;\n return isTruthyEnv(fromOpts) || isTruthyEnv(fromEnv);\n}\n\nfunction resolveMode(opts?: AnyOpts): NanoTransport {\n // Explicit escape hatch for environments where WebSockets are blocked\n // (e.g. corporate proxies). Wins over CAMUNDA_TRANSPORT.\n if (forceRest(opts)) return \"rest\";\n const fromOpts = opts?.config?.CAMUNDA_TRANSPORT as NanoTransport | undefined;\n const fromEnv = (typeof process !== \"undefined\" ? process.env?.CAMUNDA_TRANSPORT : undefined) as NanoTransport | undefined;\n return fromOpts ?? fromEnv ?? \"auto\";\n}\n\n/**\n * Default client-side submission-timeout (ms) for falcon creates, from\n * `opts.config.CAMUNDA_NANO_SUBMIT_TIMEOUT_MS` or the env var. `undefined`/`0`\n * means wait indefinitely under backpressure. A per-call `submitTimeoutMs` on\n * `createProcessInstance` input overrides this.\n */\nfunction resolveSubmitTimeoutMs(opts?: AnyOpts): number | undefined {\n const raw =\n (opts?.config?.CAMUNDA_NANO_SUBMIT_TIMEOUT_MS as string | number | undefined) ??\n (typeof process !== \"undefined\" ? process.env?.CAMUNDA_NANO_SUBMIT_TIMEOUT_MS : undefined);\n const n = typeof raw === \"string\" ? Number(raw) : raw;\n return typeof n === \"number\" && Number.isFinite(n) && n > 0 ? n : undefined;\n}\n\n/** restAddress is normalized by the SDK to end with /v2; strip it for base. */\nfunction baseFrom(restAddress: string): string {\n return normalizeBase(restAddress).replace(/\\/v2$/, \"\");\n}\n\n/**\n * Drop-in replacement for the upstream createCamundaClient. Returns the upstream\n * client wrapped in a Proxy that upgrades createProcessInstance + createJobWorker\n * to the Falcon protocol when connected to a Nano server (overridable via the\n * CAMUNDA_TRANSPORT config: \"auto\" | \"falcon\" | \"rest\").\n */\nexport function createCamundaClient(opts?: AnyOpts): ReturnType<typeof createCamundaClientBase> {\n const client = createCamundaClientBase(opts as any);\n const mode = resolveMode(opts);\n if (mode === \"rest\") return client;\n\n // Embedded (ADR 0005): bind the in-process μ-nano host directly — no detection,\n // no socket. The host is the loopback \"Nano gateway in the same process\".\n if (mode === \"embedded\") {\n if (!opts?.embeddedHost) throw new Error(\"transport 'embedded' requires opts.embeddedHost\");\n const transport = new EmbeddedTransport(opts.embeddedHost);\n return wrapClient(client, async () => transport as any, () => transport.close());\n }\n\n const restAddress = client.getConfig().restAddress;\n const base = baseFrom(restAddress);\n const submitTimeoutMs = resolveSubmitTimeoutMs(opts);\n\n let transport: FalconTransport | null = null;\n let nano: NanoInfo | null | undefined; // undefined = not yet probed\n // Sticky \"falcon is not reachable\" flag. Once we've seen a WebSocket handshake\n // fail (e.g. a proxy blocks WS), stop retrying for this client's lifetime and\n // fall back to REST — matching the escape-hatch semantics of CAMUNDA_FORCE_REST.\n let falconDead = false;\n let warnedDead = false;\n const markDead = (err: unknown) => {\n falconDead = true;\n transport = null;\n if (!warnedDead) {\n warnedDead = true;\n // eslint-disable-next-line no-console\n console.warn(\n `[@nanobpm/sdk] Falcon transport unavailable (${(err as Error)?.message ?? err}); ` +\n `falling back to REST. Set CAMUNDA_FORCE_REST=1 to skip Falcon detection.`,\n );\n }\n };\n\n const ensure = async (): Promise<FalconTransport | null> => {\n if (falconDead) return null;\n if (nano === undefined) {\n nano = mode === \"falcon\"\n ? { engine: \"nanobpmn\", falconPath: \"/falcon\" }\n : await detectNano(base);\n }\n if (!nano) return null;\n if (!transport) {\n const t = new FalconTransport(base, nano.falconPath, submitTimeoutMs);\n try {\n // Eagerly open the socket so a proxy-blocked WebSocket surfaces here\n // (single failure) rather than on every request.\n await t.connect();\n transport = t;\n } catch (e) {\n try { t.close(); } catch { /* ignore */ }\n markDead(e);\n return null;\n }\n }\n return transport;\n };\n return wrapClient(client, ensure, () => transport?.close());\n}\n\n/** Wrap an upstream client, upgrading createProcessInstance + createJobWorker to\n * a Nano transport (falcon or embedded) when `ensure` yields one. */\nfunction wrapClient(\n client: ReturnType<typeof createCamundaClientBase>,\n ensure: () => Promise<{ createInstance: Function; subscribe: Function; close: Function } | null>,\n onStop?: () => void,\n): ReturnType<typeof createCamundaClientBase> {\n return new Proxy(client, {\n get(target, prop, receiver) {\n if (prop === \"createProcessInstance\") {\n return (input: any, options?: any) => {\n return ensure().then(async (t) => {\n if (!t) return (target as any).createProcessInstance(input, options);\n try {\n const r = await (t as any).createInstance({\n processDefinitionId: input?.processDefinitionId,\n processDefinitionKey: input?.processDefinitionKey,\n variables: input?.variables,\n awaitCompletion: input?.awaitCompletion ?? false,\n fetchVariables: input?.fetchVariables,\n submitTimeoutMs: input?.submitTimeoutMs,\n });\n if (r.status >= 400) throw new Error(`createInstance failed: ${r.status} ${JSON.stringify(r.body)}`);\n const body: any = r.body ?? {};\n return r.completion ? { ...body, variables: r.completion.variables, processInstanceKey: r.completion.processInstanceKey } : body;\n } catch (e) {\n // A late WS failure (proxy severed the socket, reconnect denied) —\n // fall back to REST for this call.\n const msg = String((e as Error)?.message ?? e);\n if (msg.includes(\"falcon closed\") || msg.includes(\"falcon connect failed\")) {\n // eslint-disable-next-line no-console\n console.warn(`[@nanobpm/sdk] Falcon call failed (${msg}); retrying via REST.`);\n return (target as any).createProcessInstance(input, options);\n }\n throw e;\n }\n });\n };\n }\n if (prop === \"createJobWorker\") {\n return (cfg: any) => {\n const w = new NanoJobWorker(null as any, { ...cfg, autoStart: false });\n void ensure().then(async (t) => {\n if (!t) { (target as any).createJobWorker(cfg); return; }\n w.bindTransport(t as any);\n try { await w.start(); }\n catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `[@nanobpm/sdk] Falcon subscribe failed (${(e as Error)?.message ?? e}); ` +\n `falling back to REST job worker.`,\n );\n (target as any).createJobWorker(cfg);\n }\n });\n return w as any;\n };\n }\n if (prop === \"stopAllWorkers\") {\n return () => { onStop?.(); return (target as any).stopAllWorkers(); };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n\nexport default createCamundaClient;\n","// Nano server detection. A nanobpmn gateway advertises itself on GET /v2/topology\n// via a `nano` block carrying `falconPath`. Detecting it lets the SDK\n// upgrade to the Falcon protocol transparently.\n\nexport interface NanoInfo {\n engine: string;\n version?: string;\n falconPath: string;\n}\n\nconst cache = new Map<string, NanoInfo | null>();\n\n/** Strip trailing slashes for a tidy REST base. */\nexport function normalizeBase(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Probes a REST address once (cached) and returns the Nano engine info if the\n * server is a nanobpmn gateway, or null for stock Camunda 8.\n */\nexport async function detectNano(\n restAddress: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<NanoInfo | null> {\n const base = normalizeBase(restAddress);\n if (cache.has(base)) return cache.get(base) ?? null;\n let info: NanoInfo | null = null;\n try {\n const res = await fetchImpl(`${base}/v2/topology`, {\n headers: { accept: \"application/json\" },\n });\n if (res.ok) {\n const body: any = await res.json().catch(() => ({}));\n const nano = body?.nano;\n if (nano && typeof nano.falconPath === \"string\") {\n info = {\n engine: String(nano.engine ?? \"nanobpmn\"),\n version: nano.version ? String(nano.version) : undefined,\n falconPath: nano.falconPath,\n };\n }\n }\n } catch {\n info = null; // unreachable or non-Nano: stay on REST\n }\n cache.set(base, info);\n return info;\n}\n\n/** Test seam: clear the detection cache. */\nexport function _clearDetectionCache(): void {\n cache.clear();\n}\n\n/** Build the ws:// or wss:// falcon URL from a REST base + path. */\nexport function falconUrl(restAddress: string, path: string): string {\n let base = normalizeBase(restAddress);\n if (base.startsWith(\"https://\")) base = \"wss://\" + base.slice(\"https://\".length);\n else if (base.startsWith(\"http://\")) base = \"ws://\" + base.slice(\"http://\".length);\n return base + path;\n}\n","// Picks a WebSocket implementation: native global (browser/Deno/Node>=22) or the\n// `ws` package (Node). Kept tiny so the transport stays runtime-agnostic.\nexport type WSImpl = new (url: string) => WebSocket;\n\nlet cached: WSImpl | null = null;\n\nexport async function getWebSocket(): Promise<WSImpl> {\n if (cached) return cached;\n const g = globalThis as { WebSocket?: WSImpl };\n if (typeof g.WebSocket === \"function\") {\n cached = g.WebSocket;\n return cached;\n }\n const mod = await import(\"ws\");\n cached = (mod.default ?? mod.WebSocket) as unknown as WSImpl;\n return cached;\n}\n","// Falcon transport. One persistent WebSocket per client multiplexes:\n// * createInstance (corr-correlated CommandResult, awaitCompletion via\n// InstanceCompleted), and\n// * job subscriptions (welcome -> subscribe -> job push, replenished by\n// jobCredits; completeJob/failJob/throwError as unmetered drains).\n// Mirrors the protocol implemented by the engine (server/src/falcon.rs)\n// and the embedded worker SDK (server/src/console/worker_sdk.ts).\nimport { falconUrl } from \"./detect.js\";\nimport { getWebSocket } from \"./ws.js\";\n\ntype Json = Record<string, unknown>;\n\nexport interface JobFrame {\n jobKey: string;\n type: string;\n processInstanceKey: string;\n variables?: Record<string, unknown>;\n customHeaders?: Record<string, unknown>;\n retries?: number;\n [k: string]: unknown;\n}\n\nexport interface Subscription {\n jobType: string;\n worker: string;\n credits: number;\n timeoutMs: number;\n fetchVariables: string[] | null;\n onJob: (job: JobFrame) => void;\n}\n\ninterface Pending {\n resolve: (v: { status: number; body: unknown }) => void;\n reject: (e: unknown) => void;\n}\n\n/** A create queued behind an exhausted submission-credit window. */\ninterface CreditWaiter {\n /** Grant a credit (decrement + resolve the acquire). */\n grant: () => void;\n /** Abandon the wait (reject the acquire), e.g. on disconnect. */\n fail: (e: unknown) => void;\n}\n\n/**\n * Thrown by {@link FalconTransport.createInstance} when the gateway does\n * not acknowledge a create within `submitTimeoutMs`. On the Falcon protocol,\n * admission backpressure is expressed by the server withholding submission\n * credits (no `503`, no retry), so a create otherwise waits indefinitely for\n * intake capacity. This turns that stall into a typed rejection — treat it as\n * \"the server is backpressured\" and back off; do not tight-loop retry.\n */\nexport class SubmissionTimeoutError extends Error {\n constructor(readonly timeoutMs: number) {\n super(\n `create submission stalled: no gateway ack within ${timeoutMs}ms (server is applying admission backpressure)`,\n );\n this.name = \"SubmissionTimeoutError\";\n }\n}\n\nexport class FalconTransport {\n private url: string;\n private ws: WebSocket | null = null;\n private open = false;\n private corr = 0;\n private pending = new Map<number, Pending>();\n private awaits = new Map<number, (v: { processCompleted: boolean; variables: unknown; processInstanceKey: string }) => void>();\n private subs = new Map<string, Subscription>();\n private heartbeat: ReturnType<typeof setInterval> | null = null;\n private connectPromise: Promise<void> | null = null;\n private closed = false;\n private defaultSubmitTimeoutMs?: number;\n /**\n * Server-granted submission-credit window (seeded by `welcome`, topped up by\n * `submissionCredits`). Mirrors the engine's intake metering so creates queue\n * client-side under admission backpressure instead of flooding the gateway.\n */\n private credits = 0;\n private creditWaiters: CreditWaiter[] = [];\n\n constructor(restAddress: string, path: string, defaultSubmitTimeoutMs?: number) {\n this.url = falconUrl(restAddress, path);\n this.defaultSubmitTimeoutMs =\n defaultSubmitTimeoutMs !== undefined && defaultSubmitTimeoutMs > 0\n ? defaultSubmitTimeoutMs\n : undefined;\n }\n\n private nextCorr(): number {\n this.corr += 1;\n return this.corr;\n }\n\n private send(frame: Json): void {\n if (this.ws && this.open) this.ws.send(JSON.stringify(frame));\n }\n\n async connect(): Promise<void> {\n if (this.open) return;\n if (this.connectPromise) return this.connectPromise;\n this.connectPromise = new Promise<void>((resolve, reject) => {\n void getWebSocket().then((WS) => {\n const ws = new WS(this.url);\n this.ws = ws;\n ws.onopen = () => {};\n ws.onmessage = (ev: MessageEvent) => {\n let f: Json;\n try {\n f = JSON.parse(typeof ev.data === \"string\" ? ev.data : String(ev.data));\n } catch {\n return;\n }\n this.handle(f, resolve);\n };\n ws.onerror = () => {\n if (!this.open) reject(new Error(`falcon connect failed: ${this.url}`));\n };\n ws.onclose = () => {\n this.open = false;\n // The credit window is per-connection; a reconnect's welcome re-grants\n // a fresh one. Reset it and fail any queued creates so callers can retry\n // on the new connection rather than hang against a dead window.\n this.credits = 0;\n const waiters = this.creditWaiters;\n this.creditWaiters = [];\n for (const w of waiters) w.fail(new Error(\"falcon closed\"));\n if (this.heartbeat) clearInterval(this.heartbeat);\n // Reject in-flight commands; resubscribe on reconnect.\n for (const p of this.pending.values()) p.reject(new Error(\"falcon closed\"));\n this.pending.clear();\n if (!this.closed) setTimeout(() => void this.reconnect(), 1000);\n };\n });\n });\n return this.connectPromise;\n }\n\n private async reconnect(): Promise<void> {\n this.connectPromise = null;\n this.open = false;\n await this.connect();\n for (const sub of this.subs.values()) this.sendSubscribe(sub);\n }\n\n private handle(f: Json, resolveConnect: () => void): void {\n switch (f.type) {\n case \"welcome\": {\n this.open = true;\n this.credits = Number(f.submissionCredits ?? 0);\n const hb = Number(f.heartbeatMs ?? 0);\n if (hb > 0) {\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = setInterval(() => this.send({ type: \"heartbeat\" }), hb);\n }\n for (const sub of this.subs.values()) this.sendSubscribe(sub);\n this.releaseCreditWaiters();\n resolveConnect();\n break;\n }\n case \"job\": {\n const job = (f.job as JobFrame) ?? ({} as JobFrame);\n const sub = this.subs.get(job.type);\n if (sub) sub.onJob(job);\n break;\n }\n case \"commandResult\": {\n const corr = Number(f.corr ?? 0);\n const p = this.pending.get(corr);\n if (p) {\n this.pending.delete(corr);\n p.resolve({ status: Number(f.status ?? 0), body: f.body ?? null });\n }\n break;\n }\n case \"instanceCompleted\": {\n const corr = Number(f.corr ?? 0);\n const cb = this.awaits.get(corr);\n if (cb) {\n this.awaits.delete(corr);\n cb({\n processCompleted: Boolean(f.processCompleted),\n variables: f.variables ?? {},\n processInstanceKey: String(f.processInstanceKey ?? \"\"),\n });\n }\n break;\n }\n case \"submissionCredits\": {\n // Server topped up the create-side window (intake headroom returned).\n this.credits += Number(f.n ?? 0);\n this.releaseCreditWaiters();\n break;\n }\n // pressure / heartbeat: no client action needed yet.\n }\n }\n\n private sendSubscribe(sub: Subscription): void {\n this.send({\n type: \"subscribe\",\n jobType: sub.jobType,\n jobCredits: sub.credits,\n worker: sub.worker,\n timeout: sub.timeoutMs,\n fetchVariable: sub.fetchVariables,\n });\n }\n\n // ----- submission-credit gating ------------------------------------------\n\n /**\n * Take one submission credit, waiting for the gateway to replenish when the\n * window is exhausted (admission backpressure — no 503, no retry). When\n * `timeoutMs` elapses first, rejects with {@link SubmissionTimeoutError} and\n * removes the queued waiter so no credit slot leaks.\n */\n private acquireCredit(timeoutMs?: number): Promise<void> {\n if (this.credits > 0) {\n this.credits -= 1;\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const waiter: CreditWaiter = {\n grant: () => {\n if (timer !== undefined) clearTimeout(timer);\n this.credits -= 1;\n resolve();\n },\n fail: (e) => {\n if (timer !== undefined) clearTimeout(timer);\n reject(e);\n },\n };\n this.creditWaiters.push(waiter);\n if (timeoutMs !== undefined && timeoutMs > 0) {\n timer = setTimeout(() => {\n const i = this.creditWaiters.indexOf(waiter);\n if (i >= 0) this.creditWaiters.splice(i, 1);\n reject(new SubmissionTimeoutError(timeoutMs));\n }, timeoutMs);\n timer.unref?.();\n }\n });\n }\n\n private releaseCreditWaiters(): void {\n while (this.credits > 0 && this.creditWaiters.length > 0) {\n this.creditWaiters.shift()!.grant();\n }\n }\n\n /** Create a process instance over the stream. */\n async createInstance(input: {\n processDefinitionId?: string;\n processDefinitionKey?: string;\n variables?: Record<string, unknown>;\n awaitCompletion?: boolean;\n fetchVariables?: string[];\n requestTimeoutMs?: number;\n /**\n * Client-side bound (ms) on how long to wait for a submission credit before\n * rejecting with {@link SubmissionTimeoutError}. Overrides the transport-wide\n * default. Omit to wait indefinitely under backpressure. Never sent on the\n * wire — the server is unaware of it.\n */\n submitTimeoutMs?: number;\n }): Promise<{ status: number; body: unknown; completion?: { processCompleted: boolean; variables: unknown; processInstanceKey: string } }> {\n await this.connect();\n // Gate intake on the server's submission-credit window: block here (bounded\n // by submitTimeoutMs) rather than flooding the gateway with creates it has\n // not granted capacity for. Job completions stay unmetered.\n await this.acquireCredit(input.submitTimeoutMs ?? this.defaultSubmitTimeoutMs);\n const corr = this.nextCorr();\n let completionResolve: ((v: { processCompleted: boolean; variables: unknown; processInstanceKey: string }) => void) | null = null;\n const completion = input.awaitCompletion\n ? new Promise<{ processCompleted: boolean; variables: unknown; processInstanceKey: string }>((r) => (completionResolve = r))\n : null;\n if (completionResolve) this.awaits.set(corr, completionResolve);\n const result = await new Promise<{ status: number; body: unknown }>((resolve, reject) => {\n this.pending.set(corr, { resolve, reject });\n this.send({\n type: \"createInstance\",\n corr,\n processDefinitionId: input.processDefinitionId ?? null,\n processDefinitionKey: input.processDefinitionKey ?? null,\n variables: input.variables ?? null,\n awaitCompletion: input.awaitCompletion ?? false,\n fetchVariables: input.fetchVariables ?? null,\n requestTimeout: input.requestTimeoutMs ?? null,\n });\n });\n const done = completion ? await completion : undefined;\n return { ...result, completion: done };\n }\n\n /** Subscribe a worker; jobs arrive via sub.onJob, credits replenished by ack helpers. */\n async subscribe(sub: Subscription): Promise<void> {\n this.subs.set(sub.jobType, sub);\n await this.connect();\n this.sendSubscribe(sub);\n }\n\n unsubscribe(jobType: string): void {\n this.subs.delete(jobType);\n }\n\n completeJob(jobKey: string, variables?: Record<string, unknown>): void {\n this.send({ type: \"completeJob\", corr: this.nextCorr(), jobKey, variables: variables ?? null });\n }\n failJob(jobKey: string, retries?: number, errorMessage?: string): void {\n this.send({ type: \"failJob\", corr: this.nextCorr(), jobKey, retries: retries ?? 0, errorMessage: errorMessage ?? null });\n }\n throwError(jobKey: string, errorCode: string, errorMessage?: string): void {\n this.send({ type: \"throwError\", corr: this.nextCorr(), jobKey, errorCode, errorMessage: errorMessage ?? null });\n }\n grantCredits(jobType: string, n: number): void {\n this.send({ type: \"jobCredits\", jobType, n });\n }\n\n close(): void {\n this.closed = true;\n if (this.heartbeat) clearInterval(this.heartbeat);\n try {\n this.ws?.close(1000, \"shutdown\");\n } catch {\n /* ignore */\n }\n }\n}\n","// Embedded transport (ADR 0005, realization (a) \"in-process direct\"). Satisfies\n// the same operation seam the falcon transport does — createInstance,\n// subscribe/job-push, complete/fail/throw — but calls an in-process EmbeddedHost\n// directly: no sockets, no frames. The host wraps μ-nano.wasm and owns the wall\n// clock, durable journal, and timer/dispatch tick. Bind it via\n// createCamundaClient({ config: { CAMUNDA_TRANSPORT: \"embedded\" }, embeddedHost }).\n\n/** A job handed to a worker handler. */\nexport interface EmbeddedJob {\n jobKey: string;\n type: string;\n processInstanceKey: string;\n elementId: string;\n retries: number;\n variables: Record<string, unknown>;\n}\n\n/** The engine bridge an embedded app supplies (implemented by the app template's\n * Deno host around μ-nano.wasm). Engine-core stays clock-free; the host injects now(). */\nexport interface EmbeddedHost {\n deploy(xml: string): Promise<{ processIds: string[] }>;\n createInstance(input: { processDefinitionId?: string; variables?: Record<string, unknown> }): Promise<{ processInstanceKey: string }>;\n activateJobs(type: string, max: number, timeoutMs: number, worker: string): Promise<EmbeddedJob[]>;\n completeJob(jobKey: string, variables?: Record<string, unknown>): Promise<void>;\n failJob(jobKey: string, retries: number, errorMessage?: string): Promise<void>;\n instanceCompleted(key: string): boolean;\n instanceVariables(key: string): Record<string, unknown>;\n /** Drive timers + dispatch at wall-clock now. Returns true if anything changed. */\n tick(): void;\n}\n\ninterface Sub {\n worker: string;\n credits: number;\n timeoutMs: number;\n onJob: (j: EmbeddedJob) => void;\n}\n\n/** Pull-based dispatch over an in-process host. Structurally compatible with the\n * FalconTransport surface used by NanoJobWorker + the client proxy. */\nexport class EmbeddedTransport {\n private subs = new Map<string, Sub>();\n private timer: ReturnType<typeof setInterval> | null = null;\n private closed = false;\n constructor(private host: EmbeddedHost, private pollMs = 25) {}\n\n async createInstance(input: {\n processDefinitionId?: string;\n variables?: Record<string, unknown>;\n awaitCompletion?: boolean;\n }): Promise<{ status: number; body: unknown; completion?: { processCompleted: boolean; variables: unknown; processInstanceKey: string } }> {\n const { processInstanceKey } = await this.host.createInstance(input);\n this.host.tick();\n if (!input.awaitCompletion) return { status: 200, body: { processInstanceKey } };\n while (!this.host.instanceCompleted(processInstanceKey)) {\n this.host.tick();\n await new Promise((r) => setTimeout(r, this.pollMs));\n }\n const variables = this.host.instanceVariables(processInstanceKey);\n return { status: 200, body: { processInstanceKey, variables }, completion: { processCompleted: true, variables, processInstanceKey } };\n }\n\n async subscribe(sub: { jobType: string; worker: string; credits: number; timeoutMs: number; onJob: (j: any) => void }): Promise<void> {\n this.subs.set(sub.jobType, { worker: sub.worker, credits: sub.credits, timeoutMs: sub.timeoutMs, onJob: sub.onJob });\n if (!this.timer) this.timer = setInterval(() => this.pump(), this.pollMs);\n }\n unsubscribe(jobType: string): void { this.subs.delete(jobType); }\n\n completeJob(jobKey: string, variables?: Record<string, unknown>): void { void this.host.completeJob(jobKey, variables); }\n failJob(jobKey: string, retries?: number, errorMessage?: string): void { void this.host.failJob(jobKey, retries ?? 0, errorMessage); }\n throwError(jobKey: string, _errorCode: string, errorMessage?: string): void { void this.host.failJob(jobKey, 0, errorMessage); }\n grantCredits(jobType: string, n: number): void { const s = this.subs.get(jobType); if (s) s.credits += n; }\n\n private pump(): void {\n if (this.closed) return;\n this.host.tick();\n for (const [type, s] of this.subs) {\n if (s.credits <= 0) continue;\n void this.host.activateJobs(type, s.credits, s.timeoutMs, s.worker).then((jobs) => {\n for (const j of jobs) { if (s.credits <= 0) break; s.credits--; s.onJob(j); }\n });\n }\n }\n close(): void { this.closed = true; if (this.timer) clearInterval(this.timer); }\n}\n","// A drop-in JobWorker that drains jobs over the Falcon protocol. Mirrors the\n// upstream JobWorker surface (close/stop/start) but receives pushed jobs instead\n// of long-polling. Each handled job replenishes one credit, keeping demand at\n// maxParallelJobs.\nimport { JobActionReceiptSymbol as JobActionReceipt } from \"@camunda8/orchestration-cluster-api\";\nimport type { FalconTransport, JobFrame } from \"./transport.js\";\n\nexport interface NanoJobWorkerConfig {\n jobType: string;\n workerName?: string;\n maxParallelJobs?: number;\n jobTimeoutMs?: number;\n fetchVariables?: string[];\n jobHandler: (job: any) => Promise<typeof JobActionReceipt> | typeof JobActionReceipt;\n autoStart?: boolean;\n}\n\nexport class NanoJobWorker {\n private transport: FalconTransport;\n private cfg: NanoJobWorkerConfig;\n private credits: number;\n private stopped = false;\n readonly jobType: string;\n readonly name: string;\n\n constructor(transport: FalconTransport, cfg: NanoJobWorkerConfig) {\n this.transport = transport;\n this.cfg = cfg;\n this.jobType = cfg.jobType;\n this.credits = cfg.maxParallelJobs ?? 10;\n this.name = cfg.workerName || `worker-${cfg.jobType}`;\n if (cfg.autoStart !== false) void this.start();\n }\n\n /** Bind the transport after async Nano detection. */\n bindTransport(transport: FalconTransport): void {\n this.transport = transport;\n }\n\n async start(): Promise<void> {\n this.stopped = false;\n await this.transport.subscribe({\n jobType: this.jobType,\n worker: this.name,\n credits: this.credits,\n timeoutMs: this.cfg.jobTimeoutMs ?? 60_000,\n fetchVariables: this.cfg.fetchVariables ?? null,\n onJob: (raw) => void this.dispatch(raw),\n });\n }\n\n private enrich(raw: JobFrame) {\n let acted = false;\n const ack = (replenish = true) => {\n if (!acted) {\n acted = true;\n if (replenish) this.transport.grantCredits(this.jobType, 1);\n }\n };\n return {\n ...raw,\n complete: async (variables: Record<string, unknown> = {}) => {\n this.transport.completeJob(raw.jobKey, variables);\n ack();\n return JobActionReceipt;\n },\n fail: async (reason: { errorMessage?: string; retries?: number } = {}) => {\n this.transport.failJob(raw.jobKey, reason.retries, reason.errorMessage);\n ack();\n return JobActionReceipt;\n },\n error: async (e: { errorCode: string; errorMessage?: string }) => {\n this.transport.throwError(raw.jobKey, e.errorCode, e.errorMessage);\n ack();\n return JobActionReceipt;\n },\n ignore: async () => {\n ack();\n return JobActionReceipt;\n },\n };\n }\n\n private async dispatch(raw: JobFrame): Promise<void> {\n if (this.stopped) return;\n const job = this.enrich(raw);\n try {\n await this.cfg.jobHandler(job);\n } catch (err) {\n try {\n this.transport.failJob(raw.jobKey, 0, String(err));\n } finally {\n this.transport.grantCredits(this.jobType, 1);\n }\n }\n }\n\n stop(): void {\n this.stopped = true;\n this.transport.unsubscribe(this.jobType);\n }\n close(): void {\n this.stop();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,IAAAA,oCAEO;;;ACCP,IAAM,QAAQ,oBAAI,IAA6B;AAGxC,SAAS,cAAc,KAAqB;AACjD,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAMA,eAAsB,WACpB,aACA,YAA0B,OACA;AAC1B,QAAM,OAAO,cAAc,WAAW;AACtC,MAAI,MAAM,IAAI,IAAI,EAAG,QAAO,MAAM,IAAI,IAAI,KAAK;AAC/C,MAAI,OAAwB;AAC5B,MAAI;AACF,UAAM,MAAM,MAAM,UAAU,GAAG,IAAI,gBAAgB;AAAA,MACjD,SAAS,EAAE,QAAQ,mBAAmB;AAAA,IACxC,CAAC;AACD,QAAI,IAAI,IAAI;AACV,YAAM,OAAY,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACnD,YAAM,OAAO,MAAM;AACnB,UAAI,QAAQ,OAAO,KAAK,eAAe,UAAU;AAC/C,eAAO;AAAA,UACL,QAAQ,OAAO,KAAK,UAAU,UAAU;AAAA,UACxC,SAAS,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI;AAAA,UAC/C,YAAY,KAAK;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO;AACT;AAQO,SAAS,UAAU,aAAqB,MAAsB;AACnE,MAAI,OAAO,cAAc,WAAW;AACpC,MAAI,KAAK,WAAW,UAAU,EAAG,QAAO,WAAW,KAAK,MAAM,WAAW,MAAM;AAAA,WACtE,KAAK,WAAW,SAAS,EAAG,QAAO,UAAU,KAAK,MAAM,UAAU,MAAM;AACjF,SAAO,OAAO;AAChB;;;ACzDA,IAAI,SAAwB;AAE5B,eAAsB,eAAgC;AACpD,MAAI,OAAQ,QAAO;AACnB,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,cAAc,YAAY;AACrC,aAAS,EAAE;AACX,WAAO;AAAA,EACT;AACA,QAAM,MAAM,MAAM,OAAO,IAAI;AAC7B,WAAU,IAAI,WAAW,IAAI;AAC7B,SAAO;AACT;;;ACoCO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YAAqB,WAAmB;AACtC;AAAA,MACE,oDAAoD,SAAS;AAAA,IAC/D;AAHmB;AAInB,SAAK,OAAO;AAAA,EACd;AAAA,EALqB;AAMvB;AAEO,IAAM,kBAAN,MAAsB;AAAA,EACnB;AAAA,EACA,KAAuB;AAAA,EACvB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU,oBAAI,IAAqB;AAAA,EACnC,SAAS,oBAAI,IAAwG;AAAA,EACrH,OAAO,oBAAI,IAA0B;AAAA,EACrC,YAAmD;AAAA,EACnD,iBAAuC;AAAA,EACvC,SAAS;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU;AAAA,EACV,gBAAgC,CAAC;AAAA,EAEzC,YAAY,aAAqB,MAAc,wBAAiC;AAC9E,SAAK,MAAM,UAAU,aAAa,IAAI;AACtC,SAAK,yBACH,2BAA2B,UAAa,yBAAyB,IAC7D,yBACA;AAAA,EACR;AAAA,EAEQ,WAAmB;AACzB,SAAK,QAAQ;AACb,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,KAAK,OAAmB;AAC9B,QAAI,KAAK,MAAM,KAAK,KAAM,MAAK,GAAG,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EAC9D;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,KAAM;AACf,QAAI,KAAK,eAAgB,QAAO,KAAK;AACrC,SAAK,iBAAiB,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3D,WAAK,aAAa,EAAE,KAAK,CAAC,OAAO;AAC/B,cAAM,KAAK,IAAI,GAAG,KAAK,GAAG;AAC1B,aAAK,KAAK;AACV,WAAG,SAAS,MAAM;AAAA,QAAC;AACnB,WAAG,YAAY,CAAC,OAAqB;AACnC,cAAI;AACJ,cAAI;AACF,gBAAI,KAAK,MAAM,OAAO,GAAG,SAAS,WAAW,GAAG,OAAO,OAAO,GAAG,IAAI,CAAC;AAAA,UACxE,QAAQ;AACN;AAAA,UACF;AACA,eAAK,OAAO,GAAG,OAAO;AAAA,QACxB;AACA,WAAG,UAAU,MAAM;AACjB,cAAI,CAAC,KAAK,KAAM,QAAO,IAAI,MAAM,0BAA0B,KAAK,GAAG,EAAE,CAAC;AAAA,QACxE;AACA,WAAG,UAAU,MAAM;AACjB,eAAK,OAAO;AAIZ,eAAK,UAAU;AACf,gBAAM,UAAU,KAAK;AACrB,eAAK,gBAAgB,CAAC;AACtB,qBAAW,KAAK,QAAS,GAAE,KAAK,IAAI,MAAM,eAAe,CAAC;AAC1D,cAAI,KAAK,UAAW,eAAc,KAAK,SAAS;AAEhD,qBAAW,KAAK,KAAK,QAAQ,OAAO,EAAG,GAAE,OAAO,IAAI,MAAM,eAAe,CAAC;AAC1E,eAAK,QAAQ,MAAM;AACnB,cAAI,CAAC,KAAK,OAAQ,YAAW,MAAM,KAAK,KAAK,UAAU,GAAG,GAAI;AAAA,QAChE;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,YAA2B;AACvC,SAAK,iBAAiB;AACtB,SAAK,OAAO;AACZ,UAAM,KAAK,QAAQ;AACnB,eAAW,OAAO,KAAK,KAAK,OAAO,EAAG,MAAK,cAAc,GAAG;AAAA,EAC9D;AAAA,EAEQ,OAAO,GAAS,gBAAkC;AACxD,YAAQ,EAAE,MAAM;AAAA,MACd,KAAK,WAAW;AACd,aAAK,OAAO;AACZ,aAAK,UAAU,OAAO,EAAE,qBAAqB,CAAC;AAC9C,cAAM,KAAK,OAAO,EAAE,eAAe,CAAC;AACpC,YAAI,KAAK,GAAG;AACV,cAAI,KAAK,UAAW,eAAc,KAAK,SAAS;AAChD,eAAK,YAAY,YAAY,MAAM,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC,GAAG,EAAE;AAAA,QACzE;AACA,mBAAW,OAAO,KAAK,KAAK,OAAO,EAAG,MAAK,cAAc,GAAG;AAC5D,aAAK,qBAAqB;AAC1B,uBAAe;AACf;AAAA,MACF;AAAA,MACA,KAAK,OAAO;AACV,cAAM,MAAO,EAAE,OAAqB,CAAC;AACrC,cAAM,MAAM,KAAK,KAAK,IAAI,IAAI,IAAI;AAClC,YAAI,IAAK,KAAI,MAAM,GAAG;AACtB;AAAA,MACF;AAAA,MACA,KAAK,iBAAiB;AACpB,cAAM,OAAO,OAAO,EAAE,QAAQ,CAAC;AAC/B,cAAM,IAAI,KAAK,QAAQ,IAAI,IAAI;AAC/B,YAAI,GAAG;AACL,eAAK,QAAQ,OAAO,IAAI;AACxB,YAAE,QAAQ,EAAE,QAAQ,OAAO,EAAE,UAAU,CAAC,GAAG,MAAM,EAAE,QAAQ,KAAK,CAAC;AAAA,QACnE;AACA;AAAA,MACF;AAAA,MACA,KAAK,qBAAqB;AACxB,cAAM,OAAO,OAAO,EAAE,QAAQ,CAAC;AAC/B,cAAM,KAAK,KAAK,OAAO,IAAI,IAAI;AAC/B,YAAI,IAAI;AACN,eAAK,OAAO,OAAO,IAAI;AACvB,aAAG;AAAA,YACD,kBAAkB,QAAQ,EAAE,gBAAgB;AAAA,YAC5C,WAAW,EAAE,aAAa,CAAC;AAAA,YAC3B,oBAAoB,OAAO,EAAE,sBAAsB,EAAE;AAAA,UACvD,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MACA,KAAK,qBAAqB;AAExB,aAAK,WAAW,OAAO,EAAE,KAAK,CAAC;AAC/B,aAAK,qBAAqB;AAC1B;AAAA,MACF;AAAA,IAEF;AAAA,EACF;AAAA,EAEQ,cAAc,KAAyB;AAC7C,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS,IAAI;AAAA,MACb,YAAY,IAAI;AAAA,MAChB,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,MACb,eAAe,IAAI;AAAA,IACrB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,cAAc,WAAmC;AACvD,QAAI,KAAK,UAAU,GAAG;AACpB,WAAK,WAAW;AAChB,aAAO,QAAQ,QAAQ;AAAA,IACzB;AACA,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,UAAI;AACJ,YAAM,SAAuB;AAAA,QAC3B,OAAO,MAAM;AACX,cAAI,UAAU,OAAW,cAAa,KAAK;AAC3C,eAAK,WAAW;AAChB,kBAAQ;AAAA,QACV;AAAA,QACA,MAAM,CAAC,MAAM;AACX,cAAI,UAAU,OAAW,cAAa,KAAK;AAC3C,iBAAO,CAAC;AAAA,QACV;AAAA,MACF;AACA,WAAK,cAAc,KAAK,MAAM;AAC9B,UAAI,cAAc,UAAa,YAAY,GAAG;AAC5C,gBAAQ,WAAW,MAAM;AACvB,gBAAM,IAAI,KAAK,cAAc,QAAQ,MAAM;AAC3C,cAAI,KAAK,EAAG,MAAK,cAAc,OAAO,GAAG,CAAC;AAC1C,iBAAO,IAAI,uBAAuB,SAAS,CAAC;AAAA,QAC9C,GAAG,SAAS;AACZ,cAAM,QAAQ;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,uBAA6B;AACnC,WAAO,KAAK,UAAU,KAAK,KAAK,cAAc,SAAS,GAAG;AACxD,WAAK,cAAc,MAAM,EAAG,MAAM;AAAA,IACpC;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,eAAe,OAcsH;AACzI,UAAM,KAAK,QAAQ;AAInB,UAAM,KAAK,cAAc,MAAM,mBAAmB,KAAK,sBAAsB;AAC7E,UAAM,OAAO,KAAK,SAAS;AAC3B,QAAI,oBAAyH;AAC7H,UAAM,aAAa,MAAM,kBACrB,IAAI,QAAuF,CAAC,MAAO,oBAAoB,CAAE,IACzH;AACJ,QAAI,kBAAmB,MAAK,OAAO,IAAI,MAAM,iBAAiB;AAC9D,UAAM,SAAS,MAAM,IAAI,QAA2C,CAAC,SAAS,WAAW;AACvF,WAAK,QAAQ,IAAI,MAAM,EAAE,SAAS,OAAO,CAAC;AAC1C,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN;AAAA,QACA,qBAAqB,MAAM,uBAAuB;AAAA,QAClD,sBAAsB,MAAM,wBAAwB;AAAA,QACpD,WAAW,MAAM,aAAa;AAAA,QAC9B,iBAAiB,MAAM,mBAAmB;AAAA,QAC1C,gBAAgB,MAAM,kBAAkB;AAAA,QACxC,gBAAgB,MAAM,oBAAoB;AAAA,MAC5C,CAAC;AAAA,IACH,CAAC;AACD,UAAM,OAAO,aAAa,MAAM,aAAa;AAC7C,WAAO,EAAE,GAAG,QAAQ,YAAY,KAAK;AAAA,EACvC;AAAA;AAAA,EAGA,MAAM,UAAU,KAAkC;AAChD,SAAK,KAAK,IAAI,IAAI,SAAS,GAAG;AAC9B,UAAM,KAAK,QAAQ;AACnB,SAAK,cAAc,GAAG;AAAA,EACxB;AAAA,EAEA,YAAY,SAAuB;AACjC,SAAK,KAAK,OAAO,OAAO;AAAA,EAC1B;AAAA,EAEA,YAAY,QAAgB,WAA2C;AACrE,SAAK,KAAK,EAAE,MAAM,eAAe,MAAM,KAAK,SAAS,GAAG,QAAQ,WAAW,aAAa,KAAK,CAAC;AAAA,EAChG;AAAA,EACA,QAAQ,QAAgB,SAAkB,cAA6B;AACrE,SAAK,KAAK,EAAE,MAAM,WAAW,MAAM,KAAK,SAAS,GAAG,QAAQ,SAAS,WAAW,GAAG,cAAc,gBAAgB,KAAK,CAAC;AAAA,EACzH;AAAA,EACA,WAAW,QAAgB,WAAmB,cAA6B;AACzE,SAAK,KAAK,EAAE,MAAM,cAAc,MAAM,KAAK,SAAS,GAAG,QAAQ,WAAW,cAAc,gBAAgB,KAAK,CAAC;AAAA,EAChH;AAAA,EACA,aAAa,SAAiB,GAAiB;AAC7C,SAAK,KAAK,EAAE,MAAM,cAAc,SAAS,EAAE,CAAC;AAAA,EAC9C;AAAA,EAEA,QAAc;AACZ,SAAK,SAAS;AACd,QAAI,KAAK,UAAW,eAAc,KAAK,SAAS;AAChD,QAAI;AACF,WAAK,IAAI,MAAM,KAAM,UAAU;AAAA,IACjC,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;AClSO,IAAM,oBAAN,MAAwB;AAAA,EAI7B,YAAoB,MAA4B,SAAS,IAAI;AAAzC;AAA4B;AAAA,EAAc;AAAA,EAA1C;AAAA,EAA4B;AAAA,EAHxC,OAAO,oBAAI,IAAiB;AAAA,EAC5B,QAA+C;AAAA,EAC/C,SAAS;AAAA,EAGjB,MAAM,eAAe,OAIsH;AACzI,UAAM,EAAE,mBAAmB,IAAI,MAAM,KAAK,KAAK,eAAe,KAAK;AACnE,SAAK,KAAK,KAAK;AACf,QAAI,CAAC,MAAM,gBAAiB,QAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,mBAAmB,EAAE;AAC/E,WAAO,CAAC,KAAK,KAAK,kBAAkB,kBAAkB,GAAG;AACvD,WAAK,KAAK,KAAK;AACf,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,MAAM,CAAC;AAAA,IACrD;AACA,UAAM,YAAY,KAAK,KAAK,kBAAkB,kBAAkB;AAChE,WAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,oBAAoB,UAAU,GAAG,YAAY,EAAE,kBAAkB,MAAM,WAAW,mBAAmB,EAAE;AAAA,EACvI;AAAA,EAEA,MAAM,UAAU,KAAsH;AACpI,SAAK,KAAK,IAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,QAAQ,SAAS,IAAI,SAAS,WAAW,IAAI,WAAW,OAAO,IAAI,MAAM,CAAC;AACnH,QAAI,CAAC,KAAK,MAAO,MAAK,QAAQ,YAAY,MAAM,KAAK,KAAK,GAAG,KAAK,MAAM;AAAA,EAC1E;AAAA,EACA,YAAY,SAAuB;AAAE,SAAK,KAAK,OAAO,OAAO;AAAA,EAAG;AAAA,EAEhE,YAAY,QAAgB,WAA2C;AAAE,SAAK,KAAK,KAAK,YAAY,QAAQ,SAAS;AAAA,EAAG;AAAA,EACxH,QAAQ,QAAgB,SAAkB,cAA6B;AAAE,SAAK,KAAK,KAAK,QAAQ,QAAQ,WAAW,GAAG,YAAY;AAAA,EAAG;AAAA,EACrI,WAAW,QAAgB,YAAoB,cAA6B;AAAE,SAAK,KAAK,KAAK,QAAQ,QAAQ,GAAG,YAAY;AAAA,EAAG;AAAA,EAC/H,aAAa,SAAiB,GAAiB;AAAE,UAAM,IAAI,KAAK,KAAK,IAAI,OAAO;AAAG,QAAI,EAAG,GAAE,WAAW;AAAA,EAAG;AAAA,EAElG,OAAa;AACnB,QAAI,KAAK,OAAQ;AACjB,SAAK,KAAK,KAAK;AACf,eAAW,CAAC,MAAM,CAAC,KAAK,KAAK,MAAM;AACjC,UAAI,EAAE,WAAW,EAAG;AACpB,WAAK,KAAK,KAAK,aAAa,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS;AACjF,mBAAW,KAAK,MAAM;AAAE,cAAI,EAAE,WAAW,EAAG;AAAO,YAAE;AAAW,YAAE,MAAM,CAAC;AAAA,QAAG;AAAA,MAC9E,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,QAAc;AAAE,SAAK,SAAS;AAAM,QAAI,KAAK,MAAO,eAAc,KAAK,KAAK;AAAA,EAAG;AACjF;;;AChFA,uCAA2D;AAapD,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACT;AAAA,EACA;AAAA,EAET,YAAY,WAA4B,KAA0B;AAChE,SAAK,YAAY;AACjB,SAAK,MAAM;AACX,SAAK,UAAU,IAAI;AACnB,SAAK,UAAU,IAAI,mBAAmB;AACtC,SAAK,OAAO,IAAI,cAAc,UAAU,IAAI,OAAO;AACnD,QAAI,IAAI,cAAc,MAAO,MAAK,KAAK,MAAM;AAAA,EAC/C;AAAA;AAAA,EAGA,cAAc,WAAkC;AAC9C,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AACf,UAAM,KAAK,UAAU,UAAU;AAAA,MAC7B,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK;AAAA,MACd,WAAW,KAAK,IAAI,gBAAgB;AAAA,MACpC,gBAAgB,KAAK,IAAI,kBAAkB;AAAA,MAC3C,OAAO,CAAC,QAAQ,KAAK,KAAK,SAAS,GAAG;AAAA,IACxC,CAAC;AAAA,EACH;AAAA,EAEQ,OAAO,KAAe;AAC5B,QAAI,QAAQ;AACZ,UAAM,MAAM,CAAC,YAAY,SAAS;AAChC,UAAI,CAAC,OAAO;AACV,gBAAQ;AACR,YAAI,UAAW,MAAK,UAAU,aAAa,KAAK,SAAS,CAAC;AAAA,MAC5D;AAAA,IACF;AACA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU,OAAO,YAAqC,CAAC,MAAM;AAC3D,aAAK,UAAU,YAAY,IAAI,QAAQ,SAAS;AAChD,YAAI;AACJ,eAAO,iCAAAC;AAAA,MACT;AAAA,MACA,MAAM,OAAO,SAAsD,CAAC,MAAM;AACxE,aAAK,UAAU,QAAQ,IAAI,QAAQ,OAAO,SAAS,OAAO,YAAY;AACtE,YAAI;AACJ,eAAO,iCAAAA;AAAA,MACT;AAAA,MACA,OAAO,OAAO,MAAoD;AAChE,aAAK,UAAU,WAAW,IAAI,QAAQ,EAAE,WAAW,EAAE,YAAY;AACjE,YAAI;AACJ,eAAO,iCAAAA;AAAA,MACT;AAAA,MACA,QAAQ,YAAY;AAClB,YAAI;AACJ,eAAO,iCAAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,SAAS,KAA8B;AACnD,QAAI,KAAK,QAAS;AAClB,UAAM,MAAM,KAAK,OAAO,GAAG;AAC3B,QAAI;AACF,YAAM,KAAK,IAAI,WAAW,GAAG;AAAA,IAC/B,SAAS,KAAK;AACZ,UAAI;AACF,aAAK,UAAU,QAAQ,IAAI,QAAQ,GAAG,OAAO,GAAG,CAAC;AAAA,MACnD,UAAE;AACA,aAAK,UAAU,aAAa,KAAK,SAAS,CAAC;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAa;AACX,SAAK,UAAU;AACf,SAAK,UAAU,YAAY,KAAK,OAAO;AAAA,EACzC;AAAA,EACA,QAAc;AACZ,SAAK,KAAK;AAAA,EACZ;AACF;;;ALvFA,0BAAc,gDAjBd;AA0CA,SAAS,YAAY,GAAqB;AACxC,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,QAAM,IAAI,OAAO,CAAC,EAAE,KAAK,EAAE,YAAY;AACvC,SAAO,MAAM,MAAM,MAAM,OAAO,MAAM,SAAS,MAAM,WAAW,MAAM;AACxE;AAEA,SAAS,UAAU,MAAyB;AAC1C,QAAM,WAAY,MAAM,QAAgB;AACxC,QAAM,UACJ,OAAO,YAAY,cAAc,QAAQ,KAAK,qBAAqB;AACrE,SAAO,YAAY,QAAQ,KAAK,YAAY,OAAO;AACrD;AAEA,SAAS,YAAY,MAA+B;AAGlD,MAAI,UAAU,IAAI,EAAG,QAAO;AAC5B,QAAM,WAAW,MAAM,QAAQ;AAC/B,QAAM,UAAW,OAAO,YAAY,cAAc,QAAQ,KAAK,oBAAoB;AACnF,SAAO,YAAY,WAAW;AAChC;AAQA,SAAS,uBAAuB,MAAoC;AAClE,QAAM,MACH,MAAM,QAAQ,mCACd,OAAO,YAAY,cAAc,QAAQ,KAAK,iCAAiC;AAClF,QAAM,IAAI,OAAO,QAAQ,WAAW,OAAO,GAAG,IAAI;AAClD,SAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,IAAI,IAAI,IAAI;AACpE;AAGA,SAAS,SAAS,aAA6B;AAC7C,SAAO,cAAc,WAAW,EAAE,QAAQ,SAAS,EAAE;AACvD;AAQO,SAAS,oBAAoB,MAA4D;AAC9F,QAAM,aAAS,kCAAAC,qBAAwB,IAAW;AAClD,QAAM,OAAO,YAAY,IAAI;AAC7B,MAAI,SAAS,OAAQ,QAAO;AAI5B,MAAI,SAAS,YAAY;AACvB,QAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,iDAAiD;AAC1F,UAAMC,aAAY,IAAI,kBAAkB,KAAK,YAAY;AACzD,WAAO,WAAW,QAAQ,YAAYA,YAAkB,MAAMA,WAAU,MAAM,CAAC;AAAA,EACjF;AAEA,QAAM,cAAc,OAAO,UAAU,EAAE;AACvC,QAAM,OAAO,SAAS,WAAW;AACjC,QAAM,kBAAkB,uBAAuB,IAAI;AAEnD,MAAI,YAAoC;AACxC,MAAI;AAIJ,MAAI,aAAa;AACjB,MAAI,aAAa;AACjB,QAAM,WAAW,CAAC,QAAiB;AACjC,iBAAa;AACb,gBAAY;AACZ,QAAI,CAAC,YAAY;AACf,mBAAa;AAEb,cAAQ;AAAA,QACN,gDAAiD,KAAe,WAAW,GAAG;AAAA,MAEhF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,YAA6C;AAC1D,QAAI,WAAY,QAAO;AACvB,QAAI,SAAS,QAAW;AACtB,aAAO,SAAS,WACZ,EAAE,QAAQ,YAAY,YAAY,UAAU,IAC5C,MAAM,WAAW,IAAI;AAAA,IAC3B;AACA,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,IAAI,gBAAgB,MAAM,KAAK,YAAY,eAAe;AACpE,UAAI;AAGF,cAAM,EAAE,QAAQ;AAChB,oBAAY;AAAA,MACd,SAAS,GAAG;AACV,YAAI;AAAE,YAAE,MAAM;AAAA,QAAG,QAAQ;AAAA,QAAe;AACxC,iBAAS,CAAC;AACV,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO,WAAW,QAAQ,QAAQ,MAAM,WAAW,MAAM,CAAC;AAC5D;AAIA,SAAS,WACP,QACA,QACA,QAC4C;AAC5C,SAAO,IAAI,MAAM,QAAQ;AAAA,IACvB,IAAI,QAAQ,MAAM,UAAU;AAC1B,UAAI,SAAS,yBAAyB;AACpC,eAAO,CAAC,OAAY,YAAkB;AACpC,iBAAO,OAAO,EAAE,KAAK,OAAO,MAAM;AAChC,gBAAI,CAAC,EAAG,QAAQ,OAAe,sBAAsB,OAAO,OAAO;AACnE,gBAAI;AACF,oBAAM,IAAI,MAAO,EAAU,eAAe;AAAA,gBACxC,qBAAqB,OAAO;AAAA,gBAC5B,sBAAsB,OAAO;AAAA,gBAC7B,WAAW,OAAO;AAAA,gBAClB,iBAAiB,OAAO,mBAAmB;AAAA,gBAC3C,gBAAgB,OAAO;AAAA,gBACvB,iBAAiB,OAAO;AAAA,cAC1B,CAAC;AACD,kBAAI,EAAE,UAAU,IAAK,OAAM,IAAI,MAAM,0BAA0B,EAAE,MAAM,IAAI,KAAK,UAAU,EAAE,IAAI,CAAC,EAAE;AACnG,oBAAM,OAAY,EAAE,QAAQ,CAAC;AAC7B,qBAAO,EAAE,aAAa,EAAE,GAAG,MAAM,WAAW,EAAE,WAAW,WAAW,oBAAoB,EAAE,WAAW,mBAAmB,IAAI;AAAA,YAC9H,SAAS,GAAG;AAGV,oBAAM,MAAM,OAAQ,GAAa,WAAW,CAAC;AAC7C,kBAAI,IAAI,SAAS,eAAe,KAAK,IAAI,SAAS,uBAAuB,GAAG;AAE1E,wBAAQ,KAAK,sCAAsC,GAAG,uBAAuB;AAC7E,uBAAQ,OAAe,sBAAsB,OAAO,OAAO;AAAA,cAC7D;AACA,oBAAM;AAAA,YACR;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AACA,UAAI,SAAS,mBAAmB;AAC9B,eAAO,CAAC,QAAa;AACnB,gBAAM,IAAI,IAAI,cAAc,MAAa,EAAE,GAAG,KAAK,WAAW,MAAM,CAAC;AACrE,eAAK,OAAO,EAAE,KAAK,OAAO,MAAM;AAC9B,gBAAI,CAAC,GAAG;AAAE,cAAC,OAAe,gBAAgB,GAAG;AAAG;AAAA,YAAQ;AACxD,cAAE,cAAc,CAAQ;AACxB,gBAAI;AAAE,oBAAM,EAAE,MAAM;AAAA,YAAG,SAChB,GAAG;AAER,sBAAQ;AAAA,gBACN,2CAA4C,GAAa,WAAW,CAAC;AAAA,cAEvE;AACA,cAAC,OAAe,gBAAgB,GAAG;AAAA,YACrC;AAAA,UACF,CAAC;AACD,iBAAO;AAAA,QACT;AAAA,MACF;AACA,UAAI,SAAS,kBAAkB;AAC7B,eAAO,MAAM;AAAE,mBAAS;AAAG,iBAAQ,OAAe,eAAe;AAAA,QAAG;AAAA,MACtE;AACA,aAAO,QAAQ,IAAI,QAAQ,MAAM,QAAQ;AAAA,IAC3C;AAAA,EACF,CAAC;AACH;AAEA,IAAO,gBAAQ;","names":["import_orchestration_cluster_api","JobActionReceipt","createCamundaClientBase","transport"]}
|