@blokjs/helper 0.2.1 → 0.4.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.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The typed `$` proxy — typed sugar over the runtime's `js/...` resolver.
3
+ *
4
+ * Property access on `$` builds a path string at definition time. The
5
+ * `unwrapProxies` deep-walk in the `workflow()` factory replaces each proxy
6
+ * value with its compiled `"js/ctx.<path>"` string before the workflow is
7
+ * handed to the runner. This means:
8
+ *
9
+ * - Authors get IDE autocomplete on `$.req.body.foo`, `$.state.users[0]`, etc.
10
+ * - The runtime sees plain strings (no Proxy traversal at execution time).
11
+ * - The existing `Mapper.jsMapper` resolver works unchanged — it already
12
+ * evaluates `js/...` strings against `ctx`.
13
+ *
14
+ * @example
15
+ * import { workflow, $ } from "@blokjs/helper";
16
+ *
17
+ * workflow({
18
+ * trigger: { http: { method: "GET" } },
19
+ * steps: [
20
+ * { id: "fetch", use: "@blokjs/api-call",
21
+ * inputs: { userId: $.req.params.id } },
22
+ * { id: "respond", use: "@blokjs/respond",
23
+ * inputs: { body: $.state.fetch } }
24
+ * ]
25
+ * });
26
+ * // After `unwrapProxies` runs at definition time:
27
+ * // inputs.userId === "js/ctx.req.params.id"
28
+ * // inputs.body === "js/ctx.state.fetch"
29
+ */
30
+ /** Internal symbol used to detect proxy values during the deep-walk. */
31
+ export declare const JS_EXPR_TAG: unique symbol;
32
+ /**
33
+ * The shape of any sub-path of the `$` proxy. Property and index access
34
+ * are recursive; string conversion produces a `js/ctx....` literal.
35
+ *
36
+ * Typed as `unknown` at the leaves so authors can pass a path anywhere a
37
+ * value of any type is expected without `as` casts.
38
+ */
39
+ export type ExprPath = {
40
+ readonly [key: string]: ExprPath;
41
+ } & {
42
+ toString(): string;
43
+ toJSON(): string;
44
+ };
45
+ /**
46
+ * The top-level `$` proxy. Provides typed access to:
47
+ * - `$.req` — request envelope (alias of `ctx.request`)
48
+ * - `$.prev` — previous step's response envelope (alias of `ctx.response`)
49
+ * - `$.state` — accumulated step outputs by step id
50
+ * - `$.env` — process env mirror
51
+ * - `$.step` — current step metadata (`{ name, index, total, depth }`)
52
+ * - `$.workflow` — current workflow metadata
53
+ *
54
+ * Plus legacy fallbacks for `$.request` (= `$.req`) and `$.response` (= `$.prev`).
55
+ */
56
+ export interface DollarProxy {
57
+ readonly req: ExprPath;
58
+ readonly request: ExprPath;
59
+ readonly prev: ExprPath;
60
+ readonly response: ExprPath;
61
+ readonly state: ExprPath;
62
+ readonly vars: ExprPath;
63
+ readonly env: ExprPath;
64
+ readonly step: ExprPath;
65
+ readonly workflow: ExprPath;
66
+ /** Escape hatch — any property; returns a sub-path. */
67
+ readonly [key: string]: ExprPath;
68
+ }
69
+ /**
70
+ * The `$` proxy entry point. All paths root at `ctx`.
71
+ *
72
+ * @see DollarProxy for the typed surface.
73
+ */
74
+ export declare const $: DollarProxy;
75
+ /**
76
+ * Recursively replace any `$` proxy values inside `value` with their
77
+ * compiled `"js/ctx.<path>"` strings.
78
+ *
79
+ * Called by `workflow()` and `branch()` factories at definition time to
80
+ * convert in-memory proxy references into the wire-shape strings the
81
+ * runner's `Mapper` expects.
82
+ *
83
+ * Unwraps:
84
+ * - Proxies → `"js/ctx.<path>"` strings
85
+ * - Plain objects → walked recursively, returning a NEW object
86
+ * - Arrays → walked, returning a NEW array
87
+ *
88
+ * Leaves alone:
89
+ * - Primitives (string, number, boolean, null, undefined)
90
+ * - Class instances (anything with a non-Object prototype)
91
+ * - Functions other than the proxy itself
92
+ *
93
+ * Pure — never mutates the input.
94
+ */
95
+ export declare function unwrapProxies<T>(value: T): T;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * The typed `$` proxy — typed sugar over the runtime's `js/...` resolver.
3
+ *
4
+ * Property access on `$` builds a path string at definition time. The
5
+ * `unwrapProxies` deep-walk in the `workflow()` factory replaces each proxy
6
+ * value with its compiled `"js/ctx.<path>"` string before the workflow is
7
+ * handed to the runner. This means:
8
+ *
9
+ * - Authors get IDE autocomplete on `$.req.body.foo`, `$.state.users[0]`, etc.
10
+ * - The runtime sees plain strings (no Proxy traversal at execution time).
11
+ * - The existing `Mapper.jsMapper` resolver works unchanged — it already
12
+ * evaluates `js/...` strings against `ctx`.
13
+ *
14
+ * @example
15
+ * import { workflow, $ } from "@blokjs/helper";
16
+ *
17
+ * workflow({
18
+ * trigger: { http: { method: "GET" } },
19
+ * steps: [
20
+ * { id: "fetch", use: "@blokjs/api-call",
21
+ * inputs: { userId: $.req.params.id } },
22
+ * { id: "respond", use: "@blokjs/respond",
23
+ * inputs: { body: $.state.fetch } }
24
+ * ]
25
+ * });
26
+ * // After `unwrapProxies` runs at definition time:
27
+ * // inputs.userId === "js/ctx.req.params.id"
28
+ * // inputs.body === "js/ctx.state.fetch"
29
+ */
30
+ /** Internal symbol used to detect proxy values during the deep-walk. */
31
+ export const JS_EXPR_TAG = Symbol("blok.jsExpr");
32
+ const IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
33
+ const NUMERIC_RE = /^\d+$/;
34
+ function makeProxy(prefix) {
35
+ // Use a function as the target so `typeof` is `function` — that lets us
36
+ // distinguish proxy values from plain objects in `unwrapProxies`. The
37
+ // function is never called; it's just a tag.
38
+ const target = (() => prefix);
39
+ target[JS_EXPR_TAG] = prefix;
40
+ return new Proxy(target, {
41
+ get(_target, key) {
42
+ if (key === JS_EXPR_TAG)
43
+ return prefix;
44
+ if (key === Symbol.toPrimitive)
45
+ return (_hint) => `js/${prefix}`;
46
+ if (key === "toString")
47
+ return () => `js/${prefix}`;
48
+ if (key === "toJSON")
49
+ return () => `js/${prefix}`;
50
+ if (key === "valueOf")
51
+ return () => `js/${prefix}`;
52
+ // Don't pretend to be a thenable — Promise.resolve() probes `.then`.
53
+ if (key === "then")
54
+ return undefined;
55
+ // Ignore inherited symbols (Symbol.iterator, etc.).
56
+ if (typeof key === "symbol")
57
+ return undefined;
58
+ const k = String(key);
59
+ let next;
60
+ if (NUMERIC_RE.test(k)) {
61
+ next = `${prefix}[${k}]`;
62
+ }
63
+ else if (IDENT_RE.test(k)) {
64
+ next = `${prefix}.${k}`;
65
+ }
66
+ else {
67
+ next = `${prefix}[${JSON.stringify(k)}]`;
68
+ }
69
+ return makeProxy(next);
70
+ },
71
+ });
72
+ }
73
+ /**
74
+ * The `$` proxy entry point. All paths root at `ctx`.
75
+ *
76
+ * @see DollarProxy for the typed surface.
77
+ */
78
+ export const $ = makeProxy("ctx");
79
+ /**
80
+ * Recursively replace any `$` proxy values inside `value` with their
81
+ * compiled `"js/ctx.<path>"` strings.
82
+ *
83
+ * Called by `workflow()` and `branch()` factories at definition time to
84
+ * convert in-memory proxy references into the wire-shape strings the
85
+ * runner's `Mapper` expects.
86
+ *
87
+ * Unwraps:
88
+ * - Proxies → `"js/ctx.<path>"` strings
89
+ * - Plain objects → walked recursively, returning a NEW object
90
+ * - Arrays → walked, returning a NEW array
91
+ *
92
+ * Leaves alone:
93
+ * - Primitives (string, number, boolean, null, undefined)
94
+ * - Class instances (anything with a non-Object prototype)
95
+ * - Functions other than the proxy itself
96
+ *
97
+ * Pure — never mutates the input.
98
+ */
99
+ export function unwrapProxies(value) {
100
+ return unwrap(value);
101
+ }
102
+ function unwrap(value) {
103
+ if (value === null || value === undefined)
104
+ return value;
105
+ // Detect proxy via the tag symbol.
106
+ if (typeof value === "function") {
107
+ const tag = value[JS_EXPR_TAG];
108
+ if (typeof tag === "string") {
109
+ return `js/${tag}`;
110
+ }
111
+ // Other functions — leave as-is.
112
+ return value;
113
+ }
114
+ if (Array.isArray(value)) {
115
+ return value.map(unwrap);
116
+ }
117
+ // Plain object only — class instances pass through untouched.
118
+ if (typeof value === "object") {
119
+ const proto = Object.getPrototypeOf(value);
120
+ if (proto === null || proto === Object.prototype) {
121
+ const out = {};
122
+ for (const k of Object.keys(value)) {
123
+ out[k] = unwrap(value[k]);
124
+ }
125
+ return out;
126
+ }
127
+ }
128
+ return value;
129
+ }
130
+ //# sourceMappingURL=$.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"$.js","sourceRoot":"","sources":["../../src/proxy/$.ts"],"names":[],"mappings":"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"}