@nuvio/vite-plugin 0.5.4 → 1.0.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/dist/chunk-EZGH3CUW.js +482 -0
- package/dist/{chunk-KTNIIC2D.js → chunk-QAQAJG7B.js} +232 -52
- package/dist/index.js +132 -20
- package/dist/nuvio-dev-session.js +4 -457
- package/dist/scan.d.ts +52 -0
- package/dist/scan.js +18 -0
- package/package.json +9 -5
package/dist/index.js
CHANGED
|
@@ -1,17 +1,99 @@
|
|
|
1
1
|
import {
|
|
2
|
+
__toESM,
|
|
2
3
|
buildSourceIndex,
|
|
4
|
+
detectProjectLibraries,
|
|
3
5
|
extractIdsFromSource,
|
|
6
|
+
handleTagElementMessage,
|
|
4
7
|
pathnameFromUpgradeUrl,
|
|
5
8
|
pickBestSourceIndex,
|
|
6
|
-
readRuntimeVersions
|
|
7
|
-
|
|
9
|
+
readRuntimeVersions,
|
|
10
|
+
require_lib,
|
|
11
|
+
resolvePatchClassNameMode
|
|
12
|
+
} from "./chunk-QAQAJG7B.js";
|
|
8
13
|
|
|
9
14
|
// src/index.ts
|
|
10
15
|
import fs from "fs";
|
|
11
|
-
import
|
|
16
|
+
import path2 from "path";
|
|
12
17
|
import { WebSocket } from "ws";
|
|
13
18
|
import { WebSocketServer } from "ws";
|
|
14
19
|
import { applyPatchToSource } from "@nuvio/ast-engine";
|
|
20
|
+
|
|
21
|
+
// src/jsx-loc-transform.ts
|
|
22
|
+
var t = __toESM(require_lib(), 1);
|
|
23
|
+
import { createRequire } from "module";
|
|
24
|
+
import { parse } from "@babel/parser";
|
|
25
|
+
import traverseImport from "@babel/traverse";
|
|
26
|
+
import path from "path";
|
|
27
|
+
var require2 = createRequire(import.meta.url);
|
|
28
|
+
var generate = require2("@babel/generator").default;
|
|
29
|
+
var LOC_ATTR = "data-nuvio-loc";
|
|
30
|
+
function getTraverseFn() {
|
|
31
|
+
if (typeof traverseImport === "function") {
|
|
32
|
+
return traverseImport;
|
|
33
|
+
}
|
|
34
|
+
const d = traverseImport.default;
|
|
35
|
+
if (typeof d === "function") {
|
|
36
|
+
return d;
|
|
37
|
+
}
|
|
38
|
+
throw new Error("[Nuvio] @babel/traverse did not resolve to a callable export");
|
|
39
|
+
}
|
|
40
|
+
function hasNuvioId(opening) {
|
|
41
|
+
return opening.attributes.some(
|
|
42
|
+
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && (attr.name.name === "data-nuvio-id" || attr.name.name === LOC_ATTR)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function hasLocAttr(opening) {
|
|
46
|
+
return opening.attributes.some(
|
|
47
|
+
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: LOC_ATTR })
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
function injectJsxLocAttributes(code, fileAbs, projectRoot) {
|
|
51
|
+
if (!/\.(tsx|jsx)$/.test(fileAbs)) {
|
|
52
|
+
return { code, changed: false };
|
|
53
|
+
}
|
|
54
|
+
let ast;
|
|
55
|
+
try {
|
|
56
|
+
ast = parse(code, {
|
|
57
|
+
sourceType: "module",
|
|
58
|
+
plugins: ["typescript", "jsx"],
|
|
59
|
+
sourceFilename: fileAbs
|
|
60
|
+
});
|
|
61
|
+
} catch {
|
|
62
|
+
return { code, changed: false };
|
|
63
|
+
}
|
|
64
|
+
const rel = path.relative(projectRoot, fileAbs).split(path.sep).join("/");
|
|
65
|
+
let changed = false;
|
|
66
|
+
const traverseFn = getTraverseFn();
|
|
67
|
+
traverseFn(ast, {
|
|
68
|
+
JSXOpeningElement(p) {
|
|
69
|
+
const opening = p.node;
|
|
70
|
+
if (opening.name.type !== "JSXIdentifier") {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (hasNuvioId(opening)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (hasLocAttr(opening)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const loc = opening.loc?.start;
|
|
80
|
+
if (!loc) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const value = `${rel}:${loc.line}:${loc.column}`;
|
|
84
|
+
opening.attributes.push(
|
|
85
|
+
t.jsxAttribute(t.jsxIdentifier(LOC_ATTR), t.stringLiteral(value))
|
|
86
|
+
);
|
|
87
|
+
changed = true;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
if (!changed) {
|
|
91
|
+
return { code, changed: false };
|
|
92
|
+
}
|
|
93
|
+
return { code: generate(ast, { retainLines: true }).code, changed: true };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/index.ts
|
|
15
97
|
import {
|
|
16
98
|
NUVIO_WS_PATH,
|
|
17
99
|
PROTOCOL_VERSION,
|
|
@@ -41,7 +123,7 @@ function supplementIndexFromAppTsx(serverRoot, built, classNameMode, emitWarn =
|
|
|
41
123
|
return built;
|
|
42
124
|
}
|
|
43
125
|
for (const rel of APP_ENTRY_CANDIDATES) {
|
|
44
|
-
const appTsx =
|
|
126
|
+
const appTsx = path2.resolve(serverRoot, rel);
|
|
45
127
|
if (!fs.existsSync(appTsx)) {
|
|
46
128
|
continue;
|
|
47
129
|
}
|
|
@@ -90,9 +172,25 @@ function nuvio(options) {
|
|
|
90
172
|
let cachedIndexPayload = null;
|
|
91
173
|
let runtimeDiagnostics = { overlayCssMode: "self-contained" };
|
|
92
174
|
const idToEntry = /* @__PURE__ */ new Map();
|
|
175
|
+
let lastDuplicateErrors = [];
|
|
176
|
+
let projectRoot = process.cwd();
|
|
93
177
|
return {
|
|
94
178
|
name: "nuvio",
|
|
95
179
|
apply: "serve",
|
|
180
|
+
transform(code, id) {
|
|
181
|
+
if (!enabled) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (!id || id.includes("node_modules") || !/\.(tsx|jsx)$/.test(id)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const fileAbs = path2.isAbsolute(id) ? id : path2.resolve(projectRoot, id);
|
|
188
|
+
const { code: next, changed } = injectJsxLocAttributes(code, fileAbs, projectRoot);
|
|
189
|
+
if (!changed) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
return { code: next, map: null };
|
|
193
|
+
},
|
|
96
194
|
configureServer(server) {
|
|
97
195
|
if (!enabled) {
|
|
98
196
|
server.config.logger.info(
|
|
@@ -101,10 +199,11 @@ function nuvio(options) {
|
|
|
101
199
|
return;
|
|
102
200
|
}
|
|
103
201
|
const log = server.config.logger;
|
|
104
|
-
const fromConfigFile = typeof server.config.configFile === "string" ?
|
|
105
|
-
const serverRoot =
|
|
202
|
+
const fromConfigFile = typeof server.config.configFile === "string" ? path2.dirname(server.config.configFile) : "";
|
|
203
|
+
const serverRoot = path2.resolve(server.config.root);
|
|
204
|
+
projectRoot = path2.resolve(fromConfigFile || serverRoot);
|
|
106
205
|
const rootCandidates = [
|
|
107
|
-
|
|
206
|
+
path2.resolve(fromConfigFile || serverRoot),
|
|
108
207
|
serverRoot,
|
|
109
208
|
process.cwd()
|
|
110
209
|
];
|
|
@@ -119,12 +218,12 @@ function nuvio(options) {
|
|
|
119
218
|
}
|
|
120
219
|
};
|
|
121
220
|
const rebuildIndex = () => {
|
|
122
|
-
|
|
221
|
+
const detectedLibraries = detectProjectLibraries(serverRoot);
|
|
222
|
+
const indexOptions = { classNameMode, detectedLibraries };
|
|
223
|
+
let built = pickBestSourceIndex(rootCandidates, scanGlobs, indexOptions);
|
|
123
224
|
built = supplementIndexFromAppTsx(serverRoot, built, classNameMode, log.warn);
|
|
124
225
|
if (built.entries.length === 0) {
|
|
125
|
-
const fallback = buildSourceIndex(serverRoot, ["src/**/*.{tsx,jsx}"],
|
|
126
|
-
classNameMode
|
|
127
|
-
});
|
|
226
|
+
const fallback = buildSourceIndex(serverRoot, ["src/**/*.{tsx,jsx}"], indexOptions);
|
|
128
227
|
if (fallback.entries.length > 0) {
|
|
129
228
|
log.warn(
|
|
130
229
|
`[Nuvio] Multi-root scan yielded 0 ids; using serverRoot-only index (${fallback.entries.length} id(s)) from ${serverRoot}.`
|
|
@@ -137,10 +236,12 @@ function nuvio(options) {
|
|
|
137
236
|
for (const e of built.entries) {
|
|
138
237
|
idToEntry.set(e.id, e);
|
|
139
238
|
}
|
|
239
|
+
lastDuplicateErrors = built.duplicateErrors;
|
|
140
240
|
const versions = readRuntimeVersions(serverRoot);
|
|
141
241
|
runtimeDiagnostics = {
|
|
142
242
|
...versions,
|
|
143
|
-
overlayCssMode: "self-contained"
|
|
243
|
+
overlayCssMode: "self-contained",
|
|
244
|
+
detectedLibraries: detectedLibraries.length > 0 ? detectedLibraries : void 0
|
|
144
245
|
};
|
|
145
246
|
cachedIndexPayload = serializeServerMessage({
|
|
146
247
|
type: "indexReady",
|
|
@@ -194,14 +295,14 @@ function nuvio(options) {
|
|
|
194
295
|
}
|
|
195
296
|
};
|
|
196
297
|
const debouncedRebuild = /* @__PURE__ */ (() => {
|
|
197
|
-
let
|
|
298
|
+
let t2;
|
|
198
299
|
return () => {
|
|
199
|
-
if (
|
|
200
|
-
clearTimeout(
|
|
300
|
+
if (t2) {
|
|
301
|
+
clearTimeout(t2);
|
|
201
302
|
}
|
|
202
|
-
|
|
303
|
+
t2 = setTimeout(() => {
|
|
203
304
|
rebuildIndex();
|
|
204
|
-
|
|
305
|
+
t2 = void 0;
|
|
205
306
|
}, 120);
|
|
206
307
|
};
|
|
207
308
|
})();
|
|
@@ -300,8 +401,19 @@ function nuvio(options) {
|
|
|
300
401
|
);
|
|
301
402
|
return;
|
|
302
403
|
}
|
|
404
|
+
if (msg.type === "tagElement") {
|
|
405
|
+
const writeGuardRoot = path2.resolve(fromConfigFile || serverRoot);
|
|
406
|
+
await handleTagElementMessage(ws, msg, {
|
|
407
|
+
writeGuardRoot,
|
|
408
|
+
projectRoot,
|
|
409
|
+
idToEntry,
|
|
410
|
+
duplicateIds: lastDuplicateErrors,
|
|
411
|
+
onIndexRebuilt: debouncedRebuild
|
|
412
|
+
});
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
303
415
|
if (msg.type === "patchUndo") {
|
|
304
|
-
const writeGuardRoot =
|
|
416
|
+
const writeGuardRoot = path2.resolve(fromConfigFile || serverRoot);
|
|
305
417
|
const last = undoStack.pop();
|
|
306
418
|
if (!last) {
|
|
307
419
|
ws.send(
|
|
@@ -348,7 +460,7 @@ function nuvio(options) {
|
|
|
348
460
|
}
|
|
349
461
|
if (msg.type === "patchApply") {
|
|
350
462
|
const entry = idToEntry.get(msg.id);
|
|
351
|
-
const writeGuardRoot =
|
|
463
|
+
const writeGuardRoot = path2.resolve(fromConfigFile || serverRoot);
|
|
352
464
|
const dryRun = msg.dryRun === true;
|
|
353
465
|
const patchAckExtras = dryRun ? { dryRun: true } : {};
|
|
354
466
|
if (!entry) {
|
|
@@ -403,7 +515,7 @@ function nuvio(options) {
|
|
|
403
515
|
return;
|
|
404
516
|
}
|
|
405
517
|
const result = await applyPatchToSource(source, entry.file, msg.id, msg.ops, {
|
|
406
|
-
classNameMode,
|
|
518
|
+
classNameMode: resolvePatchClassNameMode(entry, classNameMode),
|
|
407
519
|
activeBreakpoint: msg.activeBreakpoint
|
|
408
520
|
});
|
|
409
521
|
if (!result.ok) {
|
|
@@ -1,461 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
readRuntimeVersions
|
|
7
|
-
} from "./chunk-KTNIIC2D.js";
|
|
8
|
-
|
|
9
|
-
// src/nuvio-dev-session.ts
|
|
10
|
-
import fs from "fs";
|
|
11
|
-
import path from "path";
|
|
12
|
-
import { watch } from "fs";
|
|
13
|
-
import { WebSocket, WebSocketServer } from "ws";
|
|
14
|
-
import { applyPatchToSource } from "@nuvio/ast-engine";
|
|
15
|
-
import {
|
|
16
|
-
NUVIO_WS_PATH,
|
|
17
|
-
PROTOCOL_VERSION,
|
|
18
|
-
parseClientMessage,
|
|
19
|
-
serializeServerMessage
|
|
20
|
-
} from "@nuvio/shared";
|
|
21
|
-
import { assertPathWithinRoot } from "@nuvio/shared/secure-path";
|
|
22
|
-
var APP_ENTRY_CANDIDATES = ["src/App.tsx", "src/app.tsx", "App.tsx"];
|
|
23
|
-
var DEFAULT_GLOBS = [
|
|
24
|
-
"src/**/*.{tsx,jsx}",
|
|
25
|
-
"apps/**/src/**/*.{tsx,jsx}",
|
|
26
|
-
"packages/**/src/**/*.{tsx,jsx}"
|
|
27
|
-
];
|
|
28
|
-
function nuvioWsMessageToText(data) {
|
|
29
|
-
if (typeof data === "string") {
|
|
30
|
-
return data;
|
|
31
|
-
}
|
|
32
|
-
if (Buffer.isBuffer(data)) {
|
|
33
|
-
return data.toString("utf8");
|
|
34
|
-
}
|
|
35
|
-
if (data instanceof ArrayBuffer) {
|
|
36
|
-
return Buffer.from(data).toString("utf8");
|
|
37
|
-
}
|
|
38
|
-
if (ArrayBuffer.isView(data)) {
|
|
39
|
-
const v = data;
|
|
40
|
-
return Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("utf8");
|
|
41
|
-
}
|
|
42
|
-
return String(data);
|
|
43
|
-
}
|
|
44
|
-
function isAllowedOrigin(origin) {
|
|
45
|
-
if (origin === void 0 || origin === "") {
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
const u = new URL(origin);
|
|
50
|
-
return (u.hostname === "localhost" || u.hostname === "127.0.0.1") && (u.protocol === "http:" || u.protocol === "https:");
|
|
51
|
-
} catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
function supplementIndexFromAppTsx(serverRoot, built, classNameMode, emitWarn) {
|
|
56
|
-
if (built.entries.length > 0) {
|
|
57
|
-
return built;
|
|
58
|
-
}
|
|
59
|
-
for (const rel of APP_ENTRY_CANDIDATES) {
|
|
60
|
-
const appTsx = path.resolve(serverRoot, rel);
|
|
61
|
-
if (!fs.existsSync(appTsx)) {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
const code = fs.readFileSync(appTsx, "utf8");
|
|
66
|
-
const hits = extractIdsFromSource(appTsx, code, { classNameMode });
|
|
67
|
-
if (hits.length === 0) {
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
emitWarn(
|
|
71
|
-
`[Nuvio] Source index had 0 ids; supplemented from ${appTsx} (${hits.length} id(s)).`
|
|
72
|
-
);
|
|
73
|
-
return {
|
|
74
|
-
...built,
|
|
75
|
-
entries: hits,
|
|
76
|
-
scannedFileCount: Math.max(built.scannedFileCount, 1)
|
|
77
|
-
};
|
|
78
|
-
} catch {
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return built;
|
|
82
|
-
}
|
|
83
|
-
function attachNuvioDevSession(httpServer, options) {
|
|
84
|
-
const log = options.log ?? console;
|
|
85
|
-
const enabled = options.enabled ?? process.env.NUVIO !== "0";
|
|
86
|
-
const scanGlobs = options.scanGlobs ?? DEFAULT_GLOBS;
|
|
87
|
-
const verbose = options.verbose ?? false;
|
|
88
|
-
const classNameMode = options.classNameMode ?? "literal-only";
|
|
89
|
-
const serverRoot = path.resolve(options.root);
|
|
90
|
-
const fromConfigFile = options.configDir ?? "";
|
|
91
|
-
const rootCandidates = [path.resolve(fromConfigFile || serverRoot), serverRoot, process.cwd()];
|
|
92
|
-
const rootsLabel = [...new Set(rootCandidates)].join(" | ");
|
|
93
|
-
let indexVersion = 0;
|
|
94
|
-
let cachedIndexPayload = null;
|
|
95
|
-
let runtimeDiagnostics = { overlayCssMode: "self-contained" };
|
|
96
|
-
const idToEntry = /* @__PURE__ */ new Map();
|
|
97
|
-
const wss = new WebSocketServer({ noServer: true });
|
|
98
|
-
const undoStack = [];
|
|
99
|
-
const UNDO_MAX = 32;
|
|
100
|
-
const pushUndoSnapshot = (file, contents) => {
|
|
101
|
-
undoStack.push({ file, contents });
|
|
102
|
-
while (undoStack.length > UNDO_MAX) {
|
|
103
|
-
undoStack.shift();
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
const rebuildIndex = () => {
|
|
107
|
-
if (!enabled) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
let built = pickBestSourceIndex(rootCandidates, scanGlobs, { classNameMode });
|
|
111
|
-
built = supplementIndexFromAppTsx(serverRoot, built, classNameMode, log.warn);
|
|
112
|
-
if (built.entries.length === 0) {
|
|
113
|
-
const fallback = buildSourceIndex(serverRoot, ["src/**/*.{tsx,jsx}"], { classNameMode });
|
|
114
|
-
if (fallback.entries.length > 0) {
|
|
115
|
-
log.warn(
|
|
116
|
-
`[Nuvio] Multi-root scan yielded 0 ids; using serverRoot-only index (${fallback.entries.length} id(s)).`
|
|
117
|
-
);
|
|
118
|
-
built = fallback;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
indexVersion += 1;
|
|
122
|
-
idToEntry.clear();
|
|
123
|
-
for (const e of built.entries) {
|
|
124
|
-
idToEntry.set(e.id, e);
|
|
125
|
-
}
|
|
126
|
-
runtimeDiagnostics = {
|
|
127
|
-
...readRuntimeVersions(serverRoot),
|
|
128
|
-
overlayCssMode: "self-contained"
|
|
129
|
-
};
|
|
130
|
-
cachedIndexPayload = serializeServerMessage({
|
|
131
|
-
type: "indexReady",
|
|
132
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
133
|
-
indexVersion,
|
|
134
|
-
entries: built.entries,
|
|
135
|
-
duplicateErrors: built.duplicateErrors,
|
|
136
|
-
diagnostics: runtimeDiagnostics
|
|
137
|
-
});
|
|
138
|
-
if (verbose) {
|
|
139
|
-
log.info(
|
|
140
|
-
`[Nuvio] index roots=${rootsLabel} matchedFiles=${built.scannedFileCount} uniqueIds=${built.entries.length}`
|
|
141
|
-
);
|
|
142
|
-
} else {
|
|
143
|
-
log.info(`[Nuvio] index \u2014 ${built.entries.length} id(s), ${built.scannedFileCount} file(s)`);
|
|
144
|
-
}
|
|
145
|
-
if (cachedIndexPayload && wss.clients.size > 0) {
|
|
146
|
-
for (const client of wss.clients) {
|
|
147
|
-
if (client.readyState === WebSocket.OPEN) {
|
|
148
|
-
client.send(cachedIndexPayload);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
const debouncedRebuild = /* @__PURE__ */ (() => {
|
|
154
|
-
let t;
|
|
155
|
-
return () => {
|
|
156
|
-
if (t) {
|
|
157
|
-
clearTimeout(t);
|
|
158
|
-
}
|
|
159
|
-
t = setTimeout(() => {
|
|
160
|
-
rebuildIndex();
|
|
161
|
-
t = void 0;
|
|
162
|
-
}, 120);
|
|
163
|
-
};
|
|
164
|
-
})();
|
|
165
|
-
const srcDir = path.join(serverRoot, "src");
|
|
166
|
-
let fileWatcher = null;
|
|
167
|
-
if (enabled && fs.existsSync(srcDir)) {
|
|
168
|
-
try {
|
|
169
|
-
fileWatcher = watch(srcDir, { recursive: true }, (_event, filename) => {
|
|
170
|
-
if (filename && /\.(tsx|jsx)$/.test(filename)) {
|
|
171
|
-
debouncedRebuild();
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
} catch {
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
wss.on("connection", (ws) => {
|
|
178
|
-
if (cachedIndexPayload && ws.readyState === WebSocket.OPEN) {
|
|
179
|
-
ws.send(cachedIndexPayload);
|
|
180
|
-
}
|
|
181
|
-
ws.on("message", async (data) => {
|
|
182
|
-
const text = nuvioWsMessageToText(data);
|
|
183
|
-
const msg = parseClientMessage(text);
|
|
184
|
-
if (!msg) {
|
|
185
|
-
ws.send(
|
|
186
|
-
serializeServerMessage({
|
|
187
|
-
type: "error",
|
|
188
|
-
code: "bad_message",
|
|
189
|
-
message: "Invalid client message"
|
|
190
|
-
})
|
|
191
|
-
);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
if (msg.protocolVersion !== PROTOCOL_VERSION) {
|
|
195
|
-
ws.send(
|
|
196
|
-
serializeServerMessage({
|
|
197
|
-
type: "error",
|
|
198
|
-
code: "bad_version",
|
|
199
|
-
message: `Expected protocolVersion ${PROTOCOL_VERSION}`,
|
|
200
|
-
requestId: "requestId" in msg ? msg.requestId : void 0
|
|
201
|
-
})
|
|
202
|
-
);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
if (msg.type === "ping") {
|
|
206
|
-
ws.send(
|
|
207
|
-
serializeServerMessage({
|
|
208
|
-
type: "pong",
|
|
209
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
210
|
-
requestId: msg.requestId,
|
|
211
|
-
diagnostics: runtimeDiagnostics
|
|
212
|
-
})
|
|
213
|
-
);
|
|
214
|
-
if (cachedIndexPayload) {
|
|
215
|
-
ws.send(cachedIndexPayload);
|
|
216
|
-
}
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (msg.type === "select") {
|
|
220
|
-
const entry = idToEntry.get(msg.id);
|
|
221
|
-
if (!entry) {
|
|
222
|
-
ws.send(
|
|
223
|
-
serializeServerMessage({
|
|
224
|
-
type: "selectAck",
|
|
225
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
226
|
-
requestId: msg.requestId,
|
|
227
|
-
id: msg.id,
|
|
228
|
-
ok: false,
|
|
229
|
-
errorCode: "unknown_id",
|
|
230
|
-
errorMessage: "Id not found in dev source index"
|
|
231
|
-
})
|
|
232
|
-
);
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
ws.send(
|
|
236
|
-
serializeServerMessage({
|
|
237
|
-
type: "selectAck",
|
|
238
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
239
|
-
requestId: msg.requestId,
|
|
240
|
-
id: msg.id,
|
|
241
|
-
ok: true,
|
|
242
|
-
file: entry.file,
|
|
243
|
-
line: entry.line,
|
|
244
|
-
column: entry.column,
|
|
245
|
-
patchHostId: entry.patchHostId,
|
|
246
|
-
primaryTextTargetKey: entry.primaryTextTargetKey,
|
|
247
|
-
textTargets: entry.textTargets,
|
|
248
|
-
styleTargets: entry.styleTargets,
|
|
249
|
-
hierarchyRole: entry.hierarchyRole,
|
|
250
|
-
parentHostId: entry.parentHostId,
|
|
251
|
-
childTargetIds: entry.childTargetIds,
|
|
252
|
-
rowTargets: entry.rowTargets,
|
|
253
|
-
tableMeta: entry.tableMeta,
|
|
254
|
-
tableDataField: entry.tableDataField
|
|
255
|
-
})
|
|
256
|
-
);
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
if (msg.type === "patchUndo") {
|
|
260
|
-
const writeGuardRoot = path.resolve(fromConfigFile || serverRoot);
|
|
261
|
-
const last = undoStack.pop();
|
|
262
|
-
if (!last) {
|
|
263
|
-
ws.send(
|
|
264
|
-
serializeServerMessage({
|
|
265
|
-
type: "patchUndoAck",
|
|
266
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
267
|
-
requestId: msg.requestId,
|
|
268
|
-
ok: false,
|
|
269
|
-
errorCode: "empty_stack",
|
|
270
|
-
errorMessage: "Nothing to undo"
|
|
271
|
-
})
|
|
272
|
-
);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
assertPathWithinRoot(writeGuardRoot, last.file);
|
|
277
|
-
fs.writeFileSync(last.file, last.contents, "utf8");
|
|
278
|
-
} catch (e) {
|
|
279
|
-
undoStack.push(last);
|
|
280
|
-
ws.send(
|
|
281
|
-
serializeServerMessage({
|
|
282
|
-
type: "patchUndoAck",
|
|
283
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
284
|
-
requestId: msg.requestId,
|
|
285
|
-
ok: false,
|
|
286
|
-
errorCode: "undo_write_error",
|
|
287
|
-
errorMessage: String(e)
|
|
288
|
-
})
|
|
289
|
-
);
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
ws.send(
|
|
293
|
-
serializeServerMessage({
|
|
294
|
-
type: "patchUndoAck",
|
|
295
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
296
|
-
requestId: msg.requestId,
|
|
297
|
-
ok: true,
|
|
298
|
-
file: last.file,
|
|
299
|
-
undoStackDepth: undoStack.length
|
|
300
|
-
})
|
|
301
|
-
);
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
if (msg.type === "patchApply") {
|
|
305
|
-
const entry = idToEntry.get(msg.id);
|
|
306
|
-
const writeGuardRoot = path.resolve(fromConfigFile || serverRoot);
|
|
307
|
-
const dryRun = msg.dryRun === true;
|
|
308
|
-
const patchAckExtras = dryRun ? { dryRun: true } : {};
|
|
309
|
-
if (!entry) {
|
|
310
|
-
ws.send(
|
|
311
|
-
serializeServerMessage({
|
|
312
|
-
type: "patchAck",
|
|
313
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
314
|
-
requestId: msg.requestId,
|
|
315
|
-
id: msg.id,
|
|
316
|
-
ok: false,
|
|
317
|
-
errorCode: "unknown_id",
|
|
318
|
-
errorMessage: "Id not found in dev source index",
|
|
319
|
-
...patchAckExtras
|
|
320
|
-
})
|
|
321
|
-
);
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
try {
|
|
325
|
-
assertPathWithinRoot(writeGuardRoot, entry.file);
|
|
326
|
-
} catch (e) {
|
|
327
|
-
ws.send(
|
|
328
|
-
serializeServerMessage({
|
|
329
|
-
type: "patchAck",
|
|
330
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
331
|
-
requestId: msg.requestId,
|
|
332
|
-
id: msg.id,
|
|
333
|
-
ok: false,
|
|
334
|
-
errorCode: "path_escape",
|
|
335
|
-
errorMessage: String(e),
|
|
336
|
-
...patchAckExtras
|
|
337
|
-
})
|
|
338
|
-
);
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
let source;
|
|
342
|
-
try {
|
|
343
|
-
source = fs.readFileSync(entry.file, "utf8");
|
|
344
|
-
} catch (e) {
|
|
345
|
-
ws.send(
|
|
346
|
-
serializeServerMessage({
|
|
347
|
-
type: "patchAck",
|
|
348
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
349
|
-
requestId: msg.requestId,
|
|
350
|
-
id: msg.id,
|
|
351
|
-
ok: false,
|
|
352
|
-
errorCode: "read_error",
|
|
353
|
-
errorMessage: String(e),
|
|
354
|
-
...patchAckExtras
|
|
355
|
-
})
|
|
356
|
-
);
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
const result = await applyPatchToSource(source, entry.file, msg.id, msg.ops, {
|
|
360
|
-
classNameMode,
|
|
361
|
-
activeBreakpoint: msg.activeBreakpoint
|
|
362
|
-
});
|
|
363
|
-
if (!result.ok) {
|
|
364
|
-
ws.send(
|
|
365
|
-
serializeServerMessage({
|
|
366
|
-
type: "patchAck",
|
|
367
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
368
|
-
requestId: msg.requestId,
|
|
369
|
-
id: msg.id,
|
|
370
|
-
ok: false,
|
|
371
|
-
errorCode: result.code,
|
|
372
|
-
errorMessage: result.message,
|
|
373
|
-
...patchAckExtras
|
|
374
|
-
})
|
|
375
|
-
);
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
if (dryRun) {
|
|
379
|
-
ws.send(
|
|
380
|
-
serializeServerMessage({
|
|
381
|
-
type: "patchAck",
|
|
382
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
383
|
-
requestId: msg.requestId,
|
|
384
|
-
id: msg.id,
|
|
385
|
-
ok: true,
|
|
386
|
-
diffSummary: result.diffSummary,
|
|
387
|
-
dryRun: true
|
|
388
|
-
})
|
|
389
|
-
);
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
try {
|
|
393
|
-
fs.writeFileSync(entry.file, result.source, "utf8");
|
|
394
|
-
} catch (e) {
|
|
395
|
-
ws.send(
|
|
396
|
-
serializeServerMessage({
|
|
397
|
-
type: "patchAck",
|
|
398
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
399
|
-
requestId: msg.requestId,
|
|
400
|
-
id: msg.id,
|
|
401
|
-
ok: false,
|
|
402
|
-
errorCode: "write_error",
|
|
403
|
-
errorMessage: String(e)
|
|
404
|
-
})
|
|
405
|
-
);
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
pushUndoSnapshot(entry.file, source);
|
|
409
|
-
ws.send(
|
|
410
|
-
serializeServerMessage({
|
|
411
|
-
type: "patchAck",
|
|
412
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
413
|
-
requestId: msg.requestId,
|
|
414
|
-
id: msg.id,
|
|
415
|
-
ok: true,
|
|
416
|
-
diffSummary: result.diffSummary,
|
|
417
|
-
writtenFile: entry.file,
|
|
418
|
-
undoStackDepth: undoStack.length
|
|
419
|
-
})
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
const onUpgrade = (request, socket, head) => {
|
|
425
|
-
if (!enabled) {
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
const pathname = pathnameFromUpgradeUrl(request.url);
|
|
429
|
-
if (pathname !== NUVIO_WS_PATH) {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
if (!isAllowedOrigin(request.headers.origin)) {
|
|
433
|
-
socket.destroy();
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
437
|
-
wss.emit("connection", ws, request);
|
|
438
|
-
});
|
|
439
|
-
};
|
|
440
|
-
httpServer.on("upgrade", onUpgrade);
|
|
441
|
-
if (enabled) {
|
|
442
|
-
log.info("[Nuvio] dev session attached (App Router / custom server mode)");
|
|
443
|
-
rebuildIndex();
|
|
444
|
-
} else {
|
|
445
|
-
log.info("[Nuvio] disabled (set NUVIO=1 to enable)");
|
|
446
|
-
}
|
|
447
|
-
return {
|
|
448
|
-
rebuildIndex,
|
|
449
|
-
close: () => {
|
|
450
|
-
httpServer.off("upgrade", onUpgrade);
|
|
451
|
-
fileWatcher?.close();
|
|
452
|
-
for (const client of wss.clients) {
|
|
453
|
-
client.close();
|
|
454
|
-
}
|
|
455
|
-
wss.close();
|
|
456
|
-
}
|
|
457
|
-
};
|
|
458
|
-
}
|
|
2
|
+
DEFAULT_GLOBS,
|
|
3
|
+
attachNuvioDevSession
|
|
4
|
+
} from "./chunk-EZGH3CUW.js";
|
|
5
|
+
import "./chunk-QAQAJG7B.js";
|
|
459
6
|
export {
|
|
460
7
|
DEFAULT_GLOBS as NUVIO_DEFAULT_SCAN_GLOBS,
|
|
461
8
|
attachNuvioDevSession
|