@blokjs/shared 0.7.0 → 1.1.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/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/Mapper.js +77 -7
- package/dist/utils/Mapper.js.map +1 -1
- package/dist/utils/MapperResolutionError.d.ts +6 -2
- package/dist/utils/MapperResolutionError.js +5 -1
- package/dist/utils/MapperResolutionError.js.map +1 -1
- package/dist/utils/NamedMissingStateError.d.ts +38 -0
- package/dist/utils/NamedMissingStateError.js +39 -0
- package/dist/utils/NamedMissingStateError.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/lowerRefs.d.ts +45 -0
- package/dist/utils/lowerRefs.js +190 -0
- package/dist/utils/lowerRefs.js.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -20,5 +20,8 @@ import Step from "./types/Step";
|
|
|
20
20
|
import type StreamContext from "./types/StreamContext";
|
|
21
21
|
import VarsContext from "./types/VarsContext";
|
|
22
22
|
import mapper from "./utils/Mapper";
|
|
23
|
+
import { MapperResolutionError } from "./utils/MapperResolutionError";
|
|
23
24
|
import MemoryUsage from "./utils/MemoryUsage";
|
|
24
|
-
|
|
25
|
+
import { NamedMissingStateError } from "./utils/NamedMissingStateError";
|
|
26
|
+
import { type StructuralRef, lowerRefs } from "./utils/lowerRefs";
|
|
27
|
+
export { NodeBase, Context, RequestContext, ResponseContext, RESPOND_BRAND, type RespondEnvelope, isRespondEnvelope, EnvContext, ErrorContext, LoggerContext, ConfigContext, type ConnectionContext, type StreamContext, Trigger, NodeConfigContext, FunctionContext, StateContext, VarsContext, Step, GlobalLogger, GlobalError, BlokError, type BlokErrorOpts, type NodeErrorPayload, ErrorCategory, ErrorSeverity, DEFAULT_HTTP_STATUS, DEFAULT_RETRYABLE, Metrics, MemoryUsage, type MetricsType, mapper, MapperResolutionError, NamedMissingStateError, lowerRefs, type StructuralRef, };
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ import NodeBase from "./NodeBase";
|
|
|
6
6
|
import Trigger from "./Trigger";
|
|
7
7
|
import { RESPOND_BRAND, isRespondEnvelope } from "./types/RespondEnvelope";
|
|
8
8
|
import mapper from "./utils/Mapper";
|
|
9
|
+
import { MapperResolutionError } from "./utils/MapperResolutionError";
|
|
9
10
|
import MemoryUsage from "./utils/MemoryUsage";
|
|
10
|
-
|
|
11
|
+
import { NamedMissingStateError } from "./utils/NamedMissingStateError";
|
|
12
|
+
import { lowerRefs } from "./utils/lowerRefs";
|
|
13
|
+
export { NodeBase, RESPOND_BRAND, isRespondEnvelope, Trigger, GlobalLogger, GlobalError, BlokError, ErrorCategory, ErrorSeverity, DEFAULT_HTTP_STATUS, DEFAULT_RETRYABLE, Metrics, MemoryUsage, mapper, MapperResolutionError, NamedMissingStateError, lowerRefs, };
|
|
11
14
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,EAAE,EAEjB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,aAAa,GAEb,MAAM,aAAa,CAAC;AACrB,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAoB,MAAM,WAAW,CAAC;AACtD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,OAAO,MAAM,WAAW,CAAC;AAUhC,OAAO,EAAE,aAAa,EAAwB,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAMjG,OAAO,MAAM,MAAM,gBAAgB,CAAC;AACpC,OAAO,WAAW,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,EAAE,EAEjB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,aAAa,GAEb,MAAM,aAAa,CAAC;AACrB,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAoB,MAAM,WAAW,CAAC;AACtD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,OAAO,MAAM,WAAW,CAAC;AAUhC,OAAO,EAAE,aAAa,EAAwB,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAMjG,OAAO,MAAM,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,WAAW,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAsB,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EACN,QAAQ,EAIR,aAAa,EAEb,iBAAiB,EAOjB,OAAO,EAMP,YAAY,EACZ,WAAW,EACX,SAAS,EAGT,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,OAAO,EACP,WAAW,EAEX,MAAM,EACN,qBAAqB,EACrB,sBAAsB,EACtB,SAAS,GAET,CAAC"}
|
package/dist/utils/Mapper.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _ from "lodash";
|
|
2
2
|
import { MapperResolutionError } from "./MapperResolutionError";
|
|
3
|
+
import { NamedMissingStateError } from "./NamedMissingStateError";
|
|
3
4
|
// =============================================================================
|
|
4
5
|
// Internal sentinels + helpers
|
|
5
6
|
// =============================================================================
|
|
@@ -80,6 +81,80 @@ function guessHint(expression, errorMessage) {
|
|
|
80
81
|
}
|
|
81
82
|
return null;
|
|
82
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Detect a dangling state reference — the failure case behind
|
|
86
|
+
* {@link NamedMissingStateError}. Given an expression that THREW during
|
|
87
|
+
* resolution and the live ctx, returns the missing state id ONLY when the
|
|
88
|
+
* expression's ROOT read is `ctx.state.<id>` / `ctx.vars.<id>` (or the bare
|
|
89
|
+
* `state.<id>` / `vars.<id>` root forms — `vars` aliases `state`) AND that
|
|
90
|
+
* `<id>` is genuinely absent from `ctx.state`. Returns `null` otherwise —
|
|
91
|
+
* including when `state`/`vars` appears only as a NESTED property of another
|
|
92
|
+
* object (e.g. `ctx.req.body.state.missing`), which is not a state ref at all.
|
|
93
|
+
*
|
|
94
|
+
* CRITICAL — this only ever fires on the ALREADY-FAILED path (the JS
|
|
95
|
+
* eval threw), so it adds zero happy-path cost. It uses an `in`-check,
|
|
96
|
+
* NOT `=== undefined`, so a slot that exists but holds a falsy value
|
|
97
|
+
* (`0`, `false`, `""`, `null`, even `undefined`) is NOT flagged as
|
|
98
|
+
* missing — only a never-persisted root key counts. A reference to a
|
|
99
|
+
* nested field (`ctx.state.foo.bar` where `foo` exists) is likewise not
|
|
100
|
+
* flagged: `foo` is present, so this returns `null` and the generic
|
|
101
|
+
* MapperResolutionError stands.
|
|
102
|
+
*/
|
|
103
|
+
function detectMissingStateId(expression, ctx) {
|
|
104
|
+
// Match `state.<id>` / `vars.<id>` ONLY when it is the ROOT of the
|
|
105
|
+
// expression, optionally behind a `ctx.` prefix. The leading `^` anchor
|
|
106
|
+
// is load-bearing: a `\b` boundary matched `state.`/`vars.` ANYWHERE, so
|
|
107
|
+
// `ctx.req.body.state.missing` or `ctx.config.state.X` (state/vars as a
|
|
108
|
+
// NESTED property of some OTHER object) got misclassified as a dangling
|
|
109
|
+
// state slot. Those resolve against a different root, not ctx.state, so
|
|
110
|
+
// they must stay a generic MapperResolutionError. The id stops at the
|
|
111
|
+
// next non-identifier char (`.`, `[`, `(`, whitespace, end).
|
|
112
|
+
const match = expression.match(/^(?:ctx\.)?(?:state|vars)\.([A-Za-z_$][\w$]*)/);
|
|
113
|
+
if (!match)
|
|
114
|
+
return null;
|
|
115
|
+
const id = match[1];
|
|
116
|
+
// `ctx.state` and `ctx.vars` point at the same object. Treat a missing
|
|
117
|
+
// container as "no state at all" — don't fabricate a named error.
|
|
118
|
+
const state = (ctx.state ?? ctx.vars);
|
|
119
|
+
if (state === null || typeof state !== "object")
|
|
120
|
+
return null;
|
|
121
|
+
// `in` (not `=== undefined`): a slot holding a falsy/undefined value is
|
|
122
|
+
// PRESENT and must not be flagged. Only a never-persisted key is missing.
|
|
123
|
+
if (id in state)
|
|
124
|
+
return null;
|
|
125
|
+
return id;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Build the named-missing-state message — same shape/lines as
|
|
129
|
+
* {@link buildErrorMessage} but the hint NAMES the missing id and the
|
|
130
|
+
* likely cause (typo / ephemeral / wrong as-spread / errored step).
|
|
131
|
+
*/
|
|
132
|
+
function buildMissingStateMessage(opts) {
|
|
133
|
+
const wf = opts.workflowName ?? "<unknown workflow>";
|
|
134
|
+
const step = opts.stepName ?? "<unknown step>";
|
|
135
|
+
const literal = opts.syntax === "js" ? `js/${opts.expression}` : `\${${opts.expression}}`;
|
|
136
|
+
return [
|
|
137
|
+
`[blok][mapper] Step "${step}" in workflow "${wf}" references state \`${opts.missingStateId}\`, which was never persisted.`,
|
|
138
|
+
` expression: ${literal}`,
|
|
139
|
+
` hint: no step wrote \`ctx.state.${opts.missingStateId}\`. Likely a typo'd id, an \`ephemeral: true\` step, a wrong \`as\`/\`spread\`, a step that errored, or a forEach body reading the slot before the loop populated it.`,
|
|
140
|
+
` fix: ensure a prior step's id (or its \`as:\`) is exactly "${opts.missingStateId}" and that it ran successfully without \`ephemeral: true\`.`,
|
|
141
|
+
].join("\n");
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Build the resolution error for a failed expression — a
|
|
145
|
+
* {@link NamedMissingStateError} when the failure is a dangling state
|
|
146
|
+
* reference (named, actionable), otherwise the generic
|
|
147
|
+
* {@link MapperResolutionError}. Additive: every non-state-root failure
|
|
148
|
+
* is unchanged from before.
|
|
149
|
+
*/
|
|
150
|
+
function buildResolutionError(opts) {
|
|
151
|
+
const { ctx, ...rest } = opts;
|
|
152
|
+
const missingStateId = detectMissingStateId(opts.expression, ctx);
|
|
153
|
+
if (missingStateId !== null) {
|
|
154
|
+
return new NamedMissingStateError(buildMissingStateMessage({ ...rest, missingStateId }), missingStateId, rest);
|
|
155
|
+
}
|
|
156
|
+
return new MapperResolutionError(buildErrorMessage(rest), rest);
|
|
157
|
+
}
|
|
83
158
|
/**
|
|
84
159
|
* Route a warn-mode log line to the best available sink. Prefers
|
|
85
160
|
* `ctx.logger.logLevel("warn", ...)` so the warning lands in BOTH the
|
|
@@ -250,7 +325,7 @@ class Mapper {
|
|
|
250
325
|
}
|
|
251
326
|
catch (cause) {
|
|
252
327
|
const stepCtx = readStepContext(ctx);
|
|
253
|
-
const error =
|
|
328
|
+
const error = buildResolutionError({ expression: key, syntax: "template", ...stepCtx, cause, ctx });
|
|
254
329
|
this.handleResolutionError(ctx, error);
|
|
255
330
|
return TEMPLATE_RESOLUTION_FAILED;
|
|
256
331
|
}
|
|
@@ -275,12 +350,7 @@ class Mapper {
|
|
|
275
350
|
}
|
|
276
351
|
catch (cause) {
|
|
277
352
|
const stepCtx = readStepContext(ctx);
|
|
278
|
-
const error =
|
|
279
|
-
expression,
|
|
280
|
-
syntax: "js",
|
|
281
|
-
...stepCtx,
|
|
282
|
-
cause,
|
|
283
|
-
});
|
|
353
|
+
const error = buildResolutionError({ expression, syntax: "js", ...stepCtx, cause, ctx });
|
|
284
354
|
this.handleResolutionError(ctx, error);
|
|
285
355
|
return str; // pre-v0.3.x behavior — pass through the literal string
|
|
286
356
|
}
|
package/dist/utils/Mapper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mapper.js","sourceRoot":"","sources":["../../src/utils/Mapper.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;AAKvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"Mapper.js","sourceRoot":"","sources":["../../src/utils/Mapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,8 +40,12 @@
|
|
|
40
40
|
* HTTP response).
|
|
41
41
|
*/
|
|
42
42
|
export declare class MapperResolutionError extends Error {
|
|
43
|
-
/**
|
|
44
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Defaults to `"MapperResolutionError"`. Typed `string` (not the
|
|
45
|
+
* narrow literal) so subclasses like `NamedMissingStateError` can
|
|
46
|
+
* override it with their own name.
|
|
47
|
+
*/
|
|
48
|
+
readonly name: string;
|
|
45
49
|
/** Structured diagnostic context attached at construction time. */
|
|
46
50
|
readonly context: {
|
|
47
51
|
/**
|
|
@@ -40,7 +40,11 @@
|
|
|
40
40
|
* HTTP response).
|
|
41
41
|
*/
|
|
42
42
|
export class MapperResolutionError extends Error {
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Defaults to `"MapperResolutionError"`. Typed `string` (not the
|
|
45
|
+
* narrow literal) so subclasses like `NamedMissingStateError` can
|
|
46
|
+
* override it with their own name.
|
|
47
|
+
*/
|
|
44
48
|
name = "MapperResolutionError";
|
|
45
49
|
/** Structured diagnostic context attached at construction time. */
|
|
46
50
|
context;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapperResolutionError.js","sourceRoot":"","sources":["../../src/utils/MapperResolutionError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC/C
|
|
1
|
+
{"version":3,"file":"MapperResolutionError.js","sourceRoot":"","sources":["../../src/utils/MapperResolutionError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC/C;;;;OAIG;IACsB,IAAI,GAAW,uBAAuB,CAAC;IAEhE,mEAAmE;IACnD,OAAO,CA8BrB;IAEF,YACC,OAAe,EACf,OAMC;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,kEAAkE;QAClE,4DAA4D;QAC5D,0CAA0C;QAC1C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC7D,2DAA2D;QAC3D,4DAA4D;QAC5D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,IAAoC,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC7D,CAAC;IACF,CAAC;CACD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MapperResolutionError } from "./MapperResolutionError";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a `js/ctx.state.<id>...` (or `${ctx.state.<id>...}`) input
|
|
4
|
+
* expression fails because the referenced state slot `ctx.state.<id>`
|
|
5
|
+
* was never persisted — a dangling cross-step reference.
|
|
6
|
+
*
|
|
7
|
+
* This is the runtime backstop for the auto-persist-all / typed-handle
|
|
8
|
+
* contract: it catches references the type system can't (raw `js/`
|
|
9
|
+
* strings, stale cross-runtime stubs, hand-authored JSON twins) and
|
|
10
|
+
* NAMES the missing state id and the referencing step/workflow, instead
|
|
11
|
+
* of leaving a generic `Cannot read properties of undefined (reading
|
|
12
|
+
* 'X')` that blames the consuming step's expression opaquely.
|
|
13
|
+
*
|
|
14
|
+
* A slot counts as missing ONLY when the id is absent from `ctx.state`
|
|
15
|
+
* entirely (never persisted: typo'd id, ephemeral step, wrong
|
|
16
|
+
* `as`/`spread`, a step that ran but errored, or a forEach body reading
|
|
17
|
+
* `state[as]` before the loop populated it). A slot that EXISTS but
|
|
18
|
+
* holds a falsy value (`0`, `false`, `""`, `null`) is NOT missing and
|
|
19
|
+
* still resolves — only the state ROOT key is checked, never nested
|
|
20
|
+
* fields, so a legitimately-undefined optional output never trips this.
|
|
21
|
+
*
|
|
22
|
+
* Subclass of {@link MapperResolutionError} so existing
|
|
23
|
+
* `instanceof MapperResolutionError` handlers and `BLOK_MAPPER_MODE`
|
|
24
|
+
* routing keep working unchanged; new code can `instanceof
|
|
25
|
+
* NamedMissingStateError` to special-case the dangling-ref case.
|
|
26
|
+
*/
|
|
27
|
+
export declare class NamedMissingStateError extends MapperResolutionError {
|
|
28
|
+
readonly name: string;
|
|
29
|
+
/** The state id (`ctx.state.<id>`) that was referenced but never persisted. */
|
|
30
|
+
readonly missingStateId: string;
|
|
31
|
+
constructor(message: string, missingStateId: string, context: {
|
|
32
|
+
readonly expression: string;
|
|
33
|
+
readonly syntax: "js" | "template";
|
|
34
|
+
readonly workflowName?: string;
|
|
35
|
+
readonly stepName?: string;
|
|
36
|
+
readonly cause?: unknown;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { MapperResolutionError } from "./MapperResolutionError";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a `js/ctx.state.<id>...` (or `${ctx.state.<id>...}`) input
|
|
4
|
+
* expression fails because the referenced state slot `ctx.state.<id>`
|
|
5
|
+
* was never persisted — a dangling cross-step reference.
|
|
6
|
+
*
|
|
7
|
+
* This is the runtime backstop for the auto-persist-all / typed-handle
|
|
8
|
+
* contract: it catches references the type system can't (raw `js/`
|
|
9
|
+
* strings, stale cross-runtime stubs, hand-authored JSON twins) and
|
|
10
|
+
* NAMES the missing state id and the referencing step/workflow, instead
|
|
11
|
+
* of leaving a generic `Cannot read properties of undefined (reading
|
|
12
|
+
* 'X')` that blames the consuming step's expression opaquely.
|
|
13
|
+
*
|
|
14
|
+
* A slot counts as missing ONLY when the id is absent from `ctx.state`
|
|
15
|
+
* entirely (never persisted: typo'd id, ephemeral step, wrong
|
|
16
|
+
* `as`/`spread`, a step that ran but errored, or a forEach body reading
|
|
17
|
+
* `state[as]` before the loop populated it). A slot that EXISTS but
|
|
18
|
+
* holds a falsy value (`0`, `false`, `""`, `null`) is NOT missing and
|
|
19
|
+
* still resolves — only the state ROOT key is checked, never nested
|
|
20
|
+
* fields, so a legitimately-undefined optional output never trips this.
|
|
21
|
+
*
|
|
22
|
+
* Subclass of {@link MapperResolutionError} so existing
|
|
23
|
+
* `instanceof MapperResolutionError` handlers and `BLOK_MAPPER_MODE`
|
|
24
|
+
* routing keep working unchanged; new code can `instanceof
|
|
25
|
+
* NamedMissingStateError` to special-case the dangling-ref case.
|
|
26
|
+
*/
|
|
27
|
+
export class NamedMissingStateError extends MapperResolutionError {
|
|
28
|
+
name = "NamedMissingStateError";
|
|
29
|
+
/** The state id (`ctx.state.<id>`) that was referenced but never persisted. */
|
|
30
|
+
missingStateId;
|
|
31
|
+
constructor(message, missingStateId, context) {
|
|
32
|
+
super(message, context);
|
|
33
|
+
this.missingStateId = missingStateId;
|
|
34
|
+
// Preserve the prototype chain across down-compilation so
|
|
35
|
+
// `instanceof NamedMissingStateError` holds on ES5 targets.
|
|
36
|
+
Object.setPrototypeOf(this, NamedMissingStateError.prototype);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=NamedMissingStateError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NamedMissingStateError.js","sourceRoot":"","sources":["../../src/utils/NamedMissingStateError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,OAAO,sBAAuB,SAAQ,qBAAqB;IACvC,IAAI,GAAW,wBAAwB,CAAC;IAEjE,+EAA+E;IAC/D,cAAc,CAAS;IAEvC,YACC,OAAe,EACf,cAAsB,EACtB,OAMC;QAED,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,0DAA0D;QAC1D,4DAA4D;QAC5D,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC/D,CAAC;CACD"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { default as Mapper, type MapperMode } from "./Mapper";
|
|
|
3
3
|
export { MapperResolutionError } from "./MapperResolutionError";
|
|
4
4
|
export { default as MemoryUsage } from "./MemoryUsage";
|
|
5
5
|
export { default as Metrics } from "./MetricsBase";
|
|
6
|
+
export { NamedMissingStateError } from "./NamedMissingStateError";
|
|
6
7
|
export { default as Time } from "./Time";
|
package/dist/utils/index.js
CHANGED
|
@@ -3,5 +3,6 @@ export { default as Mapper } from "./Mapper";
|
|
|
3
3
|
export { MapperResolutionError } from "./MapperResolutionError";
|
|
4
4
|
export { default as MemoryUsage } from "./MemoryUsage";
|
|
5
5
|
export { default as Metrics } from "./MetricsBase";
|
|
6
|
+
export { NamedMissingStateError } from "./NamedMissingStateError";
|
|
6
7
|
export { default as Time } from "./Time";
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAmB,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAmB,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lowerRefs — ADR 0001 Option C load-boundary lowering pass.
|
|
3
|
+
*
|
|
4
|
+
* The published/serialized IR carries STRUCTURAL handle references —
|
|
5
|
+
* `{ $ref: { step, path } }` — so the canvas, JSON twin, and AI can derive
|
|
6
|
+
* edges and catch dangling refs WITHOUT executing. The runtime, however, is
|
|
7
|
+
* byte-identical to today: the {@link Mapper} only resolves `js/ctx....`
|
|
8
|
+
* strings and raw `ctx.*` `when` strings. It has no idea what a `{$ref}` is —
|
|
9
|
+
* it walks INTO the plain object and string-resolves the inner `step`/`path`
|
|
10
|
+
* fields, never treating the node as a reference (verified by ADR 0001 probe
|
|
11
|
+
* S1 + the falsification test).
|
|
12
|
+
*
|
|
13
|
+
* This pass bridges the two layers. It runs at the workflow LOAD BOUNDARY,
|
|
14
|
+
* BEFORE the Mapper, and compiles every structural `{$ref}` into EXACTLY the
|
|
15
|
+
* wire string today's engine already resolves. The Mapper stays untouched.
|
|
16
|
+
*
|
|
17
|
+
* Scope: the STEP-INPUTS, TRIGGER-ROOT, and TPL positions.
|
|
18
|
+
* - step input value: `"js/ctx.state.<root>" + path`
|
|
19
|
+
* - `path` mapping: string segment → `.seg`, numeric → `[n]`,
|
|
20
|
+
* empty `path: []` (whole-output ref) → `"js/ctx.state.<root>"`.
|
|
21
|
+
* - `{$tpl}` (#425): a ref embedded in a string → a `js/\`…${ctx.state…}…\``
|
|
22
|
+
* template literal; string/literal segments embedded as escaped text.
|
|
23
|
+
* - recurses into plain arrays/objects; lowers nested `{$ref}`/`{$tpl}`; leaves
|
|
24
|
+
* everything else (primitives, class instances, functions) untouched.
|
|
25
|
+
*
|
|
26
|
+
* Out of scope (separate tasks):
|
|
27
|
+
* - `branch.when` bare-ctx lowering → ADR 0004.
|
|
28
|
+
*
|
|
29
|
+
* Pure + deterministic — never mutates its input. Determinism keeps the
|
|
30
|
+
* idempotency-cache key stable run-to-run (ADR 0001 "hash stability").
|
|
31
|
+
*/
|
|
32
|
+
/** The structural handle reference sentinel. */
|
|
33
|
+
export interface StructuralRef {
|
|
34
|
+
$ref: {
|
|
35
|
+
step: string;
|
|
36
|
+
path?: (string | number)[];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Recursively lower every structural `{$ref}` inside `value` to its wire
|
|
41
|
+
* string. Pure — returns a NEW value, never mutates the input. Plain
|
|
42
|
+
* objects/arrays are walked; everything else (primitives, class instances,
|
|
43
|
+
* functions, null/undefined) passes through untouched.
|
|
44
|
+
*/
|
|
45
|
+
export declare function lowerRefs<T>(value: T): T;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lowerRefs — ADR 0001 Option C load-boundary lowering pass.
|
|
3
|
+
*
|
|
4
|
+
* The published/serialized IR carries STRUCTURAL handle references —
|
|
5
|
+
* `{ $ref: { step, path } }` — so the canvas, JSON twin, and AI can derive
|
|
6
|
+
* edges and catch dangling refs WITHOUT executing. The runtime, however, is
|
|
7
|
+
* byte-identical to today: the {@link Mapper} only resolves `js/ctx....`
|
|
8
|
+
* strings and raw `ctx.*` `when` strings. It has no idea what a `{$ref}` is —
|
|
9
|
+
* it walks INTO the plain object and string-resolves the inner `step`/`path`
|
|
10
|
+
* fields, never treating the node as a reference (verified by ADR 0001 probe
|
|
11
|
+
* S1 + the falsification test).
|
|
12
|
+
*
|
|
13
|
+
* This pass bridges the two layers. It runs at the workflow LOAD BOUNDARY,
|
|
14
|
+
* BEFORE the Mapper, and compiles every structural `{$ref}` into EXACTLY the
|
|
15
|
+
* wire string today's engine already resolves. The Mapper stays untouched.
|
|
16
|
+
*
|
|
17
|
+
* Scope: the STEP-INPUTS, TRIGGER-ROOT, and TPL positions.
|
|
18
|
+
* - step input value: `"js/ctx.state.<root>" + path`
|
|
19
|
+
* - `path` mapping: string segment → `.seg`, numeric → `[n]`,
|
|
20
|
+
* empty `path: []` (whole-output ref) → `"js/ctx.state.<root>"`.
|
|
21
|
+
* - `{$tpl}` (#425): a ref embedded in a string → a `js/\`…${ctx.state…}…\``
|
|
22
|
+
* template literal; string/literal segments embedded as escaped text.
|
|
23
|
+
* - recurses into plain arrays/objects; lowers nested `{$ref}`/`{$tpl}`; leaves
|
|
24
|
+
* everything else (primitives, class instances, functions) untouched.
|
|
25
|
+
*
|
|
26
|
+
* Out of scope (separate tasks):
|
|
27
|
+
* - `branch.when` bare-ctx lowering → ADR 0004.
|
|
28
|
+
*
|
|
29
|
+
* Pure + deterministic — never mutates its input. Determinism keeps the
|
|
30
|
+
* idempotency-cache key stable run-to-run (ADR 0001 "hash stability").
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Is `value` the reserved `{$ref}` sentinel — a single-key object whose only
|
|
34
|
+
* key is `$ref` and whose `$ref.step` is a string?
|
|
35
|
+
*
|
|
36
|
+
* The single-key + string-step guard is what makes `$ref` safe to reserve:
|
|
37
|
+
* a step-inputs object that legitimately carries unrelated data (even data
|
|
38
|
+
* with the literal keys `step`/`path`) is NOT a ref and passes through
|
|
39
|
+
* untouched. ADR 0001 confirmed no current workflow uses `$ref` as user data.
|
|
40
|
+
*/
|
|
41
|
+
function isStructuralRef(value) {
|
|
42
|
+
const keys = Object.keys(value);
|
|
43
|
+
if (keys.length !== 1 || keys[0] !== "$ref")
|
|
44
|
+
return false;
|
|
45
|
+
const ref = value.$ref;
|
|
46
|
+
return typeof ref === "object" && ref !== null && typeof ref.step === "string";
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The trigger/entry-handle sentinel. The callback `workflow()` mints the
|
|
50
|
+
* trigger-payload handle (`req`) rooted at this pseudo-step (see
|
|
51
|
+
* `core/runner/src/stepBuilder.ts:makeHandle("@trigger")`). It is NOT a real
|
|
52
|
+
* step — the runner never writes `ctx.state["@trigger"]`; the trigger payload
|
|
53
|
+
* lives at `ctx.request` (TriggerBase.createContext sets `ctx.state = {}`).
|
|
54
|
+
* So a ref rooted here lowers to `js/ctx.request`, mirroring the existing
|
|
55
|
+
* `$.req` proxy. Keep this string in sync with stepBuilder's sentinel.
|
|
56
|
+
*
|
|
57
|
+
* Scope: ALL request-shaped triggers funnel into ctx.request, so the typed
|
|
58
|
+
* per-trigger entry handles (#336 — http`req`/webhook`event`/cron`tick`/
|
|
59
|
+
* worker`job`/pubsub`msg`/grpc`rpc`) all root here; the per-kind difference is
|
|
60
|
+
* a TYPE-only refinement in stepBuilder, NOT a lowering change. The greenfield
|
|
61
|
+
* `manual` (#362) `args` handle + imperative sse/ws `conn`/`stream` are NOT
|
|
62
|
+
* request-shaped and are not wired through this root.
|
|
63
|
+
*/
|
|
64
|
+
const TRIGGER_SENTINEL = "@trigger";
|
|
65
|
+
/**
|
|
66
|
+
* The tryCatch error-handle sentinel (#317). The callback `tryCatch()` mints the
|
|
67
|
+
* `error` handle the catch arm receives rooted at this pseudo-step (see
|
|
68
|
+
* `core/runner/src/stepBuilder.ts:tryCatch`). It is NOT a real step — the error
|
|
69
|
+
* envelope lives at `ctx.error` (set by `TryCatchNode` on catch entry), NOT
|
|
70
|
+
* `ctx.state["@error"]`. So a ref rooted here lowers to `js/ctx.error`, mirroring
|
|
71
|
+
* the `@trigger` → `ctx.request` branch. Keep this string in sync with stepBuilder.
|
|
72
|
+
*/
|
|
73
|
+
const ERROR_SENTINEL = "@error";
|
|
74
|
+
/** Valid JS identifier — same shape `$.ts`'s proxy encoder accepts for `.k`. */
|
|
75
|
+
const IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
76
|
+
/**
|
|
77
|
+
* Encode a single path segment into its wire-string suffix, mirroring
|
|
78
|
+
* `unwrapProxies` (core/workflow-helper/src/proxy/$.ts) EXACTLY — three
|
|
79
|
+
* branches, not two: numeric → `[n]`; valid JS identifier → `.k`; anything
|
|
80
|
+
* else (dash, dot, space, leading digit on a string key) → `[${JSON.stringify(k)}]`.
|
|
81
|
+
* The bracket-quote form is the only one that survives the Mapper's `js/...`
|
|
82
|
+
* eval — `.fan-out` would parse as `fan - out`.
|
|
83
|
+
*/
|
|
84
|
+
function encodeSegment(seg) {
|
|
85
|
+
if (typeof seg === "number")
|
|
86
|
+
return `[${seg}]`;
|
|
87
|
+
if (IDENT_RE.test(seg))
|
|
88
|
+
return `.${seg}`;
|
|
89
|
+
return `[${JSON.stringify(seg)}]`;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Compile a `path` array into the wire-string suffix the Mapper resolves.
|
|
93
|
+
* Empty path produces the empty suffix (whole-output ref).
|
|
94
|
+
*/
|
|
95
|
+
function encodePath(path) {
|
|
96
|
+
return path.map(encodeSegment).join("");
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Lower a single structural `{$ref}` into its `js/ctx.state.<root>...` wire
|
|
100
|
+
* string.
|
|
101
|
+
*
|
|
102
|
+
* `<root>` is `ref.$ref.step` LITERALLY — and that is now correct for every
|
|
103
|
+
* persistence knob (#327/#342/#339): `step()` mints each handle ALREADY rooted
|
|
104
|
+
* at its resolved state key (`as ?? id`; a spread step's per-key sub-handles
|
|
105
|
+
* root at their top-level key), so the `{$ref}.step` this pass sees is already
|
|
106
|
+
* the final `ctx.state` slot. No step→key map needed here — re-rooting happens
|
|
107
|
+
* at handle mint time in `core/runner/src/stepBuilder.ts`.
|
|
108
|
+
*/
|
|
109
|
+
function refExpr(ref) {
|
|
110
|
+
const suffix = encodePath(ref.$ref.path ?? []);
|
|
111
|
+
// Trigger-root: the `@trigger` pseudo-step's payload lives at `ctx.request`,
|
|
112
|
+
// NOT `ctx.state["@trigger"]` (the runner never populates that). Lower to
|
|
113
|
+
// `ctx.request` + the same encoded path so `req.body.name` resolves.
|
|
114
|
+
if (ref.$ref.step === TRIGGER_SENTINEL) {
|
|
115
|
+
return `ctx.request${suffix}`;
|
|
116
|
+
}
|
|
117
|
+
// Error-root: the `@error` pseudo-step's envelope lives at `ctx.error` (set by
|
|
118
|
+
// TryCatchNode on catch entry), NOT `ctx.state["@error"]`. Lower to `ctx.error`
|
|
119
|
+
// + the same encoded path so `error.message` / `error.code` resolve.
|
|
120
|
+
if (ref.$ref.step === ERROR_SENTINEL) {
|
|
121
|
+
return `ctx.error${suffix}`;
|
|
122
|
+
}
|
|
123
|
+
const root = encodeSegment(ref.$ref.step); // `.fanOut` or `["fan-out"]`
|
|
124
|
+
return `ctx.state${root}${suffix}`;
|
|
125
|
+
}
|
|
126
|
+
function lowerRef(ref) {
|
|
127
|
+
return `js/${refExpr(ref)}`;
|
|
128
|
+
}
|
|
129
|
+
function isStructuralTpl(value) {
|
|
130
|
+
const keys = Object.keys(value);
|
|
131
|
+
return keys.length === 1 && keys[0] === "$tpl" && Array.isArray(value.$tpl);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Lower a `{$tpl}` node to a `js/\`…${ctx.state…}…\`` template-literal string the
|
|
135
|
+
* Mapper resolves (`return (\`…\`)`). String segments are embedded as literal text
|
|
136
|
+
* (escaped for the backtick context); `{$ref}` segments become `${<refExpr>}` so
|
|
137
|
+
* the value's native type drives the interpolation (number/0/false preserved by
|
|
138
|
+
* JS template coercion — and falsy values are NOT dropped, unlike `||`-based code);
|
|
139
|
+
* any other literal segment is escaped into the literal text.
|
|
140
|
+
*/
|
|
141
|
+
function lowerTpl(node) {
|
|
142
|
+
let body = "";
|
|
143
|
+
for (const seg of node.$tpl) {
|
|
144
|
+
if (seg !== null && typeof seg === "object" && isStructuralRef(seg)) {
|
|
145
|
+
body += `\${${refExpr(seg)}}`;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
body += escapeTemplateText(typeof seg === "string" ? seg : String(seg));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return `js/\`${body}\``;
|
|
152
|
+
}
|
|
153
|
+
/** Escape the three chars that are special inside a backtick template literal. */
|
|
154
|
+
function escapeTemplateText(text) {
|
|
155
|
+
return text.replace(/[\\`$]/g, (c) => `\\${c}`);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Recursively lower every structural `{$ref}` inside `value` to its wire
|
|
159
|
+
* string. Pure — returns a NEW value, never mutates the input. Plain
|
|
160
|
+
* objects/arrays are walked; everything else (primitives, class instances,
|
|
161
|
+
* functions, null/undefined) passes through untouched.
|
|
162
|
+
*/
|
|
163
|
+
export function lowerRefs(value) {
|
|
164
|
+
return lower(value);
|
|
165
|
+
}
|
|
166
|
+
function lower(value) {
|
|
167
|
+
if (value === null || value === undefined || typeof value !== "object") {
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
if (Array.isArray(value)) {
|
|
171
|
+
return value.map(lower);
|
|
172
|
+
}
|
|
173
|
+
// Plain object only — class instances (custom prototype) pass through.
|
|
174
|
+
const proto = Object.getPrototypeOf(value);
|
|
175
|
+
if (proto !== null && proto !== Object.prototype) {
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
if (isStructuralRef(value)) {
|
|
179
|
+
return lowerRef(value);
|
|
180
|
+
}
|
|
181
|
+
if (isStructuralTpl(value)) {
|
|
182
|
+
return lowerTpl(value);
|
|
183
|
+
}
|
|
184
|
+
const out = {};
|
|
185
|
+
for (const k of Object.keys(value)) {
|
|
186
|
+
out[k] = lower(value[k]);
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=lowerRefs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lowerRefs.js","sourceRoot":"","sources":["../../src/utils/lowerRefs.ts"],"names":[],"mappings":"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"}
|