@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
@@ -0,0 +1,77 @@
1
+ /** Either a path into the envelope or an inline literal value. */
2
+ export type PathOrLit = {
3
+ path: string;
4
+ } | {
5
+ lit: string | number | boolean | null;
6
+ };
7
+ export type PredicateExpr = {
8
+ eq: [PathOrLit, PathOrLit];
9
+ } | {
10
+ neq: [PathOrLit, PathOrLit];
11
+ } | {
12
+ in: [PathOrLit, PathOrLit[]];
13
+ } | {
14
+ gt: [PathOrLit, PathOrLit];
15
+ } | {
16
+ gte: [PathOrLit, PathOrLit];
17
+ } | {
18
+ lt: [PathOrLit, PathOrLit];
19
+ } | {
20
+ lte: [PathOrLit, PathOrLit];
21
+ } | {
22
+ exists: PathOrLit;
23
+ } | {
24
+ not: PredicateExpr;
25
+ } | {
26
+ and: PredicateExpr[];
27
+ } | {
28
+ or: PredicateExpr[];
29
+ };
30
+ /**
31
+ * Minimal structural envelope the evaluator reads. Matches the standard
32
+ * `EventEnvelope` from `@voyant-travel/core`. Declared structurally here so the
33
+ * SDK package stays a leaf.
34
+ */
35
+ export interface PredicateEnvelope<TData = unknown> {
36
+ name: string;
37
+ data: TData;
38
+ metadata?: Record<string, unknown> | undefined;
39
+ emittedAt: string;
40
+ }
41
+ /**
42
+ * Evaluate a predicate against an event envelope. Returns `true` / `false`.
43
+ * Path resolution against missing keys yields `undefined`, which makes
44
+ * comparison ops `false` (not throw). The evaluator never throws on data
45
+ * mismatches — registration-time linting catches structural errors via
46
+ * {@link validatePredicate}.
47
+ *
48
+ * Throws `PredicateEvalError` only on unexpected shape errors (the predicate
49
+ * itself was constructed wrong, e.g. malformed operator). Drivers catch
50
+ * this and surface it as `IngestMatch.status === "skipped"` with reason
51
+ * `"where_eval_error"`.
52
+ */
53
+ export declare function evaluatePredicate(expr: PredicateExpr, envelope: PredicateEnvelope): boolean;
54
+ /**
55
+ * Resolve a path string against an envelope. Public so consumers (input
56
+ * mapper, manifest builder) can share the same path semantics without
57
+ * re-implementing them.
58
+ *
59
+ * Path syntax: dot-separated; `[N]` for array index; missing intermediate
60
+ * keys produce `undefined`. Roots: `data`, `metadata`, `name`, `emittedAt`.
61
+ *
62
+ * Returns `undefined` on any shape mismatch — that's how runtime evaluation
63
+ * stays no-throw.
64
+ */
65
+ export declare function resolvePath(path: string, envelope: PredicateEnvelope): unknown;
66
+ export interface PredicateValidationResult {
67
+ ok: boolean;
68
+ errors: string[];
69
+ }
70
+ /**
71
+ * Static structural check on a `PredicateExpr`. Catches path roots that
72
+ * aren't `data`/`metadata`/`name`/`emittedAt`, type mismatches on
73
+ * comparison operators (number vs string lhs/rhs), and malformed grammars.
74
+ * Surfaced at `trigger.on()` registration so authoring errors fail fast.
75
+ */
76
+ export declare function validatePredicate(expr: PredicateExpr): PredicateValidationResult;
77
+ //# sourceMappingURL=predicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicate.d.ts","sourceRoot":"","sources":["../../src/events/predicate.ts"],"names":[],"mappings":"AAkBA,kEAAkE;AAClE,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;CAAE,CAAA;AAIpF,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CAAE,GAC9B;IAAE,GAAG,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAA;CAAE,GAChC;IAAE,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CAAE,GAC9B;IAAE,GAAG,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CAAE,GAC9B;IAAE,GAAG,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,GAAG,EAAE,aAAa,CAAA;CAAE,GACtB;IAAE,GAAG,EAAE,aAAa,EAAE,CAAA;CAAE,GACxB;IAAE,EAAE,EAAE,aAAa,EAAE,CAAA;CAAE,CAAA;AAI3B;;;;GAIG;AACH,MAAM,WAAW,iBAAiB,CAAC,KAAK,GAAG,OAAO;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,KAAK,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IAC9C,SAAS,EAAE,MAAM,CAAA;CAClB;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAiC3F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAkC9E;AAID,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,yBAAyB,CAIhF"}
@@ -0,0 +1,347 @@
1
+ // Predicate DSL — the structured `where` filter on EventFilterDeclaration.
2
+ //
3
+ // Closed grammar of 12 operators, evaluated against the standard
4
+ // EventEnvelope shape (`data`, `metadata`, `name`, `emittedAt`). No `eval`,
5
+ // no Function constructor, no callback-via-network — everything is data.
6
+ //
7
+ // Authoring shape (from a module's source):
8
+ //
9
+ // trigger.on("promotion.changed", {
10
+ // target: bulkReindexProducts,
11
+ // where: { eq: [{ path: "data.affected.kind" }, { lit: "all" }] },
12
+ // input: { ... },
13
+ // })
14
+ //
15
+ // Architecture: docs/architecture/workflows-runtime-architecture.md §13.1.
16
+ // ---- Public API ----
17
+ /**
18
+ * Evaluate a predicate against an event envelope. Returns `true` / `false`.
19
+ * Path resolution against missing keys yields `undefined`, which makes
20
+ * comparison ops `false` (not throw). The evaluator never throws on data
21
+ * mismatches — registration-time linting catches structural errors via
22
+ * {@link validatePredicate}.
23
+ *
24
+ * Throws `PredicateEvalError` only on unexpected shape errors (the predicate
25
+ * itself was constructed wrong, e.g. malformed operator). Drivers catch
26
+ * this and surface it as `IngestMatch.status === "skipped"` with reason
27
+ * `"where_eval_error"`.
28
+ */
29
+ export function evaluatePredicate(expr, envelope) {
30
+ if ("eq" in expr) {
31
+ return strictEquals(resolveSide(expr.eq[0], envelope), resolveSide(expr.eq[1], envelope));
32
+ }
33
+ if ("neq" in expr) {
34
+ return !strictEquals(resolveSide(expr.neq[0], envelope), resolveSide(expr.neq[1], envelope));
35
+ }
36
+ if ("in" in expr) {
37
+ const lhs = resolveSide(expr.in[0], envelope);
38
+ const rhs = expr.in[1].map((item) => resolveSide(item, envelope));
39
+ return rhs.some((candidate) => strictEquals(lhs, candidate));
40
+ }
41
+ if ("gt" in expr)
42
+ return compareTwo(expr.gt, envelope, ">");
43
+ if ("gte" in expr)
44
+ return compareTwo(expr.gte, envelope, ">=");
45
+ if ("lt" in expr)
46
+ return compareTwo(expr.lt, envelope, "<");
47
+ if ("lte" in expr)
48
+ return compareTwo(expr.lte, envelope, "<=");
49
+ if ("exists" in expr) {
50
+ return resolveSide(expr.exists, envelope) !== undefined;
51
+ }
52
+ if ("not" in expr)
53
+ return !evaluatePredicate(expr.not, envelope);
54
+ if ("and" in expr) {
55
+ if (!Array.isArray(expr.and)) {
56
+ throw new PredicateEvalError("`and` clause must be an array of predicates");
57
+ }
58
+ return expr.and.every((sub) => evaluatePredicate(sub, envelope));
59
+ }
60
+ if ("or" in expr) {
61
+ if (!Array.isArray(expr.or)) {
62
+ throw new PredicateEvalError("`or` clause must be an array of predicates");
63
+ }
64
+ return expr.or.some((sub) => evaluatePredicate(sub, envelope));
65
+ }
66
+ throw new PredicateEvalError(`unknown predicate operator: ${stringify(expr)}`);
67
+ }
68
+ /**
69
+ * Resolve a path string against an envelope. Public so consumers (input
70
+ * mapper, manifest builder) can share the same path semantics without
71
+ * re-implementing them.
72
+ *
73
+ * Path syntax: dot-separated; `[N]` for array index; missing intermediate
74
+ * keys produce `undefined`. Roots: `data`, `metadata`, `name`, `emittedAt`.
75
+ *
76
+ * Returns `undefined` on any shape mismatch — that's how runtime evaluation
77
+ * stays no-throw.
78
+ */
79
+ export function resolvePath(path, envelope) {
80
+ const segments = parsePath(path);
81
+ if (segments.length === 0)
82
+ return undefined;
83
+ const [root, ...rest] = segments;
84
+ let value;
85
+ switch (root) {
86
+ case "name":
87
+ value = envelope.name;
88
+ break;
89
+ case "emittedAt":
90
+ value = envelope.emittedAt;
91
+ break;
92
+ case "data":
93
+ value = envelope.data;
94
+ break;
95
+ case "metadata":
96
+ value = envelope.metadata;
97
+ break;
98
+ default:
99
+ // Unknown roots evaluate to undefined at runtime. Registration-time
100
+ // linter surfaces this as a structural error so callers see it earlier.
101
+ return undefined;
102
+ }
103
+ for (const segment of rest) {
104
+ if (value === undefined || value === null)
105
+ return undefined;
106
+ if (typeof segment === "number") {
107
+ if (!Array.isArray(value))
108
+ return undefined;
109
+ value = value[segment];
110
+ }
111
+ else {
112
+ if (typeof value !== "object")
113
+ return undefined;
114
+ value = value[segment];
115
+ }
116
+ }
117
+ return value;
118
+ }
119
+ /**
120
+ * Static structural check on a `PredicateExpr`. Catches path roots that
121
+ * aren't `data`/`metadata`/`name`/`emittedAt`, type mismatches on
122
+ * comparison operators (number vs string lhs/rhs), and malformed grammars.
123
+ * Surfaced at `trigger.on()` registration so authoring errors fail fast.
124
+ */
125
+ export function validatePredicate(expr) {
126
+ const errors = [];
127
+ walk(expr, errors, []);
128
+ return { ok: errors.length === 0, errors };
129
+ }
130
+ function walk(expr, errors, path) {
131
+ if (typeof expr !== "object" || expr === null) {
132
+ errors.push(`${pathLabel(path)}: predicate must be an object, got ${typeof expr}`);
133
+ return;
134
+ }
135
+ const keys = Object.keys(expr);
136
+ if (keys.length !== 1) {
137
+ errors.push(`${pathLabel(path)}: a predicate object must have exactly one operator key, got ${keys.length} (${keys.join(", ")})`);
138
+ return;
139
+ }
140
+ const op = keys[0];
141
+ switch (op) {
142
+ case "eq":
143
+ case "neq":
144
+ case "gt":
145
+ case "gte":
146
+ case "lt":
147
+ case "lte": {
148
+ const raw = expr[op];
149
+ if (!Array.isArray(raw) || raw.length !== 2) {
150
+ errors.push(`${pathLabel([...path, op])}: expected [lhs, rhs] tuple`);
151
+ return;
152
+ }
153
+ const sides = raw;
154
+ validateSide(sides[0], errors, [...path, op, "0"]);
155
+ validateSide(sides[1], errors, [...path, op, "1"]);
156
+ // Type-sanity for ordered comparisons: both literals must be the same numeric/string flavor.
157
+ if (op !== "eq" && op !== "neq") {
158
+ const lhsLit = sideLitType(sides[0]);
159
+ const rhsLit = sideLitType(sides[1]);
160
+ if (lhsLit !== "unknown" &&
161
+ rhsLit !== "unknown" &&
162
+ lhsLit !== rhsLit &&
163
+ (lhsLit === "number" || lhsLit === "string")) {
164
+ errors.push(`${pathLabel([...path, op])}: ordered comparison sides must agree on type (got ${lhsLit} vs ${rhsLit})`);
165
+ }
166
+ }
167
+ return;
168
+ }
169
+ case "in": {
170
+ const tuple = expr.in;
171
+ if (!Array.isArray(tuple) || tuple.length !== 2) {
172
+ errors.push(`${pathLabel([...path, "in"])}: expected [lhs, rhs[]] tuple`);
173
+ return;
174
+ }
175
+ validateSide(tuple[0], errors, [...path, "in", "0"]);
176
+ if (!Array.isArray(tuple[1])) {
177
+ errors.push(`${pathLabel([...path, "in", "1"])}: rhs must be an array of paths/literals`);
178
+ return;
179
+ }
180
+ for (let i = 0; i < tuple[1].length; i++) {
181
+ const s = tuple[1][i];
182
+ validateSide(s, errors, [...path, "in", "1", String(i)]);
183
+ }
184
+ return;
185
+ }
186
+ case "exists":
187
+ validateSide(expr.exists, errors, [...path, "exists"]);
188
+ return;
189
+ case "not":
190
+ walk(expr.not, errors, [...path, "not"]);
191
+ return;
192
+ case "and":
193
+ case "or": {
194
+ const raw = expr[op];
195
+ if (!Array.isArray(raw)) {
196
+ errors.push(`${pathLabel([...path, op])}: ${op} must be an array of predicates`);
197
+ return;
198
+ }
199
+ const arr = raw;
200
+ for (let i = 0; i < arr.length; i++) {
201
+ const sub = arr[i];
202
+ walk(sub, errors, [...path, op, String(i)]);
203
+ }
204
+ return;
205
+ }
206
+ default:
207
+ errors.push(`${pathLabel(path)}: unknown predicate operator "${String(op)}"`);
208
+ }
209
+ }
210
+ function validateSide(side, errors, path) {
211
+ if (typeof side !== "object" || side === null) {
212
+ errors.push(`${pathLabel(path)}: expected { path } or { lit }, got ${typeof side}`);
213
+ return;
214
+ }
215
+ if ("path" in side) {
216
+ if (typeof side.path !== "string" || side.path.length === 0) {
217
+ errors.push(`${pathLabel(path)}: "path" must be a non-empty string`);
218
+ return;
219
+ }
220
+ const root = parsePath(side.path)[0];
221
+ if (root !== "data" && root !== "metadata" && root !== "name" && root !== "emittedAt") {
222
+ errors.push(`${pathLabel(path)}: path root "${String(root)}" is not one of data | metadata | name | emittedAt`);
223
+ }
224
+ return;
225
+ }
226
+ if ("lit" in side) {
227
+ const t = typeof side.lit;
228
+ if (t !== "string" && t !== "number" && t !== "boolean" && side.lit !== null) {
229
+ errors.push(`${pathLabel(path)}: lit must be string | number | boolean | null`);
230
+ }
231
+ return;
232
+ }
233
+ errors.push(`${pathLabel(path)}: must specify "path" or "lit"`);
234
+ }
235
+ // ---- Internal helpers ----
236
+ class PredicateEvalError extends Error {
237
+ constructor(message) {
238
+ super(message);
239
+ this.name = "PredicateEvalError";
240
+ }
241
+ }
242
+ function resolveSide(side, envelope) {
243
+ if ("lit" in side)
244
+ return side.lit;
245
+ if ("path" in side)
246
+ return resolvePath(side.path, envelope);
247
+ return undefined;
248
+ }
249
+ function strictEquals(a, b) {
250
+ if (a === undefined || b === undefined)
251
+ return false;
252
+ if (a === null && b === null)
253
+ return true;
254
+ if (a === null || b === null)
255
+ return false;
256
+ if (typeof a !== typeof b)
257
+ return false;
258
+ if (typeof a === "object") {
259
+ // Strict equality only for primitives + null. Object equality is not
260
+ // supported in v1; users who need it project specific paths to compare.
261
+ return false;
262
+ }
263
+ return a === b;
264
+ }
265
+ function compareTwo(sides, envelope, op) {
266
+ const lhs = resolveSide(sides[0], envelope);
267
+ const rhs = resolveSide(sides[1], envelope);
268
+ if (lhs === undefined || rhs === undefined)
269
+ return false;
270
+ if (typeof lhs !== typeof rhs)
271
+ return false;
272
+ if (typeof lhs !== "number" && typeof lhs !== "string")
273
+ return false;
274
+ switch (op) {
275
+ case ">":
276
+ return lhs > rhs;
277
+ case ">=":
278
+ return lhs >= rhs;
279
+ case "<":
280
+ return lhs < rhs;
281
+ case "<=":
282
+ return lhs <= rhs;
283
+ }
284
+ }
285
+ function sideLitType(side) {
286
+ if ("lit" in side) {
287
+ if (side.lit === null)
288
+ return "null";
289
+ const t = typeof side.lit;
290
+ if (t === "number" || t === "string" || t === "boolean")
291
+ return t;
292
+ }
293
+ return "unknown";
294
+ }
295
+ /**
296
+ * Parse a dot-and-bracket path into segments. `data.items[0].id` becomes
297
+ * `["data", "items", 0, "id"]`. Numeric segments inside `[N]` are returned
298
+ * as numbers; everything else as strings. Malformed input yields `[]`.
299
+ */
300
+ function parsePath(path) {
301
+ if (typeof path !== "string" || path.length === 0)
302
+ return [];
303
+ const segments = [];
304
+ let i = 0;
305
+ let buf = "";
306
+ const flushBuf = () => {
307
+ if (buf.length > 0) {
308
+ segments.push(buf);
309
+ buf = "";
310
+ }
311
+ };
312
+ while (i < path.length) {
313
+ const c = path[i];
314
+ if (c === ".") {
315
+ flushBuf();
316
+ i++;
317
+ continue;
318
+ }
319
+ if (c === "[") {
320
+ flushBuf();
321
+ const end = path.indexOf("]", i);
322
+ if (end === -1)
323
+ return [];
324
+ const idx = Number(path.slice(i + 1, end));
325
+ if (!Number.isInteger(idx) || idx < 0)
326
+ return [];
327
+ segments.push(idx);
328
+ i = end + 1;
329
+ continue;
330
+ }
331
+ buf += c;
332
+ i++;
333
+ }
334
+ flushBuf();
335
+ return segments;
336
+ }
337
+ function pathLabel(path) {
338
+ return path.length === 0 ? "(root)" : path.join(".");
339
+ }
340
+ function stringify(value) {
341
+ try {
342
+ return JSON.stringify(value);
343
+ }
344
+ catch {
345
+ return String(value);
346
+ }
347
+ }
@@ -0,0 +1,37 @@
1
+ import type { EventFilterManifestEntry } from "../protocol/index.js";
2
+ import type { EventFilterDeclaration } from "../trigger.js";
3
+ /**
4
+ * Internal/runtime form of a registered event filter. Carries:
5
+ * - The serializable manifest entry (sent to drivers, persisted in
6
+ * manifest stores, evaluated by the event router).
7
+ * - A debug-only structural copy of the original declaration. Not
8
+ * serialized; used by the dashboard / dev mode for human-readable
9
+ * filter inspection.
10
+ *
11
+ * Concrete `WorkflowDefinition` from `workflow.ts` satisfies the structural
12
+ * `target` shape via TypeScript compat.
13
+ */
14
+ export interface EventFilterRuntimeEntry {
15
+ readonly id: string;
16
+ readonly eventType: string;
17
+ readonly manifest: EventFilterManifestEntry;
18
+ /** Debug-only — non-serializable. */
19
+ readonly declaration: EventFilterDeclaration<unknown>;
20
+ /** Workflow id this filter targets, for quick lookup. */
21
+ readonly targetWorkflowId: string;
22
+ }
23
+ interface EventFilterRegistry {
24
+ add(entry: EventFilterRuntimeEntry): void;
25
+ list(): EventFilterRuntimeEntry[];
26
+ /** Reset to empty. Test-only — production code never calls this. */
27
+ reset(): void;
28
+ }
29
+ /** Process-local event-filter registry. Singleton per realm. */
30
+ export declare function getEventFilterRegistry(): EventFilterRegistry;
31
+ /**
32
+ * Internal: clear every registered filter. Used by tests that import the
33
+ * SDK and need a clean slate between cases. Not part of the public API.
34
+ */
35
+ export declare function __resetEventFilterRegistry(): void;
36
+ export {};
37
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/events/registry.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAI3D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAA;IAC3C,qCAAqC;IACrC,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAA;IACrD,yDAAyD;IACzD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC;AAED,UAAU,mBAAmB;IAC3B,GAAG,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAA;IACzC,IAAI,IAAI,uBAAuB,EAAE,CAAA;IACjC,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAA;CACd;AA8BD,gEAAgE;AAChE,wBAAgB,sBAAsB,IAAI,mBAAmB,CAE5D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
@@ -0,0 +1,47 @@
1
+ // Process-local registry for event-filter runtime entries.
2
+ //
3
+ // `trigger.on(eventName, filter)` adds an entry here at module-load time.
4
+ // `createApp()` (PR4) walks `getEventFilterRegistry().list()` to build a
5
+ // manifest, hand it to the configured driver, and install the EventBus
6
+ // forwarder.
7
+ //
8
+ // Backed by `globalThis` so bundles that inline their own copy of
9
+ // `@voyant-travel/workflows` still share the registry with the loader's copy
10
+ // — same pattern `getWorkflow()` uses for the workflow registry.
11
+ //
12
+ // Architecture: docs/architecture/workflows-runtime-architecture.md §12.
13
+ const REGISTRY_KEY = "__voyantEventFilterRegistry";
14
+ const globalRef = globalThis;
15
+ const REGISTRY = globalRef[REGISTRY_KEY] ?? new Map();
16
+ globalRef[REGISTRY_KEY] = REGISTRY;
17
+ const registry = {
18
+ add(entry) {
19
+ if (REGISTRY.has(entry.id)) {
20
+ // Same id implies same canonicalized declaration. HMR re-imports
21
+ // and re-evaluations of the same module file land here; replace
22
+ // (overwrite is harmless since the entry is content-addressed).
23
+ // For genuine duplicates from different declarations, the canonical
24
+ // hash would differ, so different ids would result.
25
+ REGISTRY.set(entry.id, entry);
26
+ return;
27
+ }
28
+ REGISTRY.set(entry.id, entry);
29
+ },
30
+ list() {
31
+ return [...REGISTRY.values()];
32
+ },
33
+ reset() {
34
+ REGISTRY.clear();
35
+ },
36
+ };
37
+ /** Process-local event-filter registry. Singleton per realm. */
38
+ export function getEventFilterRegistry() {
39
+ return registry;
40
+ }
41
+ /**
42
+ * Internal: clear every registered filter. Used by tests that import the
43
+ * SDK and need a clean slate between cases. Not part of the public API.
44
+ */
45
+ export function __resetEventFilterRegistry() {
46
+ registry.reset();
47
+ }
@@ -0,0 +1,114 @@
1
+ import { type ExecuteWorkflowStepRequest, type ExecuteWorkflowStepResponse, executeWorkflowStep, type StepRunner } from "../runtime/executor.js";
2
+ export type { StepJournalEntry } from "../runtime/journal.js";
3
+ export type { ExecuteWorkflowStepRequest, ExecuteWorkflowStepResponse, StepRunner };
4
+ export { executeWorkflowStep };
5
+ import { type ProtocolVersion, type WorkflowActivationMetadata } from "../protocol/index.js";
6
+ import type { RateLimiter } from "../rate-limit/index.js";
7
+ import type { JournalSlice } from "../runtime/journal.js";
8
+ import type { RunTrigger } from "../types.js";
9
+ export interface StepHandlerDeps {
10
+ /**
11
+ * Optional. Called before parsing the body. Should throw / reject
12
+ * if the request is not from a trusted orchestrator. In production
13
+ * this verifies the `X-Voyant-Dispatch-Auth` HMAC against a public
14
+ * key embedded by `voyant build`.
15
+ */
16
+ verifyRequest?: (req: Request) => void | Promise<void>;
17
+ /** Injectable clock. Defaults to Date.now. */
18
+ now?: () => number;
19
+ /** Optional structured logger. */
20
+ logger?: (level: "info" | "warn" | "error", msg: string, data?: object) => void;
21
+ /**
22
+ * Rate limiter shared across step invocations. Required when any
23
+ * registered workflow declares `options.rateLimit` on a step; see
24
+ * `createInMemoryRateLimiter` in `@voyant-travel/workflows/rate-limit` for
25
+ * the reference impl. One instance per Worker process is the
26
+ * intended cardinality — state is kept in the limiter's closure.
27
+ */
28
+ rateLimiter?: RateLimiter;
29
+ /**
30
+ * Runner for steps declared with `options.runtime === "node"`.
31
+ * Leave unset for handlers that only run edge steps; any node step
32
+ * will then fail with `NODE_RUNTIME_UNAVAILABLE`.
33
+ *
34
+ * Typical impl dispatches to a separate sandboxed context:
35
+ * - Local dev: an in-process passthrough (same Node process).
36
+ * - CF production: a Cloudflare Container binding, via
37
+ * `createCfContainerStepRunner` from `@voyant-travel/workflows-orchestrator-cloudflare`.
38
+ *
39
+ * This is bring-your-own because the right dispatch shape depends on
40
+ * the target runtime; the executor only cares that a runner exists.
41
+ */
42
+ nodeStepRunner?: StepRunner;
43
+ /**
44
+ * Read-only service resolver, surfaced to step bodies as `ctx.services`.
45
+ * The framework's `createApp()` wires this from its `ModuleContainer`;
46
+ * raw orchestrator harnesses (tests, ad-hoc scripts) typically leave
47
+ * it unset, in which case `ctx.services.resolve(...)` throws with a
48
+ * clear message. See architecture doc §11.
49
+ */
50
+ services?: import("../driver.js").ServiceResolver;
51
+ }
52
+ /** The HTTP request body the orchestrator sends. */
53
+ export interface WorkflowStepRequest {
54
+ protocolVersion: ProtocolVersion;
55
+ runId: string;
56
+ workflowId: string;
57
+ workflowVersion: string;
58
+ invocationCount: number;
59
+ input: unknown;
60
+ journal: JournalSlice;
61
+ environment: "production" | "preview" | "development";
62
+ deadline: number;
63
+ tenantMeta: {
64
+ tenantId: string;
65
+ projectId: string;
66
+ organizationId: string;
67
+ projectSlug?: string;
68
+ organizationSlug?: string;
69
+ };
70
+ runMeta: {
71
+ number: number;
72
+ attempt: number;
73
+ triggeredBy: RunTrigger;
74
+ tags: string[];
75
+ startedAt: number;
76
+ };
77
+ activation?: WorkflowActivationMetadata;
78
+ }
79
+ /** The JSON response body the tenant returns. */
80
+ export type WorkflowStepResponse = ExecuteWorkflowStepResponse;
81
+ /** Error-response envelope used for HTTP 4xx/5xx. */
82
+ export interface StepHandlerError {
83
+ error: string;
84
+ message: string;
85
+ details?: unknown;
86
+ }
87
+ export { type BuildResumeStepRequestInput, type BuildResumeStepRequestResult, buildResumeStepRequest, } from "./resume.js";
88
+ /** Build an HTTP fetch-style handler. */
89
+ export declare function createStepHandler(deps?: StepHandlerDeps): (req: Request) => Promise<Response>;
90
+ /** Per-invocation options available to callers of the transport-free entry point. */
91
+ export interface StepRequestOptions {
92
+ /** AbortSignal forwarded to `ctx.signal` inside the step body. */
93
+ signal?: AbortSignal;
94
+ /**
95
+ * Fires synchronously from `ctx.stream.*` as each chunk is produced.
96
+ * Used by orchestrators that want to broadcast chunks live
97
+ * (dashboards, queues) before the invocation returns.
98
+ */
99
+ onStreamChunk?: (chunk: import("../runtime/executor.js").StreamChunk) => void;
100
+ }
101
+ /**
102
+ * Transport-free entry point. Callers that already parsed the body
103
+ * (e.g. local orchestrator in-memory, tests) invoke this directly.
104
+ * Returns either the step response or an error envelope with the HTTP
105
+ * status the caller should use.
106
+ */
107
+ export declare function handleStepRequest(raw: unknown, deps?: StepHandlerDeps, opts?: StepRequestOptions): Promise<{
108
+ status: number;
109
+ body: WorkflowStepResponse;
110
+ } | {
111
+ status: number;
112
+ body: StepHandlerError;
113
+ }>;
114
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handler/index.ts"],"names":[],"mappings":"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"}