@teambit/dependency-resolver 1.0.1096 → 1.0.1098

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 (32) hide show
  1. package/dist/dependency-installer.d.ts +67 -2
  2. package/dist/dependency-installer.js +155 -1
  3. package/dist/dependency-installer.js.map +1 -1
  4. package/dist/dependency-linker.d.ts +23 -0
  5. package/dist/dependency-linker.js +82 -4
  6. package/dist/dependency-linker.js.map +1 -1
  7. package/dist/dependency-resolver-workspace-config.d.ts +5 -1
  8. package/dist/dependency-resolver-workspace-config.js.map +1 -1
  9. package/dist/dependency-resolver.main.runtime.d.ts +34 -0
  10. package/dist/dependency-resolver.main.runtime.js +80 -1
  11. package/dist/dependency-resolver.main.runtime.js.map +1 -1
  12. package/dist/exceptions/index.d.ts +1 -0
  13. package/dist/exceptions/index.js +13 -0
  14. package/dist/exceptions/index.js.map +1 -1
  15. package/dist/exceptions/self-hosted-virtual-store-transition.d.ts +16 -0
  16. package/dist/exceptions/self-hosted-virtual-store-transition.js +36 -0
  17. package/dist/exceptions/self-hosted-virtual-store-transition.js.map +1 -0
  18. package/dist/hoisted-resolution-bridge.d.ts +78 -0
  19. package/dist/hoisted-resolution-bridge.js +348 -0
  20. package/dist/hoisted-resolution-bridge.js.map +1 -0
  21. package/dist/hoisted-resolution-bridge.spec.d.ts +1 -0
  22. package/dist/hoisted-resolution-bridge.spec.js +233 -0
  23. package/dist/hoisted-resolution-bridge.spec.js.map +1 -0
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +37 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/package-manager.d.ts +39 -0
  28. package/dist/package-manager.js.map +1 -1
  29. package/dist/{preview-1785958716068.js → preview-1786365057144.js} +2 -2
  30. package/exceptions/index.ts +1 -0
  31. package/exceptions/self-hosted-virtual-store-transition.ts +26 -0
  32. package/package.json +28 -27
@@ -5,3 +5,4 @@ export { MainAspectNotLinkable } from './main-aspect-not-linkable';
5
5
  export { CoreAspectLinkError } from './core-aspect-link-error';
6
6
  export { NonAspectCorePackageLinkError } from './non-aspect-core-package-link-error';
7
7
  export { InvalidVersionWithPrefix } from './invalid-version-with-prefix';
8
+ export { SelfHostedVirtualStoreTransition } from './self-hosted-virtual-store-transition';
@@ -45,6 +45,12 @@ Object.defineProperty(exports, "RootDirNotDefined", {
45
45
  return _rootDirNotDefined().RootDirNotDefined;
46
46
  }
47
47
  });
48
+ Object.defineProperty(exports, "SelfHostedVirtualStoreTransition", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _selfHostedVirtualStoreTransition().SelfHostedVirtualStoreTransition;
52
+ }
53
+ });
48
54
  function _packageManagerNotFound() {
49
55
  const data = require("./package-manager-not-found");
50
56
  _packageManagerNotFound = function () {
@@ -94,5 +100,12 @@ function _invalidVersionWithPrefix() {
94
100
  };
95
101
  return data;
96
102
  }
103
+ function _selfHostedVirtualStoreTransition() {
104
+ const data = require("./self-hosted-virtual-store-transition");
105
+ _selfHostedVirtualStoreTransition = function () {
106
+ return data;
107
+ };
108
+ return data;
109
+ }
97
110
 
98
111
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_packageManagerNotFound","data","require","_rootDirNotDefined","_mainAspectNotInstallable","_mainAspectNotLinkable","_coreAspectLinkError","_nonAspectCorePackageLinkError","_invalidVersionWithPrefix"],"sources":["index.ts"],"sourcesContent":["export { PackageManagerNotFound } from './package-manager-not-found';\nexport { RootDirNotDefined } from './root-dir-not-defined';\nexport { MainAspectNotInstallable } from './main-aspect-not-installable';\nexport { MainAspectNotLinkable } from './main-aspect-not-linkable';\nexport { CoreAspectLinkError } from './core-aspect-link-error';\nexport { NonAspectCorePackageLinkError } from './non-aspect-core-package-link-error';\nexport { InvalidVersionWithPrefix } from './invalid-version-with-prefix';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAAA,wBAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,uBAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAE,mBAAA;EAAA,MAAAF,IAAA,GAAAC,OAAA;EAAAC,kBAAA,YAAAA,CAAA;IAAA,OAAAF,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAG,0BAAA;EAAA,MAAAH,IAAA,GAAAC,OAAA;EAAAE,yBAAA,YAAAA,CAAA;IAAA,OAAAH,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAI,uBAAA;EAAA,MAAAJ,IAAA,GAAAC,OAAA;EAAAG,sBAAA,YAAAA,CAAA;IAAA,OAAAJ,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAK,qBAAA;EAAA,MAAAL,IAAA,GAAAC,OAAA;EAAAI,oBAAA,YAAAA,CAAA;IAAA,OAAAL,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAM,+BAAA;EAAA,MAAAN,IAAA,GAAAC,OAAA;EAAAK,8BAAA,YAAAA,CAAA;IAAA,OAAAN,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAO,0BAAA;EAAA,MAAAP,IAAA,GAAAC,OAAA;EAAAM,yBAAA,YAAAA,CAAA;IAAA,OAAAP,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"names":["_packageManagerNotFound","data","require","_rootDirNotDefined","_mainAspectNotInstallable","_mainAspectNotLinkable","_coreAspectLinkError","_nonAspectCorePackageLinkError","_invalidVersionWithPrefix","_selfHostedVirtualStoreTransition"],"sources":["index.ts"],"sourcesContent":["export { PackageManagerNotFound } from './package-manager-not-found';\nexport { RootDirNotDefined } from './root-dir-not-defined';\nexport { MainAspectNotInstallable } from './main-aspect-not-installable';\nexport { MainAspectNotLinkable } from './main-aspect-not-linkable';\nexport { CoreAspectLinkError } from './core-aspect-link-error';\nexport { NonAspectCorePackageLinkError } from './non-aspect-core-package-link-error';\nexport { InvalidVersionWithPrefix } from './invalid-version-with-prefix';\nexport { SelfHostedVirtualStoreTransition } from './self-hosted-virtual-store-transition';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAAA,wBAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,uBAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAE,mBAAA;EAAA,MAAAF,IAAA,GAAAC,OAAA;EAAAC,kBAAA,YAAAA,CAAA;IAAA,OAAAF,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAG,0BAAA;EAAA,MAAAH,IAAA,GAAAC,OAAA;EAAAE,yBAAA,YAAAA,CAAA;IAAA,OAAAH,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAI,uBAAA;EAAA,MAAAJ,IAAA,GAAAC,OAAA;EAAAG,sBAAA,YAAAA,CAAA;IAAA,OAAAJ,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAK,qBAAA;EAAA,MAAAL,IAAA,GAAAC,OAAA;EAAAI,oBAAA,YAAAA,CAAA;IAAA,OAAAL,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAM,+BAAA;EAAA,MAAAN,IAAA,GAAAC,OAAA;EAAAK,8BAAA,YAAAA,CAAA;IAAA,OAAAN,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAO,0BAAA;EAAA,MAAAP,IAAA,GAAAC,OAAA;EAAAM,yBAAA,YAAAA,CAAA;IAAA,OAAAP,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAQ,kCAAA;EAAA,MAAAR,IAAA,GAAAC,OAAA;EAAAO,iCAAA,YAAAA,CAAA;IAAA,OAAAR,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA","ignoreList":[]}
@@ -0,0 +1,16 @@
1
+ import { BitError } from '@teambit/bit-error';
2
+ /**
3
+ * Thrown before an install that would switch this workspace between the project-local virtual
4
+ * store (`node_modules/.pnpm`) and pnpm's global virtual store while the running bit itself is
5
+ * installed inside this workspace's `node_modules`.
6
+ *
7
+ * A layout switch rebuilds the workspace's injected component packages from source, which
8
+ * discards their compiled `dist` until the end-of-install compile restores it. A bit that runs
9
+ * from those very packages loses its own code mid-install and crashes before it can recompile,
10
+ * leaving `node_modules` unusable. Steady-state installs are safe in both layouts - they
11
+ * preserve the top-level package directories - so only the one-time transition has to be driven
12
+ * by a bit that lives outside this workspace.
13
+ */
14
+ export declare class SelfHostedVirtualStoreTransition extends BitError {
15
+ constructor(workspacePath: string, enablingGlobalVirtualStore: boolean);
16
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SelfHostedVirtualStoreTransition = void 0;
7
+ function _bitError() {
8
+ const data = require("@teambit/bit-error");
9
+ _bitError = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ /**
15
+ * Thrown before an install that would switch this workspace between the project-local virtual
16
+ * store (`node_modules/.pnpm`) and pnpm's global virtual store while the running bit itself is
17
+ * installed inside this workspace's `node_modules`.
18
+ *
19
+ * A layout switch rebuilds the workspace's injected component packages from source, which
20
+ * discards their compiled `dist` until the end-of-install compile restores it. A bit that runs
21
+ * from those very packages loses its own code mid-install and crashes before it can recompile,
22
+ * leaving `node_modules` unusable. Steady-state installs are safe in both layouts - they
23
+ * preserve the top-level package directories - so only the one-time transition has to be driven
24
+ * by a bit that lives outside this workspace.
25
+ */
26
+ class SelfHostedVirtualStoreTransition extends _bitError().BitError {
27
+ constructor(workspacePath, enablingGlobalVirtualStore) {
28
+ const direction = enablingGlobalVirtualStore ? 'from the project-local virtual store to the global virtual store' : 'from the global virtual store back to the project-local virtual store';
29
+ super(`this install would switch "${workspacePath}" ${direction}, but the running bit is itself installed inside this workspace's node_modules.
30
+ The switch rebuilds this workspace's component packages from source, which would delete the running bit's compiled code mid-install and leave node_modules broken.
31
+ Run this one install with a bit installation that lives outside the workspace (e.g. a bvm-installed bit). Subsequent installs from within the workspace are safe in either layout.`);
32
+ }
33
+ }
34
+ exports.SelfHostedVirtualStoreTransition = SelfHostedVirtualStoreTransition;
35
+
36
+ //# sourceMappingURL=self-hosted-virtual-store-transition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_bitError","data","require","SelfHostedVirtualStoreTransition","BitError","constructor","workspacePath","enablingGlobalVirtualStore","direction","exports"],"sources":["self-hosted-virtual-store-transition.ts"],"sourcesContent":["import { BitError } from '@teambit/bit-error';\n\n/**\n * Thrown before an install that would switch this workspace between the project-local virtual\n * store (`node_modules/.pnpm`) and pnpm's global virtual store while the running bit itself is\n * installed inside this workspace's `node_modules`.\n *\n * A layout switch rebuilds the workspace's injected component packages from source, which\n * discards their compiled `dist` until the end-of-install compile restores it. A bit that runs\n * from those very packages loses its own code mid-install and crashes before it can recompile,\n * leaving `node_modules` unusable. Steady-state installs are safe in both layouts - they\n * preserve the top-level package directories - so only the one-time transition has to be driven\n * by a bit that lives outside this workspace.\n */\nexport class SelfHostedVirtualStoreTransition extends BitError {\n constructor(workspacePath: string, enablingGlobalVirtualStore: boolean) {\n const direction = enablingGlobalVirtualStore\n ? 'from the project-local virtual store to the global virtual store'\n : 'from the global virtual store back to the project-local virtual store';\n super(\n `this install would switch \"${workspacePath}\" ${direction}, but the running bit is itself installed inside this workspace's node_modules.\nThe switch rebuilds this workspace's component packages from source, which would delete the running bit's compiled code mid-install and leave node_modules broken.\nRun this one install with a bit installation that lives outside the workspace (e.g. a bvm-installed bit). Subsequent installs from within the workspace are safe in either layout.`\n );\n }\n}\n"],"mappings":";;;;;;AAAA,SAAAA,UAAA;EAAA,MAAAC,IAAA,GAAAC,OAAA;EAAAF,SAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAME,gCAAgC,SAASC,oBAAQ,CAAC;EAC7DC,WAAWA,CAACC,aAAqB,EAAEC,0BAAmC,EAAE;IACtE,MAAMC,SAAS,GAAGD,0BAA0B,GACxC,kEAAkE,GAClE,uEAAuE;IAC3E,KAAK,CACH,8BAA8BD,aAAa,KAAKE,SAAS;AAC/D;AACA,mLACI,CAAC;EACH;AACF;AAACC,OAAA,CAAAN,gCAAA,GAAAA,gCAAA","ignoreList":[]}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The `virtualStoreDir` pnpm recorded in a `node_modules/.modules.yaml`, or undefined when the
3
+ * manifest records none.
4
+ *
5
+ * Current pnpm writes this manifest as JSON (YAML 1.2 being a superset of it), so the structured
6
+ * read is a plain `JSON.parse` - no dependency, and correct for every value the writer can emit.
7
+ * Older versions wrote block YAML, which the line match handles. A full YAML parser is
8
+ * deliberately avoided: this runs in `bootstrap`, before any command does its work, and parsing
9
+ * the whole manifest costs ~40ms on this repo's own 415KB one against ~0.2ms for the line match
10
+ * (the manifest carries the entire hoisted alias map, so it grows with the dependency graph).
11
+ * Taking a package dependency here would also make the earliest, least recoverable step of CLI
12
+ * startup depend on module resolution - the very thing this module exists to repair.
13
+ */
14
+ export declare function parseRecordedVirtualStoreDir(modulesManifest: string): string | undefined;
15
+ /**
16
+ * Whether the workspace's last install used pnpm's global virtual store, judged by the
17
+ * `virtualStoreDir` the engine records in `node_modules/.modules.yaml`: `.pnpm` (or any path
18
+ * inside the workspace) means project-local; a path escaping the workspace means the global
19
+ * store. No manifest or no recorded value reads as project-local - a workspace that never
20
+ * installed under the global store has nothing to bridge.
21
+ */
22
+ /**
23
+ * Platform-safe path containment: `path.relative` is case-insensitive on Windows (where the
24
+ * filesystem is) and case-sensitive on posix, which a bare `startsWith` prefix check gets wrong
25
+ * for drive-letter casing differences between realpath results and given spellings. Equality
26
+ * counts as inside - every caller asks "does this path escape that root", and a path equal to
27
+ * the root has not escaped it.
28
+ */
29
+ export declare function isPathInsideOrEqual(child: string, parent: string): boolean;
30
+ /**
31
+ * Whether two spellings name the same directory. `path.relative` normalizes both sides first, so a
32
+ * trailing separator, a redundant `.`, a relative spelling and - on Windows - a difference in case
33
+ * all compare equal, which string equality would miss. Anything written by hand into `NODE_PATH`
34
+ * arrives in whatever spelling its author chose.
35
+ */
36
+ export declare function isSamePath(one: string, other: string): boolean;
37
+ export declare function isGlobalVirtualStoreLayout(workspaceRoot: string): boolean;
38
+ /**
39
+ * The root of the installation this module runs from: the nearest ancestor that owns a
40
+ * `node_modules/.modules.yaml`. For a bvm-installed bit that is the bvm version directory; for a
41
+ * workspace-provided bit it is the workspace.
42
+ *
43
+ * Two candidate starting points, because Node realpaths module filenames: under the global
44
+ * virtual store this module's `__dirname` is the *store slot* - a dead end with no
45
+ * `.modules.yaml` and no physical path back to the installation. The entry script's
46
+ * `process.argv[1]` is the path *as invoked*, unresolved through symlinks, so for a store-linked
47
+ * installation it still sits inside the installation tree. `__dirname` remains the fallback for
48
+ * setups that invoke bit through a resolved path (and for the copy-shaped installations where it
49
+ * works fine). `undefined` when neither leads to an installation (e.g. running from source).
50
+ */
51
+ export declare function selfInstallationRoot(): string | undefined;
52
+ /**
53
+ * Bridge the *running installation's* own directories when that installation is itself linked to
54
+ * the global virtual store - its packages then live in store slots and their phantom requires
55
+ * need the installation's private hoist exactly like a workspace's do. Judged by the same
56
+ * `.modules.yaml` record, read at the installation root. A conventional project-local
57
+ * installation (bvm's default) reads project-local and stays unbridged, so nothing changes for
58
+ * it or for the processes it spawns.
59
+ */
60
+ export declare function ensureSelfInstallationBridge(): void;
61
+ /**
62
+ * The directories a package resolved from `<root>` used to reach by walking up, in the order the
63
+ * walk reached them: the hoisted `node_modules/.pnpm/node_modules` first, then the root's own
64
+ * `node_modules`. Both are lost under the global virtual store, and they hold disjoint sets -
65
+ * pnpm hoists only *non-direct* dependencies, so a direct dependency of the root exists solely in
66
+ * the second. Missing directories are dropped; a root with neither yields an empty list.
67
+ *
68
+ * Shared with the type-resolution side of the bridge, which has to reach the same two directories
69
+ * through the mechanism TypeScript offers instead of `NODE_PATH`.
70
+ */
71
+ export declare function hoistedResolutionDirs(root: string): string[];
72
+ /**
73
+ * Put the given root's {@link hoistedResolutionDirs} on the resolution path of this process and
74
+ * its children. Idempotent; a no-op when neither directory exists. Callers decide *whether* the
75
+ * root needs the bridge ({@link isGlobalVirtualStoreLayout} for the pre-aspect gate, the
76
+ * dependency-resolver's own config after an install).
77
+ */
78
+ export declare function ensureHoistedDependencyResolution(workspaceRoot: string): void;
@@ -0,0 +1,348 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ensureHoistedDependencyResolution = ensureHoistedDependencyResolution;
7
+ exports.ensureSelfInstallationBridge = ensureSelfInstallationBridge;
8
+ exports.hoistedResolutionDirs = hoistedResolutionDirs;
9
+ exports.isGlobalVirtualStoreLayout = isGlobalVirtualStoreLayout;
10
+ exports.isPathInsideOrEqual = isPathInsideOrEqual;
11
+ exports.isSamePath = isSamePath;
12
+ exports.parseRecordedVirtualStoreDir = parseRecordedVirtualStoreDir;
13
+ exports.selfInstallationRoot = selfInstallationRoot;
14
+ function fs() {
15
+ const data = _interopRequireWildcard(require("fs"));
16
+ fs = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function path() {
22
+ const data = _interopRequireWildcard(require("path"));
23
+ path = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
28
+ function _url() {
29
+ const data = require("url");
30
+ _url = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
36
+ /**
37
+ * Make a workspace's privately hoisted dependencies resolvable from pnpm's global virtual store.
38
+ *
39
+ * Under the project-local virtual store, a package in `node_modules/.pnpm` resolves anything it
40
+ * requires without declaring it by walking *up* into the workspace - the hoisted
41
+ * `node_modules/.pnpm/node_modules` first, then the workspace root. Under the global virtual
42
+ * store the package lives in a store shared with every other project on the machine, with no
43
+ * workspace above it, so every such require fails.
44
+ *
45
+ * This covers phantom dependencies generally, not one class of them. Bit's core aspects are the
46
+ * case that motivated it - `@teambit/*` is required by every published env and aspect without
47
+ * being declared, because it has to be the single copy from the running installation - but any
48
+ * under-declared package in the graph resolves the same way, which is why whole directories go on
49
+ * the path rather than a hand-picked list.
50
+ *
51
+ * Both directories the walk reached are restored ({@link hoistedResolutionDirs}), because they
52
+ * hold disjoint sets: pnpm hoists only *non-direct* dependencies, so a direct dependency of the
53
+ * root - the workspace's own `mocha`, `react`, `@types/react` - is reachable through the root's
54
+ * `node_modules` and nowhere else.
55
+ *
56
+ * pnpm's answer for this layout is `NODE_PATH` pointing at the hoisted directory, which stays
57
+ * project-local under the global virtual store. pnpm sets it in the command shims it writes, but
58
+ * bit runs from bvm rather than through a shim and loads aspects in its own process, so it has to
59
+ * do this itself. `NODE_PATH` only covers CommonJS; an ESM loader (adapted from pnpm's
60
+ * `@pnpm/plugin-esm-node-path`, MIT) handles the ESM side, registered both in-process via
61
+ * `module.register` and for child processes via a `NODE_OPTIONS --import` flag. TypeScript reads
62
+ * neither, so the type-resolution half lives in `@teambit/typescript` and builds its `paths` from
63
+ * the same directories.
64
+ *
65
+ * Two call sites, and both matter:
66
+ * - `bootstrap()` in `@teambit/bit`, before any aspect loads, gated on the layout the last
67
+ * install recorded ({@link isGlobalVirtualStoreLayout}). It deep-requires this module's dist
68
+ * file directly so CLI startup never pays for the dependency-resolver barrel.
69
+ * - the install flow, right after the package manager finishes: the first install that switches
70
+ * a workspace onto the global virtual store runs with `bootstrap`'s gate still reflecting the
71
+ * old layout, yet the same process goes on to reload envs and compile from store slots. The
72
+ * installer re-applies the bridge the moment the target layout is known.
73
+ *
74
+ * Everything here is idempotent, so calling it again is always safe: `NODE_PATH` is rebuilt to the
75
+ * same value, the ESM loader re-registers only when the ordered entry list changes, and the
76
+ * process's own `NODE_OPTIONS` flag is replaced rather than stacked.
77
+ *
78
+ * One asymmetry to know about when reading the ESM half. Node runs the *last* registered loader
79
+ * first and it delegates through `defaultResolve` before its own fallback, so an earlier
80
+ * registration resolves anything it can before a later one is consulted. A re-registration
81
+ * therefore corrects what child processes inherit - the `--import` flag carries the current list -
82
+ * while in-process the earlier registration keeps its precedence for the entries it already had.
83
+ * That only diverges from CommonJS for a specifier resolvable from more than one entry across two
84
+ * registrations with different orders, which needs a process bridging two roots in alternating
85
+ * order; the CommonJS half, rebuilt on every call, is always right.
86
+ */
87
+
88
+ /**
89
+ * Source of the registered ESM loader, with the resolution entries injected at registration time.
90
+ * The entries cannot be read from `NODE_PATH` inside the loader: on modern Node the hooks run on
91
+ * a separate thread whose `process.env` is a snapshot taken at registration, so late additions -
92
+ * an install switching the workspace onto the global virtual store mid-process - would never be
93
+ * seen. Injecting the list makes each registration self-contained, at the cost of needing a new
94
+ * registration whenever the list changes - by order as much as by membership, since the loader
95
+ * searches these entries in the order given.
96
+ */
97
+ const esmNodePathLoaderSource = dirs => `
98
+ import { createRequire } from 'node:module'
99
+ import { pathToFileURL } from 'node:url'
100
+
101
+ const extraNodePaths = ${JSON.stringify(dirs)}
102
+
103
+ export async function resolve (specifier, context, defaultResolve) {
104
+ try {
105
+ return await defaultResolve(specifier, context, defaultResolve)
106
+ } catch (originalError) {
107
+ // Only bare specifiers can come from the hoisted directory; the rest are already anchored.
108
+ // Windows absolute (drive-letter) and UNC paths are path specifiers too.
109
+ if (
110
+ specifier.startsWith('.') ||
111
+ specifier.startsWith('/') ||
112
+ specifier.startsWith('node:') ||
113
+ specifier.startsWith('\\\\') ||
114
+ /^[a-zA-Z]:[\\\\/]/.test(specifier)
115
+ ) {
116
+ throw originalError
117
+ }
118
+ // createRequire anchored inside the entry searches the entry itself: Node skips appending
119
+ // /node_modules to a directory already named node_modules, and the parent step re-yields it
120
+ // (.pnpm -> .pnpm/node_modules). Exact for the entries this loader exists for, both of which
121
+ // are named node_modules; an entry not named node_modules would be searched one level deeper
122
+ // than CommonJS NODE_PATH does - those entries are already covered by the CommonJS side and
123
+ // are not ours to fix.
124
+ for (const basePath of extraNodePaths) {
125
+ try {
126
+ const require = createRequire(pathToFileURL(basePath + '/').href)
127
+ return { url: pathToFileURL(require.resolve(specifier)).href, shortCircuit: true }
128
+ } catch {}
129
+ }
130
+ throw originalError
131
+ }
132
+ }
133
+ `;
134
+ let lastRegisteredEntries;
135
+ let lastImportFlag;
136
+
137
+ /**
138
+ * The `virtualStoreDir` pnpm recorded in a `node_modules/.modules.yaml`, or undefined when the
139
+ * manifest records none.
140
+ *
141
+ * Current pnpm writes this manifest as JSON (YAML 1.2 being a superset of it), so the structured
142
+ * read is a plain `JSON.parse` - no dependency, and correct for every value the writer can emit.
143
+ * Older versions wrote block YAML, which the line match handles. A full YAML parser is
144
+ * deliberately avoided: this runs in `bootstrap`, before any command does its work, and parsing
145
+ * the whole manifest costs ~40ms on this repo's own 415KB one against ~0.2ms for the line match
146
+ * (the manifest carries the entire hoisted alias map, so it grows with the dependency graph).
147
+ * Taking a package dependency here would also make the earliest, least recoverable step of CLI
148
+ * startup depend on module resolution - the very thing this module exists to repair.
149
+ */
150
+ function parseRecordedVirtualStoreDir(modulesManifest) {
151
+ try {
152
+ const parsed = JSON.parse(modulesManifest);
153
+ return typeof parsed.virtualStoreDir === 'string' ? parsed.virtualStoreDir : undefined;
154
+ } catch {
155
+ // not JSON - a block-YAML manifest from an older pnpm
156
+ }
157
+ return modulesManifest.match(/^\s*"?virtualStoreDir"?:\s*"?([^"\n]+?)"?,?\s*$/m)?.[1];
158
+ }
159
+
160
+ /**
161
+ * Whether the workspace's last install used pnpm's global virtual store, judged by the
162
+ * `virtualStoreDir` the engine records in `node_modules/.modules.yaml`: `.pnpm` (or any path
163
+ * inside the workspace) means project-local; a path escaping the workspace means the global
164
+ * store. No manifest or no recorded value reads as project-local - a workspace that never
165
+ * installed under the global store has nothing to bridge.
166
+ */
167
+ /**
168
+ * Platform-safe path containment: `path.relative` is case-insensitive on Windows (where the
169
+ * filesystem is) and case-sensitive on posix, which a bare `startsWith` prefix check gets wrong
170
+ * for drive-letter casing differences between realpath results and given spellings. Equality
171
+ * counts as inside - every caller asks "does this path escape that root", and a path equal to
172
+ * the root has not escaped it.
173
+ */
174
+ function isPathInsideOrEqual(child, parent) {
175
+ const rel = path().relative(parent, child);
176
+ // component-aware traversal check: a child legitimately named `..foo` also starts with `..`
177
+ return !path().isAbsolute(rel) && rel !== '..' && !rel.startsWith(`..${path().sep}`);
178
+ }
179
+
180
+ /**
181
+ * Whether two spellings name the same directory. `path.relative` normalizes both sides first, so a
182
+ * trailing separator, a redundant `.`, a relative spelling and - on Windows - a difference in case
183
+ * all compare equal, which string equality would miss. Anything written by hand into `NODE_PATH`
184
+ * arrives in whatever spelling its author chose.
185
+ */
186
+ function isSamePath(one, other) {
187
+ return path().relative(one, other) === '';
188
+ }
189
+ function isGlobalVirtualStoreLayout(workspaceRoot) {
190
+ let modulesManifest;
191
+ try {
192
+ modulesManifest = fs().readFileSync(path().join(workspaceRoot, 'node_modules', '.modules.yaml'), 'utf8');
193
+ } catch {
194
+ return false;
195
+ }
196
+ const virtualStoreDir = parseRecordedVirtualStoreDir(modulesManifest);
197
+ if (!virtualStoreDir) return false;
198
+ let workspaceRealpath = workspaceRoot;
199
+ try {
200
+ workspaceRealpath = fs().realpathSync(workspaceRoot);
201
+ } catch {
202
+ // fall back to the given spelling
203
+ }
204
+ const resolved = path().resolve(workspaceRealpath, 'node_modules', virtualStoreDir);
205
+ let storeRealpath = resolved;
206
+ try {
207
+ storeRealpath = fs().realpathSync(resolved);
208
+ } catch {
209
+ // dangling recorded dir - judge by the lexical resolution
210
+ }
211
+ return !isPathInsideOrEqual(storeRealpath, workspaceRealpath);
212
+ }
213
+
214
+ /**
215
+ * The root of the installation this module runs from: the nearest ancestor that owns a
216
+ * `node_modules/.modules.yaml`. For a bvm-installed bit that is the bvm version directory; for a
217
+ * workspace-provided bit it is the workspace.
218
+ *
219
+ * Two candidate starting points, because Node realpaths module filenames: under the global
220
+ * virtual store this module's `__dirname` is the *store slot* - a dead end with no
221
+ * `.modules.yaml` and no physical path back to the installation. The entry script's
222
+ * `process.argv[1]` is the path *as invoked*, unresolved through symlinks, so for a store-linked
223
+ * installation it still sits inside the installation tree. `__dirname` remains the fallback for
224
+ * setups that invoke bit through a resolved path (and for the copy-shaped installations where it
225
+ * works fine). `undefined` when neither leads to an installation (e.g. running from source).
226
+ */
227
+ function selfInstallationRoot() {
228
+ const candidates = [process.argv[1], __dirname].filter(Boolean);
229
+ for (const candidate of candidates) {
230
+ let dir = path().dirname(path().resolve(candidate));
231
+ for (;;) {
232
+ if (fs().existsSync(path().join(dir, 'node_modules', '.modules.yaml'))) return dir;
233
+ const parent = path().dirname(dir);
234
+ if (parent === dir) break;
235
+ dir = parent;
236
+ }
237
+ }
238
+ return undefined;
239
+ }
240
+
241
+ /**
242
+ * Bridge the *running installation's* own directories when that installation is itself linked to
243
+ * the global virtual store - its packages then live in store slots and their phantom requires
244
+ * need the installation's private hoist exactly like a workspace's do. Judged by the same
245
+ * `.modules.yaml` record, read at the installation root. A conventional project-local
246
+ * installation (bvm's default) reads project-local and stays unbridged, so nothing changes for
247
+ * it or for the processes it spawns.
248
+ */
249
+ function ensureSelfInstallationBridge() {
250
+ const installationRoot = selfInstallationRoot();
251
+ if (!installationRoot) return;
252
+ if (!isGlobalVirtualStoreLayout(installationRoot)) return;
253
+ ensureHoistedDependencyResolution(installationRoot);
254
+ }
255
+
256
+ /**
257
+ * The directories a package resolved from `<root>` used to reach by walking up, in the order the
258
+ * walk reached them: the hoisted `node_modules/.pnpm/node_modules` first, then the root's own
259
+ * `node_modules`. Both are lost under the global virtual store, and they hold disjoint sets -
260
+ * pnpm hoists only *non-direct* dependencies, so a direct dependency of the root exists solely in
261
+ * the second. Missing directories are dropped; a root with neither yields an empty list.
262
+ *
263
+ * Shared with the type-resolution side of the bridge, which has to reach the same two directories
264
+ * through the mechanism TypeScript offers instead of `NODE_PATH`.
265
+ */
266
+ function hoistedResolutionDirs(root) {
267
+ return [path().join(root, 'node_modules', '.pnpm', 'node_modules'), path().join(root, 'node_modules')].filter(dir => fs().existsSync(dir));
268
+ }
269
+
270
+ /**
271
+ * Put the given root's {@link hoistedResolutionDirs} on the resolution path of this process and
272
+ * its children. Idempotent; a no-op when neither directory exists. Callers decide *whether* the
273
+ * root needs the bridge ({@link isGlobalVirtualStoreLayout} for the pre-aspect gate, the
274
+ * dependency-resolver's own config after an install).
275
+ */
276
+ function ensureHoistedDependencyResolution(workspaceRoot) {
277
+ const dirs = hoistedResolutionDirs(workspaceRoot);
278
+ if (!dirs.length) return;
279
+ const existing = process.env.NODE_PATH;
280
+ const untouched = (existing?.split(path().delimiter).filter(Boolean) ?? []).filter(
281
+ // by path rather than by spelling, so an entry naming a directory this bridge owns is replaced
282
+ // by the canonical one instead of being kept alongside it as a redundant search base
283
+ dir => !dirs.some(owned => isSamePath(dir, owned)));
284
+ // rebuilt rather than prepended, because order is resolution order and an entry already present
285
+ // is not necessarily in front of the one it has to beat: a bit that bridged the hoisted
286
+ // directory alone leaves it in `NODE_PATH` for its children, and adding the root's node_modules
287
+ // in front of it there would invert the walk the bridge exists to reproduce. Everything this
288
+ // bridge does not own keeps its relative order, behind what the walk reached first.
289
+ const next = [...dirs, ...untouched].join(path().delimiter);
290
+ if (next !== existing) {
291
+ process.env.NODE_PATH = next;
292
+ // `NODE_PATH` is read once when the module system initializes, so a later assignment only
293
+ // takes effect after re-deriving the global paths.
294
+ require('module')._initPaths();
295
+ }
296
+ registerEsmNodePathLoader();
297
+ }
298
+
299
+ /**
300
+ * The ESM half of {@link ensureHoistedDependencyResolution}.
301
+ *
302
+ * Node consults `NODE_PATH` only for CommonJS; ESM resolution ignores it entirely. Bit supports
303
+ * ESM components, so without this an ESM package in the store cannot reach the hoisted directory
304
+ * at all and the CommonJS half would only cover part of the problem.
305
+ *
306
+ * Registered two ways, because both matter:
307
+ * - `module.register` for bit's own process, which is where aspects and envs are loaded.
308
+ * - `NODE_OPTIONS`, so the processes bit spawns - env build steps, app servers, test workers -
309
+ * inherit it. They resolve their own dependencies and hit the same wall.
310
+ *
311
+ * The loader is inlined as a data URL rather than taken as a dependency so there is no file to
312
+ * ship and no install step to depend on. `module.register` needs Node 20.6, so this is skipped
313
+ * on older runtimes - the CommonJS half still applies there.
314
+ */
315
+ function registerEsmNodePathLoader() {
316
+ const nodeModule = require('module');
317
+ if (typeof nodeModule.register !== 'function') return;
318
+ // mirror the CommonJS side exactly: every current NODE_PATH entry participates, in its order
319
+ const dirs = (process.env.NODE_PATH || '').split(path().delimiter).filter(Boolean);
320
+ if (!dirs.length) return;
321
+ const entries = dirs.join(path().delimiter);
322
+ // ordered, not a set: the loader inlines the list, so a reordering leaves a registration whose
323
+ // precedence no longer matches the one CommonJS now uses
324
+ if (lastImportFlag && entries === lastRegisteredEntries) return;
325
+ const loaderUrl = `data:text/javascript,${encodeURIComponent(esmNodePathLoaderSource(dirs))}`;
326
+ const parentUrl = (0, _url().pathToFileURL)(path().join(process.cwd(), '/')).href;
327
+ try {
328
+ nodeModule.register(loaderUrl, parentUrl);
329
+ } catch {
330
+ // A runtime that rejects the loader must not take the whole CLI down with it - the CommonJS
331
+ // half of the workaround is unaffected, and only ESM packages relying on hoisting are lost.
332
+ return;
333
+ }
334
+ lastRegisteredEntries = entries;
335
+ const registration = `import{register}from'node:module';register(${JSON.stringify(loaderUrl)},${JSON.stringify(parentUrl)});`;
336
+ const importFlag = `--import=data:text/javascript,${encodeURIComponent(registration)}`;
337
+ // children get one flag carrying the full current set: replace our previous flag rather than
338
+ // stacking loaders, and match our own flag exactly - a user's `--require ts-node/register`
339
+ // in NODE_OPTIONS must not suppress the loader's propagation
340
+ if (lastImportFlag && process.env.NODE_OPTIONS?.includes(lastImportFlag)) {
341
+ process.env.NODE_OPTIONS = process.env.NODE_OPTIONS.replace(lastImportFlag, importFlag);
342
+ } else if (!process.env.NODE_OPTIONS?.includes(importFlag)) {
343
+ process.env.NODE_OPTIONS = process.env.NODE_OPTIONS ? `${process.env.NODE_OPTIONS} ${importFlag}` : importFlag;
344
+ }
345
+ lastImportFlag = importFlag;
346
+ }
347
+
348
+ //# sourceMappingURL=hoisted-resolution-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["fs","data","_interopRequireWildcard","require","path","_url","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","esmNodePathLoaderSource","dirs","JSON","stringify","lastRegisteredEntries","lastImportFlag","parseRecordedVirtualStoreDir","modulesManifest","parsed","parse","virtualStoreDir","undefined","match","isPathInsideOrEqual","child","parent","rel","relative","isAbsolute","startsWith","sep","isSamePath","one","other","isGlobalVirtualStoreLayout","workspaceRoot","readFileSync","join","workspaceRealpath","realpathSync","resolved","resolve","storeRealpath","selfInstallationRoot","candidates","process","argv","__dirname","filter","Boolean","candidate","dir","dirname","existsSync","ensureSelfInstallationBridge","installationRoot","ensureHoistedDependencyResolution","hoistedResolutionDirs","root","length","existing","env","NODE_PATH","untouched","split","delimiter","some","owned","next","_initPaths","registerEsmNodePathLoader","nodeModule","register","entries","loaderUrl","encodeURIComponent","parentUrl","pathToFileURL","cwd","href","registration","importFlag","NODE_OPTIONS","includes","replace"],"sources":["hoisted-resolution-bridge.ts"],"sourcesContent":["/**\n * Make a workspace's privately hoisted dependencies resolvable from pnpm's global virtual store.\n *\n * Under the project-local virtual store, a package in `node_modules/.pnpm` resolves anything it\n * requires without declaring it by walking *up* into the workspace - the hoisted\n * `node_modules/.pnpm/node_modules` first, then the workspace root. Under the global virtual\n * store the package lives in a store shared with every other project on the machine, with no\n * workspace above it, so every such require fails.\n *\n * This covers phantom dependencies generally, not one class of them. Bit's core aspects are the\n * case that motivated it - `@teambit/*` is required by every published env and aspect without\n * being declared, because it has to be the single copy from the running installation - but any\n * under-declared package in the graph resolves the same way, which is why whole directories go on\n * the path rather than a hand-picked list.\n *\n * Both directories the walk reached are restored ({@link hoistedResolutionDirs}), because they\n * hold disjoint sets: pnpm hoists only *non-direct* dependencies, so a direct dependency of the\n * root - the workspace's own `mocha`, `react`, `@types/react` - is reachable through the root's\n * `node_modules` and nowhere else.\n *\n * pnpm's answer for this layout is `NODE_PATH` pointing at the hoisted directory, which stays\n * project-local under the global virtual store. pnpm sets it in the command shims it writes, but\n * bit runs from bvm rather than through a shim and loads aspects in its own process, so it has to\n * do this itself. `NODE_PATH` only covers CommonJS; an ESM loader (adapted from pnpm's\n * `@pnpm/plugin-esm-node-path`, MIT) handles the ESM side, registered both in-process via\n * `module.register` and for child processes via a `NODE_OPTIONS --import` flag. TypeScript reads\n * neither, so the type-resolution half lives in `@teambit/typescript` and builds its `paths` from\n * the same directories.\n *\n * Two call sites, and both matter:\n * - `bootstrap()` in `@teambit/bit`, before any aspect loads, gated on the layout the last\n * install recorded ({@link isGlobalVirtualStoreLayout}). It deep-requires this module's dist\n * file directly so CLI startup never pays for the dependency-resolver barrel.\n * - the install flow, right after the package manager finishes: the first install that switches\n * a workspace onto the global virtual store runs with `bootstrap`'s gate still reflecting the\n * old layout, yet the same process goes on to reload envs and compile from store slots. The\n * installer re-applies the bridge the moment the target layout is known.\n *\n * Everything here is idempotent, so calling it again is always safe: `NODE_PATH` is rebuilt to the\n * same value, the ESM loader re-registers only when the ordered entry list changes, and the\n * process's own `NODE_OPTIONS` flag is replaced rather than stacked.\n *\n * One asymmetry to know about when reading the ESM half. Node runs the *last* registered loader\n * first and it delegates through `defaultResolve` before its own fallback, so an earlier\n * registration resolves anything it can before a later one is consulted. A re-registration\n * therefore corrects what child processes inherit - the `--import` flag carries the current list -\n * while in-process the earlier registration keeps its precedence for the entries it already had.\n * That only diverges from CommonJS for a specifier resolvable from more than one entry across two\n * registrations with different orders, which needs a process bridging two roots in alternating\n * order; the CommonJS half, rebuilt on every call, is always right.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { pathToFileURL } from 'url';\n\n/**\n * Source of the registered ESM loader, with the resolution entries injected at registration time.\n * The entries cannot be read from `NODE_PATH` inside the loader: on modern Node the hooks run on\n * a separate thread whose `process.env` is a snapshot taken at registration, so late additions -\n * an install switching the workspace onto the global virtual store mid-process - would never be\n * seen. Injecting the list makes each registration self-contained, at the cost of needing a new\n * registration whenever the list changes - by order as much as by membership, since the loader\n * searches these entries in the order given.\n */\nconst esmNodePathLoaderSource = (dirs: string[]) => `\nimport { createRequire } from 'node:module'\nimport { pathToFileURL } from 'node:url'\n\nconst extraNodePaths = ${JSON.stringify(dirs)}\n\nexport async function resolve (specifier, context, defaultResolve) {\n try {\n return await defaultResolve(specifier, context, defaultResolve)\n } catch (originalError) {\n // Only bare specifiers can come from the hoisted directory; the rest are already anchored.\n // Windows absolute (drive-letter) and UNC paths are path specifiers too.\n if (\n specifier.startsWith('.') ||\n specifier.startsWith('/') ||\n specifier.startsWith('node:') ||\n specifier.startsWith('\\\\\\\\') ||\n /^[a-zA-Z]:[\\\\\\\\/]/.test(specifier)\n ) {\n throw originalError\n }\n // createRequire anchored inside the entry searches the entry itself: Node skips appending\n // /node_modules to a directory already named node_modules, and the parent step re-yields it\n // (.pnpm -> .pnpm/node_modules). Exact for the entries this loader exists for, both of which\n // are named node_modules; an entry not named node_modules would be searched one level deeper\n // than CommonJS NODE_PATH does - those entries are already covered by the CommonJS side and\n // are not ours to fix.\n for (const basePath of extraNodePaths) {\n try {\n const require = createRequire(pathToFileURL(basePath + '/').href)\n return { url: pathToFileURL(require.resolve(specifier)).href, shortCircuit: true }\n } catch {}\n }\n throw originalError\n }\n}\n`;\n\nlet lastRegisteredEntries: string | undefined;\nlet lastImportFlag: string | undefined;\n\n/**\n * The `virtualStoreDir` pnpm recorded in a `node_modules/.modules.yaml`, or undefined when the\n * manifest records none.\n *\n * Current pnpm writes this manifest as JSON (YAML 1.2 being a superset of it), so the structured\n * read is a plain `JSON.parse` - no dependency, and correct for every value the writer can emit.\n * Older versions wrote block YAML, which the line match handles. A full YAML parser is\n * deliberately avoided: this runs in `bootstrap`, before any command does its work, and parsing\n * the whole manifest costs ~40ms on this repo's own 415KB one against ~0.2ms for the line match\n * (the manifest carries the entire hoisted alias map, so it grows with the dependency graph).\n * Taking a package dependency here would also make the earliest, least recoverable step of CLI\n * startup depend on module resolution - the very thing this module exists to repair.\n */\nexport function parseRecordedVirtualStoreDir(modulesManifest: string): string | undefined {\n try {\n const parsed = JSON.parse(modulesManifest) as { virtualStoreDir?: unknown };\n return typeof parsed.virtualStoreDir === 'string' ? parsed.virtualStoreDir : undefined;\n } catch {\n // not JSON - a block-YAML manifest from an older pnpm\n }\n return modulesManifest.match(/^\\s*\"?virtualStoreDir\"?:\\s*\"?([^\"\\n]+?)\"?,?\\s*$/m)?.[1];\n}\n\n/**\n * Whether the workspace's last install used pnpm's global virtual store, judged by the\n * `virtualStoreDir` the engine records in `node_modules/.modules.yaml`: `.pnpm` (or any path\n * inside the workspace) means project-local; a path escaping the workspace means the global\n * store. No manifest or no recorded value reads as project-local - a workspace that never\n * installed under the global store has nothing to bridge.\n */\n/**\n * Platform-safe path containment: `path.relative` is case-insensitive on Windows (where the\n * filesystem is) and case-sensitive on posix, which a bare `startsWith` prefix check gets wrong\n * for drive-letter casing differences between realpath results and given spellings. Equality\n * counts as inside - every caller asks \"does this path escape that root\", and a path equal to\n * the root has not escaped it.\n */\nexport function isPathInsideOrEqual(child: string, parent: string): boolean {\n const rel = path.relative(parent, child);\n // component-aware traversal check: a child legitimately named `..foo` also starts with `..`\n return !path.isAbsolute(rel) && rel !== '..' && !rel.startsWith(`..${path.sep}`);\n}\n\n/**\n * Whether two spellings name the same directory. `path.relative` normalizes both sides first, so a\n * trailing separator, a redundant `.`, a relative spelling and - on Windows - a difference in case\n * all compare equal, which string equality would miss. Anything written by hand into `NODE_PATH`\n * arrives in whatever spelling its author chose.\n */\nexport function isSamePath(one: string, other: string): boolean {\n return path.relative(one, other) === '';\n}\n\nexport function isGlobalVirtualStoreLayout(workspaceRoot: string): boolean {\n let modulesManifest: string;\n try {\n modulesManifest = fs.readFileSync(path.join(workspaceRoot, 'node_modules', '.modules.yaml'), 'utf8');\n } catch {\n return false;\n }\n const virtualStoreDir = parseRecordedVirtualStoreDir(modulesManifest);\n if (!virtualStoreDir) return false;\n let workspaceRealpath = workspaceRoot;\n try {\n workspaceRealpath = fs.realpathSync(workspaceRoot);\n } catch {\n // fall back to the given spelling\n }\n const resolved = path.resolve(workspaceRealpath, 'node_modules', virtualStoreDir);\n let storeRealpath = resolved;\n try {\n storeRealpath = fs.realpathSync(resolved);\n } catch {\n // dangling recorded dir - judge by the lexical resolution\n }\n return !isPathInsideOrEqual(storeRealpath, workspaceRealpath);\n}\n\n/**\n * The root of the installation this module runs from: the nearest ancestor that owns a\n * `node_modules/.modules.yaml`. For a bvm-installed bit that is the bvm version directory; for a\n * workspace-provided bit it is the workspace.\n *\n * Two candidate starting points, because Node realpaths module filenames: under the global\n * virtual store this module's `__dirname` is the *store slot* - a dead end with no\n * `.modules.yaml` and no physical path back to the installation. The entry script's\n * `process.argv[1]` is the path *as invoked*, unresolved through symlinks, so for a store-linked\n * installation it still sits inside the installation tree. `__dirname` remains the fallback for\n * setups that invoke bit through a resolved path (and for the copy-shaped installations where it\n * works fine). `undefined` when neither leads to an installation (e.g. running from source).\n */\nexport function selfInstallationRoot(): string | undefined {\n const candidates = [process.argv[1], __dirname].filter(Boolean) as string[];\n for (const candidate of candidates) {\n let dir = path.dirname(path.resolve(candidate));\n for (;;) {\n if (fs.existsSync(path.join(dir, 'node_modules', '.modules.yaml'))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n }\n return undefined;\n}\n\n/**\n * Bridge the *running installation's* own directories when that installation is itself linked to\n * the global virtual store - its packages then live in store slots and their phantom requires\n * need the installation's private hoist exactly like a workspace's do. Judged by the same\n * `.modules.yaml` record, read at the installation root. A conventional project-local\n * installation (bvm's default) reads project-local and stays unbridged, so nothing changes for\n * it or for the processes it spawns.\n */\nexport function ensureSelfInstallationBridge(): void {\n const installationRoot = selfInstallationRoot();\n if (!installationRoot) return;\n if (!isGlobalVirtualStoreLayout(installationRoot)) return;\n ensureHoistedDependencyResolution(installationRoot);\n}\n\n/**\n * The directories a package resolved from `<root>` used to reach by walking up, in the order the\n * walk reached them: the hoisted `node_modules/.pnpm/node_modules` first, then the root's own\n * `node_modules`. Both are lost under the global virtual store, and they hold disjoint sets -\n * pnpm hoists only *non-direct* dependencies, so a direct dependency of the root exists solely in\n * the second. Missing directories are dropped; a root with neither yields an empty list.\n *\n * Shared with the type-resolution side of the bridge, which has to reach the same two directories\n * through the mechanism TypeScript offers instead of `NODE_PATH`.\n */\nexport function hoistedResolutionDirs(root: string): string[] {\n return [path.join(root, 'node_modules', '.pnpm', 'node_modules'), path.join(root, 'node_modules')].filter((dir) =>\n fs.existsSync(dir)\n );\n}\n\n/**\n * Put the given root's {@link hoistedResolutionDirs} on the resolution path of this process and\n * its children. Idempotent; a no-op when neither directory exists. Callers decide *whether* the\n * root needs the bridge ({@link isGlobalVirtualStoreLayout} for the pre-aspect gate, the\n * dependency-resolver's own config after an install).\n */\nexport function ensureHoistedDependencyResolution(workspaceRoot: string): void {\n const dirs = hoistedResolutionDirs(workspaceRoot);\n if (!dirs.length) return;\n const existing = process.env.NODE_PATH;\n const untouched = (existing?.split(path.delimiter).filter(Boolean) ?? []).filter(\n // by path rather than by spelling, so an entry naming a directory this bridge owns is replaced\n // by the canonical one instead of being kept alongside it as a redundant search base\n (dir) => !dirs.some((owned) => isSamePath(dir, owned))\n );\n // rebuilt rather than prepended, because order is resolution order and an entry already present\n // is not necessarily in front of the one it has to beat: a bit that bridged the hoisted\n // directory alone leaves it in `NODE_PATH` for its children, and adding the root's node_modules\n // in front of it there would invert the walk the bridge exists to reproduce. Everything this\n // bridge does not own keeps its relative order, behind what the walk reached first.\n const next = [...dirs, ...untouched].join(path.delimiter);\n if (next !== existing) {\n process.env.NODE_PATH = next;\n // `NODE_PATH` is read once when the module system initializes, so a later assignment only\n // takes effect after re-deriving the global paths.\n (require('module') as { _initPaths(): void })._initPaths();\n }\n registerEsmNodePathLoader();\n}\n\n/**\n * The ESM half of {@link ensureHoistedDependencyResolution}.\n *\n * Node consults `NODE_PATH` only for CommonJS; ESM resolution ignores it entirely. Bit supports\n * ESM components, so without this an ESM package in the store cannot reach the hoisted directory\n * at all and the CommonJS half would only cover part of the problem.\n *\n * Registered two ways, because both matter:\n * - `module.register` for bit's own process, which is where aspects and envs are loaded.\n * - `NODE_OPTIONS`, so the processes bit spawns - env build steps, app servers, test workers -\n * inherit it. They resolve their own dependencies and hit the same wall.\n *\n * The loader is inlined as a data URL rather than taken as a dependency so there is no file to\n * ship and no install step to depend on. `module.register` needs Node 20.6, so this is skipped\n * on older runtimes - the CommonJS half still applies there.\n */\nfunction registerEsmNodePathLoader(): void {\n const nodeModule = require('module') as {\n register?: (specifier: string, parentURL: string) => void;\n };\n if (typeof nodeModule.register !== 'function') return;\n // mirror the CommonJS side exactly: every current NODE_PATH entry participates, in its order\n const dirs = (process.env.NODE_PATH || '').split(path.delimiter).filter(Boolean);\n if (!dirs.length) return;\n const entries = dirs.join(path.delimiter);\n // ordered, not a set: the loader inlines the list, so a reordering leaves a registration whose\n // precedence no longer matches the one CommonJS now uses\n if (lastImportFlag && entries === lastRegisteredEntries) return;\n const loaderUrl = `data:text/javascript,${encodeURIComponent(esmNodePathLoaderSource(dirs))}`;\n const parentUrl = pathToFileURL(path.join(process.cwd(), '/')).href;\n try {\n nodeModule.register(loaderUrl, parentUrl);\n } catch {\n // A runtime that rejects the loader must not take the whole CLI down with it - the CommonJS\n // half of the workaround is unaffected, and only ESM packages relying on hoisting are lost.\n return;\n }\n lastRegisteredEntries = entries;\n const registration = `import{register}from'node:module';register(${JSON.stringify(loaderUrl)},${JSON.stringify(parentUrl)});`;\n const importFlag = `--import=data:text/javascript,${encodeURIComponent(registration)}`;\n // children get one flag carrying the full current set: replace our previous flag rather than\n // stacking loaders, and match our own flag exactly - a user's `--require ts-node/register`\n // in NODE_OPTIONS must not suppress the loader's propagation\n if (lastImportFlag && process.env.NODE_OPTIONS?.includes(lastImportFlag)) {\n process.env.NODE_OPTIONS = process.env.NODE_OPTIONS.replace(lastImportFlag, importFlag);\n } else if (!process.env.NODE_OPTIONS?.includes(importFlag)) {\n process.env.NODE_OPTIONS = process.env.NODE_OPTIONS ? `${process.env.NODE_OPTIONS} ${importFlag}` : importFlag;\n }\n lastImportFlag = importFlag;\n}\n"],"mappings":";;;;;;;;;;;;;AAmDA,SAAAA,GAAA;EAAA,MAAAC,IAAA,GAAAC,uBAAA,CAAAC,OAAA;EAAAH,EAAA,YAAAA,CAAA;IAAA,OAAAC,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAG,KAAA;EAAA,MAAAH,IAAA,GAAAC,uBAAA,CAAAC,OAAA;EAAAC,IAAA,YAAAA,CAAA;IAAA,OAAAH,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AACA,SAAAI,KAAA;EAAA,MAAAJ,IAAA,GAAAE,OAAA;EAAAE,IAAA,YAAAA,CAAA;IAAA,OAAAJ,IAAA;EAAA;EAAA,OAAAA,IAAA;AAAA;AAAoC,SAAAC,wBAAAI,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAN,uBAAA,YAAAA,CAAAI,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AArDpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMkB,uBAAuB,GAAIC,IAAc,IAAK;AACpD;AACA;AACA;AACA,yBAAyBC,IAAI,CAACC,SAAS,CAACF,IAAI,CAAC;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAED,IAAIG,qBAAyC;AAC7C,IAAIC,cAAkC;;AAEtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,4BAA4BA,CAACC,eAAuB,EAAsB;EACxF,IAAI;IACF,MAAMC,MAAM,GAAGN,IAAI,CAACO,KAAK,CAACF,eAAe,CAAkC;IAC3E,OAAO,OAAOC,MAAM,CAACE,eAAe,KAAK,QAAQ,GAAGF,MAAM,CAACE,eAAe,GAAGC,SAAS;EACxF,CAAC,CAAC,MAAM;IACN;EAAA;EAEF,OAAOJ,eAAe,CAACK,KAAK,CAAC,kDAAkD,CAAC,GAAG,CAAC,CAAC;AACvF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,mBAAmBA,CAACC,KAAa,EAAEC,MAAc,EAAW;EAC1E,MAAMC,GAAG,GAAGrC,IAAI,CAAD,CAAC,CAACsC,QAAQ,CAACF,MAAM,EAAED,KAAK,CAAC;EACxC;EACA,OAAO,CAACnC,IAAI,CAAD,CAAC,CAACuC,UAAU,CAACF,GAAG,CAAC,IAAIA,GAAG,KAAK,IAAI,IAAI,CAACA,GAAG,CAACG,UAAU,CA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","ignoreList":[]}
@@ -0,0 +1 @@
1
+ export {};