@inspecto-dev/plugin 0.3.4 → 0.3.6
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 +179 -44
- 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 +108 -18
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +108 -18
- 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 +120 -20
- 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 +120 -20
- 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 +179 -44
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +179 -44
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +179 -44
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +179 -44
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +179 -44
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +179 -44
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +179 -44
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +179 -44
- package/dist/webpack.js.map +1 -1
- package/package.json +2 -2
package/dist/rspack.cjs
CHANGED
|
@@ -76,12 +76,57 @@ var DEFAULT_ESCAPE_TAGS = /* @__PURE__ */ new Set([
|
|
|
76
76
|
"NuxtLink"
|
|
77
77
|
]);
|
|
78
78
|
var JSX_EXTENSIONS = /* @__PURE__ */ new Set([".jsx", ".tsx", ".js", ".ts", ".mjs", ".mts"]);
|
|
79
|
+
function normalizeWebpackModuleRequest(id) {
|
|
80
|
+
return id.replace(/!+$/, "").replace(/^\((?:app-pages-browser|rsc|ssr)\)\/\.\//, "");
|
|
81
|
+
}
|
|
82
|
+
function extractNextModuleRequest(id) {
|
|
83
|
+
if (!id.includes("next-flight-client-entry-loader.js?")) {
|
|
84
|
+
return void 0;
|
|
85
|
+
}
|
|
86
|
+
const queryIndex = id.indexOf("?");
|
|
87
|
+
if (queryIndex === -1) {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
const params = new URLSearchParams(id.slice(queryIndex + 1).replace(/!+$/, ""));
|
|
91
|
+
for (const entry of params.getAll("modules")) {
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(entry);
|
|
94
|
+
if (typeof parsed.request === "string" && parsed.request.length > 0) {
|
|
95
|
+
return parsed.request;
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
function extractTransformFilePath(requestId) {
|
|
104
|
+
const normalizedRequestId = normalizeWebpackModuleRequest(requestId);
|
|
105
|
+
const nextModuleRequest = extractNextModuleRequest(normalizedRequestId);
|
|
106
|
+
if (nextModuleRequest) {
|
|
107
|
+
return {
|
|
108
|
+
requestId,
|
|
109
|
+
filePath: nextModuleRequest,
|
|
110
|
+
wrapped: true
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const lastLoaderSeparator = normalizedRequestId.lastIndexOf("!");
|
|
114
|
+
const resourceRequest = lastLoaderSeparator >= 0 ? normalizedRequestId.slice(lastLoaderSeparator + 1) : normalizedRequestId;
|
|
115
|
+
const queryIndex = resourceRequest.indexOf("?");
|
|
116
|
+
const filePath = queryIndex >= 0 ? resourceRequest.slice(0, queryIndex) : resourceRequest;
|
|
117
|
+
return {
|
|
118
|
+
requestId,
|
|
119
|
+
filePath,
|
|
120
|
+
wrapped: filePath !== requestId
|
|
121
|
+
};
|
|
122
|
+
}
|
|
79
123
|
function shouldTransform(filePath, options) {
|
|
124
|
+
const resolvedFilePath = extractTransformFilePath(filePath).filePath;
|
|
80
125
|
if (process.env["NODE_ENV"] === "production") return false;
|
|
81
|
-
if (
|
|
82
|
-
if (
|
|
83
|
-
if (/[/\\](dist|build|\.next|\.nuxt)[/\\]/.test(
|
|
84
|
-
const ext =
|
|
126
|
+
if (resolvedFilePath.includes("node_modules")) return false;
|
|
127
|
+
if (resolvedFilePath.startsWith("\0")) return false;
|
|
128
|
+
if (/[/\\](dist|build|\.next|\.nuxt)[/\\]/.test(resolvedFilePath)) return false;
|
|
129
|
+
const ext = resolvedFilePath.split(".").pop()?.toLowerCase();
|
|
85
130
|
if (ext && !["js", "jsx", "ts", "tsx", "mjs", "mts", "vue"].includes(ext)) {
|
|
86
131
|
return false;
|
|
87
132
|
}
|
|
@@ -309,7 +354,7 @@ function transformRouter(options) {
|
|
|
309
354
|
|
|
310
355
|
// src/server/index.ts
|
|
311
356
|
var import_node_http = __toESM(require("http"), 1);
|
|
312
|
-
var
|
|
357
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
313
358
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
314
359
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
315
360
|
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
@@ -843,6 +888,7 @@ function hasOverrides(overrides) {
|
|
|
843
888
|
|
|
844
889
|
// src/server/path-guards.ts
|
|
845
890
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
891
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
846
892
|
function isWindowsAbsolutePath(file) {
|
|
847
893
|
return /^[a-zA-Z]:[\\/]/.test(file) || /^\\\\[^\\]+\\[^\\]+/.test(file);
|
|
848
894
|
}
|
|
@@ -853,9 +899,94 @@ function resolveWorkspacePath(file, cwd) {
|
|
|
853
899
|
return import_node_path5.default.isAbsolute(file) ? import_node_path5.default.resolve(file) : import_node_path5.default.resolve(cwd, file);
|
|
854
900
|
}
|
|
855
901
|
function assertPathWithinProject(file, projectRoot) {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
902
|
+
let realFile = file;
|
|
903
|
+
let realProjectRoot = projectRoot;
|
|
904
|
+
try {
|
|
905
|
+
if (import_node_fs2.default.existsSync(file)) {
|
|
906
|
+
realFile = import_node_fs2.default.realpathSync(file);
|
|
907
|
+
}
|
|
908
|
+
} catch {
|
|
909
|
+
}
|
|
910
|
+
try {
|
|
911
|
+
if (import_node_fs2.default.existsSync(projectRoot)) {
|
|
912
|
+
realProjectRoot = import_node_fs2.default.realpathSync(projectRoot);
|
|
913
|
+
}
|
|
914
|
+
} catch {
|
|
915
|
+
}
|
|
916
|
+
if (isWithinPath(file, projectRoot) || isWithinPath(realFile, realProjectRoot)) {
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
throw new Error(
|
|
920
|
+
`Access denied: File ${normalizeForComparison(realFile)} is outside of project workspace ${normalizeForComparison(realProjectRoot)}`
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
function tryReadPackageName(packageRoot) {
|
|
924
|
+
try {
|
|
925
|
+
const packageJsonPath = import_node_path5.default.join(packageRoot, "package.json");
|
|
926
|
+
if (!import_node_fs2.default.existsSync(packageJsonPath)) return void 0;
|
|
927
|
+
const packageJson = JSON.parse(import_node_fs2.default.readFileSync(packageJsonPath, "utf8"));
|
|
928
|
+
return typeof packageJson.name === "string" ? packageJson.name : void 0;
|
|
929
|
+
} catch {
|
|
930
|
+
return void 0;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
function findNearestPackageRoot(file) {
|
|
934
|
+
let current = import_node_path5.default.dirname(file);
|
|
935
|
+
while (true) {
|
|
936
|
+
if (import_node_fs2.default.existsSync(import_node_path5.default.join(current, "package.json"))) {
|
|
937
|
+
return current;
|
|
938
|
+
}
|
|
939
|
+
const parent = import_node_path5.default.dirname(current);
|
|
940
|
+
if (parent === current) {
|
|
941
|
+
return void 0;
|
|
942
|
+
}
|
|
943
|
+
current = parent;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
function normalizeForComparison(file) {
|
|
947
|
+
return isWindowsAbsolutePath(file) ? import_node_path5.default.win32.normalize(file) : import_node_path5.default.normalize(file);
|
|
948
|
+
}
|
|
949
|
+
function pathSeparatorFor(file) {
|
|
950
|
+
return isWindowsAbsolutePath(file) ? import_node_path5.default.win32.sep : import_node_path5.default.sep;
|
|
951
|
+
}
|
|
952
|
+
function isWithinPath(file, root) {
|
|
953
|
+
const normalizedFile = normalizeForComparison(file);
|
|
954
|
+
const normalizedRoot = normalizeForComparison(root);
|
|
955
|
+
const separator = pathSeparatorFor(normalizedRoot);
|
|
956
|
+
const rootWithSep = normalizedRoot.endsWith(separator) ? normalizedRoot : normalizedRoot + separator;
|
|
957
|
+
return normalizedFile === normalizedRoot || normalizedFile.startsWith(rootWithSep);
|
|
958
|
+
}
|
|
959
|
+
function resolveLinkedDependencyEntry(projectRoot, packageName) {
|
|
960
|
+
const packageSegments = packageName.split("/");
|
|
961
|
+
const dependencyPath = import_node_path5.default.join(projectRoot, "node_modules", ...packageSegments);
|
|
962
|
+
if (!import_node_fs2.default.existsSync(dependencyPath)) return void 0;
|
|
963
|
+
try {
|
|
964
|
+
return import_node_fs2.default.realpathSync(dependencyPath);
|
|
965
|
+
} catch {
|
|
966
|
+
return dependencyPath;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
function isLinkedDependencyPath(file, projectRoot, packageName) {
|
|
970
|
+
const linkedDependencyRoot = resolveLinkedDependencyEntry(projectRoot, packageName);
|
|
971
|
+
if (!linkedDependencyRoot) return false;
|
|
972
|
+
return isWithinPath(file, linkedDependencyRoot);
|
|
973
|
+
}
|
|
974
|
+
function isLinkedDependencySourcePath(file, projectRoot) {
|
|
975
|
+
const packageRoot = findNearestPackageRoot(file);
|
|
976
|
+
if (!packageRoot) return false;
|
|
977
|
+
const packageName = tryReadPackageName(packageRoot);
|
|
978
|
+
if (!packageName) return false;
|
|
979
|
+
return isLinkedDependencyPath(file, projectRoot, packageName);
|
|
980
|
+
}
|
|
981
|
+
function assertPathWithinIdeOpenScope(file, projectRoot) {
|
|
982
|
+
try {
|
|
983
|
+
assertPathWithinProject(file, projectRoot);
|
|
984
|
+
return;
|
|
985
|
+
} catch {
|
|
986
|
+
if (isLinkedDependencySourcePath(file, projectRoot)) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
throw new Error(`Access denied: File is outside of project workspace`);
|
|
859
990
|
}
|
|
860
991
|
}
|
|
861
992
|
|
|
@@ -1060,7 +1191,7 @@ var VSCODE_FAMILY_SCHEMES = [
|
|
|
1060
1191
|
];
|
|
1061
1192
|
function handleOpenFileRequest(body, serverState2) {
|
|
1062
1193
|
const absolutePath = resolveWorkspacePath(body.file, serverState2.cwd);
|
|
1063
|
-
|
|
1194
|
+
assertPathWithinIdeOpenScope(absolutePath, serverState2.projectRoot);
|
|
1064
1195
|
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
1065
1196
|
const configuredIde = userConfig.ide;
|
|
1066
1197
|
const activeIde = serverState2.ideInfo?.ide;
|
|
@@ -1118,7 +1249,7 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
1118
1249
|
}
|
|
1119
1250
|
|
|
1120
1251
|
// src/server/project-root.ts
|
|
1121
|
-
var
|
|
1252
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
1122
1253
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
1123
1254
|
var import_node_child_process3 = require("child_process");
|
|
1124
1255
|
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
@@ -1136,7 +1267,7 @@ function resolveProjectRoot() {
|
|
|
1136
1267
|
let current = start;
|
|
1137
1268
|
while (!visited.has(current)) {
|
|
1138
1269
|
visited.add(current);
|
|
1139
|
-
if (
|
|
1270
|
+
if (import_node_fs3.default.existsSync(import_node_path6.default.join(current, ".inspecto"))) return current;
|
|
1140
1271
|
if (current === stop) break;
|
|
1141
1272
|
const parent = import_node_path6.default.dirname(current);
|
|
1142
1273
|
if (parent === current) break;
|
|
@@ -1208,28 +1339,28 @@ async function startServer() {
|
|
|
1208
1339
|
const portFile = import_node_path7.default.join(import_node_os2.default.tmpdir(), "inspecto.port.json");
|
|
1209
1340
|
try {
|
|
1210
1341
|
let portData = {};
|
|
1211
|
-
if (
|
|
1342
|
+
if (import_node_fs4.default.existsSync(portFile)) {
|
|
1212
1343
|
try {
|
|
1213
|
-
portData = JSON.parse(
|
|
1344
|
+
portData = JSON.parse(import_node_fs4.default.readFileSync(portFile, "utf-8"));
|
|
1214
1345
|
} catch (e) {
|
|
1215
1346
|
}
|
|
1216
1347
|
}
|
|
1217
1348
|
const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1218
1349
|
portData[rootHash] = port;
|
|
1219
|
-
|
|
1350
|
+
import_node_fs4.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1220
1351
|
} catch (e) {
|
|
1221
1352
|
serverLogger4.warn("Failed to write port file:", e);
|
|
1222
1353
|
}
|
|
1223
1354
|
process.once("exit", () => {
|
|
1224
1355
|
try {
|
|
1225
|
-
if (
|
|
1226
|
-
const portData = JSON.parse(
|
|
1356
|
+
if (import_node_fs4.default.existsSync(portFile)) {
|
|
1357
|
+
const portData = JSON.parse(import_node_fs4.default.readFileSync(portFile, "utf-8"));
|
|
1227
1358
|
const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1228
1359
|
delete portData[rootHash];
|
|
1229
1360
|
if (Object.keys(portData).length === 0) {
|
|
1230
|
-
|
|
1361
|
+
import_node_fs4.default.unlinkSync(portFile);
|
|
1231
1362
|
} else {
|
|
1232
|
-
|
|
1363
|
+
import_node_fs4.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1233
1364
|
}
|
|
1234
1365
|
}
|
|
1235
1366
|
} catch {
|
|
@@ -1298,8 +1429,10 @@ async function handleRequest(url, req, res) {
|
|
|
1298
1429
|
}
|
|
1299
1430
|
try {
|
|
1300
1431
|
handleOpenFileRequest(body, serverState);
|
|
1301
|
-
} catch {
|
|
1302
|
-
serverLogger4.warn(
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
serverLogger4.warn(
|
|
1434
|
+
`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}. Reason: ${err.message}`
|
|
1435
|
+
);
|
|
1303
1436
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1304
1437
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
1305
1438
|
return;
|
|
@@ -1317,8 +1450,10 @@ async function handleRequest(url, req, res) {
|
|
|
1317
1450
|
const absolutePath = resolveWorkspacePath(file, serverState.cwd);
|
|
1318
1451
|
try {
|
|
1319
1452
|
assertPathWithinProject(absolutePath, serverState.projectRoot);
|
|
1320
|
-
} catch {
|
|
1321
|
-
serverLogger4.warn(
|
|
1453
|
+
} catch (err) {
|
|
1454
|
+
serverLogger4.warn(
|
|
1455
|
+
`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}. Reason: ${err.message}`
|
|
1456
|
+
);
|
|
1322
1457
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1323
1458
|
res.end(
|
|
1324
1459
|
JSON.stringify({
|
|
@@ -1485,23 +1620,25 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
|
|
|
1485
1620
|
return data;
|
|
1486
1621
|
});
|
|
1487
1622
|
} else {
|
|
1488
|
-
compilation.hooks.processAssets
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1623
|
+
if (compilation.hooks.processAssets) {
|
|
1624
|
+
compilation.hooks.processAssets.tapPromise(
|
|
1625
|
+
{
|
|
1626
|
+
name: "inspecto-overlay",
|
|
1627
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
|
1628
|
+
},
|
|
1629
|
+
async (assets) => {
|
|
1630
|
+
const port = await serverPortFn();
|
|
1631
|
+
const mainAssetKey = Object.keys(assets).find(
|
|
1632
|
+
(key) => key.endsWith(".js") && (key.includes("main") || key.includes("app") || key.includes("umi"))
|
|
1633
|
+
);
|
|
1634
|
+
if (!mainAssetKey) return;
|
|
1635
|
+
const originalSource = assets[mainAssetKey].source();
|
|
1636
|
+
assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
|
|
1637
|
+
getWebpackAssetScript(port) + "\n" + originalSource
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1505
1642
|
}
|
|
1506
1643
|
});
|
|
1507
1644
|
}
|
|
@@ -1553,7 +1690,6 @@ var DEFAULT_OPTIONS = {
|
|
|
1553
1690
|
logLevel: "warn"
|
|
1554
1691
|
};
|
|
1555
1692
|
var DEFAULT_PORT = 5678;
|
|
1556
|
-
var getCleanId = (id) => id.split("?")[0];
|
|
1557
1693
|
var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
|
|
1558
1694
|
const options = {
|
|
1559
1695
|
...DEFAULT_OPTIONS,
|
|
@@ -1640,14 +1776,13 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
1640
1776
|
},
|
|
1641
1777
|
transformInclude(id) {
|
|
1642
1778
|
if (isProduction || !id) return false;
|
|
1643
|
-
|
|
1644
|
-
return shouldTransform(cleanId, options);
|
|
1779
|
+
return shouldTransform(id, options);
|
|
1645
1780
|
},
|
|
1646
1781
|
transform(code, id) {
|
|
1647
1782
|
if (isProduction || !id) return null;
|
|
1648
|
-
const
|
|
1783
|
+
const { filePath } = extractTransformFilePath(id);
|
|
1649
1784
|
const result = transformRouter({
|
|
1650
|
-
filePath
|
|
1785
|
+
filePath,
|
|
1651
1786
|
source: code,
|
|
1652
1787
|
projectRoot,
|
|
1653
1788
|
pluginOptions: options
|