@voyantjs/workflows 0.6.7 → 0.6.9

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 (61) hide show
  1. package/dist/auth/index.d.ts +26 -0
  2. package/dist/auth/index.d.ts.map +1 -0
  3. package/dist/auth/index.js +137 -0
  4. package/dist/conditions.d.ts +29 -0
  5. package/dist/conditions.d.ts.map +1 -0
  6. package/dist/conditions.js +5 -0
  7. package/dist/handler/index.d.ts +104 -0
  8. package/dist/handler/index.d.ts.map +1 -0
  9. package/dist/handler/index.js +238 -0
  10. package/dist/index.d.ts +6 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +10 -0
  13. package/dist/protocol/index.d.ts +187 -0
  14. package/dist/protocol/index.d.ts.map +1 -0
  15. package/dist/protocol/index.js +7 -0
  16. package/dist/rate-limit/index.d.ts +40 -0
  17. package/dist/rate-limit/index.d.ts.map +1 -0
  18. package/dist/rate-limit/index.js +139 -0
  19. package/dist/runtime/ctx.d.ts +102 -0
  20. package/dist/runtime/ctx.d.ts.map +1 -0
  21. package/dist/runtime/ctx.js +607 -0
  22. package/dist/runtime/determinism.d.ts +19 -0
  23. package/dist/runtime/determinism.d.ts.map +1 -0
  24. package/dist/runtime/determinism.js +61 -0
  25. package/dist/runtime/errors.d.ts +21 -0
  26. package/dist/runtime/errors.d.ts.map +1 -0
  27. package/dist/runtime/errors.js +45 -0
  28. package/dist/runtime/executor.d.ts +159 -0
  29. package/dist/runtime/executor.d.ts.map +1 -0
  30. package/dist/runtime/executor.js +225 -0
  31. package/dist/runtime/journal.d.ts +55 -0
  32. package/dist/runtime/journal.d.ts.map +1 -0
  33. package/dist/runtime/journal.js +28 -0
  34. package/dist/testing/index.d.ts +117 -0
  35. package/dist/testing/index.d.ts.map +1 -0
  36. package/dist/testing/index.js +595 -0
  37. package/dist/trigger.d.ts +122 -0
  38. package/dist/trigger.d.ts.map +1 -0
  39. package/dist/trigger.js +23 -0
  40. package/dist/types.d.ts +63 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +3 -0
  43. package/dist/workflow.d.ts +212 -0
  44. package/dist/workflow.d.ts.map +1 -0
  45. package/dist/workflow.js +46 -0
  46. package/package.json +30 -30
  47. package/src/auth/index.ts +46 -52
  48. package/src/conditions.ts +13 -13
  49. package/src/handler/index.ts +110 -106
  50. package/src/index.ts +7 -7
  51. package/src/protocol/index.ts +137 -71
  52. package/src/rate-limit/index.ts +77 -78
  53. package/src/runtime/ctx.ts +354 -342
  54. package/src/runtime/determinism.ts +27 -27
  55. package/src/runtime/errors.ts +17 -17
  56. package/src/runtime/executor.ts +179 -172
  57. package/src/runtime/journal.ts +25 -25
  58. package/src/testing/index.ts +268 -202
  59. package/src/trigger.ts +64 -71
  60. package/src/types.ts +16 -18
  61. package/src/workflow.ts +154 -152
@@ -0,0 +1,187 @@
1
+ export type ProtocolVersion = 1;
2
+ export declare const PROTOCOL_VERSION: ProtocolVersion;
3
+ export type { CompensationJournalEntry, JournalSlice, StepJournalEntry, WaitpointResolutionEntry, } from "../runtime/journal.js";
4
+ export type ExecutionStatus = "CREATED" | "QUEUED" | "EXECUTING" | "EXECUTING_WITH_WAITPOINTS" | "SUSPENDED" | "PENDING_CANCEL" | "FINISHED";
5
+ export type WaitpointKind = "DATETIME" | "EVENT" | "SIGNAL" | "RUN" | "MANUAL";
6
+ export interface SerializedError {
7
+ category: "USER_ERROR" | "RUNTIME_ERROR";
8
+ code: string;
9
+ message: string;
10
+ name?: string;
11
+ stack?: string;
12
+ cause?: SerializedError;
13
+ data?: Record<string, unknown>;
14
+ }
15
+ export type PayloadLocation = "INLINE" | "EXTERNAL";
16
+ export interface WorkflowManifest {
17
+ schemaVersion: 1;
18
+ projectId: string;
19
+ versionId: string;
20
+ builtAt: number;
21
+ builderVersion: string;
22
+ capabilities: string[];
23
+ workflows: WorkflowManifestEntry[];
24
+ eventFilters: EventFilterManifestEntry[];
25
+ bindings: Record<string, {
26
+ type: "d1" | "r2" | "kv" | "queue";
27
+ name: string;
28
+ }>;
29
+ environments: Record<string, {
30
+ customDomain?: string;
31
+ }>;
32
+ }
33
+ export interface WorkflowManifestEntry {
34
+ id: string;
35
+ version: string;
36
+ inputSchema?: unknown;
37
+ outputSchema?: unknown;
38
+ steps: ManifestStep[];
39
+ schedules: ManifestSchedule[];
40
+ defaultRuntime: "edge" | "node";
41
+ hasCompensation: boolean;
42
+ sourceLocation: {
43
+ file: string;
44
+ line: number;
45
+ };
46
+ }
47
+ export interface ManifestStep {
48
+ id: string;
49
+ runtime: "edge" | "node";
50
+ hasCompensation: boolean;
51
+ sourceLocation: {
52
+ file: string;
53
+ line: number;
54
+ };
55
+ }
56
+ export interface ManifestSchedule {
57
+ cron?: string;
58
+ every?: string;
59
+ at?: string;
60
+ timezone?: string;
61
+ environments?: ("production" | "preview" | "development")[];
62
+ name?: string;
63
+ }
64
+ export interface EventFilterManifestEntry {
65
+ id: string;
66
+ eventType: string;
67
+ scope?: string;
68
+ matchExpression?: string;
69
+ payloadHash: string;
70
+ targetWorkflowId: string;
71
+ }
72
+ export type StreamEvent = {
73
+ kind: "step.started";
74
+ eventId: string;
75
+ at: number;
76
+ stepId: string;
77
+ runtime: "edge" | "node";
78
+ machine?: string;
79
+ } | {
80
+ kind: "step.ok";
81
+ eventId: string;
82
+ at: number;
83
+ stepId: string;
84
+ attempt: number;
85
+ durationMs: number;
86
+ output?: unknown;
87
+ } | {
88
+ kind: "step.err";
89
+ eventId: string;
90
+ at: number;
91
+ stepId: string;
92
+ attempt: number;
93
+ error: SerializedError;
94
+ } | {
95
+ kind: "step.skipped";
96
+ eventId: string;
97
+ at: number;
98
+ stepId: string;
99
+ reason: string;
100
+ } | {
101
+ kind: "step.compensated";
102
+ eventId: string;
103
+ at: number;
104
+ stepId: string;
105
+ status: "ok" | "err";
106
+ error?: SerializedError;
107
+ } | {
108
+ kind: "waitpoint.registered";
109
+ eventId: string;
110
+ at: number;
111
+ waitpointId: string;
112
+ waitpointKind: WaitpointKind;
113
+ meta: Record<string, unknown>;
114
+ } | {
115
+ kind: "waitpoint.resolved";
116
+ eventId: string;
117
+ at: number;
118
+ waitpointId: string;
119
+ payload?: unknown;
120
+ source: "live" | "inbox" | "replay";
121
+ } | {
122
+ kind: "metadata.changed";
123
+ eventId: string;
124
+ at: number;
125
+ metadata: Record<string, unknown>;
126
+ } | {
127
+ kind: "stream.chunk";
128
+ eventId: string;
129
+ at: number;
130
+ streamId: string;
131
+ chunk: unknown;
132
+ encoding: "json" | "text" | "base64";
133
+ final: boolean;
134
+ } | {
135
+ kind: "log";
136
+ eventId: string;
137
+ at: number;
138
+ level: "info" | "warn" | "error";
139
+ message: string;
140
+ stepId?: string;
141
+ data?: object;
142
+ } | {
143
+ kind: "version.rebased";
144
+ eventId: string;
145
+ at: number;
146
+ fromVersion: string;
147
+ toVersion: string;
148
+ } | {
149
+ kind: "run.cancelled";
150
+ eventId: string;
151
+ at: number;
152
+ reason?: string;
153
+ } | {
154
+ kind: "run.finished";
155
+ eventId: string;
156
+ at: number;
157
+ status: string;
158
+ output?: unknown;
159
+ error?: SerializedError;
160
+ };
161
+ export interface JournalEventEnvelope<TKind extends string = string, TData = unknown> {
162
+ eventId: string;
163
+ runId: string;
164
+ createdAt: number;
165
+ kind: TKind;
166
+ data: TData;
167
+ snapshotId?: string;
168
+ writtenBy: "orchestrator" | "tenant" | "node";
169
+ }
170
+ export interface PublicAccessTokenClaims {
171
+ sub: "pat";
172
+ tenantId: string;
173
+ environment: "production" | "preview" | "development";
174
+ scope: ("read" | "trigger" | "cancel")[];
175
+ target: {
176
+ kind: "run";
177
+ runId: string;
178
+ } | {
179
+ kind: "workflow";
180
+ workflowId: string;
181
+ } | {
182
+ kind: "tag";
183
+ tag: string;
184
+ };
185
+ exp: number;
186
+ }
187
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/protocol/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ // @voyantjs/workflows/protocol
2
+ //
3
+ // Wire-protocol types shared with the orchestrator. Full contract
4
+ // in docs/runtime-protocol.md; types here are exported so callers
5
+ // (test harness, adapters, dashboards) can build and inspect wire
6
+ // payloads without reaching into runtime internals.
7
+ export const PROTOCOL_VERSION = 1;
@@ -0,0 +1,40 @@
1
+ import type { Duration } from "../types.js";
2
+ export interface AcquireArgs {
3
+ /** Bucket key — usually a tenant id, a url host, a user id, etc. */
4
+ key: string;
5
+ /** Maximum units the bucket can hold. */
6
+ limit: number;
7
+ /** Units the current call consumes. */
8
+ units: number;
9
+ /** Refill window in ms. `limit` tokens per `windowMs`. */
10
+ windowMs: number;
11
+ /** `queue` → wait until capacity; `fail` → throw immediately. */
12
+ onLimit: "queue" | "fail";
13
+ /** Forwarded from the run; limiter observes aborts during queue waits. */
14
+ signal?: AbortSignal;
15
+ }
16
+ export interface RateLimiter {
17
+ acquire(args: AcquireArgs): Promise<void>;
18
+ }
19
+ /** Error thrown when `onLimit === "fail"` and the bucket is empty. */
20
+ export declare class RateLimitExceededError extends Error {
21
+ readonly code = "RATE_LIMITED";
22
+ readonly retryAfterMs: number;
23
+ constructor(key: string, retryAfterMs: number);
24
+ }
25
+ export interface InMemoryLimiterOptions {
26
+ /** Injectable clock, ms since epoch. Defaults to Date.now. */
27
+ now?: () => number;
28
+ /** Injectable delay; defaults to setTimeout. Tests override this. */
29
+ delay?: (ms: number, signal?: AbortSignal) => Promise<void>;
30
+ }
31
+ /**
32
+ * Token-bucket rate limiter held in-process. Independent buckets per
33
+ * `key`; bucket parameters (`capacity`, `refillPerMs`) come from the
34
+ * `limit` / `windowMs` of the first `acquire` call and are updated on
35
+ * subsequent calls that change them.
36
+ */
37
+ export declare function createInMemoryRateLimiter(opts?: InMemoryLimiterOptions): RateLimiter;
38
+ /** Normalize a Duration to milliseconds. Same units as `toMs` in ctx.ts. */
39
+ export declare function durationToMs(d: Duration): number;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rate-limit/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAA;IACX,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAA;IAChB,iEAAiE;IACjE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAA;IACzB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1C;AAED,sEAAsE;AACtE,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,IAAI,kBAAiB;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;gBACjB,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;CAK9C;AASD,MAAM,WAAW,sBAAsB;IACrC,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,qEAAqE;IACrE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,GAAE,sBAA2B,GAAG,WAAW,CA0CxF;AAgDD,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAqBhD"}
@@ -0,0 +1,139 @@
1
+ // @voyantjs/workflows/rate-limit
2
+ //
3
+ // Reference rate limiter used by `ctx.step({ rateLimit: ... })`.
4
+ //
5
+ // A RateLimiter is a small interface: `acquire()` blocks (or throws,
6
+ // depending on `onLimit`) until `units` are available under `key` for
7
+ // a sliding window of `windowMs`. One shared limiter instance lives
8
+ // per tenant Worker process — callers wire it into `createStepHandler`
9
+ // via `{ rateLimiter: createInMemoryRateLimiter() }`.
10
+ //
11
+ // The in-memory impl is a token bucket: `capacity = limit`, refill
12
+ // rate = `limit / windowMs`. It's suitable for local dev and
13
+ // single-process deployments. Multi-region / sharded deployments
14
+ // should swap in a Durable-Object or Redis-backed implementation that
15
+ // shares state across isolates.
16
+ /** Error thrown when `onLimit === "fail"` and the bucket is empty. */
17
+ export class RateLimitExceededError extends Error {
18
+ code = "RATE_LIMITED";
19
+ retryAfterMs;
20
+ constructor(key, retryAfterMs) {
21
+ super(`rate limit exceeded for key "${key}" (retry after ${retryAfterMs}ms)`);
22
+ this.name = "RateLimitExceededError";
23
+ this.retryAfterMs = retryAfterMs;
24
+ }
25
+ }
26
+ /**
27
+ * Token-bucket rate limiter held in-process. Independent buckets per
28
+ * `key`; bucket parameters (`capacity`, `refillPerMs`) come from the
29
+ * `limit` / `windowMs` of the first `acquire` call and are updated on
30
+ * subsequent calls that change them.
31
+ */
32
+ export function createInMemoryRateLimiter(opts = {}) {
33
+ const now = opts.now ?? (() => Date.now());
34
+ const delay = opts.delay ?? defaultDelay;
35
+ const buckets = new Map();
36
+ return {
37
+ async acquire(args) {
38
+ if (args.units <= 0)
39
+ return;
40
+ if (args.limit <= 0) {
41
+ throw new Error(`rate-limit: "limit" must be > 0 (got ${args.limit}) for key "${args.key}"`);
42
+ }
43
+ if (args.windowMs <= 0) {
44
+ throw new Error(`rate-limit: "windowMs" must be > 0 (got ${args.windowMs}) for key "${args.key}"`);
45
+ }
46
+ if (args.units > args.limit) {
47
+ // The step will never be admissible — short-circuit regardless
48
+ // of onLimit to avoid hanging indefinitely under queue mode.
49
+ throw new Error(`rate-limit: units (${args.units}) > limit (${args.limit}) for key "${args.key}" — step can never be admitted`);
50
+ }
51
+ while (true) {
52
+ const bucket = refill(buckets, args, now());
53
+ if (bucket.tokens >= args.units) {
54
+ bucket.tokens -= args.units;
55
+ return;
56
+ }
57
+ const missing = args.units - bucket.tokens;
58
+ const waitMs = Math.ceil(missing / bucket.refillPerMs);
59
+ if (args.onLimit === "fail") {
60
+ throw new RateLimitExceededError(args.key, waitMs);
61
+ }
62
+ await delay(waitMs, args.signal);
63
+ if (args.signal?.aborted) {
64
+ throw args.signal.reason ?? new Error("rate-limit: aborted while queued");
65
+ }
66
+ }
67
+ },
68
+ };
69
+ }
70
+ function refill(buckets, args, nowMs) {
71
+ const refillPerMs = args.limit / args.windowMs;
72
+ let b = buckets.get(args.key);
73
+ if (!b) {
74
+ b = {
75
+ tokens: args.limit,
76
+ capacity: args.limit,
77
+ refillPerMs,
78
+ lastRefillAt: nowMs,
79
+ };
80
+ buckets.set(args.key, b);
81
+ return b;
82
+ }
83
+ // Re-parameterize if the caller changed limit / windowMs. Clamp
84
+ // tokens to the new capacity so a shrink doesn't leave stale excess.
85
+ if (b.capacity !== args.limit || b.refillPerMs !== refillPerMs) {
86
+ b.capacity = args.limit;
87
+ b.refillPerMs = refillPerMs;
88
+ if (b.tokens > b.capacity)
89
+ b.tokens = b.capacity;
90
+ }
91
+ const elapsed = Math.max(0, nowMs - b.lastRefillAt);
92
+ if (elapsed > 0) {
93
+ b.tokens = Math.min(b.capacity, b.tokens + elapsed * b.refillPerMs);
94
+ b.lastRefillAt = nowMs;
95
+ }
96
+ return b;
97
+ }
98
+ function defaultDelay(ms, signal) {
99
+ return new Promise((resolve, reject) => {
100
+ if (signal?.aborted) {
101
+ reject(signal.reason ?? new Error("aborted"));
102
+ return;
103
+ }
104
+ const timer = setTimeout(() => {
105
+ signal?.removeEventListener("abort", onAbort);
106
+ resolve();
107
+ }, ms);
108
+ const onAbort = () => {
109
+ clearTimeout(timer);
110
+ reject(signal?.reason ?? new Error("aborted"));
111
+ };
112
+ signal?.addEventListener("abort", onAbort, { once: true });
113
+ });
114
+ }
115
+ /** Normalize a Duration to milliseconds. Same units as `toMs` in ctx.ts. */
116
+ export function durationToMs(d) {
117
+ if (typeof d === "number")
118
+ return d;
119
+ const m = /^(\d+)(ms|s|m|h|d|w)$/.exec(d);
120
+ if (!m)
121
+ throw new Error(`rate-limit: invalid duration "${d}"`);
122
+ const n = Number(m[1]);
123
+ switch (m[2]) {
124
+ case "ms":
125
+ return n;
126
+ case "s":
127
+ return n * 1_000;
128
+ case "m":
129
+ return n * 60_000;
130
+ case "h":
131
+ return n * 3_600_000;
132
+ case "d":
133
+ return n * 86_400_000;
134
+ case "w":
135
+ return n * 604_800_000;
136
+ default:
137
+ throw new Error(`rate-limit: invalid duration "${d}"`);
138
+ }
139
+ }
@@ -0,0 +1,102 @@
1
+ import type { RetryPolicy, WaitpointKind } from "../types.js";
2
+ import type { EnvironmentContext, MetadataValue, RunContext, StepContext, StepFn, StepOptions, WorkflowContext } from "../workflow.js";
3
+ import { type ClockState } from "./determinism.js";
4
+ import type { JournalSlice, StepJournalEntry } from "./journal.js";
5
+ /**
6
+ * Callbacks the executor provides for operations that must reach the
7
+ * orchestrator (over HTTP in production, in-memory in tests).
8
+ */
9
+ export interface RuntimeCallbacks {
10
+ /** Run a new step and journal the result. Called only for steps not already in the journal. */
11
+ runStep(args: {
12
+ stepId: string;
13
+ attempt: number;
14
+ input: unknown;
15
+ options: StepOptions<unknown>;
16
+ fn: StepFn<unknown>;
17
+ stepCtx: StepContext;
18
+ }): Promise<StepJournalEntry>;
19
+ /**
20
+ * Called when a step completes successfully and had a `compensate`
21
+ * function declared. The executor collects these in completion order
22
+ * and runs them in reverse if the body throws or `ctx.compensate()`
23
+ * is invoked.
24
+ */
25
+ recordCompensable(args: {
26
+ stepId: string;
27
+ output: unknown;
28
+ compensate: (output: unknown) => Promise<void>;
29
+ }): void;
30
+ /** Current length of the compensable list. Used by `ctx.group` checkpoints. */
31
+ compensableLength(): number;
32
+ /**
33
+ * Remove and return compensables added since `fromIndex`. Used by
34
+ * `ctx.group` to run scoped rollback without touching outer
35
+ * compensables.
36
+ */
37
+ spliceCompensable(fromIndex: number): Array<{
38
+ stepId: string;
39
+ output: unknown;
40
+ compensate: (output: unknown) => Promise<void>;
41
+ }>;
42
+ /**
43
+ * Called by `ctx.stream()` for each chunk produced by the source.
44
+ * In production this emits a `stream.chunk` WebSocket event and
45
+ * journals the chunk; in tests the harness collects chunks.
46
+ */
47
+ pushStreamChunk(args: {
48
+ streamId: string;
49
+ seq: number;
50
+ encoding: "text" | "json" | "base64";
51
+ chunk: unknown;
52
+ final: boolean;
53
+ }): void;
54
+ /** Register a new waitpoint; execution will yield after this returns. */
55
+ registerWaitpoint(args: {
56
+ clientWaitpointId: string;
57
+ kind: WaitpointKind;
58
+ meta: Record<string, unknown>;
59
+ timeoutMs?: number;
60
+ }): void;
61
+ /** Push a metadata mutation; flushed on waitpoint yield and run completion. */
62
+ pushMetadata(op: {
63
+ op: "set" | "increment" | "append" | "remove";
64
+ key: string;
65
+ value?: unknown;
66
+ target?: "self" | "parent" | "root";
67
+ }): void;
68
+ /** Increment invocation counter when the body resumes after eviction. */
69
+ readonly invocationCount: number;
70
+ /** Cancellation signal exposed as `ctx.signal`. */
71
+ readonly abortSignal: AbortSignal;
72
+ }
73
+ export interface RuntimeEnvironment {
74
+ readonly run: RunContext;
75
+ readonly workflow: {
76
+ id: string;
77
+ version: string;
78
+ };
79
+ readonly environment: EnvironmentContext;
80
+ readonly project: {
81
+ id: string;
82
+ slug: string;
83
+ };
84
+ readonly organization: {
85
+ id: string;
86
+ slug: string;
87
+ };
88
+ }
89
+ export interface CtxBuildArgs {
90
+ env: RuntimeEnvironment;
91
+ journal: JournalSlice;
92
+ callbacks: RuntimeCallbacks;
93
+ clock: ClockState;
94
+ random: () => number;
95
+ /** Mutated as ctx.setRetry is called; each step option inherits. */
96
+ retryOverride: {
97
+ current: RetryPolicy | undefined;
98
+ };
99
+ }
100
+ export declare function buildCtx(args: CtxBuildArgs): WorkflowContext<unknown>;
101
+ export type { MetadataValue };
102
+ //# sourceMappingURL=ctx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx.d.ts","sourceRoot":"","sources":["../../src/runtime/ctx.ts"],"names":[],"mappings":"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"}