@rainbow-robotics/preview-host 1.10.1-dev.1 → 1.10.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.
- package/README.md +254 -254
- package/build.mjs +53 -53
- package/dist/assets/{AmrCapabilityControl.uMKnOOk0.js → AmrCapabilityControl.BYWtW5zh.js} +1 -1
- package/dist/assets/{RbLocalizationProvider.c-57mWsf.js → RbLocalizationProvider.DiNCanKM.js} +4 -4
- package/dist/assets/{__federation_expose_App.Cr76Vrqb.js → __federation_expose_App.CbZuUDnb.js} +4 -4
- package/dist/assets/{cssMode.DWY0mg29.js → cssMode.CzqGhfNM.js} +1 -1
- package/dist/assets/{freemarker2.BcQcIHbV.js → freemarker2.mYaWi5M5.js} +1 -1
- package/dist/assets/{handlebars.apOy76CD.js → handlebars.BUgWbRWV.js} +1 -1
- package/dist/assets/{html.FOC5wcqt.js → html.BLTM8Adn.js} +1 -1
- package/dist/assets/{htmlMode.DZcYEntg.js → htmlMode.fdt2q0gr.js} +1 -1
- package/dist/assets/{index.G9r3GUil.js → index.C-d3znW7.js} +1 -1
- package/dist/assets/{index.Dzu1iP6J.js → index.D_wrWuT_.js} +1 -1
- package/dist/assets/{index.Bxmeiw-f.js → index.NxFdZIH_.js} +1 -1
- package/dist/assets/{javascript.CEL3KJ9t.js → javascript.B5pCjX66.js} +1 -1
- package/dist/assets/{jsonMode.Clw0nKgf.js → jsonMode.CgVMHw9T.js} +1 -1
- package/dist/assets/{liquid.JBTTz117.js → liquid.DmwHQHWT.js} +1 -1
- package/dist/assets/{lspLanguageFeatures.Ap43Ejq9.js → lspLanguageFeatures.BAAq-lBp.js} +1 -1
- package/dist/assets/{mdx.B2yIdDo_.js → mdx.D5Ia3YI0.js} +1 -1
- package/dist/assets/{python.DKT8_C5B.js → python.BIAJNXcX.js} +1 -1
- package/dist/assets/{razor.z656zFnB.js → razor.DZIWSgfo.js} +1 -1
- package/dist/assets/remoteEntry.js +1 -1
- package/dist/assets/{tsMode.CJn1kWbF.js → tsMode.BRpewqMY.js} +1 -1
- package/dist/assets/{typescript.B27DsFAh.js → typescript.BTB_Qo5Z.js} +1 -1
- package/dist/assets/{useFileDownload.BVrgd27i.js → useFileDownload.B4x3iw6f.js} +1 -1
- package/dist/assets/{xml.D8-DrtSf.js → xml.DTV3f2cm.js} +1 -1
- package/dist/assets/{yaml.c2GnKl-i.js → yaml.DNOJhhHB.js} +1 -1
- package/dist/data/joint/joint_data_20250617_101757_1.csv +448 -448
- package/dist/data/robots/models.json +47 -47
- package/dist/data/robots/test.json +38 -38
- package/dist/data/service-info.json +174 -174
- package/dist/imgs/nexus/commands_tree_icons/color_folder.svg +9 -9
- package/dist/imgs/nexus/forms/gripper/g11_help.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_11.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_12.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_13.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_14.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_15.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_16.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_17.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_18.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_19_0.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_19_1.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_20.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_21.png +0 -0
- package/dist/imgs/nexus/forms/gripper/gripper_22.png +0 -0
- package/dist/imgs/profile.svg +4 -4
- package/dist/index.html +17 -17
- package/package.json +1 -1
- package/serve.mjs +193 -193
package/serve.mjs
CHANGED
|
@@ -1,193 +1,193 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Usage:
|
|
3
|
-
// rb-preview-host --plugin <staged-dir> [--port 4180] [--dist <dir>]
|
|
4
|
-
import { createServer } from "node:http";
|
|
5
|
-
import { createReadStream, existsSync, readFileSync, statSync, watch } from "node:fs";
|
|
6
|
-
import { dirname, extname, join, resolve } from "node:path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
|
|
9
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
|
|
11
|
-
function arg(name, fallback) {
|
|
12
|
-
const i = process.argv.indexOf(`--${name}`);
|
|
13
|
-
return i !== -1 && process.argv[i + 1] ? process.argv[i + 1] : fallback;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const port = Number(arg("port", "4180"));
|
|
17
|
-
const distDir = resolve(arg("dist", join(here, "dist")));
|
|
18
|
-
const pluginDir = arg("plugin", "")
|
|
19
|
-
? resolve(arg("plugin", ""))
|
|
20
|
-
: "";
|
|
21
|
-
const socketUrl = arg("socket-url", "");
|
|
22
|
-
const robotHost = arg("robot-host", "");
|
|
23
|
-
const devServerUrl = arg("dev-server-url", "");
|
|
24
|
-
const PLUGIN_BASE = "/plugin-dev";
|
|
25
|
-
const RELOAD_PATH = "/__preview_reload";
|
|
26
|
-
|
|
27
|
-
const CONTENT_TYPE = {
|
|
28
|
-
".html": "text/html; charset=utf-8",
|
|
29
|
-
".js": "text/javascript; charset=utf-8",
|
|
30
|
-
".mjs": "text/javascript; charset=utf-8",
|
|
31
|
-
".css": "text/css; charset=utf-8",
|
|
32
|
-
".json": "application/json; charset=utf-8",
|
|
33
|
-
".svg": "image/svg+xml",
|
|
34
|
-
".png": "image/png",
|
|
35
|
-
".jpg": "image/jpeg",
|
|
36
|
-
".jpeg": "image/jpeg",
|
|
37
|
-
".webp": "image/webp",
|
|
38
|
-
".gif": "image/gif",
|
|
39
|
-
".woff": "font/woff",
|
|
40
|
-
".woff2": "font/woff2",
|
|
41
|
-
".glb": "model/gltf-binary",
|
|
42
|
-
".mp3": "audio/mpeg",
|
|
43
|
-
".wasm": "application/wasm",
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
if (!existsSync(distDir)) {
|
|
47
|
-
console.error(
|
|
48
|
-
`[preview-host] dist not found at ${distDir}. Run \`node build.mjs\` first.`,
|
|
49
|
-
);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
let previewPluginId = "";
|
|
55
|
-
// Core SW category the preview program pretends to run on (command forms are keyed by it).
|
|
56
|
-
let previewBeService = "manipulate";
|
|
57
|
-
if (pluginDir) {
|
|
58
|
-
try {
|
|
59
|
-
const manifest = JSON.parse(readFileSync(resolve(pluginDir, "manifest.json"), "utf8"));
|
|
60
|
-
previewPluginId = manifest.id || "";
|
|
61
|
-
if (Array.isArray(manifest.targetCategorys) && manifest.targetCategorys[0]) {
|
|
62
|
-
previewBeService = manifest.targetCategorys[0];
|
|
63
|
-
}
|
|
64
|
-
} catch {
|
|
65
|
-
/* manifest missing/unreadable — no preview id */
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const injectedLines = [
|
|
70
|
-
" <script>",
|
|
71
|
-
" window.__RB_PLUGIN_PREVIEW_HOST__ = true;",
|
|
72
|
-
" window.__RB_ASSETS_BASE_URL__ = window.location.origin;",
|
|
73
|
-
` window.__RB_PLUGIN_PREVIEW_BASE__ = ${JSON.stringify(PLUGIN_BASE)};`,
|
|
74
|
-
];
|
|
75
|
-
if (previewPluginId) {
|
|
76
|
-
injectedLines.push(` window.__RB_PREVIEW_PLUGIN_ID__ = ${JSON.stringify(previewPluginId)};`);
|
|
77
|
-
}
|
|
78
|
-
injectedLines.push(` window.__RB_PREVIEW_BE_SERVICE__ = ${JSON.stringify(previewBeService)};`);
|
|
79
|
-
if (devServerUrl) {
|
|
80
|
-
injectedLines.push(` window.__RB_PLUGIN_DEV_SERVER_URL__ = ${JSON.stringify(devServerUrl)};`);
|
|
81
|
-
}
|
|
82
|
-
if (socketUrl) {
|
|
83
|
-
injectedLines.push(` window.__RB_PLUGIN_PREVIEW_SOCKET_URL__ = ${JSON.stringify(socketUrl)};`);
|
|
84
|
-
}
|
|
85
|
-
if (robotHost) {
|
|
86
|
-
|
|
87
|
-
injectedLines.push(` window.__RB_ROBOT_HOST__ = ${JSON.stringify(robotHost)};`);
|
|
88
|
-
}
|
|
89
|
-
injectedLines.push(" </script>");
|
|
90
|
-
|
|
91
|
-
if (pluginDir) {
|
|
92
|
-
injectedLines.push(
|
|
93
|
-
" <script>",
|
|
94
|
-
` new EventSource(${JSON.stringify(RELOAD_PATH)}).onmessage = () => location.reload();`,
|
|
95
|
-
" </script>",
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
injectedLines.push(" </head>");
|
|
99
|
-
|
|
100
|
-
function renderIndexHtml() {
|
|
101
|
-
return readFileSync(join(distDir, "index.html"), "utf8").replace(
|
|
102
|
-
"</head>",
|
|
103
|
-
injectedLines.join("\n"),
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function sendFile(res, filePath, { noStore = false } = {}) {
|
|
108
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
109
|
-
if (noStore) res.setHeader("Cache-Control", "no-store");
|
|
110
|
-
const type = CONTENT_TYPE[extname(filePath)];
|
|
111
|
-
if (type) res.setHeader("Content-Type", type);
|
|
112
|
-
createReadStream(filePath).pipe(res);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function tryServe(res, baseDir, relPath, opts) {
|
|
116
|
-
const filePath = resolve(baseDir, `.${relPath}`);
|
|
117
|
-
if (!filePath.startsWith(baseDir)) return false;
|
|
118
|
-
if (existsSync(filePath) && statSync(filePath).isFile()) {
|
|
119
|
-
sendFile(res, filePath, opts);
|
|
120
|
-
return true;
|
|
121
|
-
}
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const reloadClients = new Set();
|
|
127
|
-
if (pluginDir && existsSync(pluginDir)) {
|
|
128
|
-
let timer = null;
|
|
129
|
-
const notify = () => {
|
|
130
|
-
clearTimeout(timer);
|
|
131
|
-
timer = setTimeout(() => {
|
|
132
|
-
for (const c of reloadClients) c.write("data: reload\n\n");
|
|
133
|
-
}, 100);
|
|
134
|
-
};
|
|
135
|
-
try {
|
|
136
|
-
// Recursive: macOS/Windows always, Linux on Node 20.13+.
|
|
137
|
-
watch(pluginDir, { recursive: true }, notify);
|
|
138
|
-
} catch {
|
|
139
|
-
|
|
140
|
-
watch(pluginDir, notify);
|
|
141
|
-
console.warn(
|
|
142
|
-
"[preview-host] recursive watch unavailable — live reload limited to plugin root (upgrade to Node 20.13+ for full watch).",
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const server = createServer((req, res) => {
|
|
148
|
-
const url = (req.url || "/").split("?")[0];
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (url === RELOAD_PATH) {
|
|
152
|
-
res.writeHead(200, {
|
|
153
|
-
"Content-Type": "text/event-stream",
|
|
154
|
-
"Cache-Control": "no-cache",
|
|
155
|
-
Connection: "keep-alive",
|
|
156
|
-
"Access-Control-Allow-Origin": "*",
|
|
157
|
-
});
|
|
158
|
-
res.write("retry: 1000\n\n");
|
|
159
|
-
reloadClients.add(res);
|
|
160
|
-
req.on("close", () => reloadClients.delete(res));
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (url.startsWith(PLUGIN_BASE)) {
|
|
166
|
-
if (!pluginDir) {
|
|
167
|
-
res.statusCode = 404;
|
|
168
|
-
res.end("no --plugin dir configured");
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
const rel = url.slice(PLUGIN_BASE.length) || "/";
|
|
172
|
-
// no-store so the browser always re-fetches the freshly staged manifest/assets.
|
|
173
|
-
if (tryServe(res, pluginDir, rel, { noStore: true })) return;
|
|
174
|
-
res.statusCode = 404;
|
|
175
|
-
res.end("plugin asset not found");
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Static bundle + rb assets
|
|
180
|
-
if (url !== "/" && tryServe(res, distDir, url)) return;
|
|
181
|
-
|
|
182
|
-
// SPA fallback → injected index.html
|
|
183
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
184
|
-
res.end(renderIndexHtml());
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
server.listen(port, () => {
|
|
188
|
-
console.log(`[preview-host] mini-Muscat → http://localhost:${port}`);
|
|
189
|
-
console.log(`[preview-host] dist: ${distDir}`);
|
|
190
|
-
console.log(
|
|
191
|
-
`[preview-host] plugin: ${pluginDir || "(none — pass --plugin <dir>)"} → ${PLUGIN_BASE}`,
|
|
192
|
-
);
|
|
193
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Usage:
|
|
3
|
+
// rb-preview-host --plugin <staged-dir> [--port 4180] [--dist <dir>]
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
import { createReadStream, existsSync, readFileSync, statSync, watch } from "node:fs";
|
|
6
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
|
|
11
|
+
function arg(name, fallback) {
|
|
12
|
+
const i = process.argv.indexOf(`--${name}`);
|
|
13
|
+
return i !== -1 && process.argv[i + 1] ? process.argv[i + 1] : fallback;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const port = Number(arg("port", "4180"));
|
|
17
|
+
const distDir = resolve(arg("dist", join(here, "dist")));
|
|
18
|
+
const pluginDir = arg("plugin", "")
|
|
19
|
+
? resolve(arg("plugin", ""))
|
|
20
|
+
: "";
|
|
21
|
+
const socketUrl = arg("socket-url", "");
|
|
22
|
+
const robotHost = arg("robot-host", "");
|
|
23
|
+
const devServerUrl = arg("dev-server-url", "");
|
|
24
|
+
const PLUGIN_BASE = "/plugin-dev";
|
|
25
|
+
const RELOAD_PATH = "/__preview_reload";
|
|
26
|
+
|
|
27
|
+
const CONTENT_TYPE = {
|
|
28
|
+
".html": "text/html; charset=utf-8",
|
|
29
|
+
".js": "text/javascript; charset=utf-8",
|
|
30
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
31
|
+
".css": "text/css; charset=utf-8",
|
|
32
|
+
".json": "application/json; charset=utf-8",
|
|
33
|
+
".svg": "image/svg+xml",
|
|
34
|
+
".png": "image/png",
|
|
35
|
+
".jpg": "image/jpeg",
|
|
36
|
+
".jpeg": "image/jpeg",
|
|
37
|
+
".webp": "image/webp",
|
|
38
|
+
".gif": "image/gif",
|
|
39
|
+
".woff": "font/woff",
|
|
40
|
+
".woff2": "font/woff2",
|
|
41
|
+
".glb": "model/gltf-binary",
|
|
42
|
+
".mp3": "audio/mpeg",
|
|
43
|
+
".wasm": "application/wasm",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (!existsSync(distDir)) {
|
|
47
|
+
console.error(
|
|
48
|
+
`[preview-host] dist not found at ${distDir}. Run \`node build.mjs\` first.`,
|
|
49
|
+
);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
let previewPluginId = "";
|
|
55
|
+
// Core SW category the preview program pretends to run on (command forms are keyed by it).
|
|
56
|
+
let previewBeService = "manipulate";
|
|
57
|
+
if (pluginDir) {
|
|
58
|
+
try {
|
|
59
|
+
const manifest = JSON.parse(readFileSync(resolve(pluginDir, "manifest.json"), "utf8"));
|
|
60
|
+
previewPluginId = manifest.id || "";
|
|
61
|
+
if (Array.isArray(manifest.targetCategorys) && manifest.targetCategorys[0]) {
|
|
62
|
+
previewBeService = manifest.targetCategorys[0];
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
/* manifest missing/unreadable — no preview id */
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const injectedLines = [
|
|
70
|
+
" <script>",
|
|
71
|
+
" window.__RB_PLUGIN_PREVIEW_HOST__ = true;",
|
|
72
|
+
" window.__RB_ASSETS_BASE_URL__ = window.location.origin;",
|
|
73
|
+
` window.__RB_PLUGIN_PREVIEW_BASE__ = ${JSON.stringify(PLUGIN_BASE)};`,
|
|
74
|
+
];
|
|
75
|
+
if (previewPluginId) {
|
|
76
|
+
injectedLines.push(` window.__RB_PREVIEW_PLUGIN_ID__ = ${JSON.stringify(previewPluginId)};`);
|
|
77
|
+
}
|
|
78
|
+
injectedLines.push(` window.__RB_PREVIEW_BE_SERVICE__ = ${JSON.stringify(previewBeService)};`);
|
|
79
|
+
if (devServerUrl) {
|
|
80
|
+
injectedLines.push(` window.__RB_PLUGIN_DEV_SERVER_URL__ = ${JSON.stringify(devServerUrl)};`);
|
|
81
|
+
}
|
|
82
|
+
if (socketUrl) {
|
|
83
|
+
injectedLines.push(` window.__RB_PLUGIN_PREVIEW_SOCKET_URL__ = ${JSON.stringify(socketUrl)};`);
|
|
84
|
+
}
|
|
85
|
+
if (robotHost) {
|
|
86
|
+
|
|
87
|
+
injectedLines.push(` window.__RB_ROBOT_HOST__ = ${JSON.stringify(robotHost)};`);
|
|
88
|
+
}
|
|
89
|
+
injectedLines.push(" </script>");
|
|
90
|
+
|
|
91
|
+
if (pluginDir) {
|
|
92
|
+
injectedLines.push(
|
|
93
|
+
" <script>",
|
|
94
|
+
` new EventSource(${JSON.stringify(RELOAD_PATH)}).onmessage = () => location.reload();`,
|
|
95
|
+
" </script>",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
injectedLines.push(" </head>");
|
|
99
|
+
|
|
100
|
+
function renderIndexHtml() {
|
|
101
|
+
return readFileSync(join(distDir, "index.html"), "utf8").replace(
|
|
102
|
+
"</head>",
|
|
103
|
+
injectedLines.join("\n"),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function sendFile(res, filePath, { noStore = false } = {}) {
|
|
108
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
109
|
+
if (noStore) res.setHeader("Cache-Control", "no-store");
|
|
110
|
+
const type = CONTENT_TYPE[extname(filePath)];
|
|
111
|
+
if (type) res.setHeader("Content-Type", type);
|
|
112
|
+
createReadStream(filePath).pipe(res);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function tryServe(res, baseDir, relPath, opts) {
|
|
116
|
+
const filePath = resolve(baseDir, `.${relPath}`);
|
|
117
|
+
if (!filePath.startsWith(baseDir)) return false;
|
|
118
|
+
if (existsSync(filePath) && statSync(filePath).isFile()) {
|
|
119
|
+
sendFile(res, filePath, opts);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
const reloadClients = new Set();
|
|
127
|
+
if (pluginDir && existsSync(pluginDir)) {
|
|
128
|
+
let timer = null;
|
|
129
|
+
const notify = () => {
|
|
130
|
+
clearTimeout(timer);
|
|
131
|
+
timer = setTimeout(() => {
|
|
132
|
+
for (const c of reloadClients) c.write("data: reload\n\n");
|
|
133
|
+
}, 100);
|
|
134
|
+
};
|
|
135
|
+
try {
|
|
136
|
+
// Recursive: macOS/Windows always, Linux on Node 20.13+.
|
|
137
|
+
watch(pluginDir, { recursive: true }, notify);
|
|
138
|
+
} catch {
|
|
139
|
+
|
|
140
|
+
watch(pluginDir, notify);
|
|
141
|
+
console.warn(
|
|
142
|
+
"[preview-host] recursive watch unavailable — live reload limited to plugin root (upgrade to Node 20.13+ for full watch).",
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const server = createServer((req, res) => {
|
|
148
|
+
const url = (req.url || "/").split("?")[0];
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if (url === RELOAD_PATH) {
|
|
152
|
+
res.writeHead(200, {
|
|
153
|
+
"Content-Type": "text/event-stream",
|
|
154
|
+
"Cache-Control": "no-cache",
|
|
155
|
+
Connection: "keep-alive",
|
|
156
|
+
"Access-Control-Allow-Origin": "*",
|
|
157
|
+
});
|
|
158
|
+
res.write("retry: 1000\n\n");
|
|
159
|
+
reloadClients.add(res);
|
|
160
|
+
req.on("close", () => reloadClients.delete(res));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if (url.startsWith(PLUGIN_BASE)) {
|
|
166
|
+
if (!pluginDir) {
|
|
167
|
+
res.statusCode = 404;
|
|
168
|
+
res.end("no --plugin dir configured");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const rel = url.slice(PLUGIN_BASE.length) || "/";
|
|
172
|
+
// no-store so the browser always re-fetches the freshly staged manifest/assets.
|
|
173
|
+
if (tryServe(res, pluginDir, rel, { noStore: true })) return;
|
|
174
|
+
res.statusCode = 404;
|
|
175
|
+
res.end("plugin asset not found");
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Static bundle + rb assets
|
|
180
|
+
if (url !== "/" && tryServe(res, distDir, url)) return;
|
|
181
|
+
|
|
182
|
+
// SPA fallback → injected index.html
|
|
183
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
184
|
+
res.end(renderIndexHtml());
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
server.listen(port, () => {
|
|
188
|
+
console.log(`[preview-host] mini-Muscat → http://localhost:${port}`);
|
|
189
|
+
console.log(`[preview-host] dist: ${distDir}`);
|
|
190
|
+
console.log(
|
|
191
|
+
`[preview-host] plugin: ${pluginDir || "(none — pass --plugin <dir>)"} → ${PLUGIN_BASE}`,
|
|
192
|
+
);
|
|
193
|
+
});
|