@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.
- package/LICENSE +201 -0
- package/NOTICE +52 -0
- package/README.md +79 -0
- package/dist/auth/index.d.ts +125 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +352 -0
- package/dist/bindings.d.ts +119 -0
- package/dist/bindings.d.ts.map +1 -0
- package/dist/bindings.js +19 -0
- package/dist/client.d.ts +135 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +305 -0
- package/dist/conditions.d.ts +29 -0
- package/dist/conditions.d.ts.map +1 -0
- package/dist/conditions.js +5 -0
- package/dist/config.d.ts +93 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +7 -0
- package/dist/driver.d.ts +237 -0
- package/dist/driver.d.ts.map +1 -0
- package/dist/driver.js +53 -0
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +76 -0
- package/dist/events/compile.d.ts +34 -0
- package/dist/events/compile.d.ts.map +1 -0
- package/dist/events/compile.js +204 -0
- package/dist/events/index.d.ts +8 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +11 -0
- package/dist/events/input-mapper.d.ts +24 -0
- package/dist/events/input-mapper.d.ts.map +1 -0
- package/dist/events/input-mapper.js +169 -0
- package/dist/events/manifest-builder.d.ts +42 -0
- package/dist/events/manifest-builder.d.ts.map +1 -0
- package/dist/events/manifest-builder.js +313 -0
- package/dist/events/payload-hash.d.ts +46 -0
- package/dist/events/payload-hash.d.ts.map +1 -0
- package/dist/events/payload-hash.js +98 -0
- package/dist/events/predicate.d.ts +77 -0
- package/dist/events/predicate.d.ts.map +1 -0
- package/dist/events/predicate.js +347 -0
- package/dist/events/registry.d.ts +37 -0
- package/dist/events/registry.d.ts.map +1 -0
- package/dist/events/registry.js +47 -0
- package/dist/handler/index.d.ts +114 -0
- package/dist/handler/index.d.ts.map +1 -0
- package/dist/handler/index.js +267 -0
- package/dist/handler/resume.d.ts +41 -0
- package/dist/handler/resume.d.ts.map +1 -0
- package/dist/handler/resume.js +44 -0
- package/dist/http-ingest.d.ts +54 -0
- package/dist/http-ingest.d.ts.map +1 -0
- package/dist/http-ingest.js +214 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/protocol/index.d.ts +345 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +110 -0
- package/dist/rate-limit/index.d.ts +40 -0
- package/dist/rate-limit/index.d.ts.map +1 -0
- package/dist/rate-limit/index.js +139 -0
- package/dist/runtime/ctx.d.ts +111 -0
- package/dist/runtime/ctx.d.ts.map +1 -0
- package/dist/runtime/ctx.js +624 -0
- package/dist/runtime/determinism.d.ts +19 -0
- package/dist/runtime/determinism.d.ts.map +1 -0
- package/dist/runtime/determinism.js +61 -0
- package/dist/runtime/errors.d.ts +21 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +45 -0
- package/dist/runtime/executor.d.ts +166 -0
- package/dist/runtime/executor.d.ts.map +1 -0
- package/dist/runtime/executor.js +226 -0
- package/dist/runtime/journal.d.ts +56 -0
- package/dist/runtime/journal.d.ts.map +1 -0
- package/dist/runtime/journal.js +28 -0
- package/dist/testing/index.d.ts +117 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +599 -0
- package/dist/trigger.d.ts +37 -0
- package/dist/trigger.d.ts.map +1 -0
- package/dist/trigger.js +11 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/workflow.d.ts +222 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +55 -0
- package/package.json +120 -0
- package/src/auth/index.ts +398 -0
- package/src/bindings.ts +135 -0
- package/src/client.ts +498 -0
- package/src/conditions.ts +43 -0
- package/src/config.ts +114 -0
- package/src/driver.ts +277 -0
- package/src/errors.ts +109 -0
- package/src/events/compile.ts +268 -0
- package/src/events/index.ts +42 -0
- package/src/events/input-mapper.ts +201 -0
- package/src/events/manifest-builder.ts +372 -0
- package/src/events/payload-hash.ts +110 -0
- package/src/events/predicate.ts +390 -0
- package/src/events/registry.ts +86 -0
- package/src/handler/index.ts +413 -0
- package/src/handler/resume.ts +100 -0
- package/src/http-ingest.ts +299 -0
- package/src/index.ts +18 -0
- package/src/protocol/index.ts +483 -0
- package/src/rate-limit/index.ts +181 -0
- package/src/runtime/ctx.ts +876 -0
- package/src/runtime/determinism.ts +75 -0
- package/src/runtime/errors.ts +58 -0
- package/src/runtime/executor.ts +442 -0
- package/src/runtime/journal.ts +80 -0
- package/src/testing/index.ts +796 -0
- package/src/trigger.ts +63 -0
- package/src/types.ts +80 -0
- 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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"}
|