@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/dist/client.js ADDED
@@ -0,0 +1,305 @@
1
+ // Client-safe workflow API for app/server code that triggers or forwards
2
+ // workflow activity to a managed Voyant Cloud runtime.
3
+ const DEFAULT_ENVIRONMENT = "production";
4
+ let configuredClient;
5
+ /**
6
+ * Install the process-local `workflows` client implementation used by the
7
+ * root `@voyant-travel/workflows` singleton. Apps may call this during boot, or
8
+ * rely on deployment-injected Voyant Cloud environment variables.
9
+ */
10
+ export function configureWorkflowsClient(client) {
11
+ configuredClient = client;
12
+ }
13
+ export function getConfiguredWorkflowsClient() {
14
+ return configuredClient;
15
+ }
16
+ export const workflows = new Proxy({}, {
17
+ get(_, method) {
18
+ return (...args) => {
19
+ const client = configuredClient ?? tryCreateCloudClientFromEnv();
20
+ if (!client) {
21
+ throw new Error(`@voyant-travel/workflows: workflows.${method}() requires a configured workflows client. ` +
22
+ `Use configureWorkflowsClient(createCloudWorkflowsClient(...)) or provide the ` +
23
+ `VOYANT_CLOUD_WORKFLOWS_URL, VOYANT_CLOUD_WORKFLOW_TRIGGER_TOKEN, ` +
24
+ `VOYANT_CLOUD_APP_SLUG, and VOYANT_CLOUD_ENVIRONMENT deployment variables.`);
25
+ }
26
+ const fn = client[method];
27
+ if (typeof fn !== "function") {
28
+ throw new Error(`@voyant-travel/workflows: workflows.${method} is not implemented`);
29
+ }
30
+ return fn(...args);
31
+ };
32
+ },
33
+ });
34
+ export function createCloudWorkflowsClient(options = {}) {
35
+ const config = resolveCloudConfig(options);
36
+ const httpFetch = options.fetch ?? globalThis.fetch;
37
+ if (typeof httpFetch !== "function") {
38
+ throw new Error("@voyant-travel/workflows/client: global fetch is unavailable");
39
+ }
40
+ return {
41
+ async trigger(workflow, input, opts) {
42
+ const workflowId = workflowIdOf(workflow);
43
+ const environment = opts?.environment ?? config.environment;
44
+ const res = await cloudFetch(httpFetch, config, {
45
+ method: "POST",
46
+ path: `/apps/${encodeURIComponent(config.appSlug)}/${environment}/workflows/${encodeURIComponent(workflowId)}/runs`,
47
+ body: {
48
+ input,
49
+ options: serializeTriggerOptions(opts),
50
+ },
51
+ idempotencyKey: opts?.idempotencyKey,
52
+ });
53
+ return normalizeRun(await readJson(res), workflowId);
54
+ },
55
+ signal() {
56
+ return unsupported("signal");
57
+ },
58
+ completeToken() {
59
+ return unsupported("completeToken");
60
+ },
61
+ cancel() {
62
+ return unsupported("cancel");
63
+ },
64
+ retry() {
65
+ return unsupported("retry");
66
+ },
67
+ replay() {
68
+ return unsupported("replay");
69
+ },
70
+ get() {
71
+ return unsupported("get");
72
+ },
73
+ list() {
74
+ return unsupported("list");
75
+ },
76
+ mintAccessToken() {
77
+ return unsupported("mintAccessToken");
78
+ },
79
+ };
80
+ }
81
+ /**
82
+ * Cloud-mode driver for framework event forwarding. It does not execute runs
83
+ * locally; it forwards triggers/events/manifests to the hosted runtime using
84
+ * the same deployment-scoped credentials as the client.
85
+ */
86
+ export function createCloudWorkflowDriver(options = {}) {
87
+ const client = createCloudWorkflowsClient(options);
88
+ const config = resolveCloudConfig(options);
89
+ const httpFetch = options.fetch ?? globalThis.fetch;
90
+ const manifestRegistration = options.manifestRegistration ?? "disabled";
91
+ return {
92
+ async registerManifest(args) {
93
+ if (manifestRegistration === "disabled") {
94
+ return { versionId: args.manifest.versionId };
95
+ }
96
+ const res = await cloudFetch(httpFetch, config, {
97
+ method: "POST",
98
+ path: `/apps/${encodeURIComponent(config.appSlug)}/${args.environment}/workflow-releases`,
99
+ body: { manifest: args.manifest },
100
+ });
101
+ const body = await readJson(res);
102
+ return {
103
+ versionId: readString(body, ["versionId"]) ??
104
+ readString(body, ["data", "versionId"]) ??
105
+ args.manifest.versionId,
106
+ };
107
+ },
108
+ trigger(workflow, input, opts) {
109
+ return client.trigger(workflow, input, opts);
110
+ },
111
+ async ingestEvent(args) {
112
+ const eventId = typeof args.envelope.metadata?.eventId === "string"
113
+ ? args.envelope.metadata.eventId
114
+ : args.idempotencyKey;
115
+ const res = await cloudFetch(httpFetch, config, {
116
+ method: "POST",
117
+ path: `/apps/${encodeURIComponent(config.appSlug)}/${args.environment}/events`,
118
+ body: {
119
+ envelope: args.envelope,
120
+ idempotencyKey: args.idempotencyKey,
121
+ },
122
+ idempotencyKey: eventId,
123
+ });
124
+ return (await readJson(res));
125
+ },
126
+ async getManifest(args) {
127
+ const res = await cloudFetch(httpFetch, config, {
128
+ method: "GET",
129
+ path: `/apps/${encodeURIComponent(config.appSlug)}/${args.environment}/workflow-releases/current`,
130
+ allowStatuses: [404],
131
+ });
132
+ if (res.status === 404)
133
+ return null;
134
+ const body = await readJson(res);
135
+ return (readRecord(body, ["manifest"]) ??
136
+ readRecord(body, ["data", "manifest"]) ??
137
+ body);
138
+ },
139
+ };
140
+ }
141
+ function tryCreateCloudClientFromEnv() {
142
+ const env = defaultEnv();
143
+ if (!env.VOYANT_CLOUD_WORKFLOWS_URL ||
144
+ !env.VOYANT_CLOUD_WORKFLOW_TRIGGER_TOKEN ||
145
+ !env.VOYANT_CLOUD_APP_SLUG) {
146
+ return undefined;
147
+ }
148
+ const client = createCloudWorkflowsClient({ env });
149
+ configuredClient = client;
150
+ return client;
151
+ }
152
+ function resolveCloudConfig(options) {
153
+ const env = { ...defaultEnv(), ...options.env };
154
+ const baseUrl = options.baseUrl ?? env.VOYANT_CLOUD_WORKFLOWS_URL;
155
+ const triggerToken = options.triggerToken ?? env.VOYANT_CLOUD_WORKFLOW_TRIGGER_TOKEN;
156
+ const appSlug = options.appSlug ?? env.VOYANT_CLOUD_APP_SLUG;
157
+ const environment = parseEnvironment(options.environment ?? env.VOYANT_CLOUD_ENVIRONMENT ?? DEFAULT_ENVIRONMENT);
158
+ const missing = [
159
+ ["baseUrl", baseUrl],
160
+ ["triggerToken", triggerToken],
161
+ ["appSlug", appSlug],
162
+ ]
163
+ .filter(([, value]) => !value)
164
+ .map(([name]) => name);
165
+ if (missing.length > 0) {
166
+ throw new Error(`@voyant-travel/workflows/client: missing Cloud workflow configuration: ${missing.join(", ")}`);
167
+ }
168
+ return {
169
+ baseUrl: stripTrailingSlash(requireConfigValue(baseUrl, "baseUrl")),
170
+ triggerToken: requireConfigValue(triggerToken, "triggerToken"),
171
+ appSlug: requireConfigValue(appSlug, "appSlug"),
172
+ environment,
173
+ };
174
+ }
175
+ function requireConfigValue(value, name) {
176
+ if (!value) {
177
+ throw new Error(`@voyant-travel/workflows/client: missing Cloud workflow configuration: ${name}`);
178
+ }
179
+ return value;
180
+ }
181
+ async function cloudFetch(httpFetch, config, args) {
182
+ const headers = new Headers({
183
+ accept: "application/json",
184
+ authorization: `Bearer ${config.triggerToken}`,
185
+ });
186
+ if (args.body !== undefined)
187
+ headers.set("content-type", "application/json");
188
+ if (args.idempotencyKey)
189
+ headers.set("idempotency-key", args.idempotencyKey);
190
+ const res = await httpFetch(`${config.baseUrl}/cloud/v1${args.path}`, {
191
+ method: args.method,
192
+ headers,
193
+ body: args.body === undefined ? undefined : JSON.stringify(args.body),
194
+ });
195
+ if (!res.ok && !args.allowStatuses?.includes(res.status)) {
196
+ throw new Error(`Voyant Cloud workflows request failed: ${res.status} ${res.statusText} ${await res.text()}`);
197
+ }
198
+ return res;
199
+ }
200
+ async function readJson(res) {
201
+ const text = await res.text();
202
+ if (text.length === 0)
203
+ return {};
204
+ return JSON.parse(text);
205
+ }
206
+ function normalizeRun(body, fallbackWorkflowId) {
207
+ const source = readRecord(body, ["data", "run"]) ??
208
+ readRecord(body, ["run"]) ??
209
+ readRecord(body, ["data"]) ??
210
+ asRecord(body);
211
+ const id = readString(source, ["id"]) ?? readString(source, ["runId"]);
212
+ if (!id) {
213
+ throw new Error("Voyant Cloud workflows response did not include a run id");
214
+ }
215
+ return {
216
+ id,
217
+ workflowId: readString(source, ["workflowId"]) ??
218
+ readString(source, ["workflow", "id"]) ??
219
+ fallbackWorkflowId,
220
+ status: parseRunStatus(readString(source, ["status"]) ?? "pending"),
221
+ startedAt: readNumber(source, ["startedAt"]) ?? Date.now(),
222
+ accessToken: readString(source, ["accessToken"]),
223
+ };
224
+ }
225
+ function serializeTriggerOptions(opts) {
226
+ if (!opts)
227
+ return {};
228
+ const out = {};
229
+ for (const [key, value] of Object.entries(opts)) {
230
+ if (value === undefined || key === "environment")
231
+ continue;
232
+ out[key] = value instanceof Date ? value.toISOString() : value;
233
+ }
234
+ return out;
235
+ }
236
+ function workflowIdOf(workflow) {
237
+ return typeof workflow === "string" ? workflow : workflow.id;
238
+ }
239
+ function unsupported(method) {
240
+ throw new Error(`@voyant-travel/workflows/client: workflows.${method}() is not supported by the ` +
241
+ `managed Cloud trigger client yet.`);
242
+ }
243
+ function defaultEnv() {
244
+ const processEnv = globalThis.process?.env;
245
+ return processEnv ?? {};
246
+ }
247
+ function parseEnvironment(value) {
248
+ if (value === "production" || value === "preview" || value === "development")
249
+ return value;
250
+ throw new Error(`@voyant-travel/workflows/client: invalid environment "${value}"; expected production, preview, or development`);
251
+ }
252
+ function parseRunStatus(value) {
253
+ const normalized = value.toLowerCase();
254
+ if (normalized === "pending" ||
255
+ normalized === "queued" ||
256
+ normalized === "running" ||
257
+ normalized === "waiting" ||
258
+ normalized === "completed" ||
259
+ normalized === "failed" ||
260
+ normalized === "cancelled" ||
261
+ normalized === "cancelled_by_dev_reload" ||
262
+ normalized === "cancelled_by_version_sunset" ||
263
+ normalized === "compensated" ||
264
+ normalized === "compensation_failed" ||
265
+ normalized === "timed_out") {
266
+ return normalized;
267
+ }
268
+ return "pending";
269
+ }
270
+ function stripTrailingSlash(value) {
271
+ return value.replace(/\/+$/, "");
272
+ }
273
+ function asRecord(value) {
274
+ return typeof value === "object" && value !== null ? value : {};
275
+ }
276
+ function readRecord(value, path) {
277
+ const current = readAtPath(value, path);
278
+ return typeof current === "object" && current !== null
279
+ ? current
280
+ : undefined;
281
+ }
282
+ function readString(value, path) {
283
+ const current = readAtPath(value, path);
284
+ return typeof current === "string" && current.length > 0 ? current : undefined;
285
+ }
286
+ function readNumber(value, path) {
287
+ const current = readAtPath(value, path);
288
+ if (typeof current === "number")
289
+ return current;
290
+ if (typeof current === "string" && current.length > 0) {
291
+ const parsed = Number(current);
292
+ if (Number.isFinite(parsed))
293
+ return parsed;
294
+ }
295
+ return undefined;
296
+ }
297
+ function readAtPath(value, path) {
298
+ let current = value;
299
+ for (const part of path) {
300
+ if (typeof current !== "object" || current === null)
301
+ return undefined;
302
+ current = current[part];
303
+ }
304
+ return current;
305
+ }
@@ -0,0 +1,29 @@
1
+ import type { Duration, RunStatus } from "./types.js";
2
+ export interface EventCondition {
3
+ event: string;
4
+ match?: Record<string, unknown> | ((payload: unknown) => boolean);
5
+ }
6
+ export interface SignalCondition {
7
+ signal: string;
8
+ match?: Record<string, unknown> | ((payload: unknown) => boolean);
9
+ }
10
+ export interface TimeCondition {
11
+ after?: Duration | Date;
12
+ before?: Duration | Date;
13
+ }
14
+ export interface RunStatusCondition {
15
+ run: {
16
+ id: string;
17
+ status: RunStatus[];
18
+ };
19
+ }
20
+ export interface OrCondition {
21
+ or: Condition[];
22
+ }
23
+ export interface AndCondition {
24
+ and: Condition[];
25
+ }
26
+ export type Condition = EventCondition | SignalCondition | TimeCondition | RunStatusCondition | OrCondition | AndCondition;
27
+ export declare const or: (...conditions: Condition[]) => OrCondition;
28
+ export declare const and: (...conditions: Condition[]) => AndCondition;
29
+ //# sourceMappingURL=conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../src/conditions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAErD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAA;CAClE;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAA;CAClE;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;IACvB,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,CAAA;CACzC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,SAAS,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,SAAS,EAAE,CAAA;CACjB;AAED,MAAM,MAAM,SAAS,GACjB,cAAc,GACd,eAAe,GACf,aAAa,GACb,kBAAkB,GAClB,WAAW,GACX,YAAY,CAAA;AAEhB,eAAO,MAAM,EAAE,GAAI,GAAG,YAAY,SAAS,EAAE,KAAG,WAAmC,CAAA;AACnF,eAAO,MAAM,GAAG,GAAI,GAAG,YAAY,SAAS,EAAE,KAAG,YAAqC,CAAA"}
@@ -0,0 +1,5 @@
1
+ // Condition types used in step options (waitFor / cancelIf / skipIf)
2
+ // and in event-filter match expressions.
3
+ // Authoritative contract in docs/sdk-surface.md §4.
4
+ export const or = (...conditions) => ({ or: conditions });
5
+ export const and = (...conditions) => ({ and: conditions });
@@ -0,0 +1,93 @@
1
+ export type Duration = number | `${number}${"ms" | "s" | "m" | "h" | "d" | "w"}`;
2
+ /** Cloudflare Container instance types — see `@voyant-travel/workflows` for the size table. */
3
+ export type MachineType = "lite" | "basic" | "standard-1" | "standard-2" | "standard-3" | "standard-4" | (string & {});
4
+ export type EnvironmentName = "production" | "preview" | "development";
5
+ export type MeterKey = "edgeCpuMs" | "containerSeconds" | "warmSlotHours" | "runCount" | "activeScheduleHours" | "payloadStorageGbHour" | "retentionRunMonths";
6
+ export type BindingDeclaration = {
7
+ type: "d1";
8
+ name: string;
9
+ } | {
10
+ type: "r2";
11
+ name: string;
12
+ } | {
13
+ type: "kv";
14
+ name: string;
15
+ } | {
16
+ type: "queue";
17
+ name: string;
18
+ };
19
+ export interface EnvironmentConfig {
20
+ customDomain?: string;
21
+ }
22
+ export interface RetryPolicy {
23
+ max?: number;
24
+ backoff?: "exponential" | "linear" | "fixed";
25
+ initial?: Duration;
26
+ maxDelay?: Duration;
27
+ }
28
+ export interface BuildExtension {
29
+ name: string;
30
+ /** Open-ended hook surface; each extension defines its own contract. */
31
+ [key: string]: unknown;
32
+ }
33
+ export interface Instrumentation {
34
+ name: string;
35
+ [key: string]: unknown;
36
+ }
37
+ export interface WorkflowsConfig {
38
+ dirs?: string[];
39
+ defaults?: {
40
+ retries?: RetryPolicy;
41
+ timeout?: Duration;
42
+ timezone?: string;
43
+ machine?: MachineType;
44
+ concurrency?: {
45
+ strategy?: "queue" | "cancel-in-progress" | "cancel-newest" | "round-robin";
46
+ };
47
+ };
48
+ containerPool?: {
49
+ defaultMachine?: MachineType;
50
+ maxConcurrency?: number;
51
+ warmPoolSize?: Partial<Record<EnvironmentName, number>>;
52
+ evictionTtl?: Duration;
53
+ perPodConcurrency?: number;
54
+ scaleOutPolicy?: "none" | "onDemand";
55
+ preWarmStrategy?: "onFirstRequest" | "onDeploy";
56
+ };
57
+ build?: {
58
+ extensions?: BuildExtension[];
59
+ defineEnv?: Record<string, string>;
60
+ };
61
+ instrumentations?: Instrumentation[];
62
+ dev?: {
63
+ port?: number;
64
+ preservation?: "smart" | "always" | "never";
65
+ simulateEnvironment?: EnvironmentName;
66
+ };
67
+ billing?: {
68
+ caps?: {
69
+ monthly?: Partial<Record<MeterKey, number>>;
70
+ action?: "hard-stop" | "soft-notify";
71
+ perEnvironment?: Partial<Record<EnvironmentName, {
72
+ monthly?: Partial<Record<MeterKey, number>>;
73
+ }>>;
74
+ };
75
+ };
76
+ versioning?: {
77
+ retireAfter?: Duration;
78
+ onSunset?: "cancel" | "migrate" | "extend";
79
+ sunsetNoticePeriod?: Duration;
80
+ };
81
+ }
82
+ export interface VoyantConfig {
83
+ projectId: string;
84
+ entry: {
85
+ worker: string;
86
+ container?: string;
87
+ };
88
+ environments: Record<EnvironmentName, EnvironmentConfig>;
89
+ bindings: Record<string, BindingDeclaration>;
90
+ workflows?: WorkflowsConfig;
91
+ }
92
+ export declare function defineConfig(config: VoyantConfig): VoyantConfig;
93
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,7 @@
1
+ // @voyant-travel/workflows/config
2
+ //
3
+ // Types and `defineConfig` helper for `voyant.config.ts`.
4
+ // Contract defined in docs/sdk-surface.md §10 and docs/design.md §5.4.3.
5
+ export function defineConfig(config) {
6
+ return config;
7
+ }
@@ -0,0 +1,237 @@
1
+ import type { WorkflowManifest } from "./protocol/index.js";
2
+ import type { ListRunsOptions, Run, RunDetail, RunSummary, TriggerOptions } from "./trigger.js";
3
+ import type { EnvironmentName, WaitpointKind } from "./types.js";
4
+ import type { WorkflowDefinition } from "./workflow.js";
5
+ /**
6
+ * Read-only view of a service container. Step bodies resolve services via
7
+ * `ctx.services.resolve(...)`. The framework's `ModuleContainer`
8
+ * (in `@voyant-travel/core`) satisfies this shape structurally; we don't import
9
+ * it directly to keep `@voyant-travel/workflows` a leaf package.
10
+ */
11
+ export interface ServiceResolver {
12
+ resolve<T>(name: string): T;
13
+ has(name: string): boolean;
14
+ }
15
+ /**
16
+ * Structural shape of an event envelope as ingested by a driver. Matches
17
+ * `EventEnvelope` from `@voyant-travel/core` (`name`, `data`, `metadata?`, `emittedAt`),
18
+ * declared structurally so the SDK package doesn't import core.
19
+ */
20
+ export interface IngestEventEnvelope<TData = unknown> {
21
+ /** Event name in `<resource>.<pastTenseAction>` form. */
22
+ name: string;
23
+ /** Business payload. */
24
+ data: TData;
25
+ /** Optional metadata. `metadata.eventId` is the canonical idempotency seed
26
+ * (a fresh ULID, stamped by the framework's EventBus forwarder). External
27
+ * callers may supply their own. See architecture doc §15.2. */
28
+ metadata?: Record<string, unknown> & {
29
+ eventId?: string;
30
+ };
31
+ /** ISO timestamp string. */
32
+ emittedAt: string;
33
+ }
34
+ /**
35
+ * Minimal logger contract drivers can rely on. Matches the framework logger's
36
+ * call signature without taking a hard dependency on it.
37
+ */
38
+ export type DriverLogger = (level: "debug" | "info" | "warn" | "error", msg: string, data?: object) => void;
39
+ /**
40
+ * Deps the framework injects into a `DriverFactory` at boot. Driver factories
41
+ * close over their environment-specific options (DO bindings, DB pool, etc.)
42
+ * and read framework deps from this argument.
43
+ */
44
+ export interface DriverFactoryDeps {
45
+ /** Read-only view of the framework's `ModuleContainer`. */
46
+ services: ServiceResolver;
47
+ /** Framework logger. */
48
+ logger: DriverLogger;
49
+ /** Injectable clock — defaults to `() => Date.now()`. */
50
+ now?: () => number;
51
+ }
52
+ /**
53
+ * Concrete driver factories return this. `createApp()` calls it once, after
54
+ * the container is built, to obtain the `WorkflowDriver`.
55
+ */
56
+ export type DriverFactory = (deps: DriverFactoryDeps) => WorkflowDriver;
57
+ /**
58
+ * Argument to `driver.ingestEvent(...)`. The framework's EventBus forwarder
59
+ * builds this from the core `EventEnvelope`; external HTTP callers (the
60
+ * optional ingest adapter, voyant-cloud) build it from a wire payload.
61
+ */
62
+ export interface IngestEventArgs {
63
+ environment: EnvironmentName;
64
+ envelope: IngestEventEnvelope;
65
+ /** Optional caller-supplied idempotency override. When absent, the driver
66
+ * derives a key per match from `metadata.eventId` (or a content hash
67
+ * fallback). See architecture doc §15.2. */
68
+ idempotencyKey?: string;
69
+ }
70
+ /** Per-filter outcome from a single `ingestEvent` call. */
71
+ export type IngestMatch = {
72
+ filterId: string;
73
+ targetWorkflowId: string;
74
+ runId: string;
75
+ idempotencyKey: string;
76
+ status: "queued";
77
+ } | {
78
+ filterId: string;
79
+ status: "skipped";
80
+ reason: "where_eval_error" | "input_projection_error" | "input_schema_violation";
81
+ details?: string;
82
+ } | {
83
+ filterId: string;
84
+ targetWorkflowId: string;
85
+ status: "error";
86
+ reason: string;
87
+ };
88
+ export type IngestEventResponse = {
89
+ ok: true;
90
+ eventId: string;
91
+ matches: IngestMatch[];
92
+ } | {
93
+ ok: false;
94
+ reason: "manifest_not_registered" | "environment_mismatch" | "payload_too_large" | "trigger_failed_for_all_matches";
95
+ message?: string;
96
+ };
97
+ /**
98
+ * The mandatory driver contract. Every concrete driver — InMemory, Mode 2
99
+ * (Postgres), Mode 1 (CF edge) — implements all five methods. The compliance
100
+ * test suite (`driver-compliance.test.ts`) is the contract.
101
+ */
102
+ export interface WorkflowDriver {
103
+ /**
104
+ * Idempotent. Same manifest body returns the same `versionId` across calls.
105
+ * Failures are NOT swallowed — `createApp()`'s bootstrap surfaces rejections
106
+ * (see architecture doc §21.22).
107
+ */
108
+ registerManifest(args: {
109
+ environment: EnvironmentName;
110
+ manifest: WorkflowManifest;
111
+ }): Promise<{
112
+ versionId: string;
113
+ }>;
114
+ /**
115
+ * Trigger a workflow run by id or definition handle. Honors
116
+ * `opts.idempotencyKey` for dedup (returns the existing run on conflict).
117
+ */
118
+ trigger<TIn, TOut>(workflow: WorkflowDefinition<TIn, TOut> | string, input: TIn, opts?: TriggerOptions): Promise<Run<TOut>>;
119
+ /**
120
+ * Ingest one event. Synchronously (from the caller's POV) loads the
121
+ * registered manifest, evaluates `where`, projects `input`, and triggers
122
+ * one run per match. See architecture doc §15.
123
+ */
124
+ ingestEvent(args: IngestEventArgs): Promise<IngestEventResponse>;
125
+ /**
126
+ * Read the registered manifest. Used at boot for version-mismatch detection
127
+ * and by the dashboard for filter inspection.
128
+ */
129
+ getManifest(args: {
130
+ environment: EnvironmentName;
131
+ }): Promise<WorkflowManifest | null>;
132
+ /**
133
+ * Optional. Drains in-flight steps, refuses new triggers, awaits time-wheel
134
+ * exit. Default `gracefulMs` is 30_000.
135
+ */
136
+ shutdown?(opts?: {
137
+ gracefulMs?: number;
138
+ }): Promise<void>;
139
+ /**
140
+ * Optional read-side surface. Drivers that can support listings, run detail,
141
+ * and journal streams declare this; consumers (the dashboard) duck-type on
142
+ * `driver.admin`. See architecture doc §6.2.
143
+ */
144
+ admin?: WorkflowAdmin | Partial<WorkflowAdmin>;
145
+ }
146
+ /**
147
+ * Read-side operations. Implemented natively by the Mode 2 driver against
148
+ * Postgres, partially by Mode 1 (single-run reads only — `listRuns` is not
149
+ * implemented in self-host Mode 1; voyant-cloud provides an index layer).
150
+ * See architecture doc §6.2 + §8.3.
151
+ */
152
+ export interface WorkflowAdmin {
153
+ listRuns(opts?: ListRunsOptions): Promise<{
154
+ runs: RunSummary[];
155
+ nextCursor?: string;
156
+ }>;
157
+ getRun(runId: string): Promise<RunDetail | null>;
158
+ cancelRun(runId: string, opts?: {
159
+ reason?: string;
160
+ compensate?: boolean;
161
+ }): Promise<void>;
162
+ /**
163
+ * Subscribe to journal events for a run. The async-iterable shape lets
164
+ * dashboards stream live without polling.
165
+ */
166
+ streamRun(runId: string): AsyncIterable<AdminStreamEvent>;
167
+ }
168
+ /**
169
+ * The admin streaming surface re-uses the protocol's `StreamEvent` for
170
+ * step/waitpoint/log events; this type is its alias to keep the import
171
+ * surface narrow.
172
+ */
173
+ export type AdminStreamEvent = {
174
+ kind: "run.snapshot";
175
+ at: number;
176
+ status: string;
177
+ metadata: Record<string, unknown>;
178
+ } | {
179
+ kind: "step.started";
180
+ at: number;
181
+ stepId: string;
182
+ runtime: "edge" | "node";
183
+ } | {
184
+ kind: "step.ok";
185
+ at: number;
186
+ stepId: string;
187
+ durationMs: number;
188
+ } | {
189
+ kind: "step.err";
190
+ at: number;
191
+ stepId: string;
192
+ error: {
193
+ code: string;
194
+ message: string;
195
+ };
196
+ } | {
197
+ kind: "waitpoint.registered";
198
+ at: number;
199
+ waitpointId: string;
200
+ waitpointKind: WaitpointKind;
201
+ } | {
202
+ kind: "waitpoint.resolved";
203
+ at: number;
204
+ waitpointId: string;
205
+ } | {
206
+ kind: "log";
207
+ at: number;
208
+ level: "info" | "warn" | "error";
209
+ message: string;
210
+ } | {
211
+ kind: "run.finished";
212
+ at: number;
213
+ status: string;
214
+ };
215
+ /**
216
+ * Base class for typed driver errors. Concrete subclasses below; consumers
217
+ * `instanceof` to handle specific cases.
218
+ */
219
+ export declare class WorkflowDriverError extends Error {
220
+ readonly code: string;
221
+ readonly cause?: unknown;
222
+ constructor(code: string, message: string, opts?: {
223
+ cause?: unknown;
224
+ });
225
+ }
226
+ export declare class ManifestNotRegisteredError extends WorkflowDriverError {
227
+ constructor(environment: EnvironmentName);
228
+ }
229
+ export declare class EventTooLargeError extends WorkflowDriverError {
230
+ readonly bytes: number;
231
+ readonly limit: number;
232
+ constructor(bytes: number, limit?: number);
233
+ }
234
+ export declare class EnvironmentMismatchError extends WorkflowDriverError {
235
+ constructor(eventEnv: EnvironmentName, manifestEnv: EnvironmentName);
236
+ }
237
+ //# sourceMappingURL=driver.d.ts.map