@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/rollup.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 (filePath.includes("node_modules")) return false;
42
- if (filePath.startsWith("\0")) return false;
43
- if (/[/\\](dist|build|\.next|\.nuxt)[/\\]/.test(filePath)) return false;
44
- const ext = filePath.split(".").pop()?.toLowerCase();
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 fs4 from "fs";
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
- const relativeToRoot = isWindowsAbsolutePath(file) || isWindowsAbsolutePath(projectRoot) ? path6.win32.relative(path6.win32.normalize(projectRoot), path6.win32.normalize(file)) : path6.relative(projectRoot, file);
821
- if (relativeToRoot.startsWith("..") || path6.isAbsolute(relativeToRoot)) {
822
- throw new Error("Access denied: File is outside of project workspace");
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
- assertPathWithinProject(absolutePath, serverState2.projectRoot);
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 fs3 from "fs";
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 (fs3.existsSync(path7.join(current, ".inspecto"))) return current;
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 (fs4.existsSync(portFile)) {
1306
+ if (fs5.existsSync(portFile)) {
1176
1307
  try {
1177
- portData = JSON.parse(fs4.readFileSync(portFile, "utf-8"));
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
- fs4.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
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 (fs4.existsSync(portFile)) {
1190
- const portData = JSON.parse(fs4.readFileSync(portFile, "utf-8"));
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
- fs4.unlinkSync(portFile);
1325
+ fs5.unlinkSync(portFile);
1195
1326
  } else {
1196
- fs4.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
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(`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}`);
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(`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}`);
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.tapPromise(
1453
- {
1454
- name: "inspecto-overlay",
1455
- stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
1456
- },
1457
- async (assets) => {
1458
- const port = await serverPortFn();
1459
- const mainAssetKey = Object.keys(assets).find(
1460
- (key) => key.endsWith(".js") && (key.includes("main") || key.includes("app"))
1461
- );
1462
- if (!mainAssetKey) return;
1463
- const originalSource = assets[mainAssetKey].source();
1464
- assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
1465
- getWebpackAssetScript(port) + "\n" + originalSource
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
- const cleanId = getCleanId(id);
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 cleanId = getCleanId(id);
1747
+ const { filePath } = extractTransformFilePath(id);
1613
1748
  const result = transformRouter({
1614
- filePath: cleanId,
1749
+ filePath,
1615
1750
  source: code,
1616
1751
  projectRoot,
1617
1752
  pluginOptions: options