@inspecto-dev/plugin 0.3.3 → 0.3.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/index.cjs +180 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +179 -44
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +109 -19
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +109 -19
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/rspack/loader.cjs +49 -4
- package/dist/legacy/rspack/loader.cjs.map +1 -1
- package/dist/legacy/rspack/loader.js +49 -4
- package/dist/legacy/rspack/loader.js.map +1 -1
- package/dist/legacy/webpack4/index.cjs +121 -21
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.d.cts +2 -0
- package/dist/legacy/webpack4/index.d.ts +2 -0
- package/dist/legacy/webpack4/index.js +121 -21
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/legacy/webpack4/loader.cjs +49 -4
- package/dist/legacy/webpack4/loader.cjs.map +1 -1
- package/dist/legacy/webpack4/loader.js +49 -4
- package/dist/legacy/webpack4/loader.js.map +1 -1
- package/dist/rollup.cjs +180 -45
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +179 -44
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +180 -45
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +179 -44
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +180 -45
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +179 -44
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +180 -45
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +179 -44
- package/dist/webpack.js.map +1 -1
- package/package.json +6 -6
package/dist/vite.js
CHANGED
|
@@ -36,12 +36,57 @@ var DEFAULT_ESCAPE_TAGS = /* @__PURE__ */ new Set([
|
|
|
36
36
|
"NuxtLink"
|
|
37
37
|
]);
|
|
38
38
|
var JSX_EXTENSIONS = /* @__PURE__ */ new Set([".jsx", ".tsx", ".js", ".ts", ".mjs", ".mts"]);
|
|
39
|
+
function normalizeWebpackModuleRequest(id) {
|
|
40
|
+
return id.replace(/!+$/, "").replace(/^\((?:app-pages-browser|rsc|ssr)\)\/\.\//, "");
|
|
41
|
+
}
|
|
42
|
+
function extractNextModuleRequest(id) {
|
|
43
|
+
if (!id.includes("next-flight-client-entry-loader.js?")) {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
const queryIndex = id.indexOf("?");
|
|
47
|
+
if (queryIndex === -1) {
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
const params = new URLSearchParams(id.slice(queryIndex + 1).replace(/!+$/, ""));
|
|
51
|
+
for (const entry of params.getAll("modules")) {
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(entry);
|
|
54
|
+
if (typeof parsed.request === "string" && parsed.request.length > 0) {
|
|
55
|
+
return parsed.request;
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return void 0;
|
|
62
|
+
}
|
|
63
|
+
function extractTransformFilePath(requestId) {
|
|
64
|
+
const normalizedRequestId = normalizeWebpackModuleRequest(requestId);
|
|
65
|
+
const nextModuleRequest = extractNextModuleRequest(normalizedRequestId);
|
|
66
|
+
if (nextModuleRequest) {
|
|
67
|
+
return {
|
|
68
|
+
requestId,
|
|
69
|
+
filePath: nextModuleRequest,
|
|
70
|
+
wrapped: true
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const lastLoaderSeparator = normalizedRequestId.lastIndexOf("!");
|
|
74
|
+
const resourceRequest = lastLoaderSeparator >= 0 ? normalizedRequestId.slice(lastLoaderSeparator + 1) : normalizedRequestId;
|
|
75
|
+
const queryIndex = resourceRequest.indexOf("?");
|
|
76
|
+
const filePath = queryIndex >= 0 ? resourceRequest.slice(0, queryIndex) : resourceRequest;
|
|
77
|
+
return {
|
|
78
|
+
requestId,
|
|
79
|
+
filePath,
|
|
80
|
+
wrapped: filePath !== requestId
|
|
81
|
+
};
|
|
82
|
+
}
|
|
39
83
|
function shouldTransform(filePath, options) {
|
|
84
|
+
const resolvedFilePath = extractTransformFilePath(filePath).filePath;
|
|
40
85
|
if (process.env["NODE_ENV"] === "production") return false;
|
|
41
|
-
if (
|
|
42
|
-
if (
|
|
43
|
-
if (/[/\\](dist|build|\.next|\.nuxt)[/\\]/.test(
|
|
44
|
-
const ext =
|
|
86
|
+
if (resolvedFilePath.includes("node_modules")) return false;
|
|
87
|
+
if (resolvedFilePath.startsWith("\0")) return false;
|
|
88
|
+
if (/[/\\](dist|build|\.next|\.nuxt)[/\\]/.test(resolvedFilePath)) return false;
|
|
89
|
+
const ext = resolvedFilePath.split(".").pop()?.toLowerCase();
|
|
45
90
|
if (ext && !["js", "jsx", "ts", "tsx", "mjs", "mts", "vue"].includes(ext)) {
|
|
46
91
|
return false;
|
|
47
92
|
}
|
|
@@ -269,7 +314,7 @@ function transformRouter(options) {
|
|
|
269
314
|
|
|
270
315
|
// src/server/index.ts
|
|
271
316
|
import http from "http";
|
|
272
|
-
import
|
|
317
|
+
import fs5 from "fs";
|
|
273
318
|
import path8 from "path";
|
|
274
319
|
import os2 from "os";
|
|
275
320
|
import crypto2 from "crypto";
|
|
@@ -807,6 +852,7 @@ function hasOverrides(overrides) {
|
|
|
807
852
|
|
|
808
853
|
// src/server/path-guards.ts
|
|
809
854
|
import path6 from "path";
|
|
855
|
+
import fs3 from "fs";
|
|
810
856
|
function isWindowsAbsolutePath(file) {
|
|
811
857
|
return /^[a-zA-Z]:[\\/]/.test(file) || /^\\\\[^\\]+\\[^\\]+/.test(file);
|
|
812
858
|
}
|
|
@@ -817,9 +863,94 @@ function resolveWorkspacePath(file, cwd) {
|
|
|
817
863
|
return path6.isAbsolute(file) ? path6.resolve(file) : path6.resolve(cwd, file);
|
|
818
864
|
}
|
|
819
865
|
function assertPathWithinProject(file, projectRoot) {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
866
|
+
let realFile = file;
|
|
867
|
+
let realProjectRoot = projectRoot;
|
|
868
|
+
try {
|
|
869
|
+
if (fs3.existsSync(file)) {
|
|
870
|
+
realFile = fs3.realpathSync(file);
|
|
871
|
+
}
|
|
872
|
+
} catch {
|
|
873
|
+
}
|
|
874
|
+
try {
|
|
875
|
+
if (fs3.existsSync(projectRoot)) {
|
|
876
|
+
realProjectRoot = fs3.realpathSync(projectRoot);
|
|
877
|
+
}
|
|
878
|
+
} catch {
|
|
879
|
+
}
|
|
880
|
+
if (isWithinPath(file, projectRoot) || isWithinPath(realFile, realProjectRoot)) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
throw new Error(
|
|
884
|
+
`Access denied: File ${normalizeForComparison(realFile)} is outside of project workspace ${normalizeForComparison(realProjectRoot)}`
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
function tryReadPackageName(packageRoot) {
|
|
888
|
+
try {
|
|
889
|
+
const packageJsonPath = path6.join(packageRoot, "package.json");
|
|
890
|
+
if (!fs3.existsSync(packageJsonPath)) return void 0;
|
|
891
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
|
|
892
|
+
return typeof packageJson.name === "string" ? packageJson.name : void 0;
|
|
893
|
+
} catch {
|
|
894
|
+
return void 0;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function findNearestPackageRoot(file) {
|
|
898
|
+
let current = path6.dirname(file);
|
|
899
|
+
while (true) {
|
|
900
|
+
if (fs3.existsSync(path6.join(current, "package.json"))) {
|
|
901
|
+
return current;
|
|
902
|
+
}
|
|
903
|
+
const parent = path6.dirname(current);
|
|
904
|
+
if (parent === current) {
|
|
905
|
+
return void 0;
|
|
906
|
+
}
|
|
907
|
+
current = parent;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function normalizeForComparison(file) {
|
|
911
|
+
return isWindowsAbsolutePath(file) ? path6.win32.normalize(file) : path6.normalize(file);
|
|
912
|
+
}
|
|
913
|
+
function pathSeparatorFor(file) {
|
|
914
|
+
return isWindowsAbsolutePath(file) ? path6.win32.sep : path6.sep;
|
|
915
|
+
}
|
|
916
|
+
function isWithinPath(file, root) {
|
|
917
|
+
const normalizedFile = normalizeForComparison(file);
|
|
918
|
+
const normalizedRoot = normalizeForComparison(root);
|
|
919
|
+
const separator = pathSeparatorFor(normalizedRoot);
|
|
920
|
+
const rootWithSep = normalizedRoot.endsWith(separator) ? normalizedRoot : normalizedRoot + separator;
|
|
921
|
+
return normalizedFile === normalizedRoot || normalizedFile.startsWith(rootWithSep);
|
|
922
|
+
}
|
|
923
|
+
function resolveLinkedDependencyEntry(projectRoot, packageName) {
|
|
924
|
+
const packageSegments = packageName.split("/");
|
|
925
|
+
const dependencyPath = path6.join(projectRoot, "node_modules", ...packageSegments);
|
|
926
|
+
if (!fs3.existsSync(dependencyPath)) return void 0;
|
|
927
|
+
try {
|
|
928
|
+
return fs3.realpathSync(dependencyPath);
|
|
929
|
+
} catch {
|
|
930
|
+
return dependencyPath;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
function isLinkedDependencyPath(file, projectRoot, packageName) {
|
|
934
|
+
const linkedDependencyRoot = resolveLinkedDependencyEntry(projectRoot, packageName);
|
|
935
|
+
if (!linkedDependencyRoot) return false;
|
|
936
|
+
return isWithinPath(file, linkedDependencyRoot);
|
|
937
|
+
}
|
|
938
|
+
function isLinkedDependencySourcePath(file, projectRoot) {
|
|
939
|
+
const packageRoot = findNearestPackageRoot(file);
|
|
940
|
+
if (!packageRoot) return false;
|
|
941
|
+
const packageName = tryReadPackageName(packageRoot);
|
|
942
|
+
if (!packageName) return false;
|
|
943
|
+
return isLinkedDependencyPath(file, projectRoot, packageName);
|
|
944
|
+
}
|
|
945
|
+
function assertPathWithinIdeOpenScope(file, projectRoot) {
|
|
946
|
+
try {
|
|
947
|
+
assertPathWithinProject(file, projectRoot);
|
|
948
|
+
return;
|
|
949
|
+
} catch {
|
|
950
|
+
if (isLinkedDependencySourcePath(file, projectRoot)) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
throw new Error(`Access denied: File is outside of project workspace`);
|
|
823
954
|
}
|
|
824
955
|
}
|
|
825
956
|
|
|
@@ -1024,7 +1155,7 @@ var VSCODE_FAMILY_SCHEMES = [
|
|
|
1024
1155
|
];
|
|
1025
1156
|
function handleOpenFileRequest(body, serverState2) {
|
|
1026
1157
|
const absolutePath = resolveWorkspacePath(body.file, serverState2.cwd);
|
|
1027
|
-
|
|
1158
|
+
assertPathWithinIdeOpenScope(absolutePath, serverState2.projectRoot);
|
|
1028
1159
|
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
1029
1160
|
const configuredIde = userConfig.ide;
|
|
1030
1161
|
const activeIde = serverState2.ideInfo?.ide;
|
|
@@ -1082,7 +1213,7 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
1082
1213
|
}
|
|
1083
1214
|
|
|
1084
1215
|
// src/server/project-root.ts
|
|
1085
|
-
import
|
|
1216
|
+
import fs4 from "fs";
|
|
1086
1217
|
import path7 from "path";
|
|
1087
1218
|
import { execSync } from "child_process";
|
|
1088
1219
|
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
@@ -1100,7 +1231,7 @@ function resolveProjectRoot() {
|
|
|
1100
1231
|
let current = start;
|
|
1101
1232
|
while (!visited.has(current)) {
|
|
1102
1233
|
visited.add(current);
|
|
1103
|
-
if (
|
|
1234
|
+
if (fs4.existsSync(path7.join(current, ".inspecto"))) return current;
|
|
1104
1235
|
if (current === stop) break;
|
|
1105
1236
|
const parent = path7.dirname(current);
|
|
1106
1237
|
if (parent === current) break;
|
|
@@ -1172,28 +1303,28 @@ async function startServer() {
|
|
|
1172
1303
|
const portFile = path8.join(os2.tmpdir(), "inspecto.port.json");
|
|
1173
1304
|
try {
|
|
1174
1305
|
let portData = {};
|
|
1175
|
-
if (
|
|
1306
|
+
if (fs5.existsSync(portFile)) {
|
|
1176
1307
|
try {
|
|
1177
|
-
portData = JSON.parse(
|
|
1308
|
+
portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
1178
1309
|
} catch (e) {
|
|
1179
1310
|
}
|
|
1180
1311
|
}
|
|
1181
1312
|
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1182
1313
|
portData[rootHash] = port;
|
|
1183
|
-
|
|
1314
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1184
1315
|
} catch (e) {
|
|
1185
1316
|
serverLogger4.warn("Failed to write port file:", e);
|
|
1186
1317
|
}
|
|
1187
1318
|
process.once("exit", () => {
|
|
1188
1319
|
try {
|
|
1189
|
-
if (
|
|
1190
|
-
const portData = JSON.parse(
|
|
1320
|
+
if (fs5.existsSync(portFile)) {
|
|
1321
|
+
const portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
1191
1322
|
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1192
1323
|
delete portData[rootHash];
|
|
1193
1324
|
if (Object.keys(portData).length === 0) {
|
|
1194
|
-
|
|
1325
|
+
fs5.unlinkSync(portFile);
|
|
1195
1326
|
} else {
|
|
1196
|
-
|
|
1327
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1197
1328
|
}
|
|
1198
1329
|
}
|
|
1199
1330
|
} catch {
|
|
@@ -1262,8 +1393,10 @@ async function handleRequest(url, req, res) {
|
|
|
1262
1393
|
}
|
|
1263
1394
|
try {
|
|
1264
1395
|
handleOpenFileRequest(body, serverState);
|
|
1265
|
-
} catch {
|
|
1266
|
-
serverLogger4.warn(
|
|
1396
|
+
} catch (err) {
|
|
1397
|
+
serverLogger4.warn(
|
|
1398
|
+
`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}. Reason: ${err.message}`
|
|
1399
|
+
);
|
|
1267
1400
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1268
1401
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
1269
1402
|
return;
|
|
@@ -1281,8 +1414,10 @@ async function handleRequest(url, req, res) {
|
|
|
1281
1414
|
const absolutePath = resolveWorkspacePath(file, serverState.cwd);
|
|
1282
1415
|
try {
|
|
1283
1416
|
assertPathWithinProject(absolutePath, serverState.projectRoot);
|
|
1284
|
-
} catch {
|
|
1285
|
-
serverLogger4.warn(
|
|
1417
|
+
} catch (err) {
|
|
1418
|
+
serverLogger4.warn(
|
|
1419
|
+
`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}. Reason: ${err.message}`
|
|
1420
|
+
);
|
|
1286
1421
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1287
1422
|
res.end(
|
|
1288
1423
|
JSON.stringify({
|
|
@@ -1449,23 +1584,25 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
|
|
|
1449
1584
|
return data;
|
|
1450
1585
|
});
|
|
1451
1586
|
} else {
|
|
1452
|
-
compilation.hooks.processAssets
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1587
|
+
if (compilation.hooks.processAssets) {
|
|
1588
|
+
compilation.hooks.processAssets.tapPromise(
|
|
1589
|
+
{
|
|
1590
|
+
name: "inspecto-overlay",
|
|
1591
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
|
1592
|
+
},
|
|
1593
|
+
async (assets) => {
|
|
1594
|
+
const port = await serverPortFn();
|
|
1595
|
+
const mainAssetKey = Object.keys(assets).find(
|
|
1596
|
+
(key) => key.endsWith(".js") && (key.includes("main") || key.includes("app") || key.includes("umi"))
|
|
1597
|
+
);
|
|
1598
|
+
if (!mainAssetKey) return;
|
|
1599
|
+
const originalSource = assets[mainAssetKey].source();
|
|
1600
|
+
assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
|
|
1601
|
+
getWebpackAssetScript(port) + "\n" + originalSource
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1469
1606
|
}
|
|
1470
1607
|
});
|
|
1471
1608
|
}
|
|
@@ -1517,7 +1654,6 @@ var DEFAULT_OPTIONS = {
|
|
|
1517
1654
|
logLevel: "warn"
|
|
1518
1655
|
};
|
|
1519
1656
|
var DEFAULT_PORT = 5678;
|
|
1520
|
-
var getCleanId = (id) => id.split("?")[0];
|
|
1521
1657
|
var InspectoPlugin = createUnplugin((userOptions = {}) => {
|
|
1522
1658
|
const options = {
|
|
1523
1659
|
...DEFAULT_OPTIONS,
|
|
@@ -1604,14 +1740,13 @@ var InspectoPlugin = createUnplugin((userOptions = {}) => {
|
|
|
1604
1740
|
},
|
|
1605
1741
|
transformInclude(id) {
|
|
1606
1742
|
if (isProduction || !id) return false;
|
|
1607
|
-
|
|
1608
|
-
return shouldTransform(cleanId, options);
|
|
1743
|
+
return shouldTransform(id, options);
|
|
1609
1744
|
},
|
|
1610
1745
|
transform(code, id) {
|
|
1611
1746
|
if (isProduction || !id) return null;
|
|
1612
|
-
const
|
|
1747
|
+
const { filePath } = extractTransformFilePath(id);
|
|
1613
1748
|
const result = transformRouter({
|
|
1614
|
-
filePath
|
|
1749
|
+
filePath,
|
|
1615
1750
|
source: code,
|
|
1616
1751
|
projectRoot,
|
|
1617
1752
|
pluginOptions: options
|