@nodegx/preview 0.0.0-stage → 0.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/README.md CHANGED
@@ -1,3 +1,162 @@
1
- # Temporary Holding Version
1
+ # @nodegx/preview — standalone live-preview harness
2
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.
3
+ Render a NodeGX (OpenNoodl) project in a browser **with no editor process**, and
4
+ reload it automatically when the files on disk change.
5
+
6
+ ```bash
7
+ npx @nodegx/preview ./my-project --open
8
+ ```
9
+
10
+ That is the whole recipe: **point it at the folder your agent is editing.** An
11
+ MCP server, a script, or Claude writes v2 files; this watches them and the page
12
+ updates. It is the "see it" half of the AI-authoring loop — the editor's own
13
+ live preview is driven by its in-memory model over a WebSocket and cannot see
14
+ anything written to disk from outside.
15
+
16
+ ---
17
+
18
+ ## Usage
19
+
20
+ ```
21
+ noodl-preview <project-dir> [options]
22
+
23
+ --port <n> Port to listen on (default 8575, 0 for any free port)
24
+ --host <addr> Address to bind (default 127.0.0.1)
25
+ --debounce <ms> Quiet period before rebuilding after a change (default 120)
26
+ --no-watch Render once and serve; do not watch
27
+ --open Open the preview in the default browser
28
+ ```
29
+
30
+ Accepts a **v2 project directory** (`nodegx.project.json` + `components/`) or a
31
+ **legacy `project.json`** (the directory or the file).
32
+
33
+ From the repo root, `npm run preview -- <dir>` builds the harness first, so it is
34
+ always in step with the sources. Direct invocation is
35
+ `node packages/noodl-preview/bin/noodl-preview.js <dir>`.
36
+
37
+ ### Prerequisites
38
+
39
+ Installed from npm, the package needs nothing else. It carries the viewer runtime it renders with.
40
+
41
+ In a checkout of the NodeGX repository (`npm run preview -- ./my-project --open`), the deployed viewer runtime (`packages/noodl-editor/src/external/deploy/`) is a
42
+ build artifact and is not committed. If it is missing, the CLI says so and how to
43
+ fix it:
44
+
45
+ ```bash
46
+ npm run build:editor:_viewer
47
+ ```
48
+
49
+ ---
50
+
51
+ ## What it does
52
+
53
+ ```
54
+ project dir ──watch──> read ──> SUB-006 validate ──> ProjectModel ──> Exporter ──> serve ──SSE──> browser
55
+ │ │
56
+ └── errors ────────────────────────────────────────> diagnostics overlay
57
+ ```
58
+
59
+ - **Renders through the real deploy path.** The page it serves is the deployed
60
+ runtime template (`external/deploy/index.html` + `noodl.deploy.js`) calling
61
+ `renderDeployed`, fed by `Exporter.exportToJSON` with bundles and hashes on —
62
+ the same call `deployToFolder` makes. Component bundles are served from
63
+ `/noodl_bundles/<id>.json` exactly as a real deploy lays them out; project
64
+ assets are served from the project folder. Nothing about the export is
65
+ re-implemented here.
66
+ - **Validates before it renders.** Every snapshot goes through the SUB-006
67
+ semantic validator first. On errors the preview keeps the *last good render*
68
+ and puts the diagnostics on top of it, so a half-written edit reads as "the
69
+ edit isn't finished" instead of "the tool is broken". Warnings never block.
70
+ - **Reloads on change.** Chokidar watches the directory with a debounce (one
71
+ rebuild per burst of writes), and an injected SSE client reloads the page.
72
+ - **Touches nothing.** The harness only ever reads. It is safe to run against a
73
+ project the editor has open — it binds port 8575, clear of the editor's viewer
74
+ server on 8574.
75
+
76
+ ---
77
+
78
+ ## Verified behaviour
79
+
80
+ Checked in headless Chrome against the `tests/fixtures/hello-world` project with
81
+ the Electron editor closed:
82
+
83
+ | | |
84
+ |---|---|
85
+ | Standalone render | "Hello World!" painted, console clean, no editor process |
86
+ | Live edit | a script rewriting `nodes.json` showed up in the browser inside 1s (rebuilds measured at 3–10 ms; the wall-clock cost is the debounce plus a page reload) |
87
+ | Invalid edit | a dangling connection produced the diagnostics overlay over the previous render — the broken graph never reached the runtime |
88
+ | Recovery | removing the bad connection cleared the overlay and re-rendered |
89
+
90
+ Also run against the real 176-component corpus project
91
+ (`packages/noodl-editor/tests/testfs/big-merge-test-mine`, legacy format): it
92
+ loads, validates (12 warnings, 0 errors) and exports in **733 ms**, and the page
93
+ does *not* paint — because one of the project's own bundled modules
94
+ (`noodl_modules/se-topp-fovea`) calls `Noodl.Collection.apply(this, arguments)`,
95
+ the ES5 Backbone pattern, against today's `class Collection extends Array` in
96
+ `noodl-runtime/src/collection.js`. That is a pre-existing module/runtime
97
+ incompatibility in the fixture — a real `deployToFolder` deploy of that project
98
+ fails identically — not a harness fault. It is recorded here because it is what
99
+ the harness is *for*: the whole pipeline (module injection, asset serving,
100
+ runtime setup) ran, and the failure surfaced where a real one would.
101
+
102
+ `npm --prefix packages/noodl-preview test` runs the same paths over HTTP against
103
+ the built CLI (14 specs). They drive `dist/noodl-preview.cjs` rather than the
104
+ TypeScript sources on purpose: the risk in this package is the *bundle* — the
105
+ platform binding, module stubs, and headless node-register load — and testing the
106
+ sources would exercise none of it.
107
+
108
+ ---
109
+
110
+ ## How it works headlessly
111
+
112
+ The interesting part is that the editor's export pipeline runs in plain Node at
113
+ all. `Exporter.exportToJSON` needs a `ProjectModel` and a populated
114
+ `NodeLibrary`, both of which normally only exist inside the running Electron app.
115
+ Four shims are enough (all in `build.mjs` and `src/headless.ts`):
116
+
117
+ 1. `@noodl/platform` bound to `@noodl/platform-node`, imported before any editor
118
+ module — several read `platform.getUserDataPath()` at module scope.
119
+ 2. `bugtracker` stubbed; at import time it hijacks `console.log` and writes to a
120
+ log file, which a CLI must not do.
121
+ 3. The browser DOM globals the viewer's node modules touch at module scope
122
+ (shared with the node-catalog generator's `dom-shim.js`).
123
+ 4. `NodeLibrary` fed from `NoodlRuntime.getNodeLibrary()` — the same node-library
124
+ JSON the editor receives over the WebSocket, produced in-process instead.
125
+
126
+ No node metadata, export logic, or runtime behaviour is duplicated.
127
+
128
+ ---
129
+
130
+ ## Upgrade path: incremental hot-update
131
+
132
+ This harness does a **full page reload** on every change. That is deliberate for
133
+ a spike — it is a small amount of glue over engines that already exist, and it is
134
+ enough to demonstrate the loop.
135
+
136
+ The upgrade, when the experience proves it wants it, is to act as an `editor`
137
+ -role client of the existing viewer server (`packages/noodl-editor/src/main/src/
138
+ web-server.js`, port 8574) and emit the same `export`/`modelUpdate` messages
139
+ `ViewerConnection.ts` sends, computing the diff from before/after exports. That
140
+ buys true in-place updates at the cost of re-implementing the diff protocol —
141
+ worth it only once the payoff is proven. Deliberately not built here.
142
+
143
+ ---
144
+
145
+ ## Layout
146
+
147
+ | File | Purpose |
148
+ |------|---------|
149
+ | `src/cli.ts` | Argument parsing and the watch → rebuild → serve loop |
150
+ | `src/headless.ts` | Platform binding + node-library bootstrap |
151
+ | `src/loader.ts` | Project dir → validated export JSON, bundles and HTML |
152
+ | `src/validate.ts` | The SUB-006 gate |
153
+ | `src/server.ts` | Static + generated routes, SSE channel |
154
+ | `src/client.ts` | The injected browser script and diagnostics overlay |
155
+ | `src/watcher.ts` | Debounced chokidar watch |
156
+
157
+ Task spec: `dev-docs/tasks/phase-13-format-ai-substrate/SUB-009-LIVE-PREVIEW-HARNESS.md`
158
+
159
+ ## Licence
160
+
161
+ The preview is licensed GPL-3.0-only because it bundles code from the NodeGX editor. The source is in
162
+ [The-Low-Code-Foundation/NodeGX](https://github.com/The-Low-Code-Foundation/NodeGX), under `packages/noodl-preview`.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const dist = path.join(__dirname, '..', 'dist', 'noodl-preview.cjs');
6
+ if (!fs.existsSync(dist)) {
7
+ process.stderr.write(
8
+ 'noodl-preview: dist/noodl-preview.cjs is missing.\n' +
9
+ 'Build it first: npm --prefix packages/noodl-preview run build\n' +
10
+ '(or run `npm run preview -- <project-dir>` from the repo root, which builds for you)\n'
11
+ );
12
+ process.exit(2);
13
+ }
14
+ require(dist);