blueprint-runtime 0.0.0-stage → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +224 -3
  3. package/dist/src/blueprint/load.js +83 -0
  4. package/dist/src/blueprint/load.js.map +1 -0
  5. package/dist/src/blueprint/plan.js +202 -0
  6. package/dist/src/blueprint/plan.js.map +1 -0
  7. package/dist/src/cli.js +182 -0
  8. package/dist/src/cli.js.map +1 -0
  9. package/dist/src/expr/dates.js +152 -0
  10. package/dist/src/expr/dates.js.map +1 -0
  11. package/dist/src/expr/decimal.js +66 -0
  12. package/dist/src/expr/decimal.js.map +1 -0
  13. package/dist/src/expr/errors.js +31 -0
  14. package/dist/src/expr/errors.js.map +1 -0
  15. package/dist/src/expr/evaluate.js +250 -0
  16. package/dist/src/expr/evaluate.js.map +1 -0
  17. package/dist/src/expr/functions.js +460 -0
  18. package/dist/src/expr/functions.js.map +1 -0
  19. package/dist/src/expr/parser.js +228 -0
  20. package/dist/src/expr/parser.js.map +1 -0
  21. package/dist/src/expr/scan.js +101 -0
  22. package/dist/src/expr/scan.js.map +1 -0
  23. package/dist/src/expr/values.js +118 -0
  24. package/dist/src/expr/values.js.map +1 -0
  25. package/dist/src/findings.js +10 -0
  26. package/dist/src/findings.js.map +1 -0
  27. package/dist/src/inspect.js +313 -0
  28. package/dist/src/inspect.js.map +1 -0
  29. package/dist/src/json/parse.js +225 -0
  30. package/dist/src/json/parse.js.map +1 -0
  31. package/dist/src/registry.js +39 -0
  32. package/dist/src/registry.js.map +1 -0
  33. package/dist/src/run/case.js +122 -0
  34. package/dist/src/run/case.js.map +1 -0
  35. package/dist/src/run/compare.js +94 -0
  36. package/dist/src/run/compare.js.map +1 -0
  37. package/dist/src/run/fixtures.js +122 -0
  38. package/dist/src/run/fixtures.js.map +1 -0
  39. package/dist/src/run/modules.js +380 -0
  40. package/dist/src/run/modules.js.map +1 -0
  41. package/dist/src/run/operators.js +151 -0
  42. package/dist/src/run/operators.js.map +1 -0
  43. package/dist/src/run/scheduler.js +306 -0
  44. package/dist/src/run/scheduler.js.map +1 -0
  45. package/dist/src/run/trace.js +2 -0
  46. package/dist/src/run/trace.js.map +1 -0
  47. package/package.json +60 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Intikhab Azam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,224 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ <div align="center">
2
+
3
+ <img src="docs/header.svg" alt="blueprint-runtime: run and test Make scenario blueprints offline. 71 of 79 real Make runs reproduced exactly, 0 differ." width="100%">
4
+
5
+ # blueprint-runtime — test Make.com scenarios offline
6
+
7
+ **An offline test runner for Make.com (formerly Integromat) scenario blueprints. Replay real Make runs on your own machine, in CI, and see the first value that changed: no Make account, no credits, no network. Every behavior it claims was recorded in a real Make run; anything else is refused, never guessed.**
8
+
9
+ [![License](https://img.shields.io/badge/license-MIT-2a78d6?style=for-the-badge)](LICENSE)
10
+ [![Node](https://img.shields.io/badge/node-24%2B-2a78d6?style=for-the-badge&logo=nodedotjs&logoColor=white)](https://nodejs.org/)
11
+ [![Make runs](https://img.shields.io/badge/real%20Make%20runs-71%2F79%20match%2C%200%20differ-1baf7a?style=for-the-badge)](corpus/NOTES.md)
12
+ [![Tests](https://img.shields.io/badge/tests-472%20passing-1baf7a?style=for-the-badge)](test/)
13
+ [![Dependencies](https://img.shields.io/badge/runtime%20deps-0-eb6834?style=for-the-badge)](package.json)
14
+
15
+ [Demo](#demo) · [Results](#results) · [Quick start](#quick-start) · [CI](#run-it-in-ci-github-actions) · [How it works](#how-it-works) · [Supported](#what-runs-today) · [Fixtures](#fixtures-http-and-third-party-modules) · [FAQ](#faq) · [Limitations](#limitations)
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## What this is
22
+
23
+ You build a scenario in Make, it works, and then someone edits a mapping. The only way to know what broke is to run it again in Make, with real data and real credits.
24
+
25
+ `bpr` runs the blueprint locally instead. It replays inputs that went through the real scenario and compares every module's input and output bundles, every filter decision, the outcome and the webhook response with what Make actually produced, then points at the first difference:
26
+
27
+ ```
28
+ $ bpr test examples/broken-mapping
29
+ FAIL A-002-plain module 2 input bundle 1 at /value: Make had "ADA LOVELACE", the local run "Ada Lovelace"
30
+ ```
31
+
32
+ Someone changed `upper(1.name)` to `capitalize(1.name)`. See [examples/broken-mapping](examples/broken-mapping/).
33
+
34
+ **The rule.** Every behavior this runtime supports was observed in a real Make run, and the recordings are in [`corpus/`](corpus/NOTES.md). If a blueprint uses something that has not been observed (a module, an operator, a function, a setting), `bpr` says what and refuses. That is why some of Make's quirks are reproduced exactly: a field of a plain-text iterator bundle reads as the text itself, and arrays written as text use a comma plus a NO-BREAK SPACE. It is also why the one quirk that could not be explained is refused instead of copied: for the bundle `0`, Make returned the previous bundle's value.
35
+
36
+ ## Demo
37
+
38
+ <img src="docs/demo.gif" alt="Terminal demo, real output. 1: bpr test examples/broken-mapping reports FAIL on three recorded runs at module 2 input /value (Make had TEST, the local run Test) and PASS on the empty-name case, exit 1. 2: bpr test examples/http-fixture/cases: PASS when the HTTP fixture matches, FIXT when the fixture expects a different request body, when a fixture is never used, and when no fixture exists, exit 5." width="100%">
39
+
40
+ Generated from real command output by [`docs/make_demo.py`](docs/make_demo.py).
41
+
42
+ ## Results
43
+
44
+ ![71 of 79 real Make runs reproduced exactly, 0 differ. A straight line 9/9, B router and filters 16/16, C iterator and aggregator 17/17, C2 iterator probes 13/14, E HTTP from fixtures 5/5, T multi-bundle trigger 8/8, N now and [] 3/3, D formula probes 0/7 refused.](docs/charts/1_conformance.png)
45
+
46
+ 79 runs were recorded in a free Make account across eight scenario families. 71 are reproduced exactly and **none differ**. The 8 that are refused, not failed:
47
+
48
+ - **D (7):** the formula-probe blueprint contains `replace(s; /o/g; "0")`. Make ignored that regex in a real run for a reason nobody has recorded, so `bpr` refuses the file. The engine still matches 530 of 535 recorded formula results from these runs, plus 66 of 67 from the D2 probe set.
49
+ - **C2 (1):** the bundle `0` read the previous bundle's value in Make. That is refused rather than modeled.
50
+
51
+ On top of the runs, 225 single formulas were recorded through probe sets (D2, D3, F1) and are replayed in the tests.
52
+
53
+ ![38 of 221 public blueprints pass inspect: 38 eligible, 175 not yet supported, 8 invalid exports. Most common blockers: error-handler routes 34, json:ParseJSON 33, util:SetVariables 26, other modules per iterator bundle 26, HTTP states-as-errors off 25, other first module 23, array aggregator 21, response headers 19.](docs/charts/2_survey.png)
54
+
55
+ **How much of the real world runs today: 37 of 221 public Make blueprints on GitHub (17%), all with fixtures** (38 pass `inspect`; one is refused at run time for `md5()` of a date). It was 18 at v0.1.0: polling and app triggers (v0.2) and `[]` plus `now` (v0.3) were the biggest blockers. The chart on the right is the roadmap. Method, full table and per-file results: [`corpus/survey/`](corpus/survey/README.md).
56
+
57
+ ## Quick start
58
+
59
+ Requires Node 24 or newer (it runs the TypeScript source directly).
60
+
61
+ ```
62
+ git clone https://github.com/intikhab49/blueprint-runtime
63
+ cd blueprint-runtime
64
+ npm ci
65
+ npm run build && npm link # puts `bpr` on your PATH (or use `node src/cli.ts` everywhere below)
66
+
67
+ bpr test corpus/reference --allow-unsupported # replay all 79 recorded Make runs
68
+ bpr test examples/broken-mapping # a broken mapping, caught
69
+ bpr inspect corpus/blueprints/B.blueprint.json # what a blueprint uses, and whether it can run
70
+ ```
71
+
72
+ No Make account is needed for any of this. The recorded runs are in the repository.
73
+
74
+ ## Run it in CI (GitHub Actions)
75
+
76
+ Keep your exported blueprints and a few cases (snapshots or recorded Make runs) in a repository, and every change to a scenario gets checked before anyone imports it into Make:
77
+
78
+ ```yaml
79
+ # .github/workflows/make-scenarios.yml
80
+ name: make-scenarios
81
+ on: [push, pull_request]
82
+ jobs:
83
+ test:
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/checkout@v4
87
+ - uses: actions/setup-node@v4
88
+ with:
89
+ node-version: 24
90
+ - run: npx --yes github:intikhab49/blueprint-runtime test cases/
91
+ ```
92
+
93
+ The exit code is the verdict: `0` every case matches, `1` a mapping changed what Make would produce, `3` the blueprint uses something without recorded Make behavior, `5` a fixture is missing or wrong. `bpr inspect` works the same way as a blueprint linter: exit `0` eligible, `2` invalid file, `3` unsupported.
94
+
95
+ ## How it works
96
+
97
+ ```mermaid
98
+ flowchart LR
99
+ BP["blueprint.json<br/>exported from Make"] --> INS["inspect<br/>strict importer + plan"]
100
+ INS --> RUN["scheduler<br/>routers · filters · iterators<br/>typed expression engine"]
101
+ IN["input.json<br/>webhook payload"] --> RUN
102
+ FX["fixtures.json<br/>HTTP + app modules"] --> RUN
103
+ RUN --> TR["local trace"]
104
+ REF["reference.json<br/>Make's recorded run"] --> CMP["compare<br/>first divergence"]
105
+ TR --> CMP
106
+ CMP --> OUT["PASS / FAIL<br/>module · bundle · JSON path"]
107
+
108
+ style RUN fill:#2a78d6,color:#ffffff,stroke:#2a78d6
109
+ style OUT fill:#1baf7a,color:#ffffff,stroke:#1baf7a
110
+ style BP fill:#f0efec,stroke:#c3c2b7
111
+ style INS fill:#f0efec,stroke:#c3c2b7
112
+ style IN fill:#f0efec,stroke:#c3c2b7
113
+ style FX fill:#f0efec,stroke:#c3c2b7
114
+ style TR fill:#f0efec,stroke:#c3c2b7
115
+ style REF fill:#f0efec,stroke:#c3c2b7
116
+ style CMP fill:#f0efec,stroke:#c3c2b7
117
+ ```
118
+
119
+ - **Importer.** It is strict on purpose: duplicate JSON keys (which `JSON.parse` silently drops), oversized or too-deep files, duplicate module ids, broken routes and bad fallback indexes are reported with line and column. It also computes a semantic hash: moving modules on the canvas keeps it, while changing a mapping, filter, route or setting changes it.
120
+ - **Expression engine.** It has its own tokenizer, parser and typed evaluator for Make's formula language, and never uses `eval` (a test scans the source to prove it). `missing` and `null` stay apart, dates are real instants in the scenario's timezone, and `+ - *` use exact decimal arithmetic the way Make does. It covers 58 functions, each replayed against Make's own output.
121
+ - **Scheduler.** Routes run in order and every passing route runs, with the fallback only when none did. Filters short-circuit like Make. Iterators process bundles depth-first and the Text aggregator collects them, with operations counted the way Make counts them.
122
+ - **Comparison.** It goes module by module: input bundles, output bundles, filter decisions with their per-condition report, the outcome (success or Make's exact error) and the webhook response. Key order is ignored; `missing` vs `null` and numbers vs text are not.
123
+
124
+ ## `bpr test`
125
+
126
+ ```
127
+ bpr test <case.json | folder>... [--json] [--allow-unsupported]
128
+ ```
129
+
130
+ A case names a blueprint, an input, optional fixtures and the run Make actually produced. The input is the webhook payload, or, for a third-party app trigger such as Google Sheets "Watch rows", the list of bundles the trigger emitted (the connector itself is not verified; how a run processes several bundles was recorded with Make's Basic trigger, corpus T):
131
+
132
+ ```json
133
+ { "schemaVersion": 1, "name": "A-002-plain", "blueprint": "../../blueprints/A.blueprint.json",
134
+ "input": "./input.json", "environment": { "timezone": "Asia/Karachi" }, "expected": "./reference.json" }
135
+ ```
136
+
137
+ If the blueprint uses `now`, give the case a clock: `"environment": { "now": "2026-10-10T12:00:00.000Z" }`. Every module then reads that instant. In Make, `now` is the time each module starts, so it moves on during a run; a recorded reference can use `"now": "recorded"` to replay Make's own start times.
138
+
139
+ **Snapshots.** You don't need a recorded Make run to start: `bpr run blueprint.json --input input.json > expected.json` saves what the scenario produces today, and a case with `"expected": "./expected.json"` turns that into a regression test. Differences are then reported against "the snapshot", not against Make, because a snapshot proves consistency, not Make compatibility.
140
+
141
+ Exit codes: `0` all matched · `1` a case differs · `2` invalid case · `3` something without recorded Make behavior (`--allow-unsupported` lets those pass) · `5` a fixture is missing, wrong or unused · `6` local limit.
142
+
143
+ `bpr run <blueprint.json> --input <payload.json> [--fixtures <fixtures.json>] [--timezone <IANA>]` prints the local trace.
144
+
145
+ ## `bpr inspect`
146
+
147
+ ```
148
+ bpr inspect <blueprint.json>... [--json]
149
+ ```
150
+
151
+ It lists every module, where it sits (main flow, route, fallback, error handler), every `{{…}}` expression with its references and functions, the fixtures the blueprint needs, and everything without recorded Make behavior, each with its reason. A file it calls eligible also runs without a refusal: the survey checked all 18 against the scheduler. Exit codes: `0` eligible · `2` invalid file · `3` uses something unsupported.
152
+
153
+ ## What runs today
154
+
155
+ | | Supported (recorded in Make) | Not yet (refused with the reason) |
156
+ |---|---|---|
157
+ | **Triggers** | Custom webhook; Basic trigger; any third-party app trigger (Google Sheets, RSS, Typeform, …) with its bundles as the case input; several bundles per run, each through the whole flow | mail hooks, scenarios that start with an action (HTTP, Set variable), an aggregator on a trigger that emitted nothing |
158
+ | **Flow** | routers (every passing route, fallback route), filters with 31 operators and Make's short-circuiting, iterators with or without a Text aggregator (`\n`, `\t` or custom separator) | error-handler routes, array aggregator, repeaters, routers or responses running once per iterator bundle, multi-cycle runs |
159
+ | **Modules** | Set variable, Webhook response, Sleep, HTTP "Make a request" v3 (from fixtures: 200, 201, 404 recorded), any third-party app module from a fixture | `json:ParseJSON`, `util:SetVariables`, Ignore, the newer `http:MakeRequest`, code modules, data stores |
160
+ | **Expressions** | 58 functions, operators with Make's precedence and decimal arithmetic, 1-based indexes, `[]` (which reads the **first** element in Make, not all of them), `now` (from a test clock, or Make's recorded start time per module), Make's text conversion of arrays and objects | `now` in filters and aggregators, other keywords (`timestamp`, `uuid`, …), `var.*` custom variables, regex literals, single-quoted text |
161
+ | **HTTP** | request built from the mapping and checked against the fixture, response shaped exactly as Make does | other statuses, custom request headers, auth, query-string fields, "Evaluate all states as errors" off |
162
+
163
+ Full detail and evidence for every row: [`corpus/NOTES.md`](corpus/NOTES.md).
164
+
165
+ ## Fixtures (HTTP and third-party modules)
166
+
167
+ A case can add `"fixtures": "./fixtures.json"`. There are two modes:
168
+
169
+ | Mode | For | Checked | Proves |
170
+ |---|---|---|---|
171
+ | `http` | `http:ActionSendData` v3 | the request the module builds (method, URL, content type, body) must equal the fixture's | request construction and everything downstream; the response becomes the output bundle exactly as Make shapes it (`statusCode`, `headers`, `cookieHeaders`, `data`, `fileSize`) |
172
+ | `module` | third-party app modules (e.g. `google-sheets:addRow`) | the mapped input bundle must equal the fixture's | downstream logic only; the connector itself is not verified |
173
+
174
+ ```json
175
+ { "schemaVersion": 1, "fixtures": [
176
+ { "module": 2, "occurrence": 1, "mode": "http",
177
+ "request": { "method": "POST", "url": "https://api.example.test/x", "contentType": "application/json", "body": "{\"q\":\"a\"}" },
178
+ "response": { "status": 200, "headers": [["content-type", "application/json"]], "body": "{\"answer\":42}" } } ] }
179
+ ```
180
+
181
+ `occurrence` is the module's invocation number, because an iterator makes a module run several times. Fixtures fail closed: no fixture, a different request or input, a fixture of the wrong mode, two fixtures for one invocation, or a fixture never used all stop the case with exit `5`. There is no network fallback. Modules that run inside Make (`json`, `regexp`, `util`, …) can never be replaced by a fixture. See [examples/http-fixture](examples/http-fixture/).
182
+
183
+ ## FAQ
184
+
185
+ **How do I test a Make.com scenario without running it in Make?**
186
+ Export the scenario's blueprint (scenario menu → Export blueprint) and save a sample input. `bpr run blueprint.json --input input.json > expected.json` saves a snapshot of everything the scenario produces; a case pointing at it fails the moment an edit changes any module's output (see [`bpr test`](#bpr-test)). For proof against Make itself, the expected run can be one recorded in Make instead: that is how the 79 cases in `corpus/reference/` were made, with the tools in [`tools/`](tools/). Those need a Make account and API token, and a one-command recorder is not built yet.
187
+
188
+ **Does it work with Integromat blueprints?**
189
+ Integromat is Make's former name, and the blueprint format is the same. Exports wrapped as `{"blueprint": …}` or Make API responses are unwrapped automatically.
190
+
191
+ **Can it validate or lint a blueprint before I import it?**
192
+ Yes: `bpr inspect blueprint.json` checks the structure strictly (duplicate keys, broken routes, references to modules that do not run first), lists every expression, and names everything it cannot vouch for. Exit code `0` means it can run offline.
193
+
194
+ **Does it call Make, Google Sheets, OpenAI or any other API?**
195
+ No. HTTP and app modules run from fixtures you write, a missing fixture fails the test, and nothing ever goes over the network. No Make account or API token is needed.
196
+
197
+ **What does `[]` mean in a Make mapping like `{{1.choices[].message.content}}`?**
198
+ It reads the first element, not all of them; this was recorded in Make, and bpr does the same. Make's `map()` function reads every element.
199
+
200
+ **Is it an official Make tool?**
201
+ No. It is an independent open source project that works with Make blueprints; every behavior comes from runs recorded in a real Make account (see [`corpus/`](corpus/NOTES.md)).
202
+
203
+ ## How the evidence was collected
204
+
205
+ Everything in [`corpus/`](corpus/NOTES.md) comes from a free Make account. Scenarios were imported over the API, run with chosen payloads, and every module's input and output bundles were pulled from Make's own run log. HTTP probes called another scenario of the same account, so nothing left Make. The capture tools are in [`tools/`](tools/); they need your own Make API token (`.make-token`) and webhook URLs (`.make-hooks.json`), and both files are gitignored. Each recorded run became a test case in [`corpus/reference/`](corpus/reference/).
206
+
207
+ ## Limitations
208
+
209
+ - **It covers a narrow slice of Make.** That slice is reproduced exactly, but most real blueprints use something outside it (see the survey). Every refusal names its reason, and the blockers chart is the order things should be added in.
210
+ - **A fixture proves your scenario's handling of a response, not the service.** A third-party connector is never verified.
211
+ - **Recorded on one account, one region (eu1), one timezone (UTC+5)**, during October 2026. Make can change its behavior; rerunning the capture tools would show it.
212
+ - **There are inferred details**, each marked in the code and NOTES. For example, `cookieHeaders` is `[]` for a response without cookies, because every recorded response had one.
213
+
214
+ ## Develop
215
+
216
+ ```
217
+ npm ci
218
+ npm run typecheck
219
+ npm test # 472 tests, including every recorded Make run
220
+ npm run build
221
+ python docs/make_charts.py && python docs/make_header.py && python docs/make_demo.py # README images
222
+ ```
223
+
224
+ Works with Make blueprints. Not affiliated with or endorsed by Make or Celonis. MIT licensed; the example blueprints in `corpus/public/make-skills/` are Make's own, under their MIT license.
@@ -0,0 +1,83 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { isObject, JsonParseError, parseJson } from '../json/parse.js';
3
+ import { buildPlan } from './plan.js';
4
+ export const DEFAULT_LIMITS = {
5
+ maxBytes: 10 * 1024 * 1024,
6
+ maxDepth: 64,
7
+ maxModules: 1000,
8
+ };
9
+ export function loadBlueprint(input, limits = DEFAULT_LIMITS) {
10
+ const result = {
11
+ sha256: createHash('sha256').update(input).digest('hex'),
12
+ bytes: input.byteLength,
13
+ format: 'unknown',
14
+ doc: null,
15
+ json: null,
16
+ plan: null,
17
+ findings: [],
18
+ };
19
+ const error = (code, message, extra = {}) => {
20
+ result.findings.push({ code, severity: 'error', message, ...extra });
21
+ return result;
22
+ };
23
+ if (input.byteLength > limits.maxBytes) {
24
+ return error('BP_TOO_LARGE', `File is ${input.byteLength} bytes; the limit is ${limits.maxBytes}`);
25
+ }
26
+ let text;
27
+ try {
28
+ text = new TextDecoder('utf-8', { fatal: true }).decode(input);
29
+ }
30
+ catch {
31
+ return error('BP_NOT_UTF8', 'File is not valid UTF-8');
32
+ }
33
+ try {
34
+ result.json = parseJson(text, limits.maxDepth);
35
+ }
36
+ catch (e) {
37
+ if (e instanceof JsonParseError) {
38
+ return error(e.code, e.message, e.pointer === undefined ? { loc: e.loc } : { loc: e.loc, pointer: e.pointer });
39
+ }
40
+ throw e;
41
+ }
42
+ const root = result.json.value;
43
+ if (!isObject(root))
44
+ return error('BP_NOT_AN_OBJECT', 'A blueprint is a JSON object', { pointer: '' });
45
+ // Exports are often saved wrapped: {"blueprint": {...}} or the API's {"response": {"blueprint": {...}}}.
46
+ let doc = root;
47
+ let base = '';
48
+ const inner = (o, k) => (isObject(o[k]) ? o[k] : null);
49
+ if (!Array.isArray(root['flow'])) {
50
+ const wrapped = inner(root, 'blueprint') ?? (inner(root, 'response') && inner(inner(root, 'response'), 'blueprint'));
51
+ if (wrapped && Array.isArray(wrapped['flow'])) {
52
+ doc = wrapped;
53
+ base = isObject(root['blueprint']) ? '/blueprint' : '/response/blueprint';
54
+ result.findings.push({ code: 'FORMAT_WRAPPED', severity: 'warning', message: `The blueprint is wrapped in ${base.slice(1).split('/').map((k) => `"${k}"`).join(' → ')}; inspecting the blueprint inside`, pointer: base });
55
+ }
56
+ }
57
+ result.doc = doc;
58
+ if (Array.isArray(doc['flow'])) {
59
+ result.format = 'blueprint';
60
+ }
61
+ else if (Array.isArray(doc['modules'])) {
62
+ result.format = 'modules-schema';
63
+ result.findings.push({
64
+ code: 'FORMAT_MODULES_SCHEMA',
65
+ severity: 'unsupported',
66
+ message: 'This file uses Make\'s flat "modules" format (parent/follows links), not an exported blueprint. ' +
67
+ 'Open the scenario in Make and use ⋮ → Export blueprint, then inspect that file.',
68
+ pointer: `${base}/modules`,
69
+ });
70
+ return result;
71
+ }
72
+ else {
73
+ return error('BP_NO_FLOW', 'No top-level "flow" array; this does not look like an exported Make blueprint', { pointer: '' });
74
+ }
75
+ const { plan, findings } = buildPlan(doc, limits, base);
76
+ result.plan = plan;
77
+ for (const f of findings) {
78
+ const loc = f.pointer === undefined ? undefined : result.json.locatePointer(f.pointer);
79
+ result.findings.push(loc ? { ...f, loc } : f);
80
+ }
81
+ return result;
82
+ }
83
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/blueprint/load.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,202 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { escapePointerToken, isObject } from '../json/parse.js';
3
+ import { KNOWN_MODULE_KEYS } from '../registry.js';
4
+ /** Stable JSON: object keys sorted, arrays kept in order. */
5
+ export function canonicalJson(v) {
6
+ if (v === undefined)
7
+ return 'null';
8
+ if (Array.isArray(v))
9
+ return `[${v.map(canonicalJson).join(',')}]`;
10
+ if (isObject(v)) {
11
+ return `{${Object.keys(v)
12
+ .sort()
13
+ .map((k) => `${JSON.stringify(k)}:${canonicalJson(v[k])}`)
14
+ .join(',')}}`;
15
+ }
16
+ return JSON.stringify(v);
17
+ }
18
+ export function buildPlan(doc, limits, base = '') {
19
+ const findings = [];
20
+ const modules = [];
21
+ const firstSeen = new Map();
22
+ const err = (code, message, pointer) => findings.push({ code, severity: 'error', message, pointer });
23
+ const warn = (code, message, pointer) => findings.push({ code, severity: 'warning', message, pointer });
24
+ let tooMany = false;
25
+ const walkFlow = (flow, pointer, branch, upstreamIn) => {
26
+ if (!Array.isArray(flow)) {
27
+ err('BP_FLOW_NOT_ARRAY', 'Expected an array of modules', pointer);
28
+ return;
29
+ }
30
+ const upstream = [...upstreamIn];
31
+ flow.forEach((raw, i) => {
32
+ const p = `${pointer}/${i}`;
33
+ if (tooMany)
34
+ return;
35
+ if (modules.length >= limits.maxModules) {
36
+ err('BP_TOO_MANY_MODULES', `More than ${limits.maxModules} modules`, p);
37
+ tooMany = true;
38
+ return;
39
+ }
40
+ if (!isObject(raw)) {
41
+ err('BP_MODULE_NOT_OBJECT', 'Expected a module object', p);
42
+ return;
43
+ }
44
+ // Make exports the editor's empty module slot with "id": null (public survey); give it a
45
+ // negative id of its own so it cannot collide with, or be referenced as, a real module.
46
+ const id = raw['id'] === null && raw['module'] === 'placeholder:Placeholder' ? -(modules.length + 1) : raw['id'];
47
+ if (typeof id !== 'number' || !Number.isSafeInteger(id) || (id < 1 && raw['module'] !== 'placeholder:Placeholder')) {
48
+ err('BP_BAD_MODULE_ID', `Module id must be a positive integer, got ${JSON.stringify(id ?? null)}`, `${p}/id`);
49
+ return;
50
+ }
51
+ const prev = firstSeen.get(id);
52
+ if (prev !== undefined) {
53
+ err('BP_DUPLICATE_MODULE_ID', `Module id ${id} is used twice (first at ${prev})`, `${p}/id`);
54
+ return;
55
+ }
56
+ firstSeen.set(id, p);
57
+ const moduleName = raw['module'];
58
+ const colon = typeof moduleName === 'string' ? moduleName.indexOf(':') : -1;
59
+ if (typeof moduleName !== 'string' || colon < 1 || colon === moduleName.length - 1) {
60
+ err('BP_BAD_MODULE_NAME', `Module ${id}: "module" must look like "app:name", got ${JSON.stringify(moduleName ?? null)}`, `${p}/module`);
61
+ return;
62
+ }
63
+ // Make's own exports contain version 0 (its AI Agent module, ai-local-agent:RunLocalAIAgent)
64
+ // and no version at all on placeholder:Placeholder, the empty module slot of the editor
65
+ // (public survey, 2026-10-10). Anything else must be a whole number.
66
+ const rawVersion = raw['version'];
67
+ const version = rawVersion === undefined && moduleName === 'placeholder:Placeholder' ? 0 : rawVersion;
68
+ if (typeof version !== 'number' || !Number.isSafeInteger(version) || version < 0) {
69
+ err('BP_BAD_MODULE_VERSION', `Module ${id}: "version" must be a whole number, got ${JSON.stringify(version ?? null)}`, `${p}/version`);
70
+ return;
71
+ }
72
+ if (i > 0 && modules.length > 0) {
73
+ const before = flow[i - 1];
74
+ if (isObject(before) && before['routes'] !== undefined) {
75
+ err('BP_MODULE_AFTER_ROUTER', `Module ${id} follows a router in the same flow; after a router, execution only continues inside its routes`, p);
76
+ }
77
+ }
78
+ const parameters = raw['parameters'] ?? {};
79
+ if (!isObject(parameters))
80
+ err('BP_BAD_PARAMETERS', `Module ${id}: "parameters" must be an object`, `${p}/parameters`);
81
+ const filter = readFilter(raw['filter'], `${p}/filter`, id, err);
82
+ const unknownKeys = Object.keys(raw).filter((k) => !KNOWN_MODULE_KEYS.has(k));
83
+ for (const k of unknownKeys)
84
+ warn('BP_UNKNOWN_MODULE_KEY', `Module ${id}: unknown key "${k}" (not seen in exported blueprints)`, `${p}/${escapePointerToken(k)}`);
85
+ const pm = {
86
+ id,
87
+ module: moduleName,
88
+ app: moduleName.slice(0, colon),
89
+ name: moduleName.slice(colon + 1),
90
+ version,
91
+ pointer: p,
92
+ order: modules.length,
93
+ branch,
94
+ upstream: [...upstream],
95
+ parameters: isObject(parameters) ? parameters : {},
96
+ mapper: raw['mapper'] ?? null,
97
+ filter,
98
+ hasErrorHandler: raw['onerror'] !== undefined,
99
+ unknownKeys,
100
+ };
101
+ modules.push(pm);
102
+ upstream.push(id);
103
+ const routes = raw['routes'];
104
+ if (routes !== undefined) {
105
+ if (moduleName !== 'builtin:BasicRouter')
106
+ err('BP_ROUTES_ON_NON_ROUTER', `Module ${id} (${moduleName}) has "routes" but is not a router`, `${p}/routes`);
107
+ if (!Array.isArray(routes)) {
108
+ err('BP_ROUTES_NOT_ARRAY', `Router ${id}: "routes" must be an array`, `${p}/routes`);
109
+ }
110
+ else {
111
+ pm.routeCount = routes.length;
112
+ if (routes.length === 0)
113
+ warn('BP_ROUTER_NO_ROUTES', `Router ${id} has no routes`, `${p}/routes`);
114
+ routes.forEach((route, r) => {
115
+ const rp = `${p}/routes/${r}`;
116
+ if (!isObject(route)) {
117
+ err('BP_ROUTE_NOT_OBJECT', `Router ${id}: route ${r + 1} must be an object with a "flow" array`, rp);
118
+ return;
119
+ }
120
+ walkFlow(route['flow'], `${rp}/flow`, [...branch, { owner: id, kind: 'route', index: r }], upstream);
121
+ });
122
+ const elseIdx = isObject(parameters) ? parameters['else'] : undefined;
123
+ if (elseIdx !== undefined) {
124
+ if (typeof elseIdx !== 'number' || !Number.isSafeInteger(elseIdx) || elseIdx < 0 || elseIdx >= routes.length) {
125
+ err('BP_BAD_ELSE_ROUTE', `Router ${id}: fallback route index ${JSON.stringify(elseIdx)} is not one of its ${routes.length} routes`, `${p}/parameters/else`);
126
+ }
127
+ else {
128
+ pm.elseRoute = elseIdx;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ else if (moduleName === 'builtin:BasicRouter') {
134
+ // Make exports a router with no routes attached without a "routes" key (public survey).
135
+ pm.routeCount = 0;
136
+ }
137
+ const onerror = raw['onerror'];
138
+ if (onerror !== undefined) {
139
+ // Error-handler modules see the failing module's inputs, not its outputs.
140
+ walkFlow(onerror, `${p}/onerror`, [...branch, { owner: id, kind: 'onerror', index: 0 }], upstream.slice(0, -1));
141
+ }
142
+ });
143
+ };
144
+ walkFlow(doc['flow'], `${base}/flow`, [], []);
145
+ if (findings.some((f) => f.severity === 'error'))
146
+ return { plan: null, findings };
147
+ const meta = isObject(doc['metadata']) ? doc['metadata'] : {};
148
+ const settings = {};
149
+ if (isObject(meta['scenario']))
150
+ settings['scenario'] = meta['scenario'];
151
+ if (meta['instant'] !== undefined)
152
+ settings['instant'] = meta['instant'];
153
+ const semantic = {
154
+ settings,
155
+ modules: modules.map((m) => ({
156
+ id: m.id,
157
+ module: m.module,
158
+ version: m.version,
159
+ branch: m.branch.map((b) => ({ owner: b.owner, kind: b.kind, index: b.index })),
160
+ parameters: m.parameters,
161
+ mapper: m.mapper,
162
+ filter: m.filter ? m.filter.conditions.map((g) => g.map((c) => ({ a: c.a, o: c.o, b: c.b ?? null }))) : null,
163
+ elseRoute: m.elseRoute ?? null,
164
+ hasErrorHandler: m.hasErrorHandler,
165
+ })),
166
+ };
167
+ const semanticHash = createHash('sha256').update(canonicalJson(semantic)).digest('hex');
168
+ const name = doc['name'];
169
+ return { plan: { name: typeof name === 'string' ? name : null, settings, modules, semanticHash }, findings };
170
+ }
171
+ function readFilter(raw, pointer, id, err) {
172
+ if (raw === undefined || raw === null)
173
+ return null;
174
+ if (!isObject(raw)) {
175
+ err('BP_BAD_FILTER', `Module ${id}: "filter" must be an object`, pointer);
176
+ return null;
177
+ }
178
+ const conds = raw['conditions'] ?? [];
179
+ if (!Array.isArray(conds) || !conds.every((g) => Array.isArray(g))) {
180
+ err('BP_BAD_FILTER', `Module ${id}: filter "conditions" must be an array of arrays (OR of ANDs)`, `${pointer}/conditions`);
181
+ return null;
182
+ }
183
+ const conditions = [];
184
+ conds.forEach((group, gi) => {
185
+ const out = [];
186
+ group.forEach((c, ci) => {
187
+ const cp = `${pointer}/conditions/${gi}/${ci}`;
188
+ if (!isObject(c) || typeof c['o'] !== 'string' || c['a'] === undefined) {
189
+ err('BP_BAD_FILTER_CONDITION', `Module ${id}: each filter condition needs "a" and an operator "o"`, cp);
190
+ return;
191
+ }
192
+ const cond = { a: c['a'], o: c['o'] };
193
+ if (c['b'] !== undefined)
194
+ cond.b = c['b'];
195
+ out.push(cond);
196
+ });
197
+ conditions.push(out);
198
+ });
199
+ const label = raw['name'];
200
+ return { label: typeof label === 'string' ? label : null, conditions };
201
+ }
202
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/blueprint/plan.ts"],"names":[],"mappings":"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"}