|
| 1 | +/** |
| 2 | + * Capabilities table for workflow runs based on their `@workflow/core` version. |
| 3 | + * |
| 4 | + * When resuming a hook or webhook, the payload must be encoded in a format |
| 5 | + * that the *target* workflow run's deployment can decode. This module provides |
| 6 | + * a way to look up what serialization formats a given `@workflow/core` version |
| 7 | + * supports, so that newer deployments can avoid encoding payloads in formats |
| 8 | + * that older deployments don't understand (e.g., the `encr` encryption format). |
| 9 | + * |
| 10 | + * ## Adding a new format |
| 11 | + * |
| 12 | + * When a new serialization format is introduced: |
| 13 | + * 1. Add the format constant to `SerializationFormat` in `serialization.ts` |
| 14 | + * 2. Add an entry to `FORMAT_VERSION_TABLE` below with the minimum |
| 15 | + * `@workflow/core` version that supports it |
| 16 | + * 3. The `getRunCapabilities()` function will automatically include it |
| 17 | + */ |
| 18 | + |
| 19 | +import semver from 'semver'; |
| 20 | +import { |
| 21 | + SerializationFormat, |
| 22 | + type SerializationFormatType, |
| 23 | +} from './serialization.js'; |
| 24 | + |
| 25 | +/** |
| 26 | + * Capabilities of a workflow run based on its `@workflow/core` version. |
| 27 | + */ |
| 28 | +export interface RunCapabilities { |
| 29 | + /** |
| 30 | + * The set of serialization format prefixes that the target run can decode. |
| 31 | + * Use `supportedFormats.has(SerializationFormat.ENCRYPTED)` to check |
| 32 | + * if encryption is supported, etc. |
| 33 | + */ |
| 34 | + supportedFormats: ReadonlySet<SerializationFormatType>; |
| 35 | +} |
| 36 | + |
| 37 | +/** |
| 38 | + * Maps serialization format identifiers to the minimum `@workflow/core` |
| 39 | + * version that introduced support for them. Formats not listed here are |
| 40 | + * assumed to be supported by all specVersion 2 runs (e.g., `devl`). |
| 41 | + */ |
| 42 | +const FORMAT_VERSION_TABLE: ReadonlyArray<{ |
| 43 | + format: SerializationFormatType; |
| 44 | + minVersion: string; |
| 45 | +}> = [ |
| 46 | + { format: SerializationFormat.ENCRYPTED, minVersion: '4.2.0-beta.64' }, |
| 47 | + // Future entries: |
| 48 | + // { format: SerializationFormat.CBOR, minVersion: '5.x.y' }, |
| 49 | + // { format: SerializationFormat.ENCRYPTED_V2, minVersion: '5.x.y' }, |
| 50 | +]; |
| 51 | + |
| 52 | +/** |
| 53 | + * The set of formats supported by all specVersion 2 runs, regardless of |
| 54 | + * `@workflow/core` version. These are the baseline formats that were present |
| 55 | + * from the start of the specVersion 2 protocol. |
| 56 | + */ |
| 57 | +const BASELINE_FORMATS: ReadonlySet<SerializationFormatType> = new Set([ |
| 58 | + SerializationFormat.DEVALUE_V1, |
| 59 | +]); |
| 60 | + |
| 61 | +/** |
| 62 | + * Look up what serialization capabilities a workflow run supports based on |
| 63 | + * its `@workflow/core` version string (from `executionContext.workflowCoreVersion`). |
| 64 | + * |
| 65 | + * When the version is `undefined` (e.g. very old runs that predate the field), |
| 66 | + * we assume the most conservative capabilities (baseline formats only). |
| 67 | + */ |
| 68 | +export function getRunCapabilities( |
| 69 | + workflowCoreVersion: string | undefined |
| 70 | +): RunCapabilities { |
| 71 | + if (!workflowCoreVersion) { |
| 72 | + return { supportedFormats: BASELINE_FORMATS }; |
| 73 | + } |
| 74 | + |
| 75 | + const formats = new Set<SerializationFormatType>(BASELINE_FORMATS); |
| 76 | + |
| 77 | + for (const { format, minVersion } of FORMAT_VERSION_TABLE) { |
| 78 | + if (semver.gte(workflowCoreVersion, minVersion)) { |
| 79 | + formats.add(format); |
| 80 | + } |
| 81 | + } |
| 82 | + |
| 83 | + return { supportedFormats: formats }; |
| 84 | +} |
0 commit comments