@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.
Files changed (39) hide show
  1. package/dist/index.cjs +179 -44
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +179 -44
  4. package/dist/index.js.map +1 -1
  5. package/dist/legacy/rspack/index.cjs +108 -18
  6. package/dist/legacy/rspack/index.cjs.map +1 -1
  7. package/dist/legacy/rspack/index.js +108 -18
  8. package/dist/legacy/rspack/index.js.map +1 -1
  9. package/dist/legacy/rspack/loader.cjs +49 -4
  10. package/dist/legacy/rspack/loader.cjs.map +1 -1
  11. package/dist/legacy/rspack/loader.js +49 -4
  12. package/dist/legacy/rspack/loader.js.map +1 -1
  13. package/dist/legacy/webpack4/index.cjs +120 -20
  14. package/dist/legacy/webpack4/index.cjs.map +1 -1
  15. package/dist/legacy/webpack4/index.d.cts +2 -0
  16. package/dist/legacy/webpack4/index.d.ts +2 -0
  17. package/dist/legacy/webpack4/index.js +120 -20
  18. package/dist/legacy/webpack4/index.js.map +1 -1
  19. package/dist/legacy/webpack4/loader.cjs +49 -4
  20. package/dist/legacy/webpack4/loader.cjs.map +1 -1
  21. package/dist/legacy/webpack4/loader.js +49 -4
  22. package/dist/legacy/webpack4/loader.js.map +1 -1
  23. package/dist/rollup.cjs +179 -44
  24. package/dist/rollup.cjs.map +1 -1
  25. package/dist/rollup.js +179 -44
  26. package/dist/rollup.js.map +1 -1
  27. package/dist/rspack.cjs +179 -44
  28. package/dist/rspack.cjs.map +1 -1
  29. package/dist/rspack.js +179 -44
  30. package/dist/rspack.js.map +1 -1
  31. package/dist/vite.cjs +179 -44
  32. package/dist/vite.cjs.map +1 -1
  33. package/dist/vite.js +179 -44
  34. package/dist/vite.js.map +1 -1
  35. package/dist/webpack.cjs +179 -44
  36. package/dist/webpack.cjs.map +1 -1
  37. package/dist/webpack.js +179 -44
  38. package/dist/webpack.js.map +1 -1
  39. package/package.json +2 -2
package/dist/vite.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 (filePath.includes("node_modules")) return false;
82
- if (filePath.startsWith("\0")) return false;
83
- if (/[/\\](dist|build|\.next|\.nuxt)[/\\]/.test(filePath)) return false;
84
- const ext = filePath.split(".").pop()?.toLowerCase();
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 import_node_fs3 = __toESM(require("fs"), 1);
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
- const relativeToRoot = isWindowsAbsolutePath(file) || isWindowsAbsolutePath(projectRoot) ? import_node_path5.default.win32.relative(import_node_path5.default.win32.normalize(projectRoot), import_node_path5.default.win32.normalize(file)) : import_node_path5.default.relative(projectRoot, file);
857
- if (relativeToRoot.startsWith("..") || import_node_path5.default.isAbsolute(relativeToRoot)) {
858
- throw new Error("Access denied: File is outside of project workspace");
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
- assertPathWithinProject(absolutePath, serverState2.projectRoot);
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 import_node_fs2 = __toESM(require("fs"), 1);
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 (import_node_fs2.default.existsSync(import_node_path6.default.join(current, ".inspecto"))) return current;
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 (import_node_fs3.default.existsSync(portFile)) {
1342
+ if (import_node_fs4.default.existsSync(portFile)) {
1212
1343
  try {
1213
- portData = JSON.parse(import_node_fs3.default.readFileSync(portFile, "utf-8"));
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
- import_node_fs3.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
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 (import_node_fs3.default.existsSync(portFile)) {
1226
- const portData = JSON.parse(import_node_fs3.default.readFileSync(portFile, "utf-8"));
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
- import_node_fs3.default.unlinkSync(portFile);
1361
+ import_node_fs4.default.unlinkSync(portFile);
1231
1362
  } else {
1232
- import_node_fs3.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
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(`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}`);
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(`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}`);
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.tapPromise(
1489
- {
1490
- name: "inspecto-overlay",
1491
- stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
1492
- },
1493
- async (assets) => {
1494
- const port = await serverPortFn();
1495
- const mainAssetKey = Object.keys(assets).find(
1496
- (key) => key.endsWith(".js") && (key.includes("main") || key.includes("app"))
1497
- );
1498
- if (!mainAssetKey) return;
1499
- const originalSource = assets[mainAssetKey].source();
1500
- assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
1501
- getWebpackAssetScript(port) + "\n" + originalSource
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
- const cleanId = getCleanId(id);
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 cleanId = getCleanId(id);
1783
+ const { filePath } = extractTransformFilePath(id);
1649
1784
  const result = transformRouter({
1650
- filePath: cleanId,
1785
+ filePath,
1651
1786
  source: code,
1652
1787
  projectRoot,
1653
1788
  pluginOptions: options