@glubean/sdk 0.3.2 → 0.5.0
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/dist/contract-core.d.ts +15 -7
- package/dist/contract-core.d.ts.map +1 -1
- package/dist/contract-core.js +632 -150
- package/dist/contract-core.js.map +1 -1
- package/dist/contract-flow-condition.d.ts +229 -0
- package/dist/contract-flow-condition.d.ts.map +1 -0
- package/dist/contract-flow-condition.js +457 -0
- package/dist/contract-flow-condition.js.map +1 -0
- package/dist/contract-flow-poll.d.ts +157 -0
- package/dist/contract-flow-poll.d.ts.map +1 -0
- package/dist/contract-flow-poll.js +223 -0
- package/dist/contract-flow-poll.js.map +1 -0
- package/dist/contract-http/adapter.d.ts.map +1 -1
- package/dist/contract-http/adapter.js +23 -0
- package/dist/contract-http/adapter.js.map +1 -1
- package/dist/contract-http/types.d.ts +9 -0
- package/dist/contract-http/types.d.ts.map +1 -1
- package/dist/contract-types.d.ts +300 -21
- package/dist/contract-types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/test/builder.d.ts +28 -1
- package/dist/test/builder.d.ts.map +1 -1
- package/dist/test/builder.js +194 -4
- package/dist/test/builder.js.map +1 -1
- package/dist/types.d.ts +123 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conditional branching — predicate foundation (Phase 1).
|
|
3
|
+
*
|
|
4
|
+
* The declarative (L2) predicate layer for `flow().condition` / `switchOn` /
|
|
5
|
+
* `switchCond` (design: internal/40-discovery/proposals/contract-flow-condition.md).
|
|
6
|
+
*
|
|
7
|
+
* A predicate is built ONLY through `predicateScope(...)` (`when` / `all` / `any`
|
|
8
|
+
* / `not`) — never hand-authored — so every node is:
|
|
9
|
+
* - **branded** (unforgeable: a module-private symbol users can't set), so a
|
|
10
|
+
* plain object literal is not assignable where a `BranchPredicate` is expected;
|
|
11
|
+
* - **path-extracted at construction** via the strict lens Proxy, so runtime
|
|
12
|
+
* evaluation reads a captured path (safe traversal, never re-invokes the lens);
|
|
13
|
+
* - **gated**: the lens must be a single member-access chain (no calls / ternary
|
|
14
|
+
* / operators / free-variable reads) — the projection guarantee depends on it;
|
|
15
|
+
* - **frozen** (deeply), so it can't be mutated after the purity checks ran.
|
|
16
|
+
*
|
|
17
|
+
* This file is the L2 declarative tier only. Runtime branch nodes, the builder
|
|
18
|
+
* surface, and the opaque (L1/L0) tiers land in later phases.
|
|
19
|
+
*/
|
|
20
|
+
import { extractSelectorPath, LensPurityError } from "./contract-core.js";
|
|
21
|
+
// Unforgeable brand: a module-private symbol attached (non-enumerable) to every
|
|
22
|
+
// node produced by `when`/`all`/`any`/`not`. It is a REAL runtime symbol (not a
|
|
23
|
+
// type-only `declare const`), so `assertL2Predicate` can reject a hand-authored
|
|
24
|
+
// declarative object — which never went through the selector source / strict
|
|
25
|
+
// Proxy gate — even from JS / `as any` callers. Not exported, so unforgeable.
|
|
26
|
+
const PREDICATE_BRAND = Symbol("glubean.branch-predicate");
|
|
27
|
+
// --- P0 single-selector source gate -----------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Reject any lens that is not a single member-access chain off its one
|
|
30
|
+
* parameter (optional chaining allowed): `s => s.a.b`, `s => s.a?.b`.
|
|
31
|
+
*
|
|
32
|
+
* The strict lens Proxy already throws on method calls / `new` / arithmetic
|
|
33
|
+
* (via coercion), but it CANNOT see a pure ternary (`s.flag ? s.a : s.b` —
|
|
34
|
+
* `ToBoolean` on the proxy object never traps) or a free-variable / `Date.now()`
|
|
35
|
+
* read that bypasses the state entirely. This source check closes both: the
|
|
36
|
+
* projected path is then guaranteed to match what runs. (Full AST analysis is
|
|
37
|
+
* a future P1 enrichment; this string check is the P0 gate.)
|
|
38
|
+
*/
|
|
39
|
+
export function assertSelectorSource(fn) {
|
|
40
|
+
const src = fn.toString().trim();
|
|
41
|
+
const arrowAt = src.indexOf("=>");
|
|
42
|
+
if (arrowAt < 0) {
|
|
43
|
+
throw new LensPurityError("lens", "predicate lens must be an arrow function");
|
|
44
|
+
}
|
|
45
|
+
const paramSrc = src.slice(0, arrowAt).trim();
|
|
46
|
+
const pm = paramSrc.match(/^\(?\s*([A-Za-z_$][\w$]*)\s*\)?$/);
|
|
47
|
+
if (!pm) {
|
|
48
|
+
throw new LensPurityError("lens", `predicate lens must be a single-parameter arrow (no async, no destructuring); got "${paramSrc} =>"`);
|
|
49
|
+
}
|
|
50
|
+
const param = pm[1];
|
|
51
|
+
let body = src.slice(arrowAt + 2).trim();
|
|
52
|
+
if (body.startsWith("{")) {
|
|
53
|
+
const bm = body.match(/^\{\s*return\s+([\s\S]+?);?\s*\}$/);
|
|
54
|
+
if (!bm) {
|
|
55
|
+
throw new LensPurityError("lens", "predicate lens with a block body must be a single `return <member chain>`");
|
|
56
|
+
}
|
|
57
|
+
body = bm[1].trim();
|
|
58
|
+
}
|
|
59
|
+
// strip balanced wrapping parens
|
|
60
|
+
while (body.startsWith("(") && body.endsWith(")"))
|
|
61
|
+
body = body.slice(1, -1).trim();
|
|
62
|
+
const escaped = param.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
63
|
+
const chain = new RegExp(`^${escaped}(?:\\??\\.[A-Za-z_$][\\w$]*)+$`);
|
|
64
|
+
if (!chain.test(body)) {
|
|
65
|
+
throw new LensPurityError("lens", `predicate lens must be a single member-access chain off "${param}" ` +
|
|
66
|
+
`(no calls, operators, ternaries, indexing, or other identifiers); got: ${body}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// --- operand validation ------------------------------------------------------
|
|
70
|
+
function assertFiniteScalar(value, op) {
|
|
71
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
72
|
+
throw new LensPurityError(`predicate.${op}`, `operand must be a finite number; NaN/Infinity are not JSON-safe and never match`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const RELATIONAL_OPS = new Set(["gt", "gte", "lt", "lte"]);
|
|
76
|
+
/**
|
|
77
|
+
* Relational ops (gt/gte/lt/lte) require a numeric operand. The type layer
|
|
78
|
+
* already enforces this, but JS / `as any` callers could pass a string / null /
|
|
79
|
+
* boolean, and runtime comparison would then rely on JS coercion (e.g.
|
|
80
|
+
* `5 > null` is `true`) — silently wrong. Reject at construction + validation.
|
|
81
|
+
*/
|
|
82
|
+
function assertRelationalOperand(op, value) {
|
|
83
|
+
if (RELATIONAL_OPS.has(op) && typeof value !== "number") {
|
|
84
|
+
throw new LensPurityError(`predicate.${op}`, `relational operand for "${op}" must be a number; got ${value === null ? "null" : typeof value}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Reject anything that isn't a JSON scalar (string / number / boolean / null).
|
|
89
|
+
* The type layer already enforces this for typed callers, but JS / `as any`
|
|
90
|
+
* callers can smuggle in `undefined` (dropped by JSON.stringify), `bigint`
|
|
91
|
+
* (JSON.stringify throws), symbols, objects, or functions — all of which would
|
|
92
|
+
* make the extracted projection non-JSON-safe and break scanner/Cloud.
|
|
93
|
+
*/
|
|
94
|
+
function assertJsonScalar(value, op) {
|
|
95
|
+
if (value === null)
|
|
96
|
+
return;
|
|
97
|
+
const t = typeof value;
|
|
98
|
+
if (t === "string" || t === "number" || t === "boolean")
|
|
99
|
+
return;
|
|
100
|
+
throw new LensPurityError(`${op}`, `case value must be a JSON scalar (string / number / boolean / null); got ${t}`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Validate value-switch case values (build-time). A value-switch is an exact
|
|
104
|
+
* match-set, so values must be:
|
|
105
|
+
* 1. JSON scalars — non-scalars (undefined/bigint/symbol/object/function) are
|
|
106
|
+
* not projection-safe (see assertJsonScalar);
|
|
107
|
+
* 2. unique — a duplicate makes the second case unreachable (first-match) and
|
|
108
|
+
* turns the switch order-dependent, violating "order doesn't matter";
|
|
109
|
+
* 3. finite (numbers) — NaN/Infinity become `null` under JSON.stringify (not
|
|
110
|
+
* projection-safe) and `=== NaN` never matches.
|
|
111
|
+
*/
|
|
112
|
+
export function assertSwitchCaseValues(values) {
|
|
113
|
+
const seen = new Set();
|
|
114
|
+
for (const v of values) {
|
|
115
|
+
assertJsonScalar(v, "switchOn");
|
|
116
|
+
assertFiniteScalar(v, "switchOn");
|
|
117
|
+
if (seen.has(v)) {
|
|
118
|
+
throw new LensPurityError("switchOn", `duplicate case value ${JSON.stringify(v)} — value-switch values must be unique ` +
|
|
119
|
+
`(a duplicate is unreachable under first-match and makes the switch order-dependent)`);
|
|
120
|
+
}
|
|
121
|
+
seen.add(v);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// --- predicate construction (the only way to make a BranchPredicate) ---------
|
|
125
|
+
function brandFreeze(node) {
|
|
126
|
+
// Real runtime brand (non-enumerable so it never leaks into spreads / JSON /
|
|
127
|
+
// the extracted projection), then deep-freeze. Only this function sets it.
|
|
128
|
+
Object.defineProperty(node, PREDICATE_BRAND, {
|
|
129
|
+
value: true,
|
|
130
|
+
enumerable: false,
|
|
131
|
+
writable: false,
|
|
132
|
+
configurable: false,
|
|
133
|
+
});
|
|
134
|
+
return Object.freeze(node);
|
|
135
|
+
}
|
|
136
|
+
/** Runtime brand check — true only for nodes produced by `predicateScope`. */
|
|
137
|
+
function isBrandedPredicate(node) {
|
|
138
|
+
return (typeof node === "object" &&
|
|
139
|
+
node !== null &&
|
|
140
|
+
node[PREDICATE_BRAND] === true);
|
|
141
|
+
}
|
|
142
|
+
function selectorPath(lens) {
|
|
143
|
+
assertSelectorSource(lens); // P0 source gate (ternary / free-var / calls)
|
|
144
|
+
return Object.freeze(extractSelectorPath(lens)); // strict-Proxy path + Proxy purity
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build a `PredicateScope<S>`. The runtime is untyped (`any`); the public typing
|
|
148
|
+
* comes from the `PredicateScope<S>` / `WhenClause<S, V>` interfaces it is cast to.
|
|
149
|
+
*/
|
|
150
|
+
export function predicateScope() {
|
|
151
|
+
const when = (lens) => {
|
|
152
|
+
const path = selectorPath(lens);
|
|
153
|
+
const compare = (op, value) => {
|
|
154
|
+
assertJsonScalar(value, `predicate.${op}`);
|
|
155
|
+
assertFiniteScalar(value, op);
|
|
156
|
+
assertRelationalOperand(op, value);
|
|
157
|
+
return brandFreeze({ kind: "compare", op, lens, path, value });
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
eq: (value) => compare("eq", value),
|
|
161
|
+
ne: (value) => compare("ne", value),
|
|
162
|
+
gt: (value) => compare("gt", value),
|
|
163
|
+
gte: (value) => compare("gte", value),
|
|
164
|
+
lt: (value) => compare("lt", value),
|
|
165
|
+
lte: (value) => compare("lte", value),
|
|
166
|
+
in: (values) => {
|
|
167
|
+
values.forEach((v) => {
|
|
168
|
+
assertJsonScalar(v, "predicate.in");
|
|
169
|
+
assertFiniteScalar(v, "in");
|
|
170
|
+
});
|
|
171
|
+
return brandFreeze({ kind: "in", lens, path, values: Object.freeze([...values]) });
|
|
172
|
+
},
|
|
173
|
+
exists: () => brandFreeze({ kind: "presence", op: "exists", lens, path }),
|
|
174
|
+
absent: () => brandFreeze({ kind: "presence", op: "absent", lens, path }),
|
|
175
|
+
truthy: () => brandFreeze({ kind: "presence", op: "truthy", lens, path }),
|
|
176
|
+
falsy: () => brandFreeze({ kind: "presence", op: "falsy", lens, path }),
|
|
177
|
+
matches: (pattern) => {
|
|
178
|
+
const re = typeof pattern === "string" ? new RegExp(pattern) : pattern;
|
|
179
|
+
return brandFreeze({
|
|
180
|
+
kind: "matches",
|
|
181
|
+
lens,
|
|
182
|
+
path,
|
|
183
|
+
pattern: re.source,
|
|
184
|
+
...(re.flags ? { flags: re.flags } : {}),
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
const combine = (kind, clauses) => {
|
|
190
|
+
if (clauses.length === 0) {
|
|
191
|
+
throw new LensPurityError(`predicate.${kind}`, `${kind}() needs at least one clause`);
|
|
192
|
+
}
|
|
193
|
+
return brandFreeze({ kind, clauses: Object.freeze([...clauses]) });
|
|
194
|
+
};
|
|
195
|
+
return {
|
|
196
|
+
when: when,
|
|
197
|
+
all: (...clauses) => combine("and", clauses),
|
|
198
|
+
any: (...clauses) => combine("or", clauses),
|
|
199
|
+
not: (clause) => brandFreeze({ kind: "not", clause }),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// --- runtime evaluation ------------------------------------------------------
|
|
203
|
+
/** Safe path traversal: returns `undefined` if any intermediate is null/undefined. */
|
|
204
|
+
function resolvePath(state, path) {
|
|
205
|
+
let cur = state;
|
|
206
|
+
for (const seg of path) {
|
|
207
|
+
if (cur === null || cur === undefined)
|
|
208
|
+
return undefined;
|
|
209
|
+
cur = cur[seg];
|
|
210
|
+
}
|
|
211
|
+
return cur;
|
|
212
|
+
}
|
|
213
|
+
/** Evaluate a declarative predicate against a concrete state. Pure, no I/O. */
|
|
214
|
+
export function evalPredicate(pred, state) {
|
|
215
|
+
switch (pred.kind) {
|
|
216
|
+
case "compare": {
|
|
217
|
+
const actual = resolvePath(state, pred.path);
|
|
218
|
+
switch (pred.op) {
|
|
219
|
+
case "eq":
|
|
220
|
+
return actual === pred.value;
|
|
221
|
+
case "ne":
|
|
222
|
+
return actual !== pred.value;
|
|
223
|
+
case "gt":
|
|
224
|
+
return typeof actual === "number" && actual > pred.value;
|
|
225
|
+
case "gte":
|
|
226
|
+
return typeof actual === "number" && actual >= pred.value;
|
|
227
|
+
case "lt":
|
|
228
|
+
return typeof actual === "number" && actual < pred.value;
|
|
229
|
+
case "lte":
|
|
230
|
+
return typeof actual === "number" && actual <= pred.value;
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
case "in": {
|
|
235
|
+
const actual = resolvePath(state, pred.path);
|
|
236
|
+
return pred.values.some((v) => v === actual);
|
|
237
|
+
}
|
|
238
|
+
case "presence": {
|
|
239
|
+
const actual = resolvePath(state, pred.path);
|
|
240
|
+
switch (pred.op) {
|
|
241
|
+
case "exists":
|
|
242
|
+
return actual !== undefined;
|
|
243
|
+
case "absent":
|
|
244
|
+
return actual === undefined;
|
|
245
|
+
case "truthy":
|
|
246
|
+
return !!actual;
|
|
247
|
+
case "falsy":
|
|
248
|
+
return !actual;
|
|
249
|
+
}
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
case "matches": {
|
|
253
|
+
const actual = resolvePath(state, pred.path);
|
|
254
|
+
return typeof actual === "string" && new RegExp(pred.pattern, pred.flags).test(actual);
|
|
255
|
+
}
|
|
256
|
+
case "and":
|
|
257
|
+
return pred.clauses.every((c) => evalPredicate(c, state));
|
|
258
|
+
case "or":
|
|
259
|
+
return pred.clauses.some((c) => evalPredicate(c, state));
|
|
260
|
+
case "not":
|
|
261
|
+
return !evalPredicate(pred.clause, state);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// --- L2 predicate tree validation (second line of defense) -------------------
|
|
265
|
+
const COMPARE_OPS = new Set(["eq", "ne", "gt", "gte", "lt", "lte"]);
|
|
266
|
+
const PRESENCE_OPS = new Set(["exists", "absent", "truthy", "falsy"]);
|
|
267
|
+
function assertPath(path, op) {
|
|
268
|
+
if (!Array.isArray(path) || !path.every((seg) => typeof seg === "string")) {
|
|
269
|
+
throw new LensPurityError(op, `predicate path must be a string[]`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Recursively validate a declarative (L2) predicate tree before it is stored
|
|
274
|
+
* by `condition` / `switchCond`. The `BranchPredicate` brand is type-only
|
|
275
|
+
* (erased at runtime), so a JS / `as any` caller could return a hand-forged
|
|
276
|
+
* object from the predicate callback — e.g. `{ kind: "opaque", ... }` (which
|
|
277
|
+
* would bypass the `conditionFn`/`conditionAsync` message requirement and emit
|
|
278
|
+
* an unlabeled opaque gate) or a node with a non-JSON `value`. This is the
|
|
279
|
+
* runtime counterpart to the (type-only) brand: it guarantees every stored L2
|
|
280
|
+
* predicate is a well-formed, JSON-safe declarative tree.
|
|
281
|
+
*/
|
|
282
|
+
export function assertL2Predicate(node, op = "condition") {
|
|
283
|
+
// Brand gate (primary): only nodes built by `predicateScope` carry the
|
|
284
|
+
// module-private brand, so a hand-authored object — which bypassed the
|
|
285
|
+
// selector source / strict-Proxy gate (its `path` could reference anything) —
|
|
286
|
+
// is rejected here even from JS / `as any`. The structural checks below are
|
|
287
|
+
// belt-and-suspenders for the (already-validated) branded shape.
|
|
288
|
+
if (!isBrandedPredicate(node)) {
|
|
289
|
+
throw new LensPurityError(op, `${op}() requires a declarative predicate built via the predicate scope ` +
|
|
290
|
+
`(w.when / all / any / not). The value did not come from the scope — ` +
|
|
291
|
+
`forged / hand-authored predicate objects are rejected (they bypass the ` +
|
|
292
|
+
`selector source + purity gate). For opaque logic use conditionFn / conditionAsync.`);
|
|
293
|
+
}
|
|
294
|
+
const n = node;
|
|
295
|
+
switch (n.kind) {
|
|
296
|
+
case "compare": {
|
|
297
|
+
const c = node;
|
|
298
|
+
if (typeof c.op !== "string" || !COMPARE_OPS.has(c.op)) {
|
|
299
|
+
throw new LensPurityError(op, `invalid compare op ${JSON.stringify(c.op)}`);
|
|
300
|
+
}
|
|
301
|
+
assertPath(c.path, op);
|
|
302
|
+
assertJsonScalar(c.value, op);
|
|
303
|
+
assertFiniteScalar(c.value, op);
|
|
304
|
+
assertRelationalOperand(c.op, c.value);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
case "in": {
|
|
308
|
+
const c = node;
|
|
309
|
+
assertPath(c.path, op);
|
|
310
|
+
if (!Array.isArray(c.values)) {
|
|
311
|
+
throw new LensPurityError(op, `in.values must be an array`);
|
|
312
|
+
}
|
|
313
|
+
c.values.forEach((v) => {
|
|
314
|
+
assertJsonScalar(v, op);
|
|
315
|
+
assertFiniteScalar(v, op);
|
|
316
|
+
});
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
case "presence": {
|
|
320
|
+
const c = node;
|
|
321
|
+
if (typeof c.op !== "string" || !PRESENCE_OPS.has(c.op)) {
|
|
322
|
+
throw new LensPurityError(op, `invalid presence op ${JSON.stringify(c.op)}`);
|
|
323
|
+
}
|
|
324
|
+
assertPath(c.path, op);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
case "matches": {
|
|
328
|
+
const c = node;
|
|
329
|
+
assertPath(c.path, op);
|
|
330
|
+
if (typeof c.pattern !== "string") {
|
|
331
|
+
throw new LensPurityError(op, `matches.pattern must be a string`);
|
|
332
|
+
}
|
|
333
|
+
if (c.flags !== undefined && typeof c.flags !== "string") {
|
|
334
|
+
throw new LensPurityError(op, `matches.flags must be a string`);
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
case "and":
|
|
339
|
+
case "or": {
|
|
340
|
+
const c = node;
|
|
341
|
+
if (!Array.isArray(c.clauses) || c.clauses.length === 0) {
|
|
342
|
+
throw new LensPurityError(op, `${n.kind}.clauses must be a non-empty array`);
|
|
343
|
+
}
|
|
344
|
+
c.clauses.forEach((cl) => assertL2Predicate(cl, op));
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
case "not": {
|
|
348
|
+
const c = node;
|
|
349
|
+
assertL2Predicate(c.clause, op);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
default:
|
|
353
|
+
throw new LensPurityError(op, `${op}() requires a declarative (L2) predicate from the predicate scope; ` +
|
|
354
|
+
`got kind ${JSON.stringify(n.kind)}. For opaque / async logic use ` +
|
|
355
|
+
`conditionFn / conditionAsync (which require a \`message\`).`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function isOpaque(p) {
|
|
359
|
+
return p.kind === "opaque";
|
|
360
|
+
}
|
|
361
|
+
/** Evaluate one predicate-mode case predicate (L2 declarative sync / L1 sync / L0 async). */
|
|
362
|
+
async function evalCasePredicate(pred, state, ctx) {
|
|
363
|
+
if (isOpaque(pred)) {
|
|
364
|
+
const out = pred.fn(ctx, state);
|
|
365
|
+
if (pred.sync && out && typeof out.then === "function") {
|
|
366
|
+
throw new Error("conditionFn (L1) predicate must be synchronous — it returned a thenable. Use conditionAsync for async/I-O predicates.");
|
|
367
|
+
}
|
|
368
|
+
const result = await out;
|
|
369
|
+
// The API types the predicate as `boolean`, but JS / `as any` callers can
|
|
370
|
+
// return a truthy non-boolean (e.g. the string "false", an object). Fail
|
|
371
|
+
// fast instead of letting `selectBranchSteps`' `if` silently take a branch
|
|
372
|
+
// on a coerced value.
|
|
373
|
+
if (typeof result !== "boolean") {
|
|
374
|
+
throw new Error(`${pred.sync ? "conditionFn (L1)" : "conditionAsync (L0)"} predicate must return a boolean; ` +
|
|
375
|
+
`got ${result === null ? "null" : typeof result}`);
|
|
376
|
+
}
|
|
377
|
+
return result;
|
|
378
|
+
}
|
|
379
|
+
return evalPredicate(pred, state);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Select the steps a branch takes against a concrete state (first-match → default).
|
|
383
|
+
* Always async (L0 opaque predicates may be async). For value-mode the subject lens
|
|
384
|
+
* is evaluated exactly once: flow uses the captured `path` (safe traversal, no throw
|
|
385
|
+
* on missing intermediates), test calls the lens.
|
|
386
|
+
*/
|
|
387
|
+
export async function selectBranchSteps(step, state, ctx) {
|
|
388
|
+
if (step.mode === "value") {
|
|
389
|
+
const subject = step.subject.path
|
|
390
|
+
? resolvePath(state, step.subject.path)
|
|
391
|
+
: step.subject.lens(ctx, state);
|
|
392
|
+
for (const c of step.cases) {
|
|
393
|
+
if (subject === c.value)
|
|
394
|
+
return c.steps;
|
|
395
|
+
}
|
|
396
|
+
return step.default;
|
|
397
|
+
}
|
|
398
|
+
for (const c of step.cases) {
|
|
399
|
+
if (await evalCasePredicate(c.predicate, state, ctx))
|
|
400
|
+
return c.steps;
|
|
401
|
+
}
|
|
402
|
+
return step.default;
|
|
403
|
+
}
|
|
404
|
+
/** Map a runtime predicate (path already captured at construction) to JSON-safe form. */
|
|
405
|
+
export function extractPredicate(pred) {
|
|
406
|
+
if (isOpaque(pred)) {
|
|
407
|
+
return { kind: "opaque", strictness: pred.sync ? "L1" : "L0", mayDoAsyncIO: !pred.sync };
|
|
408
|
+
}
|
|
409
|
+
switch (pred.kind) {
|
|
410
|
+
case "compare":
|
|
411
|
+
return { kind: "compare", op: pred.op, path: [...pred.path], value: pred.value };
|
|
412
|
+
case "in":
|
|
413
|
+
return { kind: "in", path: [...pred.path], values: [...pred.values] };
|
|
414
|
+
case "presence":
|
|
415
|
+
return { kind: "presence", op: pred.op, path: [...pred.path] };
|
|
416
|
+
case "matches":
|
|
417
|
+
return {
|
|
418
|
+
kind: "matches",
|
|
419
|
+
path: [...pred.path],
|
|
420
|
+
pattern: pred.pattern,
|
|
421
|
+
...(pred.flags ? { flags: pred.flags } : {}),
|
|
422
|
+
};
|
|
423
|
+
case "and":
|
|
424
|
+
case "or":
|
|
425
|
+
return { kind: pred.kind, clauses: pred.clauses.map(extractPredicate) };
|
|
426
|
+
case "not":
|
|
427
|
+
return { kind: "not", clause: extractPredicate(pred.clause) };
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Normalize a runtime branch step to JSON-safe form. `recurse` normalizes a
|
|
432
|
+
* sub-step list (provided by normalizeFlow so nested branches recurse).
|
|
433
|
+
*/
|
|
434
|
+
export function extractBranchStep(step, recurse) {
|
|
435
|
+
if (step.mode === "value") {
|
|
436
|
+
return {
|
|
437
|
+
kind: "branch",
|
|
438
|
+
mode: "value",
|
|
439
|
+
...(step.name ? { name: step.name } : {}),
|
|
440
|
+
subjectPath: step.subject.path ? [...step.subject.path] : [],
|
|
441
|
+
cases: step.cases.map((c) => ({ value: c.value, steps: recurse(c.steps) })),
|
|
442
|
+
default: recurse(step.default),
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
kind: "branch",
|
|
447
|
+
mode: "predicate",
|
|
448
|
+
...(step.name ? { name: step.name } : {}),
|
|
449
|
+
cases: step.cases.map((c) => ({
|
|
450
|
+
...(c.message ? { message: c.message } : {}),
|
|
451
|
+
predicate: extractPredicate(c.predicate),
|
|
452
|
+
steps: recurse(c.steps),
|
|
453
|
+
})),
|
|
454
|
+
default: recurse(step.default),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
//# sourceMappingURL=contract-flow-condition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-flow-condition.js","sourceRoot":"","sources":["../src/contract-flow-condition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module contract-flow-poll
|
|
3
|
+
*
|
|
4
|
+
* Bounded poll-until primitive for `contract.flow()` — runtime + projection.
|
|
5
|
+
*
|
|
6
|
+
* A poll repeats ONE contract case until an exit predicate over the RESPONSE
|
|
7
|
+
* holds, BOUNDED by a total wall-clock deadline and/or a finite per-attempt
|
|
8
|
+
* budget. It is the projectable subset of "loop" (a self-loop on one node), as
|
|
9
|
+
* opposed to the arbitrary loops that stay in `test()`. See the design proposal
|
|
10
|
+
* `internal/40-discovery/proposals/contract-flow-poll.md`.
|
|
11
|
+
*
|
|
12
|
+
* This module owns the poll-specific runtime types, the bounded-retry helpers
|
|
13
|
+
* (quarantined ctx, budget race), the exit-predicate evaluator (three strictness
|
|
14
|
+
* tiers, reusing the condition predicate foundation), the build-time bound
|
|
15
|
+
* validation, and the JSON-safe projection. The execution LOOP lives in
|
|
16
|
+
* `contract-core.ts` (it needs the shared committed-state cell).
|
|
17
|
+
*/
|
|
18
|
+
import type { ContractCaseRef, ProtocolContract, FieldMapping } from "./contract-types.js";
|
|
19
|
+
import type { TestContext } from "./types.js";
|
|
20
|
+
import { type BranchPredicate, type ExtractedPredicate } from "./contract-flow-condition.js";
|
|
21
|
+
/**
|
|
22
|
+
* Runtime representation of a `flow().poll()` step. Carries live callbacks +
|
|
23
|
+
* the live contract ref. Never serialized — `extractPollStep` produces the
|
|
24
|
+
* JSON-safe form.
|
|
25
|
+
*
|
|
26
|
+
* The exit predicate (`until`) is over the RESPONSE (not state): L2 declarative
|
|
27
|
+
* (`BranchPredicate`, projectable) or opaque (L1 sync / L0 async, marked). The
|
|
28
|
+
* opaque form additionally receives `state` so a poll can wait for the response
|
|
29
|
+
* to reflect something already in state (e.g. `res.version >= state.lastSeen`).
|
|
30
|
+
*/
|
|
31
|
+
export interface RuntimePollStep {
|
|
32
|
+
kind: "poll";
|
|
33
|
+
name?: string;
|
|
34
|
+
ref: ContractCaseRef<any, any, any, any>;
|
|
35
|
+
caseKey: string;
|
|
36
|
+
/** Live contract instance (mirrors ref.contract). */
|
|
37
|
+
contract: ProtocolContract<any, any, any>;
|
|
38
|
+
bindings?: {
|
|
39
|
+
in?: (state: any) => any;
|
|
40
|
+
out?: (state: any, response: any) => any;
|
|
41
|
+
accept?: readonly unknown[];
|
|
42
|
+
};
|
|
43
|
+
/** Exit predicate — L2 declarative (over the response) or opaque (gets ctx, res, state). */
|
|
44
|
+
until: BranchPredicate<any> | {
|
|
45
|
+
kind: "opaque";
|
|
46
|
+
sync: boolean;
|
|
47
|
+
fn: (ctx: TestContext, res: any, state: any) => boolean | Promise<boolean>;
|
|
48
|
+
};
|
|
49
|
+
/** Author-supplied label (opaque tiers require it; L2 can auto-generate). */
|
|
50
|
+
message?: string;
|
|
51
|
+
/** Interval between attempts (ms). */
|
|
52
|
+
every: number;
|
|
53
|
+
/** Multiplier applied to `every` after each retry (1 = fixed). Capped at BACKOFF_CAP_MS. */
|
|
54
|
+
backoff: number;
|
|
55
|
+
/** Total wall-clock bound (ms). */
|
|
56
|
+
timeoutMs?: number;
|
|
57
|
+
/** Per-attempt budget (ms) — required when `timeoutMs` is absent. */
|
|
58
|
+
perAttemptTimeoutMs?: number;
|
|
59
|
+
/** Max attempts (>= 1). */
|
|
60
|
+
maxAttempts?: number;
|
|
61
|
+
}
|
|
62
|
+
/** Backoff cap — mirrors the test() step retry-backoff ceiling. */
|
|
63
|
+
export declare const BACKOFF_CAP_MS = 30000;
|
|
64
|
+
/** Default interval between attempts when `every` is omitted. */
|
|
65
|
+
export declare const DEFAULT_EVERY_MS = 1000;
|
|
66
|
+
export declare class PollExhaustedError extends Error {
|
|
67
|
+
readonly attempts: number;
|
|
68
|
+
constructor(stepLabel: string, attempts: number, detail?: string);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A child `TestContext` that isolates the **pass/fail-affecting** APIs of a poll
|
|
72
|
+
* attempt — `assert` / `expect` / `validate` / `fail` — so a probe's validation
|
|
73
|
+
* noise or a timed-out orphan's late failure cannot corrupt the run's pass/fail
|
|
74
|
+
* outcome. Those are buffered and either flushed (the satisfying attempt / an
|
|
75
|
+
* in-budget deliberate failure) or discarded (probe / orphan).
|
|
76
|
+
*
|
|
77
|
+
* Everything else PASSES THROUGH to the real ctx and emits per-attempt, by
|
|
78
|
+
* design — and this is deliberate, not an oversight:
|
|
79
|
+
* - Observability (`trace` / `metric` / `log` / `action` / `event`): the
|
|
80
|
+
* polling requests genuinely happened; their traces/metrics are wanted (you
|
|
81
|
+
* want to see "polled 3×"). Buffering them would also be inconsistent: the
|
|
82
|
+
* adapter's HTTP client is pre-bound to the real ctx at construction, so its
|
|
83
|
+
* auto-traces emit to the real ctx regardless of this wrapper — there is no
|
|
84
|
+
* way to intercept them here, so we don't pretend to.
|
|
85
|
+
* - Accessors / side effects (`vars` / `secrets` / `session` / `http`): a
|
|
86
|
+
* predicate that reads/writes these runs against the live ctx, exactly like
|
|
87
|
+
* a condition predicate does (which is also evaluated against the real ctx).
|
|
88
|
+
*
|
|
89
|
+
* `skip` is pure control flow — the real `skip` only throws a SkipError (it
|
|
90
|
+
* emits nothing), so it is delegated. The poll loop catches any rejection from a
|
|
91
|
+
* raced-out attempt so a late skip/fail cannot surface as an unhandled rejection.
|
|
92
|
+
*/
|
|
93
|
+
export interface QuarantinedContext extends TestContext {
|
|
94
|
+
/** Replay all buffered emissions onto a real ctx (the satisfying attempt / in-budget predicate). */
|
|
95
|
+
flushTo(target: TestContext): void;
|
|
96
|
+
/** True if any buffered assertion / validation / fail recorded a failure. */
|
|
97
|
+
hasFailure(): boolean;
|
|
98
|
+
}
|
|
99
|
+
export declare function quarantinedCtx(real: TestContext): QuarantinedContext;
|
|
100
|
+
/**
|
|
101
|
+
* Race a promise against a finite budget (ms). If the budget elapses first,
|
|
102
|
+
* reject with `onTimeout()`. A non-finite budget degrades to a plain await
|
|
103
|
+
* (build-time validation guarantees attempt budgets are finite, so this only
|
|
104
|
+
* happens defensively).
|
|
105
|
+
*/
|
|
106
|
+
export declare function raceBudget<T>(promise: Promise<T>, budgetMs: number, onTimeout: () => Error): Promise<T>;
|
|
107
|
+
/**
|
|
108
|
+
* Evaluate a poll exit predicate. L2 declarative reads the RESPONSE (`evalPredicate`
|
|
109
|
+
* with subject = response). Opaque tiers get `(ctx, res, state)`. Non-boolean
|
|
110
|
+
* results fail fast (mirrors condition Phase 6); a thrown error / `ctx.skip()`
|
|
111
|
+
* propagates to the caller.
|
|
112
|
+
*/
|
|
113
|
+
export declare function evalPollExit(until: RuntimePollStep["until"], response: unknown, ctx: TestContext, state: unknown): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Validate poll bounds at construction. Two rules (both required), plus
|
|
116
|
+
* finiteness on every timing value (an `Infinity` bound would un-bound the loop):
|
|
117
|
+
* 1. total stop condition: `timeout` OR `maxAttempts`
|
|
118
|
+
* 2. finite per-attempt budget: `timeout` OR `perAttemptTimeout`
|
|
119
|
+
* (so `maxAttempts`-only — with no per-attempt budget — is illegal: a single
|
|
120
|
+
* hung request/predicate could block forever before the attempt counter advances.)
|
|
121
|
+
*/
|
|
122
|
+
export declare function validatePollBounds(bounds: {
|
|
123
|
+
timeout?: number;
|
|
124
|
+
maxAttempts?: number;
|
|
125
|
+
perAttemptTimeout?: number;
|
|
126
|
+
every?: number;
|
|
127
|
+
backoff?: number;
|
|
128
|
+
}, stepLabel: string): void;
|
|
129
|
+
export interface ExtractedPollStep {
|
|
130
|
+
kind: "poll";
|
|
131
|
+
name?: string;
|
|
132
|
+
contractId: string;
|
|
133
|
+
caseKey: string;
|
|
134
|
+
protocol: string;
|
|
135
|
+
target: string;
|
|
136
|
+
inputs?: FieldMapping[];
|
|
137
|
+
outputs?: FieldMapping[];
|
|
138
|
+
accept?: ReadonlyArray<string | number>;
|
|
139
|
+
/** Exit predicate — L2 precise (compare/in/...) or `{kind:"opaque",...}`. */
|
|
140
|
+
until: ExtractedPredicate;
|
|
141
|
+
message?: string;
|
|
142
|
+
every: number;
|
|
143
|
+
backoff: number;
|
|
144
|
+
timeoutMs?: number;
|
|
145
|
+
perAttemptTimeoutMs?: number;
|
|
146
|
+
maxAttempts?: number;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Normalize a runtime poll step to JSON-safe form. `dryRun` produces the
|
|
150
|
+
* input/output field mappings (the same Proxy dry-run normalizeFlow uses for a
|
|
151
|
+
* contract-call step), so the poll node carries data-flow edges like a step.
|
|
152
|
+
*/
|
|
153
|
+
export declare function extractPollStep(step: RuntimePollStep, dryRun: (step: RuntimePollStep) => {
|
|
154
|
+
inputs?: FieldMapping[];
|
|
155
|
+
outputs?: FieldMapping[];
|
|
156
|
+
}): ExtractedPollStep;
|
|
157
|
+
//# sourceMappingURL=contract-flow-poll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-flow-poll.d.ts","sourceRoot":"","sources":["../src/contract-flow-poll.ts"],"names":[],"mappings":"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"}
|