@magneticjs/cli 0.1.4 → 0.1.5
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/cli.js +15 -5
- package/package.json +1 -1
- package/src/bundler.ts +27 -10
- package/wasm/magnetic.js +1 -0
package/dist/cli.js
CHANGED
|
@@ -151,21 +151,24 @@ import { build } from "esbuild";
|
|
|
151
151
|
import { join as join2, dirname as dirname2 } from "node:path";
|
|
152
152
|
import { mkdirSync, existsSync as existsSync2, statSync as statSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, copyFileSync } from "node:fs";
|
|
153
153
|
import { createRequire } from "node:module";
|
|
154
|
-
function
|
|
154
|
+
function copyFrameworkAsset(filename, appDir, monorepoRoot) {
|
|
155
155
|
const publicDir = join2(appDir, "public");
|
|
156
|
-
const dest = join2(publicDir,
|
|
156
|
+
const dest = join2(publicDir, filename);
|
|
157
157
|
if (existsSync2(dest)) return true;
|
|
158
158
|
const candidates = [];
|
|
159
159
|
if (monorepoRoot) {
|
|
160
|
-
candidates.push(join2(monorepoRoot, "js/packages/magnetic-server/wasm
|
|
160
|
+
candidates.push(join2(monorepoRoot, "js/packages/magnetic-server/wasm", filename));
|
|
161
|
+
if (filename === "magnetic.js") {
|
|
162
|
+
candidates.push(join2(monorepoRoot, "js/packages/sdk-web-runtime/dist/magnetic.min.js"));
|
|
163
|
+
}
|
|
161
164
|
}
|
|
162
165
|
try {
|
|
163
166
|
const require2 = createRequire(join2(appDir, "package.json"));
|
|
164
167
|
const serverPkg = require2.resolve("@magneticjs/server");
|
|
165
|
-
candidates.push(join2(dirname2(serverPkg), "..", "wasm",
|
|
168
|
+
candidates.push(join2(dirname2(serverPkg), "..", "wasm", filename));
|
|
166
169
|
} catch {
|
|
167
170
|
}
|
|
168
|
-
candidates.push(join2(import.meta.dirname || __dirname, "..", "wasm",
|
|
171
|
+
candidates.push(join2(import.meta.dirname || __dirname, "..", "wasm", filename));
|
|
169
172
|
for (const src of candidates) {
|
|
170
173
|
if (existsSync2(src)) {
|
|
171
174
|
mkdirSync(publicDir, { recursive: true });
|
|
@@ -175,6 +178,12 @@ function copyTransportWasm(appDir, monorepoRoot) {
|
|
|
175
178
|
}
|
|
176
179
|
return false;
|
|
177
180
|
}
|
|
181
|
+
function copyTransportWasm(appDir, monorepoRoot) {
|
|
182
|
+
return copyFrameworkAsset("transport.wasm", appDir, monorepoRoot);
|
|
183
|
+
}
|
|
184
|
+
function copyClientRuntime(appDir, monorepoRoot) {
|
|
185
|
+
return copyFrameworkAsset("magnetic.js", appDir, monorepoRoot);
|
|
186
|
+
}
|
|
178
187
|
async function bundleApp(opts) {
|
|
179
188
|
const outDir = opts.outDir || join2(opts.appDir, "dist");
|
|
180
189
|
const outFile = opts.outFile || "app.js";
|
|
@@ -182,6 +191,7 @@ async function bundleApp(opts) {
|
|
|
182
191
|
if (!existsSync2(outDir)) {
|
|
183
192
|
mkdirSync(outDir, { recursive: true });
|
|
184
193
|
}
|
|
194
|
+
copyClientRuntime(opts.appDir, opts.monorepoRoot);
|
|
185
195
|
copyTransportWasm(opts.appDir, opts.monorepoRoot);
|
|
186
196
|
const alias = {};
|
|
187
197
|
if (opts.monorepoRoot) {
|
package/package.json
CHANGED
package/src/bundler.ts
CHANGED
|
@@ -27,33 +27,35 @@ export interface BundleResult {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Copy
|
|
31
|
-
*
|
|
30
|
+
* Copy a framework asset into the app's public/ directory.
|
|
31
|
+
* Searches monorepo, npm-installed @magneticjs/server, and CLI's own wasm/ dir.
|
|
32
32
|
*/
|
|
33
|
-
|
|
33
|
+
function copyFrameworkAsset(filename: string, appDir: string, monorepoRoot?: string): boolean {
|
|
34
34
|
const publicDir = join(appDir, 'public');
|
|
35
|
-
const dest = join(publicDir,
|
|
35
|
+
const dest = join(publicDir, filename);
|
|
36
36
|
|
|
37
37
|
// Already there — skip
|
|
38
38
|
if (existsSync(dest)) return true;
|
|
39
39
|
|
|
40
|
-
// Candidate locations for the WASM file
|
|
41
40
|
const candidates: string[] = [];
|
|
42
41
|
|
|
43
|
-
// Monorepo
|
|
42
|
+
// Monorepo paths
|
|
44
43
|
if (monorepoRoot) {
|
|
45
|
-
candidates.push(join(monorepoRoot, 'js/packages/magnetic-server/wasm
|
|
44
|
+
candidates.push(join(monorepoRoot, 'js/packages/magnetic-server/wasm', filename));
|
|
45
|
+
if (filename === 'magnetic.js') {
|
|
46
|
+
candidates.push(join(monorepoRoot, 'js/packages/sdk-web-runtime/dist/magnetic.min.js'));
|
|
47
|
+
}
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
// npm-installed @magneticjs/server
|
|
49
51
|
try {
|
|
50
52
|
const require = createRequire(join(appDir, 'package.json'));
|
|
51
53
|
const serverPkg = require.resolve('@magneticjs/server');
|
|
52
|
-
candidates.push(join(dirname(serverPkg), '..', 'wasm',
|
|
54
|
+
candidates.push(join(dirname(serverPkg), '..', 'wasm', filename));
|
|
53
55
|
} catch {}
|
|
54
56
|
|
|
55
57
|
// CLI's own bundled copy (sibling to dist/)
|
|
56
|
-
candidates.push(join(import.meta.dirname || __dirname, '..', 'wasm',
|
|
58
|
+
candidates.push(join(import.meta.dirname || __dirname, '..', 'wasm', filename));
|
|
57
59
|
|
|
58
60
|
for (const src of candidates) {
|
|
59
61
|
if (existsSync(src)) {
|
|
@@ -66,6 +68,20 @@ export function copyTransportWasm(appDir: string, monorepoRoot?: string): boolea
|
|
|
66
68
|
return false;
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Copy transport.wasm into the app's public/ directory.
|
|
73
|
+
*/
|
|
74
|
+
export function copyTransportWasm(appDir: string, monorepoRoot?: string): boolean {
|
|
75
|
+
return copyFrameworkAsset('transport.wasm', appDir, monorepoRoot);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Copy magnetic.js client runtime into the app's public/ directory.
|
|
80
|
+
*/
|
|
81
|
+
export function copyClientRuntime(appDir: string, monorepoRoot?: string): boolean {
|
|
82
|
+
return copyFrameworkAsset('magnetic.js', appDir, monorepoRoot);
|
|
83
|
+
}
|
|
84
|
+
|
|
69
85
|
/**
|
|
70
86
|
* Bundle the generated bridge code into an IIFE for V8 consumption.
|
|
71
87
|
* Uses esbuild with stdin so no temp file is needed.
|
|
@@ -79,7 +95,8 @@ export async function bundleApp(opts: BundleOptions): Promise<BundleResult> {
|
|
|
79
95
|
mkdirSync(outDir, { recursive: true });
|
|
80
96
|
}
|
|
81
97
|
|
|
82
|
-
// Ensure
|
|
98
|
+
// Ensure framework assets are in public/
|
|
99
|
+
copyClientRuntime(opts.appDir, opts.monorepoRoot);
|
|
83
100
|
copyTransportWasm(opts.appDir, opts.monorepoRoot);
|
|
84
101
|
|
|
85
102
|
// Resolve @magneticjs/server — in monorepo use actual path, otherwise npm package
|
package/wasm/magnetic.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(d) {var M = self.Magnetic = {};var root = null;var es = null;var wasm = null;var status = "disconnected";var queue = [];var keys = {};var deb = {};var lastHash = "";var enc = new TextEncoder();M.status = function() { return status; };M.connect = function(url, mount) {root = typeof mount == "string" ? d.querySelector(mount) : mount;es = new EventSource(url);es.onmessage = function(ev) {try {var raw = ev.data;if (wasm && wasm.store) {var bytes = enc.encode(raw);if (bytes.length <= 16384) {new Uint8Array(wasm.memory.buffer).set(bytes, wasm.input_ptr());if (wasm.store(bytes.length) === 0) return;}} else {var h = fnv(raw);if (h === lastHash) return;lastHash = h;}apply(JSON.parse(raw));} catch(e) { console.error("[magnetic] SSE error:", e); }};es.onerror = function() {if (wasm) status = "offline";};status = "connected";bind();};M.disconnect = function() {if (es) { es.close(); es = null; }status = "disconnected";};function apply(snap) {if (!root || !snap || !snap.root) return;var n = snap.root;if (n.key && keys[n.key] && keys[n.key].parentNode === root) {patch(keys[n.key], n);return;}root.textContent = "";root.appendChild(create(n));}M._apply = apply;function create(n) {var el = d.createElement(n.tag);if (n.key) { el.dataset.key = n.key; keys[n.key] = el; }setAttrs(el, n);if (n.events) for (var v in n.events) el.dataset["a_" + v] = n.events[v];if (n.text != null) el.textContent = n.text;if (n.children) for (var i = 0; i < n.children.length; i++) el.appendChild(create(n.children[i]));return el;}function patch(el, n) {setAttrs(el, n);if (n.events) {for (var v in n.events) el.dataset["a_" + v] = n.events[v];}var da = el.dataset;for (var dk in da) {if (dk.indexOf("a_") === 0) {var ev = dk.slice(2);if (!n.events || !(ev in n.events)) delete da[dk];}}if (n.children) {reconcile(el, n.children);} else if (n.text != null && n.tag != "input" && n.tag != "textarea") {el.textContent = n.text;} else if (!n.children && n.text == null && n.tag != "input" && n.tag != "textarea") {while (el.firstChild) {purgeKeys(el.firstChild);el.removeChild(el.firstChild);}}}function purgeKeys(el) {var k = el.dataset ? el.dataset.key : null;if (k) delete keys[k];var ch = el.firstChild;while (ch) { purgeKeys(ch); ch = ch.nextSibling; }}function reconcile(parent, descs) {var i, c, el, k;var newEls = [];var wantKeys = {};for (i = 0; i < descs.length; i++) {c = descs[i];if (c.key && keys[c.key]) {el = keys[c.key];patch(el, c);wantKeys[c.key] = true;} else {el = create(c);if (c.key) wantKeys[c.key] = true;}newEls.push(el);}var ch = parent.firstChild;while (ch) {var nx = ch.nextSibling;k = ch.dataset ? ch.dataset.key : null;if (!k || !wantKeys[k]) {purgeKeys(ch);parent.removeChild(ch);}ch = nx;}for (i = 0; i < newEls.length; i++) {if (parent.childNodes[i] !== newEls[i]) {parent.insertBefore(newEls[i], parent.childNodes[i] || null);}}}function setAttrs(el, n) {if (n.attrs) for (var k in n.attrs) el.setAttribute(k, n.attrs[k]);}function bind() {d.addEventListener("click", function(e) {var t = e.target.closest("[data-a_click]");if (t) { e.preventDefault(); send(t.dataset.a_click, {}); }});d.addEventListener("submit", function(e) {var t = e.target.closest("[data-a_submit]");if (t) {e.preventDefault();var p = {}, f = new FormData(t);f.forEach(function(v, k) { p[k] = v; });send(t.dataset.a_submit, p);t.querySelectorAll("input").forEach(function(i) { i.value = ""; });}});d.addEventListener("input", function(e) {var t = e.target.closest("[data-a_input]");if (t) {var a = t.dataset.a_input;clearTimeout(deb[a]);deb[a] = setTimeout(function() { send(a, { value: t.value }); }, 300);}});}M.send = send;function send(action, payload) {if (action.indexOf("navigate:") === 0) {var path = action.slice(9);history.pushState({}, "", path);action = "navigate";payload = { path: path };}var body = JSON.stringify({ action: action, payload: payload });fetch("/actions/" + encodeURIComponent(action), {method: "POST",headers: { "Content-Type": "application/json" },body: body}).then(function(r) { return r.text(); }).then(function(raw) {if (!raw || raw[0] !== "{") return;if (wasm && wasm.store) {var bytes = enc.encode(raw);if (bytes.length <= 16384) {new Uint8Array(wasm.memory.buffer).set(bytes, wasm.input_ptr());wasm.store(bytes.length);}} else {lastHash = fnv(raw);}try { apply(JSON.parse(raw)); } catch(e) {}}).catch(function() {});if (status != "connected") queue.push(body);}self.addEventListener("popstate", function() {send("navigate", { path: location.pathname + location.search });});M.loadWasm = function(url) {if (wasm !== null) return;wasm = 0;fetch(url).then(function(r) { return r.arrayBuffer(); }).then(function(b) { return WebAssembly.instantiate(b, {}); }).then(function(result) {wasm = result.instance.exports;while (queue.length) {var q = JSON.parse(queue.shift());send(q.action, q.payload);}}).catch(function() { wasm = null; });};function fnv(s) {var h = 0x811c9dc5;for (var i = 0; i < s.length; i++) {h ^= s.charCodeAt(i);h = Math.imul(h, 0x01000193);}return h;}})(document);
|