@patchstack/connect 0.3.30 → 0.3.32

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 CHANGED
@@ -384,7 +384,7 @@ async function walkNodeModules(cwd) {
384
384
  seen.set(await (0, import_promises4.realpath)(cwd), -1);
385
385
  } catch {
386
386
  }
387
- return dedupeByShallowest(await walk(root, 0, seen));
387
+ return dedupeByShallowest(await walk(root, 0, seen, cwd));
388
388
  }
389
389
  function dedupeByShallowest(found) {
390
390
  const best = /* @__PURE__ */ new Map();
@@ -395,7 +395,7 @@ function dedupeByShallowest(found) {
395
395
  return [...best.values()].map(({ entry }) => entry);
396
396
  }
397
397
  var CONCURRENCY = 32;
398
- async function walk(dir, depth, seen) {
398
+ async function walk(dir, depth, seen, root) {
399
399
  let names;
400
400
  try {
401
401
  names = await (0, import_promises4.readdir)(dir);
@@ -407,7 +407,7 @@ async function walk(dir, depth, seen) {
407
407
  const fullPath = import_node_path3.default.join(dir, name);
408
408
  const resolved = await claim(fullPath, seen, depth);
409
409
  if (resolved === null) return [];
410
- if (PACKAGE_STORE_DIRS.has(name)) return walk(fullPath, depth, seen);
410
+ if (PACKAGE_STORE_DIRS.has(name)) return walk(fullPath, depth, seen, root);
411
411
  if (name.startsWith("@")) {
412
412
  let subNames;
413
413
  try {
@@ -420,16 +420,16 @@ async function walk(dir, depth, seen) {
420
420
  const scopedDir = import_node_path3.default.join(fullPath, sub);
421
421
  const scopedReal = await claim(scopedDir, seen, depth);
422
422
  if (scopedReal === null) return [];
423
- return packageAndNested(scopedDir, scopedReal, depth, seen);
423
+ return packageAndNested(scopedDir, scopedReal, depth, seen, root);
424
424
  });
425
425
  return scoped.flat();
426
426
  }
427
- return packageAndNested(fullPath, resolved, depth, seen);
427
+ return packageAndNested(fullPath, resolved, depth, seen, root);
428
428
  });
429
429
  return perEntry.flat();
430
430
  }
431
- async function packageAndNested(pkgDir, resolved, depth, seen) {
432
- const [own, nested] = await Promise.all([readPackage(pkgDir, depth), walkNested(pkgDir, depth, seen)]);
431
+ async function packageAndNested(pkgDir, resolved, depth, seen, root) {
432
+ const [own, nested] = await Promise.all([readPackage(pkgDir, depth, root), walkNested(pkgDir, depth, seen, root)]);
433
433
  return own === null ? nested : [{ entry: own, realpath: resolved, depth }, ...nested];
434
434
  }
435
435
  async function mapLimit(items, fn) {
@@ -444,7 +444,10 @@ async function mapLimit(items, fn) {
444
444
  await Promise.all(workers);
445
445
  return results;
446
446
  }
447
- async function readPackage(pkgDir, depth) {
447
+ function installLocation(root, pkgDir, impl = import_node_path3.default) {
448
+ return impl.relative(root, pkgDir).split(impl.sep).join("/");
449
+ }
450
+ async function readPackage(pkgDir, depth, root) {
448
451
  let raw;
449
452
  try {
450
453
  raw = await (0, import_promises4.readFile)(import_node_path3.default.join(pkgDir, "package.json"), "utf8");
@@ -463,14 +466,14 @@ async function readPackage(pkgDir, depth) {
463
466
  if (typeof parsed.version !== "string" || parsed.version.length === 0) {
464
467
  return null;
465
468
  }
466
- return { name: parsed.name, version: parsed.version, direct: depth === 0 };
469
+ return { name: parsed.name, version: parsed.version, path: installLocation(root, pkgDir), direct: depth === 0 };
467
470
  }
468
- async function walkNested(pkgDir, depth, seen) {
471
+ async function walkNested(pkgDir, depth, seen, root) {
469
472
  const nested = import_node_path3.default.join(pkgDir, "node_modules");
470
473
  if (await claim(nested, seen, depth + 1) === null) {
471
474
  return [];
472
475
  }
473
- return walk(nested, depth + 1, seen);
476
+ return walk(nested, depth + 1, seen, root);
474
477
  }
475
478
  async function claim(dir, seen, depth) {
476
479
  let resolved;
@@ -1113,21 +1116,33 @@ async function exists(filePath) {
1113
1116
  }
1114
1117
 
1115
1118
  // src/normalize.ts
1116
- function buildWirePayload(manifest) {
1119
+ function buildWirePayload(manifest, options = {}) {
1120
+ const withPaths = options.installPaths === true;
1117
1121
  const seen = /* @__PURE__ */ new Map();
1118
1122
  const wirePackages = [];
1123
+ const byIdentity = /* @__PURE__ */ new Map();
1124
+ let entriesWithoutPath = 0;
1119
1125
  for (const entry of manifest.packages) {
1126
+ const identity = `${entry.name}@${entry.version}`;
1127
+ const location = withPaths && entry.path !== void 0 && entry.path !== "" ? entry.path : void 0;
1128
+ if (location === void 0) entriesWithoutPath++;
1129
+ const existing = byIdentity.get(identity);
1130
+ if (existing) {
1131
+ if (location !== void 0) addPath(existing, location);
1132
+ continue;
1133
+ }
1120
1134
  const versions = seen.get(entry.name);
1121
1135
  if (versions) {
1122
- if (versions.has(entry.version)) {
1123
- continue;
1124
- }
1125
1136
  versions.add(entry.version);
1126
1137
  } else {
1127
1138
  seen.set(entry.name, /* @__PURE__ */ new Set([entry.version]));
1128
1139
  }
1129
- wirePackages.push({ name: entry.name, version: entry.version });
1140
+ const wire = { name: entry.name, version: entry.version };
1141
+ if (location !== void 0) addPath(wire, location);
1142
+ byIdentity.set(identity, wire);
1143
+ wirePackages.push(wire);
1130
1144
  }
1145
+ for (const wire of wirePackages) wire.paths?.sort();
1131
1146
  wirePackages.sort((a, b) => {
1132
1147
  if (a.name === b.name) {
1133
1148
  return compareVersions(a.version, b.version);
@@ -1141,7 +1156,18 @@ function buildWirePayload(manifest) {
1141
1156
  }
1142
1157
  }
1143
1158
  return {
1144
- payload: { ecosystem: manifest.ecosystem, packages: wirePackages },
1159
+ payload: {
1160
+ ecosystem: manifest.ecosystem,
1161
+ packages: wirePackages,
1162
+ // Every entry had a location, so a missing path anywhere means the package is not installed there.
1163
+ // One entry without one forfeits that for the whole payload: a consumer reading a short `paths` has
1164
+ // no way to tell which entry was the incomplete one.
1165
+ //
1166
+ // No separate check for "locations were not requested": with them off every entry counts as without
1167
+ // one, so this is already false — which is the default, and the safe direction. An explicit
1168
+ // `withPaths &&` here was a guard no test could distinguish from its absence.
1169
+ installPathsComplete: entriesWithoutPath === 0 && manifest.packages.length > 0
1170
+ },
1145
1171
  stats: {
1146
1172
  uniqueNames: seen.size,
1147
1173
  duplicateNames,
@@ -1149,6 +1175,10 @@ function buildWirePayload(manifest) {
1149
1175
  }
1150
1176
  };
1151
1177
  }
1178
+ function addPath(wire, installPath) {
1179
+ if (wire.paths === void 0) wire.paths = [installPath];
1180
+ else if (!wire.paths.includes(installPath)) wire.paths.push(installPath);
1181
+ }
1152
1182
  function compareVersions(a, b) {
1153
1183
  if (a === b) {
1154
1184
  return 0;
@@ -1724,7 +1754,7 @@ async function scanAndReport(options = {}) {
1724
1754
  const cwd = options.cwd ?? process.cwd();
1725
1755
  const config = options.config ?? await resolveConfig({ cwd });
1726
1756
  const manifest = await scanLockfile(cwd);
1727
- const { payload, stats } = buildWirePayload(manifest);
1757
+ const { payload, stats } = buildWirePayload(manifest, { installPaths: options.installPaths === true });
1728
1758
  const response = await postManifest(config, payload);
1729
1759
  if (config.siteUuid === null && response.uuid !== void 0 && response.uuid.length > 0) {
1730
1760
  await persistSiteUuid(cwd, response.uuid);