@nanobpm/nano-sdk 1.1.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/dist/index.cjs CHANGED
@@ -481,7 +481,18 @@ var NanoJobWorker = class {
481
481
 
482
482
  // src/index.ts
483
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
+ }
484
494
  function resolveMode(opts) {
495
+ if (forceRest(opts)) return "rest";
485
496
  const fromOpts = opts?.config?.CAMUNDA_TRANSPORT;
486
497
  const fromEnv = typeof process !== "undefined" ? process.env?.CAMUNDA_TRANSPORT : void 0;
487
498
  return fromOpts ?? fromEnv ?? "auto";
@@ -508,12 +519,38 @@ function createCamundaClient(opts) {
508
519
  const submitTimeoutMs = resolveSubmitTimeoutMs(opts);
509
520
  let transport = null;
510
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
+ };
511
534
  const ensure = async () => {
535
+ if (falconDead) return null;
512
536
  if (nano === void 0) {
513
537
  nano = mode === "falcon" ? { engine: "nanobpmn", falconPath: "/falcon" } : await detectNano(base);
514
538
  }
515
539
  if (!nano) return null;
516
- if (!transport) transport = new FalconTransport(base, nano.falconPath, submitTimeoutMs);
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
+ }
517
554
  return transport;
518
555
  };
519
556
  return wrapClient(client, ensure, () => transport?.close());
@@ -525,28 +562,46 @@ function wrapClient(client, ensure, onStop) {
525
562
  return (input, options) => {
526
563
  return ensure().then(async (t) => {
527
564
  if (!t) return target.createProcessInstance(input, options);
528
- const r = await t.createInstance({
529
- processDefinitionId: input?.processDefinitionId,
530
- processDefinitionKey: input?.processDefinitionKey,
531
- variables: input?.variables,
532
- awaitCompletion: input?.awaitCompletion ?? false,
533
- fetchVariables: input?.fetchVariables,
534
- submitTimeoutMs: input?.submitTimeoutMs
535
- });
536
- if (r.status >= 400) throw new Error(`createInstance failed: ${r.status} ${JSON.stringify(r.body)}`);
537
- const body = r.body ?? {};
538
- return r.completion ? { ...body, variables: r.completion.variables, processInstanceKey: r.completion.processInstanceKey } : body;
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
+ }
539
585
  });
540
586
  };
541
587
  }
542
588
  if (prop === "createJobWorker") {
543
589
  return (cfg) => {
544
590
  const w = new NanoJobWorker(null, { ...cfg, autoStart: false });
545
- void ensure().then((t) => {
546
- if (t) {
547
- w.bindTransport(t);
548
- void w.start();
549
- } else target.createJobWorker(cfg);
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
+ }
550
605
  });
551
606
  return w;
552
607
  };
@@ -1 +1 @@
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> & { CAMUNDA_TRANSPORT?: NanoTransport; CAMUNDA_REST_ADDRESS?: string; CAMUNDA_NANO_SUBMIT_TIMEOUT_MS?: string | number };\n /** Embedded (ADR 0005) in-process engine host; required when transport is \"embedded\". */\n embeddedHost?: EmbeddedHost;\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/**\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\n const ensure = async (): Promise<FalconTransport | 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) transport = new FalconTransport(base, nano.falconPath, submitTimeoutMs);\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 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 });\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 as any); void w.start(); }\n else (target as any).createJobWorker(cfg);\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":"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","names":["import_orchestration_cluster_api","JobActionReceipt","createCamundaClientBase","transport"]}
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"]}
package/dist/index.d.cts CHANGED
@@ -209,6 +209,12 @@ type AnyOpts = Parameters<typeof createCamundaClient$1>[0] & {
209
209
  CAMUNDA_TRANSPORT?: NanoTransport;
210
210
  CAMUNDA_REST_ADDRESS?: string;
211
211
  CAMUNDA_NANO_SUBMIT_TIMEOUT_MS?: string | number;
212
+ /**
213
+ * Force plain REST even when the gateway advertises Falcon. Useful for
214
+ * environments where WebSockets are blocked (corporate proxies etc.).
215
+ * Accepts any truthy string (`1`, `true`, `yes`, `on`).
216
+ */
217
+ CAMUNDA_FORCE_REST?: string | boolean | number;
212
218
  };
213
219
  /** Embedded (ADR 0005) in-process engine host; required when transport is "embedded". */
214
220
  embeddedHost?: EmbeddedHost;
package/dist/index.d.ts CHANGED
@@ -209,6 +209,12 @@ type AnyOpts = Parameters<typeof createCamundaClient$1>[0] & {
209
209
  CAMUNDA_TRANSPORT?: NanoTransport;
210
210
  CAMUNDA_REST_ADDRESS?: string;
211
211
  CAMUNDA_NANO_SUBMIT_TIMEOUT_MS?: string | number;
212
+ /**
213
+ * Force plain REST even when the gateway advertises Falcon. Useful for
214
+ * environments where WebSockets are blocked (corporate proxies etc.).
215
+ * Accepts any truthy string (`1`, `true`, `yes`, `on`).
216
+ */
217
+ CAMUNDA_FORCE_REST?: string | boolean | number;
212
218
  };
213
219
  /** Embedded (ADR 0005) in-process engine host; required when transport is "embedded". */
214
220
  embeddedHost?: EmbeddedHost;
package/dist/index.js CHANGED
@@ -442,7 +442,18 @@ var NanoJobWorker = class {
442
442
 
443
443
  // src/index.ts
444
444
  export * from "@camunda8/orchestration-cluster-api";
445
+ function isTruthyEnv(v) {
446
+ if (v === void 0 || v === null) return false;
447
+ const s = String(v).trim().toLowerCase();
448
+ return s !== "" && s !== "0" && s !== "off" && s !== "false" && s !== "no";
449
+ }
450
+ function forceRest(opts) {
451
+ const fromOpts = opts?.config?.CAMUNDA_FORCE_REST;
452
+ const fromEnv = typeof process !== "undefined" ? process.env?.CAMUNDA_FORCE_REST : void 0;
453
+ return isTruthyEnv(fromOpts) || isTruthyEnv(fromEnv);
454
+ }
445
455
  function resolveMode(opts) {
456
+ if (forceRest(opts)) return "rest";
446
457
  const fromOpts = opts?.config?.CAMUNDA_TRANSPORT;
447
458
  const fromEnv = typeof process !== "undefined" ? process.env?.CAMUNDA_TRANSPORT : void 0;
448
459
  return fromOpts ?? fromEnv ?? "auto";
@@ -469,12 +480,38 @@ function createCamundaClient(opts) {
469
480
  const submitTimeoutMs = resolveSubmitTimeoutMs(opts);
470
481
  let transport = null;
471
482
  let nano;
483
+ let falconDead = false;
484
+ let warnedDead = false;
485
+ const markDead = (err) => {
486
+ falconDead = true;
487
+ transport = null;
488
+ if (!warnedDead) {
489
+ warnedDead = true;
490
+ console.warn(
491
+ `[@nanobpm/sdk] Falcon transport unavailable (${err?.message ?? err}); falling back to REST. Set CAMUNDA_FORCE_REST=1 to skip Falcon detection.`
492
+ );
493
+ }
494
+ };
472
495
  const ensure = async () => {
496
+ if (falconDead) return null;
473
497
  if (nano === void 0) {
474
498
  nano = mode === "falcon" ? { engine: "nanobpmn", falconPath: "/falcon" } : await detectNano(base);
475
499
  }
476
500
  if (!nano) return null;
477
- if (!transport) transport = new FalconTransport(base, nano.falconPath, submitTimeoutMs);
501
+ if (!transport) {
502
+ const t = new FalconTransport(base, nano.falconPath, submitTimeoutMs);
503
+ try {
504
+ await t.connect();
505
+ transport = t;
506
+ } catch (e) {
507
+ try {
508
+ t.close();
509
+ } catch {
510
+ }
511
+ markDead(e);
512
+ return null;
513
+ }
514
+ }
478
515
  return transport;
479
516
  };
480
517
  return wrapClient(client, ensure, () => transport?.close());
@@ -486,28 +523,46 @@ function wrapClient(client, ensure, onStop) {
486
523
  return (input, options) => {
487
524
  return ensure().then(async (t) => {
488
525
  if (!t) return target.createProcessInstance(input, options);
489
- const r = await t.createInstance({
490
- processDefinitionId: input?.processDefinitionId,
491
- processDefinitionKey: input?.processDefinitionKey,
492
- variables: input?.variables,
493
- awaitCompletion: input?.awaitCompletion ?? false,
494
- fetchVariables: input?.fetchVariables,
495
- submitTimeoutMs: input?.submitTimeoutMs
496
- });
497
- if (r.status >= 400) throw new Error(`createInstance failed: ${r.status} ${JSON.stringify(r.body)}`);
498
- const body = r.body ?? {};
499
- return r.completion ? { ...body, variables: r.completion.variables, processInstanceKey: r.completion.processInstanceKey } : body;
526
+ try {
527
+ const r = await t.createInstance({
528
+ processDefinitionId: input?.processDefinitionId,
529
+ processDefinitionKey: input?.processDefinitionKey,
530
+ variables: input?.variables,
531
+ awaitCompletion: input?.awaitCompletion ?? false,
532
+ fetchVariables: input?.fetchVariables,
533
+ submitTimeoutMs: input?.submitTimeoutMs
534
+ });
535
+ if (r.status >= 400) throw new Error(`createInstance failed: ${r.status} ${JSON.stringify(r.body)}`);
536
+ const body = r.body ?? {};
537
+ return r.completion ? { ...body, variables: r.completion.variables, processInstanceKey: r.completion.processInstanceKey } : body;
538
+ } catch (e) {
539
+ const msg = String(e?.message ?? e);
540
+ if (msg.includes("falcon closed") || msg.includes("falcon connect failed")) {
541
+ console.warn(`[@nanobpm/sdk] Falcon call failed (${msg}); retrying via REST.`);
542
+ return target.createProcessInstance(input, options);
543
+ }
544
+ throw e;
545
+ }
500
546
  });
501
547
  };
502
548
  }
503
549
  if (prop === "createJobWorker") {
504
550
  return (cfg) => {
505
551
  const w = new NanoJobWorker(null, { ...cfg, autoStart: false });
506
- void ensure().then((t) => {
507
- if (t) {
508
- w.bindTransport(t);
509
- void w.start();
510
- } else target.createJobWorker(cfg);
552
+ void ensure().then(async (t) => {
553
+ if (!t) {
554
+ target.createJobWorker(cfg);
555
+ return;
556
+ }
557
+ w.bindTransport(t);
558
+ try {
559
+ await w.start();
560
+ } catch (e) {
561
+ console.warn(
562
+ `[@nanobpm/sdk] Falcon subscribe failed (${e?.message ?? e}); falling back to REST job worker.`
563
+ );
564
+ target.createJobWorker(cfg);
565
+ }
511
566
  });
512
567
  return w;
513
568
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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> & { CAMUNDA_TRANSPORT?: NanoTransport; CAMUNDA_REST_ADDRESS?: string; CAMUNDA_NANO_SUBMIT_TIMEOUT_MS?: string | number };\n /** Embedded (ADR 0005) in-process engine host; required when transport is \"embedded\". */\n embeddedHost?: EmbeddedHost;\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/**\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\n const ensure = async (): Promise<FalconTransport | 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) transport = new FalconTransport(base, nano.falconPath, submitTimeoutMs);\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 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 });\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 as any); void w.start(); }\n else (target as any).createJobWorker(cfg);\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":"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","names":["transport"]}
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":"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","names":["transport"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Drop-in replacement for @camunda8/orchestration-cluster-api that upgrades to the Nano Falcon protocol when connected to a Nano server.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",