JavaScript / TypeScript
@quantumbpm/sdk — TypeScript-first, async, runs on Node.js 18+.
Installation
npm install @quantumbpm/sdk
Quick start
import { QuantumBPM, Vars, ZitadelTokenProvider } from '@quantumbpm/sdk';
const provider = new ZitadelTokenProvider(
'./service-account.json',
'https://auth.quantumbpm.com',
'your-zitadel-project-id',
);
const client = new QuantumBPM({
baseUrl: 'https://api.quantumbpm.com',
projectId: 'YOUR_PROJECT_ID',
tokenProvider: provider,
});
const result = await client.dmn.evaluate(
'loan-eligibility',
new Vars().set('requestedAmt', 1000).set('creditScore', 720),
);
console.log(result);
BPMN
const draft = await client.bpmn.createResource('loan-process', bpmnXml);
await client.bpmn.deployResource(draft.id);
const deployed = await client.bpmn.getResource(draft.id);
const processDef = deployed.processes![0];
const workflowId = await client.bpmn.startInstance(
processDef.id,
new Vars().set('applicantID', 'u-123'),
);
Correlation keys (businessId)
Stamp a caller-supplied correlation key (order number, ticket ID, etc.) on a new instance by passing businessId in the options object. The key is inherited by every child instance, external job, user task, and DMN execution emitted by the process — workers read it as job.businessId.
await client.bpmn.startInstance(processDef.id, vars, { businessId: 'ORDER-42' });
// Filter listings by the same key.
const instances = await client.bpmn.listInstances({ businessId: 'ORDER-42' });
const tasks = await client.bpmn.listUserTasks({ businessId: 'ORDER-42' });
// DMN evaluations stamp it on the resulting execution row.
const result = await client.dmn.evaluate('loan-eligibility', vars, {
businessId: 'ORDER-42',
});
External job workers
The runtime uses native AbortController for cancellation. Handlers run with per-task-type concurrency limits.
import { Vars, BpmnError } from '@quantumbpm/sdk';
const ac = new AbortController();
const worker = client.newWorker({ clientId: 'billing-svc' });
worker.handle('send-email', async (job) => {
const recipient = job.vars.get<string>('recipient');
await emailer.send(recipient);
return new Vars().set('messageID', 'msg-123'); // → Complete
}, { maxJobs: 10, lockDuration: '1m' });
await worker.run(ac.signal); // resolves when ac.abort() fires
Throw a BpmnError to fail with a code boundary error events can catch:
throw new BpmnError('INSUFFICIENT_FUNDS', new Vars().set('balance', 12));
Any other thrown value (or rejected promise) is reported with the code WORKER_ERROR and the message attached as the error variable (truncated to 2048 bytes by default, configurable via the maxErrorMessageBytes worker option). A boundary error event with errorRef="WORKER_ERROR" will catch it once the retry budget is exhausted — see Failure handling.
Use the generic on handle<TVars> for typed dispatch — the SDK exposes job.typed cast to TVars:
interface EmailJob { recipient: string; subject: string }
worker.handle<EmailJob>('send-email', async (job) => {
await emailer.send(job.typed.recipient, job.typed.subject);
return new Vars();
});
Full reference
See the SDK README for the complete API surface and TypeScript type definitions.