@antongolub/lockfile 0.0.0-snapshot.61 → 0.0.0-snapshot.63

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 (46) hide show
  1. package/README.md +7 -0
  2. package/dist/{_npm-flat-types-C6TSaidU.d.ts → _npm-flat-types-CR16JZFS.d.ts} +1 -1
  3. package/dist/{_pnpm-flat-core-NEg8x-yf.d.ts → _pnpm-flat-core-DmGs4UQu.d.ts} +1 -1
  4. package/dist/{_yarn-berry-core-CLT-3m_j.d.ts → _yarn-berry-core-BhE-AhmX.d.ts} +1 -1
  5. package/dist/complete.d.ts +2 -2
  6. package/dist/formats/bun-text.d.ts +19 -2
  7. package/dist/formats/bun-text.js +214 -7
  8. package/dist/formats/npm-1.d.ts +1 -1
  9. package/dist/formats/npm-1.js +32 -4
  10. package/dist/formats/npm-2.d.ts +2 -2
  11. package/dist/formats/npm-2.js +36 -7
  12. package/dist/formats/npm-3.d.ts +2 -2
  13. package/dist/formats/npm-3.js +31 -3
  14. package/dist/formats/pnpm-v5.d.ts +1 -1
  15. package/dist/formats/pnpm-v5.js +32 -11
  16. package/dist/formats/pnpm-v6.d.ts +2 -2
  17. package/dist/formats/pnpm-v6.js +33 -12
  18. package/dist/formats/pnpm-v9.d.ts +2 -2
  19. package/dist/formats/pnpm-v9.js +33 -12
  20. package/dist/formats/yarn-berry-v10.d.ts +2 -2
  21. package/dist/formats/yarn-berry-v10.js +55 -21
  22. package/dist/formats/yarn-berry-v4.d.ts +2 -2
  23. package/dist/formats/yarn-berry-v4.js +55 -21
  24. package/dist/formats/yarn-berry-v5.d.ts +2 -2
  25. package/dist/formats/yarn-berry-v5.js +55 -21
  26. package/dist/formats/yarn-berry-v6.d.ts +2 -2
  27. package/dist/formats/yarn-berry-v6.js +55 -21
  28. package/dist/formats/yarn-berry-v7.d.ts +2 -2
  29. package/dist/formats/yarn-berry-v7.js +55 -21
  30. package/dist/formats/yarn-berry-v8.d.ts +2 -2
  31. package/dist/formats/yarn-berry-v8.js +55 -21
  32. package/dist/formats/yarn-berry-v9.d.ts +2 -2
  33. package/dist/formats/yarn-berry-v9.js +55 -21
  34. package/dist/formats/yarn-classic.d.ts +1 -1
  35. package/dist/formats/yarn-classic.js +34 -7
  36. package/dist/{graph-B_G4OKqF.d.ts → graph-CPo-SvS2.d.ts} +2 -1
  37. package/dist/index.d.ts +6 -6
  38. package/dist/index.js +1158 -202
  39. package/dist/{modify-VjOK9KTg.d.ts → modify-DuBV5-5V.d.ts} +2 -2
  40. package/dist/modify.d.ts +3 -3
  41. package/dist/{optimize-cMIkc20f.d.ts → optimize-B6TOjYyj.d.ts} +1 -1
  42. package/dist/optimize.d.ts +2 -2
  43. package/dist/registry.d.ts +6 -6
  44. package/dist/registry.js +2 -2
  45. package/dist/{types-CGeGAM7Z.d.ts → types-BPMSHpCF.d.ts} +1 -1
  46. package/package.json +5 -1
package/README.md CHANGED
@@ -24,6 +24,13 @@ Published as `0.0.0-snapshot.*` builds — the first stable release is pending.
24
24
  [SCHEMAS.md](./SCHEMAS.md) maps each format id to the package-manager versions
25
25
  that emit it.
26
26
 
27
+ > **ℹ️ Active R&D — snapshot channel.** While the project is under active research &
28
+ > development, every release ships to the **snapshot channel** (`0.0.0-snapshot.N`,
29
+ > published under the `snapshot` npm dist-tag) rather than `latest`. Install the newest
30
+ > snapshot with `npm i @antongolub/lockfile@snapshot`, or pin an exact build
31
+ > (e.g. `npm i @antongolub/lockfile@0.0.0-snapshot.61`). The first stable `latest`
32
+ > release is pending.
33
+
27
34
  | Format | `detect` | `parse` | `stringify` |
28
35
  |--------|:-:|:-:|:-:|
29
36
  | `npm-1` · `npm-2` · `npm-3` | ✓ | ✓ | ✓ |
@@ -1,4 +1,4 @@
1
- import { D as Diagnostic, O as OverrideConstraint } from './graph-B_G4OKqF.js';
1
+ import { D as Diagnostic, O as OverrideConstraint } from './graph-CPo-SvS2.js';
2
2
 
3
3
  interface NpmFamilyParseOptions {
4
4
  }
@@ -1,4 +1,4 @@
1
- import { D as Diagnostic, O as OverrideConstraint } from './graph-B_G4OKqF.js';
1
+ import { D as Diagnostic, O as OverrideConstraint } from './graph-CPo-SvS2.js';
2
2
 
3
3
  interface PnpmFamilyParseOptions {
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { O as OverrideConstraint, D as Diagnostic } from './graph-B_G4OKqF.js';
1
+ import { O as OverrideConstraint, D as Diagnostic } from './graph-CPo-SvS2.js';
2
2
 
3
3
  interface YarnBerryFamilyParseOptions {
4
4
  workspaceRoot?: string;
@@ -1,5 +1,5 @@
1
- import { N as NodeId, D as Diagnostic, G as Graph, E as EdgeTriple, a as Node, b as EdgeKind } from './graph-B_G4OKqF.js';
2
- import { R as RegistryAdapter } from './types-CGeGAM7Z.js';
1
+ import { N as NodeId, D as Diagnostic, G as Graph, E as EdgeTriple, a as Node, b as EdgeKind } from './graph-CPo-SvS2.js';
2
+ import { R as RegistryAdapter } from './types-BPMSHpCF.js';
3
3
 
4
4
  interface CompletionSeed {
5
5
  /** NodeIds the modifier added in the just-completed mutate phase. */
@@ -1,9 +1,18 @@
1
- import { D as Diagnostic, G as Graph } from '../graph-B_G4OKqF.js';
1
+ import { O as OverrideConstraint, D as Diagnostic, G as Graph } from '../graph-CPo-SvS2.js';
2
2
 
3
3
  interface BunTextParseOptions {
4
4
  }
5
5
  interface BunTextStringifyOptions {
6
6
  lineEnding?: 'lf' | 'crlf';
7
+ /**
8
+ * Caller-supplied canonical override constraints (ADR-0025). bun's `overrides`
9
+ * block is npm-shaped, so these project through the npm grammar
10
+ * (`projectOverrides(_, 'npm')`). An explicit `[]` suppresses the verbatim
11
+ * carrier captured at parse; `undefined` falls back to it. This is the
12
+ * audit-fix write path — `pinOverride` results land here as a forced
13
+ * resolution into bun's top-level `overrides`.
14
+ */
15
+ overrides?: OverrideConstraint[];
7
16
  onDiagnostic?: (diagnostic: Diagnostic) => void;
8
17
  }
9
18
  interface BunTextManifest {
@@ -19,6 +28,14 @@ interface BunTextEnrichOptions {
19
28
  }
20
29
  interface BunTextOptimizeOptions {
21
30
  }
31
+ /**
32
+ * Canonical override constraints captured from a bun-text graph's top-level
33
+ * `overrides` block (ADR-0025 §6, A2). Mirrors `getPnpmOverridesCanonical` /
34
+ * npm's `rootMeta.overrides` so `index.ts` `overridesOf` can fold a bun source's
35
+ * overrides into a cross-PM conversion. Returns undefined when the graph carries
36
+ * no overrides block (or the sidecar was lost to a bare `mutate`).
37
+ */
38
+ declare function getBunOverridesCanonical(graph: Graph): OverrideConstraint[] | undefined;
22
39
  declare function check(input: string): boolean;
23
40
  declare function parse(input: string, _options?: BunTextParseOptions): Graph;
24
41
  declare function stringify(graph: Graph, options?: BunTextStringifyOptions): string;
@@ -31,4 +48,4 @@ declare function optimize(graph: Graph, _options?: BunTextOptimizeOptions): {
31
48
  diagnostics: Diagnostic[];
32
49
  };
33
50
 
34
- export { type BunTextEnrichOptions, type BunTextManifest, type BunTextOptimizeOptions, type BunTextParseOptions, type BunTextStringifyOptions, check, enrich, optimize, parse, stringify };
51
+ export { type BunTextEnrichOptions, type BunTextManifest, type BunTextOptimizeOptions, type BunTextParseOptions, type BunTextStringifyOptions, check, enrich, getBunOverridesCanonical, optimize, parse, stringify };
@@ -723,6 +723,13 @@ function emitWorkspaceCollapsed(edge, fromSpecifier, onDiagnostic) {
723
723
  if (onDiagnostic === void 0) return;
724
724
  onDiagnostic(workspaceCollapsedDiagnostic(edge, fromSpecifier));
725
725
  }
726
+ function overrideParentRefDropped(pkg, to) {
727
+ return {
728
+ code: "OVERRIDE_PARENT_REF_DROPPED",
729
+ severity: "warning",
730
+ message: `override ${pkg}=${to}: npm $name self-ref has no yarn/pnpm equivalent; emitted verbatim`
731
+ };
732
+ }
726
733
 
727
734
  // src/main/ts/recipe/workspace.ts
728
735
  function isWorkspaceSpecifier(s) {
@@ -771,11 +778,168 @@ function nodeVersionOf(id) {
771
778
  return paren < 0 ? rest : rest.slice(0, paren);
772
779
  }
773
780
 
781
+ // src/main/ts/recipe/overrides.ts
782
+ function splitNameVersion(selector) {
783
+ let depth = 0;
784
+ let lastAt = -1;
785
+ for (let i = 0; i < selector.length; i++) {
786
+ const c = selector[i];
787
+ if (c === "(") depth++;
788
+ else if (c === ")") depth--;
789
+ else if (c === "@" && depth === 0 && i >= 1) lastAt = i;
790
+ }
791
+ if (lastAt <= 0) return { package: selector };
792
+ const name = selector.slice(0, lastAt);
793
+ const version = selector.slice(lastAt + 1);
794
+ if (name.length === 0 || version.length === 0) return { package: selector };
795
+ return { package: name, versionCondition: version };
796
+ }
797
+ function captureOverrides(block, pm, onDiagnostic) {
798
+ if (block === null || typeof block !== "object") {
799
+ return { canonical: [], native: {} };
800
+ }
801
+ let canonical;
802
+ const native = {};
803
+ switch (pm) {
804
+ case "npm": {
805
+ native.npmOverrides = block;
806
+ canonical = captureNpm(block, []);
807
+ break;
808
+ }
809
+ case "yarn": {
810
+ const flat = asStringRecord(block);
811
+ native.yarnResolutions = flat;
812
+ canonical = captureFlat(flat, splitYarnKey);
813
+ break;
814
+ }
815
+ case "pnpm": {
816
+ const flat = asStringRecord(block);
817
+ native.pnpmOverrides = flat;
818
+ canonical = captureFlat(flat, splitPnpmKey);
819
+ break;
820
+ }
821
+ }
822
+ return { canonical, native };
823
+ }
824
+ function captureNpm(block, parentPath) {
825
+ const out = [];
826
+ for (const [key, value] of Object.entries(block)) {
827
+ if (key === ".") {
828
+ if (parentPath.length === 0) continue;
829
+ const pkg2 = parentPath[parentPath.length - 1];
830
+ const ancestors = parentPath.slice(0, -1);
831
+ if (typeof value === "string") out.push(constraint(pkg2, ancestors, value));
832
+ continue;
833
+ }
834
+ const { package: pkg } = splitNameVersion(key);
835
+ if (typeof value === "string") {
836
+ out.push(constraint(pkg, parentPath, value));
837
+ } else if (value !== null && typeof value === "object") {
838
+ out.push(...captureNpm(value, [...parentPath, pkg]));
839
+ }
840
+ }
841
+ return out;
842
+ }
843
+ function captureFlat(flat, splitKey) {
844
+ const out = [];
845
+ for (const [key, to] of Object.entries(flat)) {
846
+ const { package: pkg, parentPath, versionCondition } = splitKey(key);
847
+ out.push(constraint(pkg, parentPath, to, versionCondition));
848
+ }
849
+ return out;
850
+ }
851
+ function splitYarnKey(key) {
852
+ const segments = splitYarnPathSegments(key);
853
+ const leaf = segments[segments.length - 1];
854
+ const { package: pkg, versionCondition } = splitNameVersion(leaf);
855
+ const parentPath = segments.slice(0, -1).filter((s) => s !== "**");
856
+ return versionCondition !== void 0 ? { package: pkg, parentPath, versionCondition } : { package: pkg, parentPath };
857
+ }
858
+ function splitYarnPathSegments(key) {
859
+ const raw = key.split("/");
860
+ const segments = [];
861
+ for (let i = 0; i < raw.length; i++) {
862
+ const piece = raw[i];
863
+ if (piece.startsWith("@") && i + 1 < raw.length) {
864
+ segments.push(`${piece}/${raw[i + 1]}`);
865
+ i++;
866
+ } else {
867
+ segments.push(piece);
868
+ }
869
+ }
870
+ return segments;
871
+ }
872
+ function splitPnpmKey(key) {
873
+ const segments = key.split(">").filter((s) => s.length > 0);
874
+ const leaf = segments[segments.length - 1];
875
+ const { package: pkg, versionCondition } = splitNameVersion(leaf);
876
+ const parentPath = segments.slice(0, -1).map((s) => splitNameVersion(s).package);
877
+ return versionCondition !== void 0 ? { package: pkg, parentPath, versionCondition } : { package: pkg, parentPath };
878
+ }
879
+ function constraint(pkg, parentPath, to, versionCondition) {
880
+ const c = { package: pkg, to };
881
+ if (parentPath.length > 0) c.parentPath = parentPath;
882
+ if (versionCondition !== void 0 && versionCondition !== "") {
883
+ c.versionCondition = versionCondition;
884
+ }
885
+ if (to.startsWith("$")) c.selfRef = true;
886
+ return c;
887
+ }
888
+ function asStringRecord(block) {
889
+ const out = {};
890
+ for (const [k, v] of Object.entries(block)) {
891
+ if (typeof v === "string") out[k] = v;
892
+ }
893
+ return out;
894
+ }
895
+ function projectOverrides(canonical, pm, onDiagnostic) {
896
+ return pm === "npm" ? projectNpm(canonical) : projectPnpm(canonical, onDiagnostic);
897
+ }
898
+ function projectNpm(canonical) {
899
+ const root = {};
900
+ for (const c of canonical) {
901
+ const leafKey = c.versionCondition ? `${c.package}@${c.versionCondition}` : c.package;
902
+ let node = root;
903
+ for (const seg of c.parentPath ?? []) {
904
+ const existing = node[seg];
905
+ if (typeof existing === "object" && existing !== null) {
906
+ node = existing;
907
+ } else {
908
+ const nested = typeof existing === "string" ? { ".": existing } : {};
909
+ node[seg] = nested;
910
+ node = nested;
911
+ }
912
+ }
913
+ const existingLeaf = node[leafKey];
914
+ if (existingLeaf !== null && typeof existingLeaf === "object") {
915
+ existingLeaf["."] = c.to;
916
+ } else {
917
+ node[leafKey] = c.to;
918
+ }
919
+ }
920
+ return root;
921
+ }
922
+ function projectPnpm(canonical, onDiagnostic) {
923
+ const out = {};
924
+ for (const c of canonical) {
925
+ const leaf = c.versionCondition ? `${c.package}@${c.versionCondition}` : c.package;
926
+ const key = c.parentPath && c.parentPath.length > 0 ? `${c.parentPath.join(">")}>${leaf}` : leaf;
927
+ if (c.selfRef && onDiagnostic !== void 0) {
928
+ onDiagnostic(overrideParentRefDropped(c.package, c.to));
929
+ }
930
+ out[key] = c.to;
931
+ }
932
+ return out;
933
+ }
934
+
774
935
  // src/main/ts/formats/bun-text.ts
775
936
  var sidecarByGraph = /* @__PURE__ */ new WeakMap();
776
937
  function rememberSidecar(graph, sidecar) {
777
938
  sidecarByGraph.set(graph, sidecar);
778
939
  }
940
+ function getBunOverridesCanonical(graph) {
941
+ return sidecarByGraph.get(graph)?.canonicalOverrides;
942
+ }
779
943
  function check(input) {
780
944
  if (!/"lockfileVersion"\s*:\s*1\b/.test(input)) return false;
781
945
  if (!/"workspaces"\s*:\s*\{/.test(input)) return false;
@@ -950,6 +1114,17 @@ function parse(input, _options = {}) {
950
1114
  const consumerScope = buildConsumerScope(packagesKey, packages, packageByName);
951
1115
  addBlockEdges(builder, diagnostics, entry.id, entry.inner, consumerScope, void 0, peerDeclarations);
952
1116
  }
1117
+ let nativeOverrides;
1118
+ let canonicalOverrides;
1119
+ if (lf.overrides !== void 0 && lf.overrides !== null && typeof lf.overrides === "object") {
1120
+ nativeOverrides = lf.overrides;
1121
+ const captured = captureOverrides(lf.overrides, "npm");
1122
+ if (captured.canonical.length > 0) canonicalOverrides = captured.canonical;
1123
+ }
1124
+ const trustedDependencies = Array.isArray(lf.trustedDependencies) ? lf.trustedDependencies.filter((v) => typeof v === "string") : void 0;
1125
+ const patchedDependencies = lf.patchedDependencies !== void 0 && lf.patchedDependencies !== null && typeof lf.patchedDependencies === "object" ? Object.fromEntries(
1126
+ Object.entries(lf.patchedDependencies).filter((e) => typeof e[1] === "string")
1127
+ ) : void 0;
953
1128
  for (const diagnostic of diagnostics) {
954
1129
  builder.diagnostic(diagnostic);
955
1130
  }
@@ -961,7 +1136,11 @@ function parse(input, _options = {}) {
961
1136
  workspaces: workspaceSidecar,
962
1137
  workspaceByPath,
963
1138
  nodes: nodeSidecar,
964
- peerDeclarations
1139
+ peerDeclarations,
1140
+ nativeOverrides,
1141
+ canonicalOverrides,
1142
+ trustedDependencies,
1143
+ patchedDependencies
965
1144
  };
966
1145
  rememberSidecar(graph, sidecar);
967
1146
  return graph;
@@ -1013,13 +1192,34 @@ function stringify(graph, options = {}) {
1013
1192
  const key = chooseNodeEmitKey(node, sidecar, packagesBlock);
1014
1193
  packagesBlock[key] = [`${node.name}@${node.version}`, "", inner, integrity];
1015
1194
  }
1016
- const json = renderJsonc({
1195
+ const overridesBlock = resolveOverridesBlock(options.overrides, sidecar, emitDiagnostic);
1196
+ const out = {
1017
1197
  lockfileVersion: 1,
1018
- workspaces: workspacesBlock,
1019
- packages: packagesBlock
1020
- });
1198
+ workspaces: workspacesBlock
1199
+ };
1200
+ if (overridesBlock !== void 0 && Object.keys(overridesBlock).length > 0) {
1201
+ out.overrides = overridesBlock;
1202
+ }
1203
+ out.packages = packagesBlock;
1204
+ if (sidecar?.patchedDependencies !== void 0 && Object.keys(sidecar.patchedDependencies).length > 0) {
1205
+ out.patchedDependencies = sortRecord(sidecar.patchedDependencies);
1206
+ }
1207
+ if (sidecar?.trustedDependencies !== void 0 && sidecar.trustedDependencies.length > 0) {
1208
+ out.trustedDependencies = [...sidecar.trustedDependencies].sort(cmpStr2);
1209
+ }
1210
+ const json = renderJsonc(out);
1021
1211
  return options.lineEnding === "crlf" ? json.replace(/\n/g, "\r\n") : json;
1022
1212
  }
1213
+ function resolveOverridesBlock(callerOverrides, sidecar, emitDiagnostic) {
1214
+ if (callerOverrides !== void 0) {
1215
+ return callerOverrides.length > 0 ? projectOverrides(callerOverrides, "npm", emitDiagnostic) : void 0;
1216
+ }
1217
+ if (sidecar?.nativeOverrides !== void 0) return sidecar.nativeOverrides;
1218
+ if (sidecar?.canonicalOverrides !== void 0 && sidecar.canonicalOverrides.length > 0) {
1219
+ return projectOverrides(sidecar.canonicalOverrides, "npm", emitDiagnostic);
1220
+ }
1221
+ return void 0;
1222
+ }
1023
1223
  function enrich(graph, options = {}) {
1024
1224
  const sidecar = sidecarByGraph.get(graph);
1025
1225
  const diagnostics = [];
@@ -1489,8 +1689,15 @@ function pruneSidecar(sidecar, graph) {
1489
1689
  const [srcId] = key.split("|");
1490
1690
  return srcId !== void 0 && reachableIds.has(srcId);
1491
1691
  })
1492
- )
1692
+ ),
1693
+ // Top-level fidelity blocks are project-global (not per-node), so they
1694
+ // survive an orphan-prune verbatim — pruning unreachable nodes never
1695
+ // invalidates a declared override / trusted / patched entry.
1696
+ nativeOverrides: sidecar.nativeOverrides,
1697
+ canonicalOverrides: sidecar.canonicalOverrides,
1698
+ trustedDependencies: sidecar.trustedDependencies,
1699
+ patchedDependencies: sidecar.patchedDependencies
1493
1700
  };
1494
1701
  }
1495
1702
 
1496
- export { check, enrich, optimize, parse, stringify };
1703
+ export { check, enrich, getBunOverridesCanonical, optimize, parse, stringify };
@@ -1,4 +1,4 @@
1
- import { D as Diagnostic, G as Graph } from '../graph-B_G4OKqF.js';
1
+ import { D as Diagnostic, G as Graph } from '../graph-CPo-SvS2.js';
2
2
 
3
3
  interface Npm1ParseOptions {
4
4
  }
@@ -737,8 +737,19 @@ function parse(raw, options = {}) {
737
737
  }
738
738
  function parseInner(protocol, spec, raw, options) {
739
739
  switch (protocol) {
740
- case "npm":
741
- return { type: "tarball", url: deriveRegistryUrl(options.name, spec) };
740
+ case "npm": {
741
+ const bindIdx = spec.indexOf("::");
742
+ const version = bindIdx >= 0 ? spec.slice(0, bindIdx) : spec;
743
+ const bindSuffix = bindIdx >= 0 ? spec.slice(bindIdx + 2) : void 0;
744
+ if (bindSuffix !== void 0) {
745
+ const archiveUrl = archiveUrlOfBind(bindSuffix);
746
+ if (archiveUrl !== void 0) {
747
+ return { type: "tarball", url: archiveUrl };
748
+ }
749
+ return { type: "tarball", url: deriveRegistryUrl(options.name, version), bind: bindSuffix };
750
+ }
751
+ return { type: "tarball", url: deriveRegistryUrl(options.name, version) };
752
+ }
742
753
  case "portal":
743
754
  return { type: "directory", path: normaliseDirectoryPath(spec) };
744
755
  case "file":
@@ -767,6 +778,20 @@ function deriveRegistryUrl(name, spec) {
767
778
  function looksLikeNpmName(s) {
768
779
  return /^(?:@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*$/i.test(s);
769
780
  }
781
+ function archiveUrlOfBind(bindSuffix) {
782
+ for (const pair of bindSuffix.split("&")) {
783
+ const eq = pair.indexOf("=");
784
+ if (eq < 0) continue;
785
+ if (pair.slice(0, eq) !== "__archiveUrl") continue;
786
+ const enc = pair.slice(eq + 1);
787
+ try {
788
+ return decodeURIComponent(enc);
789
+ } catch {
790
+ return void 0;
791
+ }
792
+ }
793
+ return void 0;
794
+ }
770
795
  function registryUrlOf(name, version) {
771
796
  const tail = name.startsWith("@") ? name.split("/").slice(1).join("/") : name;
772
797
  return `https://registry.npmjs.org/${name}/-/${tail}-${version}.tgz`;
@@ -923,6 +948,9 @@ function canonicalSourceStringOf(resolution) {
923
948
  return `git\0${resolution.url}\0${resolution.sha}`;
924
949
  case "tarball": {
925
950
  const host = hostOfTarballUrl(resolution.url);
951
+ if (resolution.bind !== void 0) {
952
+ return `tarball\0${host ?? resolution.url}\0bind=${resolution.bind}`;
953
+ }
926
954
  return host !== void 0 && REGISTRY_HOSTS.has(host) ? void 0 : `tarball\0${host ?? resolution.url}`;
927
955
  }
928
956
  case "directory":
@@ -1057,7 +1085,6 @@ function parse2(input, _options = {}) {
1057
1085
  version,
1058
1086
  peerContext: []
1059
1087
  };
1060
- if (resolved !== void 0) node.resolution = resolved;
1061
1088
  if (source !== void 0) node.source = source;
1062
1089
  builder.addNode(node);
1063
1090
  const payload = {};
@@ -1066,6 +1093,7 @@ function parse2(input, _options = {}) {
1066
1093
  if (!isEmptyIntegrity(integrity)) payload.integrity = integrity;
1067
1094
  }
1068
1095
  if (resolved !== void 0) {
1096
+ payload.nativeResolution = resolved;
1069
1097
  const canonical = parse(resolved, { sourceKind: "npm-resolved" });
1070
1098
  if (canonical.type === "unknown") {
1071
1099
  diagnostics.push({
@@ -1521,7 +1549,7 @@ function buildEntry(node, installPath, graph, sidecar, treeByParent) {
1521
1549
  const entry = { version: node.version };
1522
1550
  const nodeSide = sidecar?.nodes.get(node.id);
1523
1551
  const tarball = graph.tarballOf(node.id);
1524
- const resolutionStr = node.resolution ?? deriveResolvedFromCanonical(tarball?.resolution);
1552
+ const resolutionStr = tarball?.nativeResolution ?? deriveResolvedFromCanonical(tarball?.resolution);
1525
1553
  if (resolutionStr !== void 0) {
1526
1554
  if (/^(git[+:]|github:)/.test(resolutionStr)) {
1527
1555
  entry.version = resolutionStr;
@@ -1,5 +1,5 @@
1
- import { G as Graph, D as Diagnostic } from '../graph-B_G4OKqF.js';
2
- import { N as NpmFamilyEnrichOptions, a as NpmFamilyOptimizeOptions, b as NpmFamilyParseOptions, c as NpmFamilyStringifyOptions } from '../_npm-flat-types-C6TSaidU.js';
1
+ import { G as Graph, D as Diagnostic } from '../graph-CPo-SvS2.js';
2
+ import { N as NpmFamilyEnrichOptions, a as NpmFamilyOptimizeOptions, b as NpmFamilyParseOptions, c as NpmFamilyStringifyOptions } from '../_npm-flat-types-CR16JZFS.js';
3
3
 
4
4
  interface Npm2ParseOptions extends NpmFamilyParseOptions {
5
5
  }
@@ -791,8 +791,19 @@ function parse(raw, options = {}) {
791
791
  }
792
792
  function parseInner(protocol, spec, raw, options) {
793
793
  switch (protocol) {
794
- case "npm":
795
- return { type: "tarball", url: deriveRegistryUrl(options.name, spec) };
794
+ case "npm": {
795
+ const bindIdx = spec.indexOf("::");
796
+ const version = bindIdx >= 0 ? spec.slice(0, bindIdx) : spec;
797
+ const bindSuffix = bindIdx >= 0 ? spec.slice(bindIdx + 2) : void 0;
798
+ if (bindSuffix !== void 0) {
799
+ const archiveUrl = archiveUrlOfBind(bindSuffix);
800
+ if (archiveUrl !== void 0) {
801
+ return { type: "tarball", url: archiveUrl };
802
+ }
803
+ return { type: "tarball", url: deriveRegistryUrl(options.name, version), bind: bindSuffix };
804
+ }
805
+ return { type: "tarball", url: deriveRegistryUrl(options.name, version) };
806
+ }
796
807
  case "portal":
797
808
  return { type: "directory", path: normaliseDirectoryPath(spec) };
798
809
  case "file":
@@ -821,6 +832,20 @@ function deriveRegistryUrl(name, spec) {
821
832
  function looksLikeNpmName(s) {
822
833
  return /^(?:@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*$/i.test(s);
823
834
  }
835
+ function archiveUrlOfBind(bindSuffix) {
836
+ for (const pair of bindSuffix.split("&")) {
837
+ const eq = pair.indexOf("=");
838
+ if (eq < 0) continue;
839
+ if (pair.slice(0, eq) !== "__archiveUrl") continue;
840
+ const enc = pair.slice(eq + 1);
841
+ try {
842
+ return decodeURIComponent(enc);
843
+ } catch {
844
+ return void 0;
845
+ }
846
+ }
847
+ return void 0;
848
+ }
824
849
  function registryUrlOf(name, version) {
825
850
  const tail = name.startsWith("@") ? name.split("/").slice(1).join("/") : name;
826
851
  return `https://registry.npmjs.org/${name}/-/${tail}-${version}.tgz`;
@@ -977,6 +1002,9 @@ function canonicalSourceStringOf(resolution) {
977
1002
  return `git\0${resolution.url}\0${resolution.sha}`;
978
1003
  case "tarball": {
979
1004
  const host = hostOfTarballUrl(resolution.url);
1005
+ if (resolution.bind !== void 0) {
1006
+ return `tarball\0${host ?? resolution.url}\0bind=${resolution.bind}`;
1007
+ }
980
1008
  return host !== void 0 && REGISTRY_HOSTS.has(host) ? void 0 : `tarball\0${host ?? resolution.url}`;
981
1009
  }
982
1010
  case "directory":
@@ -1941,7 +1969,7 @@ function buildNodeModulesEntry(graph, node, nodeSide, config, emitDiagnostic = (
1941
1969
  }
1942
1970
  body.version = node.version;
1943
1971
  const tarball = graph.tarballOf(node.id);
1944
- const resolved = node.resolution ?? config.hooks?.recoverResolvedForNode?.(graph, node) ?? deriveResolvedFromCanonical(tarball?.resolution);
1972
+ const resolved = tarball?.nativeResolution ?? config.hooks?.recoverResolvedForNode?.(graph, node) ?? deriveResolvedFromCanonical(tarball?.resolution);
1945
1973
  if (resolved !== void 0) body.resolved = resolved;
1946
1974
  if (tarball?.integrity !== void 0) {
1947
1975
  const sri = emitSri(tarball.integrity);
@@ -2233,15 +2261,16 @@ function buildLegacyNodeEntry(ctx, node, parentInstallPrefix) {
2233
2261
  const entry = {};
2234
2262
  if (node.version !== void 0) entry.version = node.version;
2235
2263
  const tarball = ctx.graph.tarballOf(node.id);
2264
+ const native = tarball?.nativeResolution;
2236
2265
  const sourceResolved = sidecarResolvedFor(ctx, node) ?? deriveLegacyResolvedFromCanonical(tarball?.resolution);
2237
- if (node.resolution !== void 0) {
2238
- const looksLikeGit = /^git[+@]/.test(node.resolution);
2266
+ if (native !== void 0) {
2267
+ const looksLikeGit = /^git[+@]/.test(native);
2239
2268
  if (looksLikeGit) {
2240
- entry.version = node.resolution;
2269
+ entry.version = native;
2241
2270
  const fromSpec = synthesizeFromSpec(ctx, node);
2242
2271
  if (fromSpec !== void 0) entry.from = fromSpec;
2243
2272
  } else {
2244
- entry.resolved = node.resolution;
2273
+ entry.resolved = native;
2245
2274
  }
2246
2275
  } else if (sourceResolved !== void 0) {
2247
2276
  const looksLikeGit = /^git[+@]/.test(sourceResolved);
@@ -1,5 +1,5 @@
1
- import { G as Graph, D as Diagnostic } from '../graph-B_G4OKqF.js';
2
- import { N as NpmFamilyEnrichOptions, a as NpmFamilyOptimizeOptions, b as NpmFamilyParseOptions, c as NpmFamilyStringifyOptions } from '../_npm-flat-types-C6TSaidU.js';
1
+ import { G as Graph, D as Diagnostic } from '../graph-CPo-SvS2.js';
2
+ import { N as NpmFamilyEnrichOptions, a as NpmFamilyOptimizeOptions, b as NpmFamilyParseOptions, c as NpmFamilyStringifyOptions } from '../_npm-flat-types-CR16JZFS.js';
3
3
 
4
4
  interface Npm3ParseOptions extends NpmFamilyParseOptions {
5
5
  }
@@ -791,8 +791,19 @@ function parse(raw, options = {}) {
791
791
  }
792
792
  function parseInner(protocol, spec, raw, options) {
793
793
  switch (protocol) {
794
- case "npm":
795
- return { type: "tarball", url: deriveRegistryUrl(options.name, spec) };
794
+ case "npm": {
795
+ const bindIdx = spec.indexOf("::");
796
+ const version = bindIdx >= 0 ? spec.slice(0, bindIdx) : spec;
797
+ const bindSuffix = bindIdx >= 0 ? spec.slice(bindIdx + 2) : void 0;
798
+ if (bindSuffix !== void 0) {
799
+ const archiveUrl = archiveUrlOfBind(bindSuffix);
800
+ if (archiveUrl !== void 0) {
801
+ return { type: "tarball", url: archiveUrl };
802
+ }
803
+ return { type: "tarball", url: deriveRegistryUrl(options.name, version), bind: bindSuffix };
804
+ }
805
+ return { type: "tarball", url: deriveRegistryUrl(options.name, version) };
806
+ }
796
807
  case "portal":
797
808
  return { type: "directory", path: normaliseDirectoryPath(spec) };
798
809
  case "file":
@@ -821,6 +832,20 @@ function deriveRegistryUrl(name, spec) {
821
832
  function looksLikeNpmName(s) {
822
833
  return /^(?:@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*$/i.test(s);
823
834
  }
835
+ function archiveUrlOfBind(bindSuffix) {
836
+ for (const pair of bindSuffix.split("&")) {
837
+ const eq = pair.indexOf("=");
838
+ if (eq < 0) continue;
839
+ if (pair.slice(0, eq) !== "__archiveUrl") continue;
840
+ const enc = pair.slice(eq + 1);
841
+ try {
842
+ return decodeURIComponent(enc);
843
+ } catch {
844
+ return void 0;
845
+ }
846
+ }
847
+ return void 0;
848
+ }
824
849
  function registryUrlOf(name, version) {
825
850
  const tail = name.startsWith("@") ? name.split("/").slice(1).join("/") : name;
826
851
  return `https://registry.npmjs.org/${name}/-/${tail}-${version}.tgz`;
@@ -977,6 +1002,9 @@ function canonicalSourceStringOf(resolution) {
977
1002
  return `git\0${resolution.url}\0${resolution.sha}`;
978
1003
  case "tarball": {
979
1004
  const host = hostOfTarballUrl(resolution.url);
1005
+ if (resolution.bind !== void 0) {
1006
+ return `tarball\0${host ?? resolution.url}\0bind=${resolution.bind}`;
1007
+ }
980
1008
  return host !== void 0 && REGISTRY_HOSTS.has(host) ? void 0 : `tarball\0${host ?? resolution.url}`;
981
1009
  }
982
1010
  case "directory":
@@ -1941,7 +1969,7 @@ function buildNodeModulesEntry(graph, node, nodeSide, config, emitDiagnostic = (
1941
1969
  }
1942
1970
  body.version = node.version;
1943
1971
  const tarball = graph.tarballOf(node.id);
1944
- const resolved = node.resolution ?? config.hooks?.recoverResolvedForNode?.(graph, node) ?? deriveResolvedFromCanonical(tarball?.resolution);
1972
+ const resolved = tarball?.nativeResolution ?? config.hooks?.recoverResolvedForNode?.(graph, node) ?? deriveResolvedFromCanonical(tarball?.resolution);
1945
1973
  if (resolved !== void 0) body.resolved = resolved;
1946
1974
  if (tarball?.integrity !== void 0) {
1947
1975
  const sri = emitSri(tarball.integrity);
@@ -1,4 +1,4 @@
1
- import { D as Diagnostic, G as Graph } from '../graph-B_G4OKqF.js';
1
+ import { D as Diagnostic, G as Graph } from '../graph-CPo-SvS2.js';
2
2
 
3
3
  interface PnpmV5ParseOptions {
4
4
  }