bpmn-engine

Upgrade

v25 → v26

Version 26 runs on bpmn-elements@18, which refactors parallel gateway convergence and removes sequence flow discards altogether. Most diagrams run unchanged, but the behavioural changes are in the elements, not the engine, so read the bpmn-elements upgrade guide first. What follows is what changes from the engine’s point of view.

Peer dependencies

bpmn-elements, bpmn-moddle, moddle-context-serializer, smqp, and debug are peer dependencies. Install and pin them yourself, see peer dependencies for the supported ranges. smqp@15 or later is required.

bpmn-moddle 9 and 10 are both supported — see bpmn-moddle 9 vs 10 for the import change.

Sequence flows are no longer discarded

An untaken branch is left untouched instead of propagating a chain of discards. For an engine host this means:

The details, including converging parallel gateways and shake output, are in the bpmn-elements upgrade guide.

Resuming state saved by v25

State saved by v25 can be recovered and resumed by v26. bpmn-elements@18 stamps definition state with a stateVersion and migrates older state on resume: start events are reconciled to the mutually exclusive rule and stale discard tokens left on process queues are acked, so they no longer strand process completion. No action is required beyond resuming; saving again stamps the current version. See resuming state saved by v17.

Types

The engine ships hand-maintained TypeScript declarations. Recompile a TypeScript host against them:

< v14

Since v14 of the engine output is no longer shared between definition and processes. To upgrade a saved state before version 14 you can run the following script that adds process environment to state.

export function upgradeStateToVersion14(state) {
  const stateVersion = getSemverVersion(state.engineVersion);
  if (!stateVersion || stateVersion.major >= 14) return state;

  return polyfillProcessEnvironment(state);
}

function polyfillProcessEnvironment(state) {
  if (!state.definitions?.length) return state;

  const polyfilledState = JSON.parse(JSON.stringify(state));
  for (const definition of polyfilledState.definitions) {
    if (!definition.environment) continue;
    if (!definition.execution) continue;
    if (!definition.execution.processes) continue;

    for (const bp of definition.execution.processes) {
      addProcessEnvironment(definition.environment, bp);
    }
  }

  return polyfilledState;
}

function addProcessEnvironment(environment, processState) {
  processState.environment = JSON.parse(JSON.stringify(environment));
}

function getSemverVersion(version) {
  if (typeof version !== 'string') return;
  const match = version.match(/^(\d+)\.(\d+)\.(\d+)/);
  if (!match) return;
  const [, major, minor, patch] = match;
  return {
    major: Number(major),
    minor: Number(minor),
    patch: Number(patch),
  };
}