@voyant-travel/workflows 0.107.10

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.
Files changed (120) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +52 -0
  3. package/README.md +79 -0
  4. package/dist/auth/index.d.ts +125 -0
  5. package/dist/auth/index.d.ts.map +1 -0
  6. package/dist/auth/index.js +352 -0
  7. package/dist/bindings.d.ts +119 -0
  8. package/dist/bindings.d.ts.map +1 -0
  9. package/dist/bindings.js +19 -0
  10. package/dist/client.d.ts +135 -0
  11. package/dist/client.d.ts.map +1 -0
  12. package/dist/client.js +305 -0
  13. package/dist/conditions.d.ts +29 -0
  14. package/dist/conditions.d.ts.map +1 -0
  15. package/dist/conditions.js +5 -0
  16. package/dist/config.d.ts +93 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +7 -0
  19. package/dist/driver.d.ts +237 -0
  20. package/dist/driver.d.ts.map +1 -0
  21. package/dist/driver.js +53 -0
  22. package/dist/errors.d.ts +58 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +76 -0
  25. package/dist/events/compile.d.ts +34 -0
  26. package/dist/events/compile.d.ts.map +1 -0
  27. package/dist/events/compile.js +204 -0
  28. package/dist/events/index.d.ts +8 -0
  29. package/dist/events/index.d.ts.map +1 -0
  30. package/dist/events/index.js +11 -0
  31. package/dist/events/input-mapper.d.ts +24 -0
  32. package/dist/events/input-mapper.d.ts.map +1 -0
  33. package/dist/events/input-mapper.js +169 -0
  34. package/dist/events/manifest-builder.d.ts +42 -0
  35. package/dist/events/manifest-builder.d.ts.map +1 -0
  36. package/dist/events/manifest-builder.js +313 -0
  37. package/dist/events/payload-hash.d.ts +46 -0
  38. package/dist/events/payload-hash.d.ts.map +1 -0
  39. package/dist/events/payload-hash.js +98 -0
  40. package/dist/events/predicate.d.ts +77 -0
  41. package/dist/events/predicate.d.ts.map +1 -0
  42. package/dist/events/predicate.js +347 -0
  43. package/dist/events/registry.d.ts +37 -0
  44. package/dist/events/registry.d.ts.map +1 -0
  45. package/dist/events/registry.js +47 -0
  46. package/dist/handler/index.d.ts +114 -0
  47. package/dist/handler/index.d.ts.map +1 -0
  48. package/dist/handler/index.js +267 -0
  49. package/dist/handler/resume.d.ts +41 -0
  50. package/dist/handler/resume.d.ts.map +1 -0
  51. package/dist/handler/resume.js +44 -0
  52. package/dist/http-ingest.d.ts +54 -0
  53. package/dist/http-ingest.d.ts.map +1 -0
  54. package/dist/http-ingest.js +214 -0
  55. package/dist/index.d.ts +6 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +10 -0
  58. package/dist/protocol/index.d.ts +345 -0
  59. package/dist/protocol/index.d.ts.map +1 -0
  60. package/dist/protocol/index.js +110 -0
  61. package/dist/rate-limit/index.d.ts +40 -0
  62. package/dist/rate-limit/index.d.ts.map +1 -0
  63. package/dist/rate-limit/index.js +139 -0
  64. package/dist/runtime/ctx.d.ts +111 -0
  65. package/dist/runtime/ctx.d.ts.map +1 -0
  66. package/dist/runtime/ctx.js +624 -0
  67. package/dist/runtime/determinism.d.ts +19 -0
  68. package/dist/runtime/determinism.d.ts.map +1 -0
  69. package/dist/runtime/determinism.js +61 -0
  70. package/dist/runtime/errors.d.ts +21 -0
  71. package/dist/runtime/errors.d.ts.map +1 -0
  72. package/dist/runtime/errors.js +45 -0
  73. package/dist/runtime/executor.d.ts +166 -0
  74. package/dist/runtime/executor.d.ts.map +1 -0
  75. package/dist/runtime/executor.js +226 -0
  76. package/dist/runtime/journal.d.ts +56 -0
  77. package/dist/runtime/journal.d.ts.map +1 -0
  78. package/dist/runtime/journal.js +28 -0
  79. package/dist/testing/index.d.ts +117 -0
  80. package/dist/testing/index.d.ts.map +1 -0
  81. package/dist/testing/index.js +599 -0
  82. package/dist/trigger.d.ts +37 -0
  83. package/dist/trigger.d.ts.map +1 -0
  84. package/dist/trigger.js +11 -0
  85. package/dist/types.d.ts +63 -0
  86. package/dist/types.d.ts.map +1 -0
  87. package/dist/types.js +3 -0
  88. package/dist/workflow.d.ts +222 -0
  89. package/dist/workflow.d.ts.map +1 -0
  90. package/dist/workflow.js +55 -0
  91. package/package.json +120 -0
  92. package/src/auth/index.ts +398 -0
  93. package/src/bindings.ts +135 -0
  94. package/src/client.ts +498 -0
  95. package/src/conditions.ts +43 -0
  96. package/src/config.ts +114 -0
  97. package/src/driver.ts +277 -0
  98. package/src/errors.ts +109 -0
  99. package/src/events/compile.ts +268 -0
  100. package/src/events/index.ts +42 -0
  101. package/src/events/input-mapper.ts +201 -0
  102. package/src/events/manifest-builder.ts +372 -0
  103. package/src/events/payload-hash.ts +110 -0
  104. package/src/events/predicate.ts +390 -0
  105. package/src/events/registry.ts +86 -0
  106. package/src/handler/index.ts +413 -0
  107. package/src/handler/resume.ts +100 -0
  108. package/src/http-ingest.ts +299 -0
  109. package/src/index.ts +18 -0
  110. package/src/protocol/index.ts +483 -0
  111. package/src/rate-limit/index.ts +181 -0
  112. package/src/runtime/ctx.ts +876 -0
  113. package/src/runtime/determinism.ts +75 -0
  114. package/src/runtime/errors.ts +58 -0
  115. package/src/runtime/executor.ts +442 -0
  116. package/src/runtime/journal.ts +80 -0
  117. package/src/testing/index.ts +796 -0
  118. package/src/trigger.ts +63 -0
  119. package/src/types.ts +80 -0
  120. package/src/workflow.ts +328 -0
package/src/trigger.ts ADDED
@@ -0,0 +1,63 @@
1
+ // Event filter declarations, plus compatibility re-exports for the
2
+ // client-safe workflows trigger surface.
3
+ // Authoritative contract in docs/sdk-surface.md §6.
4
+
5
+ import type { WorkflowHandle } from "./workflow.js"
6
+
7
+ // ---- workflows.* ----
8
+
9
+ export type {
10
+ ListRunsOptions,
11
+ MintAccessTokenOptions,
12
+ PublicAccessToken,
13
+ Run,
14
+ RunDetail,
15
+ RunSummary,
16
+ TriggerOptions,
17
+ WorkflowsClient,
18
+ } from "./client.js"
19
+ export { workflows } from "./client.js"
20
+
21
+ // ---- trigger.on ----
22
+
23
+ import { compileAndRegister } from "./events/compile.js"
24
+ import type { InputMapper } from "./events/input-mapper.js"
25
+ import type { PredicateExpr } from "./events/predicate.js"
26
+ import type { EventFilterRuntimeEntry } from "./events/registry.js"
27
+
28
+ /**
29
+ * Declarative binding from an event name to a target workflow. Authors call
30
+ * `trigger.on(eventName, declaration)` at module-load time; the framework
31
+ * collects the entries via the process-local registry (see
32
+ * `./events/registry.js`) and ships them in the manifest.
33
+ *
34
+ * `where` and `input` are structured DSLs (no callbacks) so the runtime
35
+ * can evaluate them anywhere — in-process for self-host, server-side for
36
+ * managed deployments. The previous `match` callback is no longer
37
+ * supported; registration throws if it's set.
38
+ */
39
+ export interface EventFilterDeclaration<T> {
40
+ target: WorkflowHandle<T, unknown>
41
+ /** Structured predicate; see `@voyant-travel/workflows/events` `PredicateExpr`. */
42
+ where?: PredicateExpr
43
+ /** Structured input projection; see `@voyant-travel/workflows/events` `InputMapper`. */
44
+ input?: InputMapper
45
+ }
46
+
47
+ export interface TriggerApi {
48
+ /**
49
+ * Register an event filter targeting `event`. Returns the
50
+ * {@link EventFilterRuntimeEntry} so authors can drop it directly into
51
+ * `Module.eventFilters` / `Plugin.eventFilters` — the entry structurally
52
+ * satisfies core's `EventFilterDescriptor` (matching `id` + `eventType`)
53
+ * and carries the manifest payload `createApp()` needs to register with
54
+ * the driver.
55
+ */
56
+ on<T = unknown>(event: string, filter: EventFilterDeclaration<T>): EventFilterRuntimeEntry
57
+ }
58
+
59
+ export const trigger: TriggerApi = {
60
+ on<T>(event: string, filter: EventFilterDeclaration<T>): EventFilterRuntimeEntry {
61
+ return compileAndRegister(event, filter)
62
+ },
63
+ }
package/src/types.ts ADDED
@@ -0,0 +1,80 @@
1
+ // Core type aliases used across the SDK.
2
+ // Authoritative definitions in docs/sdk-surface.md §0 and §2.
3
+
4
+ export type Duration = number | `${number}${"ms" | "s" | "m" | "h" | "d" | "w"}`
5
+
6
+ /**
7
+ * Cloudflare Container instance types — the set Voyant Cloud honors
8
+ * for `runtime: "node"` steps. Match the sizes published at
9
+ * https://developers.cloudflare.com/containers/ (as of
10
+ * compat-date 2026-04-01).
11
+ *
12
+ * | name | vCPU | memory | disk |
13
+ * | ----------- | ----- | ------- | ----- |
14
+ * | lite | 1/16 | 256 MiB | 2 GB |
15
+ * | basic | 1/4 | 1 GiB | 4 GB |
16
+ * | standard-1 | 1/2 | 4 GiB | 8 GB |
17
+ * | standard-2 | 1 | 6 GiB | 12 GB |
18
+ * | standard-3 | 2 | 8 GiB | 16 GB |
19
+ * | standard-4 | 4 | 12 GiB | 20 GB |
20
+ *
21
+ * The open `(string & {})` escape hatch accepts CF custom instance
22
+ * types (up to 4 vCPU / 12 GiB / 20 GB, min 3 GiB RAM per vCPU) —
23
+ * rendered as `"custom-<vcpu>-<ramGiB>"` by convention.
24
+ */
25
+ export type MachineType =
26
+ | "lite"
27
+ | "basic"
28
+ | "standard-1"
29
+ | "standard-2"
30
+ | "standard-3"
31
+ | "standard-4"
32
+ | (string & {})
33
+
34
+ export type EnvironmentName = "production" | "preview" | "development"
35
+
36
+ export type RunStatus =
37
+ | "pending"
38
+ | "queued"
39
+ | "running"
40
+ | "waiting"
41
+ | "completed"
42
+ | "failed"
43
+ | "cancelled"
44
+ | "cancelled_by_dev_reload"
45
+ | "cancelled_by_version_sunset"
46
+ | "compensated"
47
+ | "compensation_failed"
48
+ | "timed_out"
49
+
50
+ export type ExecutionStatus =
51
+ | "CREATED"
52
+ | "QUEUED"
53
+ | "EXECUTING"
54
+ | "EXECUTING_WITH_WAITPOINTS"
55
+ | "SUSPENDED"
56
+ | "PENDING_CANCEL"
57
+ | "FINISHED"
58
+
59
+ export type WaitpointKind = "DATETIME" | "EVENT" | "SIGNAL" | "RUN" | "MANUAL"
60
+
61
+ export interface RetryPolicy {
62
+ max?: number
63
+ backoff?: "exponential" | "linear" | "fixed"
64
+ initial?: Duration
65
+ maxDelay?: Duration
66
+ }
67
+
68
+ export interface RateLimitSpec {
69
+ key: string | ((input: unknown, ctx: { run: { id: string }; project: { id: string } }) => string)
70
+ limit: number | ((input: unknown) => number)
71
+ units?: number | ((input: unknown) => number)
72
+ window: Duration
73
+ onLimit?: "queue" | "fail"
74
+ }
75
+
76
+ export type RunTrigger =
77
+ | { kind: "api"; actor?: string; accessTokenId?: string }
78
+ | { kind: "schedule"; scheduleId: string }
79
+ | { kind: "event"; eventId: string; eventType: string; filterId: string }
80
+ | { kind: "parent"; parentRunId: string; parentStepId: string }
@@ -0,0 +1,328 @@
1
+ // Workflow declaration and the `ctx` object.
2
+ // Authoritative contract in docs/sdk-surface.md §2–§3.
3
+
4
+ import type { Condition } from "./conditions.js"
5
+ import type { ServiceResolver } from "./driver.js"
6
+ import type {
7
+ Duration,
8
+ EnvironmentName,
9
+ MachineType,
10
+ RateLimitSpec,
11
+ RetryPolicy,
12
+ RunStatus,
13
+ RunTrigger,
14
+ } from "./types.js"
15
+
16
+ // ---- Workflow ----
17
+
18
+ export interface WorkflowHandle<TInput = unknown, TOutput = unknown> {
19
+ readonly id: string
20
+ /** Phantom; used only for TypeScript inference of `workflows.trigger(...)`. */
21
+ readonly __input?: TInput
22
+ readonly __output?: TOutput
23
+ }
24
+
25
+ export interface WorkflowConfig<TInput, TOutput> {
26
+ id: string
27
+ input?: unknown
28
+ output?: unknown
29
+ description?: string
30
+ schedule?: ScheduleDeclaration | ScheduleDeclaration[]
31
+ concurrency?: ConcurrencyPolicy<TInput>
32
+ retry?: RetryPolicy
33
+ timeout?: Duration
34
+ defaultRuntime?: "edge" | "node"
35
+ tags?: string[]
36
+ run: (input: TInput, ctx: WorkflowContext<TInput>) => Promise<TOutput>
37
+ }
38
+
39
+ /**
40
+ * Internal registered form of a workflow. The executor takes this
41
+ * plus a request and drives the body.
42
+ */
43
+ export interface WorkflowDefinition<TInput = unknown, TOutput = unknown>
44
+ extends WorkflowHandle<TInput, TOutput> {
45
+ readonly config: WorkflowConfig<TInput, TOutput>
46
+ }
47
+
48
+ export type ScheduleDeclaration = (
49
+ | { cron: string }
50
+ | { every: Duration }
51
+ | { at: string | Date }
52
+ ) & {
53
+ timezone?: string
54
+ input?: unknown | (() => unknown | Promise<unknown>)
55
+ enabled?: boolean
56
+ overlap?: "skip" | "queue" | "allow"
57
+ environments?: EnvironmentName[]
58
+ name?: string
59
+ }
60
+
61
+ export interface ConcurrencyPolicy<TInput> {
62
+ key?: string | ((input: TInput) => string)
63
+ limit?: number
64
+ strategy?: "queue" | "cancel-in-progress" | "cancel-newest" | "round-robin"
65
+ }
66
+
67
+ /**
68
+ * Process-local registry. Backed by globalThis so bundles that inline
69
+ * their own copy of @voyant-travel/workflows still share the registry with
70
+ * the loader's copy (voyant build relies on this to extract the
71
+ * manifest from a user bundle at load-time). Module-local `const`
72
+ * would create a private map per bundle copy.
73
+ */
74
+ const REGISTRY_KEY = "__voyantWorkflowRegistry" as const
75
+ const globalRef = globalThis as typeof globalThis &
76
+ Record<typeof REGISTRY_KEY, Map<string, WorkflowDefinition> | undefined>
77
+ const REGISTRY: Map<string, WorkflowDefinition> =
78
+ globalRef[REGISTRY_KEY] ?? new Map<string, WorkflowDefinition>()
79
+ globalRef[REGISTRY_KEY] = REGISTRY
80
+
81
+ /** Declare a workflow. See docs/sdk-surface.md §2.1. */
82
+ export function workflow<TInput = unknown, TOutput = unknown>(
83
+ config: WorkflowConfig<TInput, TOutput>,
84
+ ): WorkflowDefinition<TInput, TOutput> {
85
+ // Vite / Cloudflare workerd HMR re-evaluates modules in place, so a
86
+ // workflow file that registers ids at import-time will be re-imported
87
+ // on every save. Throwing on duplicate ids would surface real
88
+ // collisions but also kills the entire dev loop. The CLI's pre-flight
89
+ // (`voyant workflows build`) is the right place to catch genuine
90
+ // duplicates across files; here we replace + warn so HMR keeps
91
+ // working. Production bundles run this once at startup, so the
92
+ // duplicate path is effectively dev-only.
93
+ if (REGISTRY.has(config.id)) {
94
+ console.warn(
95
+ `[workflows] workflow id "${config.id}" re-registered — assuming HMR re-import. ` +
96
+ `If this is a real duplicate, \`voyant workflows build\` will reject the bundle.`,
97
+ )
98
+ }
99
+ const def: WorkflowDefinition<TInput, TOutput> = {
100
+ id: config.id,
101
+ config,
102
+ }
103
+ REGISTRY.set(config.id, def as WorkflowDefinition)
104
+ return def
105
+ }
106
+
107
+ /** Internal: look up a registered workflow by id. */
108
+ export function getWorkflow(id: string): WorkflowDefinition | undefined {
109
+ return REGISTRY.get(id)
110
+ }
111
+
112
+ /**
113
+ * Internal: enumerate every registered workflow. Used by the CLI to list
114
+ * workflows discovered from a loaded entry file. Not part of the stable
115
+ * public API — implementation detail of the SDK/CLI pair.
116
+ */
117
+ export function __listRegisteredWorkflows(): WorkflowDefinition[] {
118
+ return [...REGISTRY.values()]
119
+ }
120
+
121
+ /**
122
+ * Internal: clear the workflow registry. Called by the CLI between
123
+ * builds / hot-reloads to drop stale workflows before re-importing
124
+ * the tenant bundle, and by test suites in beforeEach to isolate
125
+ * runs. Not part of the stable public API.
126
+ */
127
+ export function __resetRegistry(): void {
128
+ REGISTRY.clear()
129
+ }
130
+
131
+ // ---- Context ----
132
+
133
+ export interface RunContext {
134
+ id: string
135
+ number: number
136
+ attempt: number
137
+ triggeredBy: RunTrigger
138
+ tags: readonly string[]
139
+ startedAt: number
140
+ }
141
+
142
+ export interface EnvironmentContext {
143
+ name: EnvironmentName
144
+ git?: {
145
+ commit: string
146
+ branch: string
147
+ pr?: { number: number; url: string }
148
+ }
149
+ }
150
+
151
+ export interface WorkflowContext<_TInput = unknown> {
152
+ readonly run: RunContext
153
+ readonly workflow: { id: string; version: string }
154
+ readonly environment: EnvironmentContext
155
+ readonly project: { id: string; slug: string }
156
+ readonly organization: { id: string; slug: string }
157
+ readonly invocationCount: number
158
+ readonly signal: AbortSignal
159
+
160
+ /**
161
+ * Read-only view of the framework's service container. Step bodies resolve
162
+ * shared services (db, indexer, etc.) via `ctx.services.resolve("name")`.
163
+ * The framework wires this from `createApp()`'s `ModuleContainer` through
164
+ * `StepHandlerDeps.services`. When no container is plumbed (driver not
165
+ * configured with `services`, or in raw orchestrator tests), `resolve(...)`
166
+ * throws with a clear message and `has(...)` returns `false`.
167
+ */
168
+ readonly services: ServiceResolver
169
+
170
+ step: StepApi
171
+ sleep: (duration: Duration) => Promise<void>
172
+ waitForEvent: WaitForEventApi
173
+ waitForSignal: WaitForSignalApi
174
+ waitForToken: WaitForTokenApi
175
+ invoke: InvokeApi
176
+ parallel: ParallelApi
177
+ stream: StreamApi
178
+ group: GroupApi
179
+ compensate: () => Promise<never>
180
+ metadata: MetadataApi
181
+
182
+ now: () => number
183
+ random: () => number
184
+ randomUUID: () => string
185
+
186
+ setRetry: (policy: RetryPolicy) => void
187
+ }
188
+
189
+ // ---- Step ----
190
+
191
+ export interface StepApi {
192
+ <T>(id: string, fn: StepFn<T>): Promise<T>
193
+ <T>(id: string, opts: StepOptions<T>, fn: StepFn<T>): Promise<T>
194
+ }
195
+
196
+ export type StepFn<T> = (stepCtx: StepContext) => Promise<T>
197
+
198
+ export interface StepContext {
199
+ signal: AbortSignal
200
+ attempt: number
201
+ log: (level: "info" | "warn" | "error", msg: string, data?: object) => void
202
+ }
203
+
204
+ export interface StepOptions<T = unknown> {
205
+ runtime?: "edge" | "node"
206
+ machine?: MachineType
207
+ timeout?: Duration
208
+ retry?: RetryPolicy | { max: 0 }
209
+ idempotencyKey?: string
210
+ compensate?: (output: T) => Promise<void>
211
+ rateLimit?: RateLimitSpec
212
+ waitFor?: Condition
213
+ cancelIf?: Condition
214
+ skipIf?: Condition
215
+ }
216
+
217
+ // ---- Waits ----
218
+
219
+ export interface Waitable<T> extends PromiseLike<T | null> {
220
+ [Symbol.asyncIterator](): AsyncIterableIterator<T>
221
+ close(): void
222
+ }
223
+
224
+ export type WaitForEventApi = <T = unknown>(
225
+ eventType: string,
226
+ opts?: WaitForEventOptions<T>,
227
+ ) => Waitable<T>
228
+
229
+ export interface WaitForEventOptions<T> {
230
+ match?: Partial<T> | ((payload: T) => boolean)
231
+ timeout?: Duration
232
+ lookback?: Duration
233
+ bufferSize?: number
234
+ onTimeout?: "null" | "throw"
235
+ }
236
+
237
+ export type WaitForSignalApi = <T = unknown>(
238
+ name: string,
239
+ opts?: WaitForSignalOptions<T>,
240
+ ) => Waitable<T>
241
+ export interface WaitForSignalOptions<T> extends WaitForEventOptions<T> {}
242
+
243
+ export type WaitForTokenApi = <T = unknown>(opts?: WaitForTokenOptions<T>) => Promise<TokenWait<T>>
244
+ export interface WaitForTokenOptions<_T> {
245
+ tokenId?: string
246
+ timeout?: Duration
247
+ onTimeout?: "null" | "throw"
248
+ schema?: unknown
249
+ }
250
+ export interface TokenWait<T> {
251
+ tokenId: string
252
+ url: string
253
+ wait: () => Promise<T | null>
254
+ }
255
+
256
+ // ---- Invoke / parallel ----
257
+
258
+ export type InvokeApi = <TIn, TOut>(
259
+ workflow: WorkflowHandle<TIn, TOut>,
260
+ input: TIn,
261
+ opts?: InvokeOptions,
262
+ ) => Promise<TOut>
263
+
264
+ export interface InvokeOptions {
265
+ idempotencyKey?: string
266
+ tags?: string[]
267
+ lockToVersion?: string
268
+ /**
269
+ * Fire-and-forget child run. The child is still triggered and
270
+ * persisted, but the parent does not wait for its output or error.
271
+ * The awaited result resolves to `undefined`; callers should not use
272
+ * detached invokes for control flow.
273
+ */
274
+ detach?: boolean
275
+ }
276
+
277
+ export type ParallelApi = <T, R>(
278
+ items: readonly T[],
279
+ fn: (item: T, index: number) => Promise<R>,
280
+ opts?: ParallelOptions,
281
+ ) => Promise<R[]>
282
+
283
+ export interface ParallelOptions {
284
+ concurrency?: number
285
+ settle?: boolean
286
+ }
287
+
288
+ // ---- Streams ----
289
+
290
+ export interface StreamApi {
291
+ text(streamId: string, source: AsyncIterable<string>): Promise<void>
292
+ json<T>(streamId: string, source: AsyncIterable<T>): Promise<void>
293
+ bytes(streamId: string, source: AsyncIterable<Uint8Array>): Promise<void>
294
+ <T>(streamId: string, fn: () => AsyncGenerator<T>): Promise<void>
295
+ }
296
+
297
+ // ---- Groups (scoped compensation) ----
298
+
299
+ export type GroupApi = <T>(name: string, fn: (scope: GroupScope) => Promise<T>) => Promise<T>
300
+ export interface GroupScope {
301
+ step: StepApi
302
+ compensate: () => Promise<never>
303
+ }
304
+
305
+ // ---- Metadata ----
306
+
307
+ export type MetadataValue =
308
+ | string
309
+ | number
310
+ | boolean
311
+ | null
312
+ | MetadataValue[]
313
+ | { [key: string]: MetadataValue }
314
+
315
+ export interface MetadataMutatorSubset {
316
+ set(key: string, value: MetadataValue): void
317
+ increment(key: string, by?: number): void
318
+ append<T>(key: string, value: T): void
319
+ remove(key: string): void
320
+ }
321
+
322
+ export interface MetadataApi extends MetadataMutatorSubset {
323
+ flush(): Promise<void>
324
+ parent?: MetadataMutatorSubset
325
+ root?: MetadataMutatorSubset
326
+ }
327
+
328
+ export type { RunStatus }