@camunda8/orchestration-cluster-api 8.9.0-alpha.8 → 9.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/logger.cjs CHANGED
@@ -42,7 +42,7 @@ function createLogger(opts = {}) {
42
42
  return ORDER[currentLevel] >= ORDER[need];
43
43
  }
44
44
  function evalArgs(args) {
45
- return args.map((a) => typeof a === "function" && a.length === 0 ? a() : a).flat();
45
+ return args.flatMap((a) => typeof a === "function" && a.length === 0 ? a() : a);
46
46
  }
47
47
  function emit(level, scope, rawArgs) {
48
48
  if (!isEnabled(level)) return;
@@ -70,7 +70,7 @@ function createLogger(opts = {}) {
70
70
  } else {
71
71
  const tag = `[camunda-sdk][${level}]${scope ? `[${scope}]` : ""}`;
72
72
  const method = level === "error" ? "error" : level === "warn" ? "warn" : "log";
73
- console[method](tag, code + ":", msg, data ?? "");
73
+ console[method](tag, `${code}:`, msg, data ?? "");
74
74
  }
75
75
  }
76
76
  const make = (scope) => ({
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/logger.ts","../src/runtime/logger.ts"],"sourcesContent":["// Deprecated: global logger API removed. Per-client logger accessible via client.logger().\nexport type { LogEvent, LogLevel, LogTransport, Logger } from './runtime/logger';\nexport { createLogger } from './runtime/logger';\n","// Per-client logger (no global singleton). Construct via createLogger.\n\n// Added 'silly' for deep diagnostics (unsafe: logs HTTP bodies when enabled elsewhere)\nexport type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | 'silly';\nexport interface LogEvent {\n level: LogLevel;\n scope: string;\n ts: number;\n args: any[];\n code?: string;\n data?: any;\n}\nexport type LogTransport = (e: LogEvent) => void;\nconst ORDER: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n trace: 5,\n silly: 6,\n};\n\nexport interface Logger {\n level(): LogLevel;\n setLevel(level: LogLevel): void; // internal use\n setTransport(t?: LogTransport): void; // internal use\n error(...a: any[]): void;\n warn(...a: any[]): void;\n info(...a: any[]): void;\n debug(...a: any[]): void;\n trace(...a: any[]): void;\n silly(...a: any[]): void;\n scope(child: string): Logger;\n code(level: LogLevel, code: string, msg: string, data?: any): void;\n}\n\nexport interface CreateLoggerOptions {\n level?: LogLevel;\n transport?: LogTransport;\n scope?: string;\n}\n\nexport function createLogger(opts: CreateLoggerOptions = {}): Logger {\n let currentLevel: LogLevel = opts.level || 'error';\n let transport: LogTransport | undefined = opts.transport;\n const baseScope = opts.scope || '';\n\n function isEnabled(need: LogLevel) {\n return ORDER[currentLevel] >= ORDER[need];\n }\n function evalArgs(args: any[]): any[] {\n // Support lazy function args: if an arg is a function with zero arity, call it.\n return args.map((a) => (typeof a === 'function' && a.length === 0 ? a() : a)).flat();\n }\n function emit(level: LogLevel, scope: string, rawArgs: any[]) {\n if (!isEnabled(level)) return;\n const args = evalArgs(rawArgs);\n const evt: LogEvent = { level, scope, ts: Date.now(), args };\n if (transport) {\n try {\n transport(evt);\n } catch {\n /* ignore transport errors */\n }\n } else {\n const tag = `[camunda-sdk][${level}]${scope ? `[${scope}]` : ''}`;\n const method = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';\n // eslint-disable-next-line no-console\n console[method](tag, ...args);\n }\n }\n function emitCode(level: LogLevel, scope: string, code: string, msg: string, data?: any) {\n if (!isEnabled(level)) return;\n const evt: LogEvent = { level, scope, ts: Date.now(), args: [msg], code, data };\n if (transport) {\n try {\n transport(evt);\n // eslint-disable-next-line no-empty\n } catch {}\n } else {\n const tag = `[camunda-sdk][${level}]${scope ? `[${scope}]` : ''}`;\n const method = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';\n // eslint-disable-next-line no-console\n console[method](tag, code + ':', msg, data ?? '');\n }\n }\n const make = (scope: string): Logger => ({\n level: () => currentLevel,\n setLevel(l: LogLevel) {\n currentLevel = l;\n },\n setTransport(t?: LogTransport) {\n transport = t;\n },\n error: (...a: any[]) => emit('error', scope, a),\n warn: (...a: any[]) => emit('warn', scope, a),\n info: (...a: any[]) => emit('info', scope, a),\n debug: (...a: any[]) => emit('debug', scope, a),\n trace: (...a: any[]) => emit('trace', scope, a),\n silly: (...a: any[]) => emit('silly', scope, a),\n scope(child: string) {\n return make(scope ? `${scope}:${child}` : child);\n },\n code(l: LogLevel, code: string, msg: string, data?: any) {\n emitCode(l, scope, code, msg, data);\n },\n });\n return make(baseScope);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACaA,IAAM,QAAkC;AAAA,EACtC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;AAsBO,SAAS,aAAa,OAA4B,CAAC,GAAW;AACnE,MAAI,eAAyB,KAAK,SAAS;AAC3C,MAAI,YAAsC,KAAK;AAC/C,QAAM,YAAY,KAAK,SAAS;AAEhC,WAAS,UAAU,MAAgB;AACjC,WAAO,MAAM,YAAY,KAAK,MAAM,IAAI;AAAA,EAC1C;AACA,WAAS,SAAS,MAAoB;AAEpC,WAAO,KAAK,IAAI,CAAC,MAAO,OAAO,MAAM,cAAc,EAAE,WAAW,IAAI,EAAE,IAAI,CAAE,EAAE,KAAK;AAAA,EACrF;AACA,WAAS,KAAK,OAAiB,OAAe,SAAgB;AAC5D,QAAI,CAAC,UAAU,KAAK,EAAG;AACvB,UAAM,OAAO,SAAS,OAAO;AAC7B,UAAM,MAAgB,EAAE,OAAO,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK;AAC3D,QAAI,WAAW;AACb,UAAI;AACF,kBAAU,GAAG;AAAA,MACf,QAAQ;AAAA,MAER;AAAA,IACF,OAAO;AACL,YAAM,MAAM,iBAAiB,KAAK,IAAI,QAAQ,IAAI,KAAK,MAAM,EAAE;AAC/D,YAAM,SAAS,UAAU,UAAU,UAAU,UAAU,SAAS,SAAS;AAEzE,cAAQ,MAAM,EAAE,KAAK,GAAG,IAAI;AAAA,IAC9B;AAAA,EACF;AACA,WAAS,SAAS,OAAiB,OAAe,MAAc,KAAa,MAAY;AACvF,QAAI,CAAC,UAAU,KAAK,EAAG;AACvB,UAAM,MAAgB,EAAE,OAAO,OAAO,IAAI,KAAK,IAAI,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,KAAK;AAC9E,QAAI,WAAW;AACb,UAAI;AACF,kBAAU,GAAG;AAAA,MAEf,QAAQ;AAAA,MAAC;AAAA,IACX,OAAO;AACL,YAAM,MAAM,iBAAiB,KAAK,IAAI,QAAQ,IAAI,KAAK,MAAM,EAAE;AAC/D,YAAM,SAAS,UAAU,UAAU,UAAU,UAAU,SAAS,SAAS;AAEzE,cAAQ,MAAM,EAAE,KAAK,OAAO,KAAK,KAAK,QAAQ,EAAE;AAAA,IAClD;AAAA,EACF;AACA,QAAM,OAAO,CAAC,WAA2B;AAAA,IACvC,OAAO,MAAM;AAAA,IACb,SAAS,GAAa;AACpB,qBAAe;AAAA,IACjB;AAAA,IACA,aAAa,GAAkB;AAC7B,kBAAY;AAAA,IACd;AAAA,IACA,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,MAAM,IAAI,MAAa,KAAK,QAAQ,OAAO,CAAC;AAAA,IAC5C,MAAM,IAAI,MAAa,KAAK,QAAQ,OAAO,CAAC;AAAA,IAC5C,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,MAAM,OAAe;AACnB,aAAO,KAAK,QAAQ,GAAG,KAAK,IAAI,KAAK,KAAK,KAAK;AAAA,IACjD;AAAA,IACA,KAAK,GAAa,MAAc,KAAa,MAAY;AACvD,eAAS,GAAG,OAAO,MAAM,KAAK,IAAI;AAAA,IACpC;AAAA,EACF;AACA,SAAO,KAAK,SAAS;AACvB;","names":[]}
1
+ {"version":3,"sources":["../src/logger.ts","../src/runtime/logger.ts"],"sourcesContent":["// Deprecated: global logger API removed. Per-client logger accessible via client.logger().\nexport type { LogEvent, Logger, LogLevel, LogTransport } from './runtime/logger';\nexport { createLogger } from './runtime/logger';\n","// Per-client logger (no global singleton). Construct via createLogger.\n\n// Added 'silly' for deep diagnostics (unsafe: logs HTTP bodies when enabled elsewhere)\nexport type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | 'silly';\nexport interface LogEvent {\n level: LogLevel;\n scope: string;\n ts: number;\n args: any[];\n code?: string;\n data?: any;\n}\nexport type LogTransport = (e: LogEvent) => void;\nconst ORDER: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n trace: 5,\n silly: 6,\n};\n\nexport interface Logger {\n level(): LogLevel;\n setLevel(level: LogLevel): void; // internal use\n setTransport(t?: LogTransport): void; // internal use\n error(...a: any[]): void;\n warn(...a: any[]): void;\n info(...a: any[]): void;\n debug(...a: any[]): void;\n trace(...a: any[]): void;\n silly(...a: any[]): void;\n scope(child: string): Logger;\n code(level: LogLevel, code: string, msg: string, data?: any): void;\n}\n\nexport interface CreateLoggerOptions {\n level?: LogLevel;\n transport?: LogTransport;\n scope?: string;\n}\n\nexport function createLogger(opts: CreateLoggerOptions = {}): Logger {\n let currentLevel: LogLevel = opts.level || 'error';\n let transport: LogTransport | undefined = opts.transport;\n const baseScope = opts.scope || '';\n\n function isEnabled(need: LogLevel) {\n return ORDER[currentLevel] >= ORDER[need];\n }\n function evalArgs(args: any[]): any[] {\n // Support lazy function args: if an arg is a function with zero arity, call it.\n return args.flatMap((a) => (typeof a === 'function' && a.length === 0 ? a() : a));\n }\n function emit(level: LogLevel, scope: string, rawArgs: any[]) {\n if (!isEnabled(level)) return;\n const args = evalArgs(rawArgs);\n const evt: LogEvent = { level, scope, ts: Date.now(), args };\n if (transport) {\n try {\n transport(evt);\n } catch {\n /* ignore transport errors */\n }\n } else {\n const tag = `[camunda-sdk][${level}]${scope ? `[${scope}]` : ''}`;\n const method = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';\n\n console[method](tag, ...args);\n }\n }\n function emitCode(level: LogLevel, scope: string, code: string, msg: string, data?: any) {\n if (!isEnabled(level)) return;\n const evt: LogEvent = { level, scope, ts: Date.now(), args: [msg], code, data };\n if (transport) {\n try {\n transport(evt);\n } catch {}\n } else {\n const tag = `[camunda-sdk][${level}]${scope ? `[${scope}]` : ''}`;\n const method = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';\n\n console[method](tag, `${code}:`, msg, data ?? '');\n }\n }\n const make = (scope: string): Logger => ({\n level: () => currentLevel,\n setLevel(l: LogLevel) {\n currentLevel = l;\n },\n setTransport(t?: LogTransport) {\n transport = t;\n },\n error: (...a: any[]) => emit('error', scope, a),\n warn: (...a: any[]) => emit('warn', scope, a),\n info: (...a: any[]) => emit('info', scope, a),\n debug: (...a: any[]) => emit('debug', scope, a),\n trace: (...a: any[]) => emit('trace', scope, a),\n silly: (...a: any[]) => emit('silly', scope, a),\n scope(child: string) {\n return make(scope ? `${scope}:${child}` : child);\n },\n code(l: LogLevel, code: string, msg: string, data?: any) {\n emitCode(l, scope, code, msg, data);\n },\n });\n return make(baseScope);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACaA,IAAM,QAAkC;AAAA,EACtC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;AAsBO,SAAS,aAAa,OAA4B,CAAC,GAAW;AACnE,MAAI,eAAyB,KAAK,SAAS;AAC3C,MAAI,YAAsC,KAAK;AAC/C,QAAM,YAAY,KAAK,SAAS;AAEhC,WAAS,UAAU,MAAgB;AACjC,WAAO,MAAM,YAAY,KAAK,MAAM,IAAI;AAAA,EAC1C;AACA,WAAS,SAAS,MAAoB;AAEpC,WAAO,KAAK,QAAQ,CAAC,MAAO,OAAO,MAAM,cAAc,EAAE,WAAW,IAAI,EAAE,IAAI,CAAE;AAAA,EAClF;AACA,WAAS,KAAK,OAAiB,OAAe,SAAgB;AAC5D,QAAI,CAAC,UAAU,KAAK,EAAG;AACvB,UAAM,OAAO,SAAS,OAAO;AAC7B,UAAM,MAAgB,EAAE,OAAO,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK;AAC3D,QAAI,WAAW;AACb,UAAI;AACF,kBAAU,GAAG;AAAA,MACf,QAAQ;AAAA,MAER;AAAA,IACF,OAAO;AACL,YAAM,MAAM,iBAAiB,KAAK,IAAI,QAAQ,IAAI,KAAK,MAAM,EAAE;AAC/D,YAAM,SAAS,UAAU,UAAU,UAAU,UAAU,SAAS,SAAS;AAEzE,cAAQ,MAAM,EAAE,KAAK,GAAG,IAAI;AAAA,IAC9B;AAAA,EACF;AACA,WAAS,SAAS,OAAiB,OAAe,MAAc,KAAa,MAAY;AACvF,QAAI,CAAC,UAAU,KAAK,EAAG;AACvB,UAAM,MAAgB,EAAE,OAAO,OAAO,IAAI,KAAK,IAAI,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,KAAK;AAC9E,QAAI,WAAW;AACb,UAAI;AACF,kBAAU,GAAG;AAAA,MACf,QAAQ;AAAA,MAAC;AAAA,IACX,OAAO;AACL,YAAM,MAAM,iBAAiB,KAAK,IAAI,QAAQ,IAAI,KAAK,MAAM,EAAE;AAC/D,YAAM,SAAS,UAAU,UAAU,UAAU,UAAU,SAAS,SAAS;AAEzE,cAAQ,MAAM,EAAE,KAAK,GAAG,IAAI,KAAK,KAAK,QAAQ,EAAE;AAAA,IAClD;AAAA,EACF;AACA,QAAM,OAAO,CAAC,WAA2B;AAAA,IACvC,OAAO,MAAM;AAAA,IACb,SAAS,GAAa;AACpB,qBAAe;AAAA,IACjB;AAAA,IACA,aAAa,GAAkB;AAC7B,kBAAY;AAAA,IACd;AAAA,IACA,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,MAAM,IAAI,MAAa,KAAK,QAAQ,OAAO,CAAC;AAAA,IAC5C,MAAM,IAAI,MAAa,KAAK,QAAQ,OAAO,CAAC;AAAA,IAC5C,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,OAAO,IAAI,MAAa,KAAK,SAAS,OAAO,CAAC;AAAA,IAC9C,MAAM,OAAe;AACnB,aAAO,KAAK,QAAQ,GAAG,KAAK,IAAI,KAAK,KAAK,KAAK;AAAA,IACjD;AAAA,IACA,KAAK,GAAa,MAAc,KAAa,MAAY;AACvD,eAAS,GAAG,OAAO,MAAM,KAAK,IAAI;AAAA,IACpC;AAAA,EACF;AACA,SAAO,KAAK,SAAS;AACvB;","names":[]}
package/dist/logger.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  createLogger
3
- } from "./chunk-W6JB7JZH.js";
3
+ } from "./chunk-KQ4UL2WX.js";
4
+ import "./chunk-DGUM43GV.js";
4
5
  export {
5
6
  createLogger
6
7
  };
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ // src/runtime/threadWorkerEntry.ts
4
+ var import_node_worker_threads = require("worker_threads");
5
+
6
+ // src/runtime/clientProxy.ts
7
+ var _counter = 0;
8
+ function fallbackUUID() {
9
+ return `${Date.now().toString(36)}-${(++_counter).toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
10
+ }
11
+ function createClientProxy(port) {
12
+ return new Proxy({}, {
13
+ get(_, method) {
14
+ if (typeof method === "symbol") return void 0;
15
+ if (method === "then") return void 0;
16
+ if (method === "toJSON") return void 0;
17
+ return (...args) => {
18
+ const callId = globalThis.crypto?.randomUUID ? globalThis.crypto.randomUUID() : fallbackUUID();
19
+ const msg = { type: "client-call", callId, method, args };
20
+ port.postMessage(msg);
21
+ return new Promise((resolve, reject) => {
22
+ const handler = (reply) => {
23
+ if (reply.type !== "client-call-result" || reply.callId !== callId) return;
24
+ port.off("message", handler);
25
+ if (reply.error !== void 0) {
26
+ reject(new Error(reply.error));
27
+ } else {
28
+ resolve(reply.result);
29
+ }
30
+ };
31
+ port.on("message", handler);
32
+ });
33
+ };
34
+ }
35
+ });
36
+ }
37
+
38
+ // src/runtime/threadWorkerEntry.ts
39
+ var JobActionReceipt = "JOB_ACTION_RECEIPT";
40
+ if (!import_node_worker_threads.parentPort) {
41
+ throw new Error("threadWorkerEntry must run inside a worker_threads Worker");
42
+ }
43
+ var handlerCache = /* @__PURE__ */ new Map();
44
+ async function loadHandler(handlerModule) {
45
+ const cached = handlerCache.get(handlerModule);
46
+ if (cached) return cached;
47
+ const isPath = handlerModule.startsWith(".") || handlerModule.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(handlerModule);
48
+ const modulePath = isPath ? new URL(handlerModule, `file://${process.cwd()}/`).href : handlerModule;
49
+ const mod = await import(modulePath);
50
+ const handler = mod.default ?? mod.handler;
51
+ if (typeof handler !== "function") {
52
+ throw new Error(
53
+ `Threaded handler module '${handlerModule}' must export a default function or named 'handler' export`
54
+ );
55
+ }
56
+ handlerCache.set(handlerModule, handler);
57
+ return handler;
58
+ }
59
+ import_node_worker_threads.parentPort.on("message", async (msg) => {
60
+ if (msg.type !== "job") return;
61
+ const { taskId, jobData, handlerModule, clientPort } = msg;
62
+ try {
63
+ const handlerFn = await loadHandler(handlerModule);
64
+ const clientProxy = createClientProxy(clientPort);
65
+ const job = createJobProxy(jobData, clientProxy);
66
+ await handlerFn(job, clientProxy);
67
+ if (!job.acknowledged) {
68
+ const result2 = {
69
+ type: "job-result",
70
+ taskId,
71
+ ok: false,
72
+ error: `Handler for '${handlerModule}' returned without acknowledging the job. Call job.complete(), job.fail(), job.error(), or job.ignore().`
73
+ };
74
+ import_node_worker_threads.parentPort.postMessage(result2);
75
+ return;
76
+ }
77
+ const result = {
78
+ type: "job-result",
79
+ taskId,
80
+ ok: true,
81
+ completionAction: job._completionAction || void 0
82
+ };
83
+ import_node_worker_threads.parentPort.postMessage(result);
84
+ } catch (err) {
85
+ const result = {
86
+ type: "job-result",
87
+ taskId,
88
+ ok: false,
89
+ error: err?.message || String(err)
90
+ };
91
+ import_node_worker_threads.parentPort.postMessage(result);
92
+ } finally {
93
+ if (clientPort && typeof clientPort.close === "function") {
94
+ clientPort.close();
95
+ }
96
+ }
97
+ });
98
+ function createJobProxy(jobData, client) {
99
+ const acknowledged = { value: false };
100
+ const ack = () => {
101
+ acknowledged.value = true;
102
+ job.acknowledged = true;
103
+ };
104
+ const job = { ...jobData };
105
+ job.complete = async (variables = {}, result) => {
106
+ ack();
107
+ job._completionAction = {
108
+ method: "completeJob",
109
+ args: [{ variables, jobKey: jobData.jobKey, ...result !== void 0 && { result } }]
110
+ };
111
+ return JobActionReceipt;
112
+ };
113
+ job.fail = async (reason) => {
114
+ ack();
115
+ job._completionAction = {
116
+ method: "failJob",
117
+ args: [{ ...reason, jobKey: jobData.jobKey }]
118
+ };
119
+ return JobActionReceipt;
120
+ };
121
+ job.error = async (error) => {
122
+ ack();
123
+ job._completionAction = {
124
+ method: "throwJobError",
125
+ args: [{ ...error, jobKey: jobData.jobKey }]
126
+ };
127
+ return JobActionReceipt;
128
+ };
129
+ job.cancelWorkflow = async () => {
130
+ ack();
131
+ job._completionAction = {
132
+ method: "cancelProcessInstance",
133
+ args: [{ processInstanceKey: jobData.processInstanceKey }]
134
+ };
135
+ return JobActionReceipt;
136
+ };
137
+ job.ignore = async () => {
138
+ ack();
139
+ return JobActionReceipt;
140
+ };
141
+ job.modifyJobTimeout = ({ newTimeoutMs }) => client.updateJob({ changeset: { timeout: newTimeoutMs }, jobKey: jobData.jobKey });
142
+ job.modifyRetries = ({ retries }) => client.updateJob({ changeset: { retries }, jobKey: jobData.jobKey });
143
+ return job;
144
+ }
145
+ import_node_worker_threads.parentPort.postMessage({ type: "ready" });
146
+ //# sourceMappingURL=threadWorkerEntry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/threadWorkerEntry.ts","../src/runtime/clientProxy.ts"],"sourcesContent":["/**\n * Worker thread entry point for the shared ThreadPool.\n *\n * Each thread in the pool runs this script. It:\n * 1. Waits for job messages on parentPort\n * 2. Dynamically imports and caches the handler module per handlerModule path\n * 3. Creates a client proxy + job proxy per job\n * 4. Calls the handler, sends back the result\n *\n * Threads are generic — the handler module is specified per-job, not per-thread.\n * Handlers are cached by module path so each import happens only once per thread.\n */\nimport { parentPort } from 'node:worker_threads';\nimport type { JobResult as ApiJobResult } from '../gen/types.gen';\nimport { createClientProxy } from './clientProxy.ts';\n\n// Inline the JobActionReceipt constant to avoid importing the full SDK dependency chain\n// (jobWorker.ts → ../gen/CamundaClient → entire SDK) in the worker thread.\nconst JobActionReceipt = 'JOB_ACTION_RECEIPT' as const;\n\nif (!parentPort) {\n throw new Error('threadWorkerEntry must run inside a worker_threads Worker');\n}\n\ninterface JobMessage {\n type: 'job';\n /** Unique ID for this job dispatch (correlates response) */\n taskId: string;\n /** Serialized job data (plain object, no methods) */\n jobData: Record<string, unknown>;\n /** Handler module path — resolved per job, cached per thread */\n handlerModule: string;\n}\n\ninterface JobResult {\n type: 'job-result';\n taskId: string;\n ok: boolean;\n error?: string;\n /** When the handler acknowledged the job via complete/fail/error,\n * the action is captured here for the main thread to execute. */\n completionAction?: {\n method: string;\n args: unknown[];\n };\n}\n\n/** Cache of loaded handlers keyed by module path. Each thread loads a handler once per unique path. */\nconst handlerCache = new Map<string, (job: any, client: any) => Promise<any>>();\n\nasync function loadHandler(\n handlerModule: string\n): Promise<(job: any, client: any) => Promise<any>> {\n const cached = handlerCache.get(handlerModule);\n if (cached) return cached;\n\n // Convert filesystem paths to file:// URLs for dynamic import().\n // Handles relative (./ ../) paths, Unix absolute (/), and Windows absolute (C:\\).\n const isPath =\n handlerModule.startsWith('.') ||\n handlerModule.startsWith('/') ||\n /^[a-zA-Z]:[\\\\/]/.test(handlerModule);\n const modulePath = isPath\n ? new URL(handlerModule, `file://${process.cwd()}/`).href\n : handlerModule;\n const mod = await import(modulePath);\n const handler = mod.default ?? mod.handler;\n if (typeof handler !== 'function') {\n throw new Error(\n `Threaded handler module '${handlerModule}' must export a default function or named 'handler' export`\n );\n }\n handlerCache.set(handlerModule, handler);\n return handler;\n}\n\nparentPort.on('message', async (msg: JobMessage & { clientPort?: any }) => {\n if (msg.type !== 'job') return;\n\n const { taskId, jobData, handlerModule, clientPort } = msg as JobMessage & {\n clientPort: import('node:worker_threads').MessagePort;\n };\n\n try {\n const handlerFn = await loadHandler(handlerModule);\n\n // Create a client proxy for this job's MessagePort\n const clientProxy = createClientProxy(clientPort);\n\n // Build a job-like object with proxied action methods\n const job = createJobProxy(jobData, clientProxy);\n\n await handlerFn(job, clientProxy);\n\n // If the handler never acknowledged the job (no complete/fail/error/ignore),\n // treat it as an error so the broker can retry rather than silently dropping it.\n if (!job.acknowledged) {\n const result: JobResult = {\n type: 'job-result',\n taskId,\n ok: false,\n error:\n `Handler for '${handlerModule}' returned without acknowledging the job. ` +\n 'Call job.complete(), job.fail(), job.error(), or job.ignore().',\n };\n parentPort!.postMessage(result);\n return;\n }\n\n const result: JobResult = {\n type: 'job-result',\n taskId,\n ok: true,\n completionAction: job._completionAction || undefined,\n };\n parentPort!.postMessage(result);\n } catch (err: any) {\n const result: JobResult = {\n type: 'job-result',\n taskId,\n ok: false,\n error: err?.message || String(err),\n };\n parentPort!.postMessage(result);\n } finally {\n // Close this job's client port\n if (clientPort && typeof clientPort.close === 'function') {\n clientPort.close();\n }\n }\n});\n\n/**\n * Build a job object with action methods that proxy through the client.\n * The job data is plain serialized data from the main thread.\n * Action methods (complete, fail, error, etc.) call back to the main thread client.\n */\nfunction createJobProxy(jobData: Record<string, unknown>, client: any): any {\n const acknowledged = { value: false };\n const ack = () => {\n acknowledged.value = true;\n job.acknowledged = true;\n };\n\n const job: any = { ...jobData };\n\n /**\n * Completion actions (complete/fail/error/cancelWorkflow) are stored as intent\n * rather than proxied through the MessagePort. The thread returns immediately,\n * and the main thread executes the API call asynchronously. This keeps threads\n * free for CPU work instead of blocking on I/O round-trips.\n */\n\n job.complete = async (variables: Record<string, unknown> = {}, result?: ApiJobResult) => {\n ack();\n job._completionAction = {\n method: 'completeJob',\n args: [{ variables, jobKey: jobData.jobKey, ...(result !== undefined && { result }) }],\n };\n return JobActionReceipt;\n };\n\n job.fail = async (reason: any) => {\n ack();\n job._completionAction = {\n method: 'failJob',\n args: [{ ...reason, jobKey: jobData.jobKey }],\n };\n return JobActionReceipt;\n };\n\n job.error = async (error: any) => {\n ack();\n job._completionAction = {\n method: 'throwJobError',\n args: [{ ...error, jobKey: jobData.jobKey }],\n };\n return JobActionReceipt;\n };\n\n job.cancelWorkflow = async () => {\n ack();\n job._completionAction = {\n method: 'cancelProcessInstance',\n args: [{ processInstanceKey: jobData.processInstanceKey }],\n };\n return JobActionReceipt;\n };\n\n job.ignore = async () => {\n ack();\n return JobActionReceipt;\n };\n\n // Non-completion actions still proxy through the client (rare, need response)\n job.modifyJobTimeout = ({ newTimeoutMs }: { newTimeoutMs: number }) =>\n client.updateJob({ changeset: { timeout: newTimeoutMs }, jobKey: jobData.jobKey });\n\n job.modifyRetries = ({ retries }: { retries: number }) =>\n client.updateJob({ changeset: { retries }, jobKey: jobData.jobKey });\n\n return job;\n}\n\n// Signal ready\nparentPort.postMessage({ type: 'ready' });\n","/**\n * Client proxy for worker_threads: allows threaded job handlers to call\n * CamundaClient methods transparently via MessagePort.\n *\n * Main thread side: installClientCallHandler(port, client)\n * Worker thread side: createClientProxy(port) → CamundaClient-shaped proxy\n */\n\nimport type { MessagePort } from 'node:worker_threads';\nimport type { CamundaClient } from '../gen/CamundaClient';\n\n// Wire protocol\nexport interface ClientCallMessage {\n type: 'client-call';\n callId: string;\n method: string;\n args: unknown[];\n}\n\nexport interface ClientCallResult {\n type: 'client-call-result';\n callId: string;\n result?: unknown;\n error?: string;\n}\n\n/** Fallback UUID generator for runtimes where globalThis.crypto.randomUUID is unavailable. */\nlet _counter = 0;\nfunction fallbackUUID(): string {\n return `${Date.now().toString(36)}-${(++_counter).toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Create a Proxy that looks like CamundaClient but forwards every method call\n * over a MessagePort to the main thread. Runs inside a worker thread.\n */\nexport function createClientProxy(port: MessagePort): CamundaClient {\n return new Proxy({} as CamundaClient, {\n get(_, method: string) {\n // Ignore symbol properties and common non-method accesses\n if (typeof method === 'symbol') return undefined;\n if (method === 'then') return undefined; // Prevent Proxy from being treated as thenable\n if (method === 'toJSON') return undefined;\n\n return (...args: unknown[]) => {\n const callId = globalThis.crypto?.randomUUID\n ? globalThis.crypto.randomUUID()\n : fallbackUUID();\n const msg: ClientCallMessage = { type: 'client-call', callId, method, args };\n port.postMessage(msg);\n return new Promise<unknown>((resolve, reject) => {\n const handler = (reply: ClientCallResult) => {\n if (reply.type !== 'client-call-result' || reply.callId !== callId) return;\n port.off('message', handler);\n if (reply.error !== undefined) {\n reject(new Error(reply.error));\n } else {\n resolve(reply.result);\n }\n };\n port.on('message', handler);\n });\n };\n },\n });\n}\n\n/**\n * Install a message handler on a MessagePort (main thread side) that\n * receives client-call messages from a worker thread and executes them\n * on the real CamundaClient instance.\n */\nexport function installClientCallHandler(port: MessagePort, client: CamundaClient): void {\n port.on('message', async (msg: ClientCallMessage) => {\n if (msg.type !== 'client-call') return;\n try {\n const fn = (client as any)[msg.method];\n if (typeof fn !== 'function') {\n throw new Error(`CamundaClient has no method '${msg.method}'`);\n }\n const result = await fn.apply(client, msg.args);\n const reply: ClientCallResult = { type: 'client-call-result', callId: msg.callId, result };\n port.postMessage(reply);\n } catch (err: any) {\n const reply: ClientCallResult = {\n type: 'client-call-result',\n callId: msg.callId,\n error: err?.message || String(err),\n };\n port.postMessage(reply);\n }\n });\n}\n"],"mappings":"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","names":["result"]}
@@ -0,0 +1,144 @@
1
+ // src/runtime/threadWorkerEntry.ts
2
+ import { parentPort } from "worker_threads";
3
+
4
+ // src/runtime/clientProxy.ts
5
+ var _counter = 0;
6
+ function fallbackUUID() {
7
+ return `${Date.now().toString(36)}-${(++_counter).toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
8
+ }
9
+ function createClientProxy(port) {
10
+ return new Proxy({}, {
11
+ get(_, method) {
12
+ if (typeof method === "symbol") return void 0;
13
+ if (method === "then") return void 0;
14
+ if (method === "toJSON") return void 0;
15
+ return (...args) => {
16
+ const callId = globalThis.crypto?.randomUUID ? globalThis.crypto.randomUUID() : fallbackUUID();
17
+ const msg = { type: "client-call", callId, method, args };
18
+ port.postMessage(msg);
19
+ return new Promise((resolve, reject) => {
20
+ const handler = (reply) => {
21
+ if (reply.type !== "client-call-result" || reply.callId !== callId) return;
22
+ port.off("message", handler);
23
+ if (reply.error !== void 0) {
24
+ reject(new Error(reply.error));
25
+ } else {
26
+ resolve(reply.result);
27
+ }
28
+ };
29
+ port.on("message", handler);
30
+ });
31
+ };
32
+ }
33
+ });
34
+ }
35
+
36
+ // src/runtime/threadWorkerEntry.ts
37
+ var JobActionReceipt = "JOB_ACTION_RECEIPT";
38
+ if (!parentPort) {
39
+ throw new Error("threadWorkerEntry must run inside a worker_threads Worker");
40
+ }
41
+ var handlerCache = /* @__PURE__ */ new Map();
42
+ async function loadHandler(handlerModule) {
43
+ const cached = handlerCache.get(handlerModule);
44
+ if (cached) return cached;
45
+ const isPath = handlerModule.startsWith(".") || handlerModule.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(handlerModule);
46
+ const modulePath = isPath ? new URL(handlerModule, `file://${process.cwd()}/`).href : handlerModule;
47
+ const mod = await import(modulePath);
48
+ const handler = mod.default ?? mod.handler;
49
+ if (typeof handler !== "function") {
50
+ throw new Error(
51
+ `Threaded handler module '${handlerModule}' must export a default function or named 'handler' export`
52
+ );
53
+ }
54
+ handlerCache.set(handlerModule, handler);
55
+ return handler;
56
+ }
57
+ parentPort.on("message", async (msg) => {
58
+ if (msg.type !== "job") return;
59
+ const { taskId, jobData, handlerModule, clientPort } = msg;
60
+ try {
61
+ const handlerFn = await loadHandler(handlerModule);
62
+ const clientProxy = createClientProxy(clientPort);
63
+ const job = createJobProxy(jobData, clientProxy);
64
+ await handlerFn(job, clientProxy);
65
+ if (!job.acknowledged) {
66
+ const result2 = {
67
+ type: "job-result",
68
+ taskId,
69
+ ok: false,
70
+ error: `Handler for '${handlerModule}' returned without acknowledging the job. Call job.complete(), job.fail(), job.error(), or job.ignore().`
71
+ };
72
+ parentPort.postMessage(result2);
73
+ return;
74
+ }
75
+ const result = {
76
+ type: "job-result",
77
+ taskId,
78
+ ok: true,
79
+ completionAction: job._completionAction || void 0
80
+ };
81
+ parentPort.postMessage(result);
82
+ } catch (err) {
83
+ const result = {
84
+ type: "job-result",
85
+ taskId,
86
+ ok: false,
87
+ error: err?.message || String(err)
88
+ };
89
+ parentPort.postMessage(result);
90
+ } finally {
91
+ if (clientPort && typeof clientPort.close === "function") {
92
+ clientPort.close();
93
+ }
94
+ }
95
+ });
96
+ function createJobProxy(jobData, client) {
97
+ const acknowledged = { value: false };
98
+ const ack = () => {
99
+ acknowledged.value = true;
100
+ job.acknowledged = true;
101
+ };
102
+ const job = { ...jobData };
103
+ job.complete = async (variables = {}, result) => {
104
+ ack();
105
+ job._completionAction = {
106
+ method: "completeJob",
107
+ args: [{ variables, jobKey: jobData.jobKey, ...result !== void 0 && { result } }]
108
+ };
109
+ return JobActionReceipt;
110
+ };
111
+ job.fail = async (reason) => {
112
+ ack();
113
+ job._completionAction = {
114
+ method: "failJob",
115
+ args: [{ ...reason, jobKey: jobData.jobKey }]
116
+ };
117
+ return JobActionReceipt;
118
+ };
119
+ job.error = async (error) => {
120
+ ack();
121
+ job._completionAction = {
122
+ method: "throwJobError",
123
+ args: [{ ...error, jobKey: jobData.jobKey }]
124
+ };
125
+ return JobActionReceipt;
126
+ };
127
+ job.cancelWorkflow = async () => {
128
+ ack();
129
+ job._completionAction = {
130
+ method: "cancelProcessInstance",
131
+ args: [{ processInstanceKey: jobData.processInstanceKey }]
132
+ };
133
+ return JobActionReceipt;
134
+ };
135
+ job.ignore = async () => {
136
+ ack();
137
+ return JobActionReceipt;
138
+ };
139
+ job.modifyJobTimeout = ({ newTimeoutMs }) => client.updateJob({ changeset: { timeout: newTimeoutMs }, jobKey: jobData.jobKey });
140
+ job.modifyRetries = ({ retries }) => client.updateJob({ changeset: { retries }, jobKey: jobData.jobKey });
141
+ return job;
142
+ }
143
+ parentPort.postMessage({ type: "ready" });
144
+ //# sourceMappingURL=threadWorkerEntry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/threadWorkerEntry.ts","../src/runtime/clientProxy.ts"],"sourcesContent":["/**\n * Worker thread entry point for the shared ThreadPool.\n *\n * Each thread in the pool runs this script. It:\n * 1. Waits for job messages on parentPort\n * 2. Dynamically imports and caches the handler module per handlerModule path\n * 3. Creates a client proxy + job proxy per job\n * 4. Calls the handler, sends back the result\n *\n * Threads are generic — the handler module is specified per-job, not per-thread.\n * Handlers are cached by module path so each import happens only once per thread.\n */\nimport { parentPort } from 'node:worker_threads';\nimport type { JobResult as ApiJobResult } from '../gen/types.gen';\nimport { createClientProxy } from './clientProxy.ts';\n\n// Inline the JobActionReceipt constant to avoid importing the full SDK dependency chain\n// (jobWorker.ts → ../gen/CamundaClient → entire SDK) in the worker thread.\nconst JobActionReceipt = 'JOB_ACTION_RECEIPT' as const;\n\nif (!parentPort) {\n throw new Error('threadWorkerEntry must run inside a worker_threads Worker');\n}\n\ninterface JobMessage {\n type: 'job';\n /** Unique ID for this job dispatch (correlates response) */\n taskId: string;\n /** Serialized job data (plain object, no methods) */\n jobData: Record<string, unknown>;\n /** Handler module path — resolved per job, cached per thread */\n handlerModule: string;\n}\n\ninterface JobResult {\n type: 'job-result';\n taskId: string;\n ok: boolean;\n error?: string;\n /** When the handler acknowledged the job via complete/fail/error,\n * the action is captured here for the main thread to execute. */\n completionAction?: {\n method: string;\n args: unknown[];\n };\n}\n\n/** Cache of loaded handlers keyed by module path. Each thread loads a handler once per unique path. */\nconst handlerCache = new Map<string, (job: any, client: any) => Promise<any>>();\n\nasync function loadHandler(\n handlerModule: string\n): Promise<(job: any, client: any) => Promise<any>> {\n const cached = handlerCache.get(handlerModule);\n if (cached) return cached;\n\n // Convert filesystem paths to file:// URLs for dynamic import().\n // Handles relative (./ ../) paths, Unix absolute (/), and Windows absolute (C:\\).\n const isPath =\n handlerModule.startsWith('.') ||\n handlerModule.startsWith('/') ||\n /^[a-zA-Z]:[\\\\/]/.test(handlerModule);\n const modulePath = isPath\n ? new URL(handlerModule, `file://${process.cwd()}/`).href\n : handlerModule;\n const mod = await import(modulePath);\n const handler = mod.default ?? mod.handler;\n if (typeof handler !== 'function') {\n throw new Error(\n `Threaded handler module '${handlerModule}' must export a default function or named 'handler' export`\n );\n }\n handlerCache.set(handlerModule, handler);\n return handler;\n}\n\nparentPort.on('message', async (msg: JobMessage & { clientPort?: any }) => {\n if (msg.type !== 'job') return;\n\n const { taskId, jobData, handlerModule, clientPort } = msg as JobMessage & {\n clientPort: import('node:worker_threads').MessagePort;\n };\n\n try {\n const handlerFn = await loadHandler(handlerModule);\n\n // Create a client proxy for this job's MessagePort\n const clientProxy = createClientProxy(clientPort);\n\n // Build a job-like object with proxied action methods\n const job = createJobProxy(jobData, clientProxy);\n\n await handlerFn(job, clientProxy);\n\n // If the handler never acknowledged the job (no complete/fail/error/ignore),\n // treat it as an error so the broker can retry rather than silently dropping it.\n if (!job.acknowledged) {\n const result: JobResult = {\n type: 'job-result',\n taskId,\n ok: false,\n error:\n `Handler for '${handlerModule}' returned without acknowledging the job. ` +\n 'Call job.complete(), job.fail(), job.error(), or job.ignore().',\n };\n parentPort!.postMessage(result);\n return;\n }\n\n const result: JobResult = {\n type: 'job-result',\n taskId,\n ok: true,\n completionAction: job._completionAction || undefined,\n };\n parentPort!.postMessage(result);\n } catch (err: any) {\n const result: JobResult = {\n type: 'job-result',\n taskId,\n ok: false,\n error: err?.message || String(err),\n };\n parentPort!.postMessage(result);\n } finally {\n // Close this job's client port\n if (clientPort && typeof clientPort.close === 'function') {\n clientPort.close();\n }\n }\n});\n\n/**\n * Build a job object with action methods that proxy through the client.\n * The job data is plain serialized data from the main thread.\n * Action methods (complete, fail, error, etc.) call back to the main thread client.\n */\nfunction createJobProxy(jobData: Record<string, unknown>, client: any): any {\n const acknowledged = { value: false };\n const ack = () => {\n acknowledged.value = true;\n job.acknowledged = true;\n };\n\n const job: any = { ...jobData };\n\n /**\n * Completion actions (complete/fail/error/cancelWorkflow) are stored as intent\n * rather than proxied through the MessagePort. The thread returns immediately,\n * and the main thread executes the API call asynchronously. This keeps threads\n * free for CPU work instead of blocking on I/O round-trips.\n */\n\n job.complete = async (variables: Record<string, unknown> = {}, result?: ApiJobResult) => {\n ack();\n job._completionAction = {\n method: 'completeJob',\n args: [{ variables, jobKey: jobData.jobKey, ...(result !== undefined && { result }) }],\n };\n return JobActionReceipt;\n };\n\n job.fail = async (reason: any) => {\n ack();\n job._completionAction = {\n method: 'failJob',\n args: [{ ...reason, jobKey: jobData.jobKey }],\n };\n return JobActionReceipt;\n };\n\n job.error = async (error: any) => {\n ack();\n job._completionAction = {\n method: 'throwJobError',\n args: [{ ...error, jobKey: jobData.jobKey }],\n };\n return JobActionReceipt;\n };\n\n job.cancelWorkflow = async () => {\n ack();\n job._completionAction = {\n method: 'cancelProcessInstance',\n args: [{ processInstanceKey: jobData.processInstanceKey }],\n };\n return JobActionReceipt;\n };\n\n job.ignore = async () => {\n ack();\n return JobActionReceipt;\n };\n\n // Non-completion actions still proxy through the client (rare, need response)\n job.modifyJobTimeout = ({ newTimeoutMs }: { newTimeoutMs: number }) =>\n client.updateJob({ changeset: { timeout: newTimeoutMs }, jobKey: jobData.jobKey });\n\n job.modifyRetries = ({ retries }: { retries: number }) =>\n client.updateJob({ changeset: { retries }, jobKey: jobData.jobKey });\n\n return job;\n}\n\n// Signal ready\nparentPort.postMessage({ type: 'ready' });\n","/**\n * Client proxy for worker_threads: allows threaded job handlers to call\n * CamundaClient methods transparently via MessagePort.\n *\n * Main thread side: installClientCallHandler(port, client)\n * Worker thread side: createClientProxy(port) → CamundaClient-shaped proxy\n */\n\nimport type { MessagePort } from 'node:worker_threads';\nimport type { CamundaClient } from '../gen/CamundaClient';\n\n// Wire protocol\nexport interface ClientCallMessage {\n type: 'client-call';\n callId: string;\n method: string;\n args: unknown[];\n}\n\nexport interface ClientCallResult {\n type: 'client-call-result';\n callId: string;\n result?: unknown;\n error?: string;\n}\n\n/** Fallback UUID generator for runtimes where globalThis.crypto.randomUUID is unavailable. */\nlet _counter = 0;\nfunction fallbackUUID(): string {\n return `${Date.now().toString(36)}-${(++_counter).toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Create a Proxy that looks like CamundaClient but forwards every method call\n * over a MessagePort to the main thread. Runs inside a worker thread.\n */\nexport function createClientProxy(port: MessagePort): CamundaClient {\n return new Proxy({} as CamundaClient, {\n get(_, method: string) {\n // Ignore symbol properties and common non-method accesses\n if (typeof method === 'symbol') return undefined;\n if (method === 'then') return undefined; // Prevent Proxy from being treated as thenable\n if (method === 'toJSON') return undefined;\n\n return (...args: unknown[]) => {\n const callId = globalThis.crypto?.randomUUID\n ? globalThis.crypto.randomUUID()\n : fallbackUUID();\n const msg: ClientCallMessage = { type: 'client-call', callId, method, args };\n port.postMessage(msg);\n return new Promise<unknown>((resolve, reject) => {\n const handler = (reply: ClientCallResult) => {\n if (reply.type !== 'client-call-result' || reply.callId !== callId) return;\n port.off('message', handler);\n if (reply.error !== undefined) {\n reject(new Error(reply.error));\n } else {\n resolve(reply.result);\n }\n };\n port.on('message', handler);\n });\n };\n },\n });\n}\n\n/**\n * Install a message handler on a MessagePort (main thread side) that\n * receives client-call messages from a worker thread and executes them\n * on the real CamundaClient instance.\n */\nexport function installClientCallHandler(port: MessagePort, client: CamundaClient): void {\n port.on('message', async (msg: ClientCallMessage) => {\n if (msg.type !== 'client-call') return;\n try {\n const fn = (client as any)[msg.method];\n if (typeof fn !== 'function') {\n throw new Error(`CamundaClient has no method '${msg.method}'`);\n }\n const result = await fn.apply(client, msg.args);\n const reply: ClientCallResult = { type: 'client-call-result', callId: msg.callId, result };\n port.postMessage(reply);\n } catch (err: any) {\n const reply: ClientCallResult = {\n type: 'client-call-result',\n callId: msg.callId,\n error: err?.message || String(err),\n };\n port.postMessage(reply);\n }\n });\n}\n"],"mappings":";AAYA,SAAS,kBAAkB;;;ACe3B,IAAI,WAAW;AACf,SAAS,eAAuB;AAC9B,SAAO,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,UAAU,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAC3G;AAMO,SAAS,kBAAkB,MAAkC;AAClE,SAAO,IAAI,MAAM,CAAC,GAAoB;AAAA,IACpC,IAAI,GAAG,QAAgB;AAErB,UAAI,OAAO,WAAW,SAAU,QAAO;AACvC,UAAI,WAAW,OAAQ,QAAO;AAC9B,UAAI,WAAW,SAAU,QAAO;AAEhC,aAAO,IAAI,SAAoB;AAC7B,cAAM,SAAS,WAAW,QAAQ,aAC9B,WAAW,OAAO,WAAW,IAC7B,aAAa;AACjB,cAAM,MAAyB,EAAE,MAAM,eAAe,QAAQ,QAAQ,KAAK;AAC3E,aAAK,YAAY,GAAG;AACpB,eAAO,IAAI,QAAiB,CAAC,SAAS,WAAW;AAC/C,gBAAM,UAAU,CAAC,UAA4B;AAC3C,gBAAI,MAAM,SAAS,wBAAwB,MAAM,WAAW,OAAQ;AACpE,iBAAK,IAAI,WAAW,OAAO;AAC3B,gBAAI,MAAM,UAAU,QAAW;AAC7B,qBAAO,IAAI,MAAM,MAAM,KAAK,CAAC;AAAA,YAC/B,OAAO;AACL,sBAAQ,MAAM,MAAM;AAAA,YACtB;AAAA,UACF;AACA,eAAK,GAAG,WAAW,OAAO;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AD/CA,IAAM,mBAAmB;AAEzB,IAAI,CAAC,YAAY;AACf,QAAM,IAAI,MAAM,2DAA2D;AAC7E;AA0BA,IAAM,eAAe,oBAAI,IAAqD;AAE9E,eAAe,YACb,eACkD;AAClD,QAAM,SAAS,aAAa,IAAI,aAAa;AAC7C,MAAI,OAAQ,QAAO;AAInB,QAAM,SACJ,cAAc,WAAW,GAAG,KAC5B,cAAc,WAAW,GAAG,KAC5B,kBAAkB,KAAK,aAAa;AACtC,QAAM,aAAa,SACf,IAAI,IAAI,eAAe,UAAU,QAAQ,IAAI,CAAC,GAAG,EAAE,OACnD;AACJ,QAAM,MAAM,MAAM,OAAO;AACzB,QAAM,UAAU,IAAI,WAAW,IAAI;AACnC,MAAI,OAAO,YAAY,YAAY;AACjC,UAAM,IAAI;AAAA,MACR,4BAA4B,aAAa;AAAA,IAC3C;AAAA,EACF;AACA,eAAa,IAAI,eAAe,OAAO;AACvC,SAAO;AACT;AAEA,WAAW,GAAG,WAAW,OAAO,QAA2C;AACzE,MAAI,IAAI,SAAS,MAAO;AAExB,QAAM,EAAE,QAAQ,SAAS,eAAe,WAAW,IAAI;AAIvD,MAAI;AACF,UAAM,YAAY,MAAM,YAAY,aAAa;AAGjD,UAAM,cAAc,kBAAkB,UAAU;AAGhD,UAAM,MAAM,eAAe,SAAS,WAAW;AAE/C,UAAM,UAAU,KAAK,WAAW;AAIhC,QAAI,CAAC,IAAI,cAAc;AACrB,YAAMA,UAAoB;AAAA,QACxB,MAAM;AAAA,QACN;AAAA,QACA,IAAI;AAAA,QACJ,OACE,gBAAgB,aAAa;AAAA,MAEjC;AACA,iBAAY,YAAYA,OAAM;AAC9B;AAAA,IACF;AAEA,UAAM,SAAoB;AAAA,MACxB,MAAM;AAAA,MACN;AAAA,MACA,IAAI;AAAA,MACJ,kBAAkB,IAAI,qBAAqB;AAAA,IAC7C;AACA,eAAY,YAAY,MAAM;AAAA,EAChC,SAAS,KAAU;AACjB,UAAM,SAAoB;AAAA,MACxB,MAAM;AAAA,MACN;AAAA,MACA,IAAI;AAAA,MACJ,OAAO,KAAK,WAAW,OAAO,GAAG;AAAA,IACnC;AACA,eAAY,YAAY,MAAM;AAAA,EAChC,UAAE;AAEA,QAAI,cAAc,OAAO,WAAW,UAAU,YAAY;AACxD,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF;AACF,CAAC;AAOD,SAAS,eAAe,SAAkC,QAAkB;AAC1E,QAAM,eAAe,EAAE,OAAO,MAAM;AACpC,QAAM,MAAM,MAAM;AAChB,iBAAa,QAAQ;AACrB,QAAI,eAAe;AAAA,EACrB;AAEA,QAAM,MAAW,EAAE,GAAG,QAAQ;AAS9B,MAAI,WAAW,OAAO,YAAqC,CAAC,GAAG,WAA0B;AACvF,QAAI;AACJ,QAAI,oBAAoB;AAAA,MACtB,QAAQ;AAAA,MACR,MAAM,CAAC,EAAE,WAAW,QAAQ,QAAQ,QAAQ,GAAI,WAAW,UAAa,EAAE,OAAO,EAAG,CAAC;AAAA,IACvF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,OAAO,WAAgB;AAChC,QAAI;AACJ,QAAI,oBAAoB;AAAA,MACtB,QAAQ;AAAA,MACR,MAAM,CAAC,EAAE,GAAG,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,OAAO,UAAe;AAChC,QAAI;AACJ,QAAI,oBAAoB;AAAA,MACtB,QAAQ;AAAA,MACR,MAAM,CAAC,EAAE,GAAG,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,YAAY;AAC/B,QAAI;AACJ,QAAI,oBAAoB;AAAA,MACtB,QAAQ;AAAA,MACR,MAAM,CAAC,EAAE,oBAAoB,QAAQ,mBAAmB,CAAC;AAAA,IAC3D;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,YAAY;AACvB,QAAI;AACJ,WAAO;AAAA,EACT;AAGA,MAAI,mBAAmB,CAAC,EAAE,aAAa,MACrC,OAAO,UAAU,EAAE,WAAW,EAAE,SAAS,aAAa,GAAG,QAAQ,QAAQ,OAAO,CAAC;AAEnF,MAAI,gBAAgB,CAAC,EAAE,QAAQ,MAC7B,OAAO,UAAU,EAAE,WAAW,EAAE,QAAQ,GAAG,QAAQ,QAAQ,OAAO,CAAC;AAErE,SAAO;AACT;AAGA,WAAW,YAAY,EAAE,MAAM,QAAQ,CAAC;","names":["result"]}