isolate-package 1.30.0-0 → 1.31.0

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.d.mts CHANGED
@@ -20,7 +20,13 @@ type IsolateConfigResolved = {
20
20
  targetPackagePath?: string;
21
21
  tsconfigPath: string;
22
22
  workspacePackages?: string[];
23
- workspaceRoot: string;
23
+ /**
24
+ * Path to the workspace root, relative to the target package directory.
25
+ * When omitted, the workspace root is auto-detected by walking upward from
26
+ * the target package directory looking for a pnpm-workspace.yaml, a
27
+ * package.json with a `workspaces` field, or a rush.json.
28
+ */
29
+ workspaceRoot?: string;
24
30
  forceNpm: boolean;
25
31
  pickFromScripts?: string[];
26
32
  omitFromScripts?: string[];
@@ -45,5 +51,11 @@ declare function isolate(config?: IsolateConfig): Promise<string>;
45
51
  */
46
52
  declare function getInternalPackageNames(config?: IsolateConfig): Promise<string[]>;
47
53
  //#endregion
48
- export { type IsolateConfig, type Logger, defineConfig, getInternalPackageNames, isolate };
54
+ //#region src/index.d.ts
55
+ /** Used by firebase-tools-with-isolate to type the dynamic import */
56
+ type IsolateExports = {
57
+ isolate: typeof isolate;
58
+ };
59
+ //#endregion
60
+ export { type IsolateConfig, IsolateExports, type Logger, defineConfig, getInternalPackageNames, isolate };
49
61
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
- import { c as detectPackageManager, i as defineConfig, l as readTypedJson, n as listInternalPackages, o as resolveConfig, r as createPackagesRegistry, s as resolveWorkspacePaths, t as isolate } from "./isolate-BZjQHi0U.mjs";
1
+ import { c as detectPackageManager, i as defineConfig, l as readTypedJson, n as listInternalPackages, o as resolveConfig, r as createPackagesRegistry, s as resolveWorkspacePaths, t as isolate } from "./isolate-DtNAHzfa.mjs";
2
2
  import path from "node:path";
3
-
4
3
  //#region src/get-internal-package-names.ts
5
4
  /**
6
5
  * Get the names of all internal workspace packages that the target package
@@ -16,7 +15,7 @@ async function getInternalPackageNames(config) {
16
15
  detectPackageManager(workspaceRootDir);
17
16
  return listInternalPackages(await readTypedJson(path.join(targetPackageDir, "package.json")), await createPackagesRegistry(workspaceRootDir, resolvedConfig.workspacePackages), { includeDevDependencies: resolvedConfig.includeDevDependencies });
18
17
  }
19
-
20
18
  //#endregion
21
19
  export { defineConfig, getInternalPackageNames, isolate };
20
+
22
21
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/get-internal-package-names.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { IsolateConfig } from \"./lib/config\";\nimport { resolveConfig, resolveWorkspacePaths } from \"./lib/config\";\nimport { detectPackageManager } from \"./lib/package-manager\";\nimport { createPackagesRegistry, listInternalPackages } from \"./lib/registry\";\nimport type { PackageManifest } from \"./lib/types\";\nimport { readTypedJson } from \"./lib/utils\";\n\n/**\n * Get the names of all internal workspace packages that the target package\n * depends on. This is useful for tools like tsup that need a list of internal\n * packages to include in `noExternal`.\n *\n * If no config is passed, it reads from `isolate.config.{ts,js,json}` in the\n * current working directory.\n */\nexport async function getInternalPackageNames(\n config?: IsolateConfig,\n): Promise<string[]> {\n const resolvedConfig = resolveConfig(config);\n const { targetPackageDir, workspaceRootDir } =\n resolveWorkspacePaths(resolvedConfig);\n\n detectPackageManager(workspaceRootDir);\n\n const targetPackageManifest = await readTypedJson<PackageManifest>(\n path.join(targetPackageDir, \"package.json\"),\n );\n\n const packagesRegistry = await createPackagesRegistry(\n workspaceRootDir,\n resolvedConfig.workspacePackages,\n );\n\n return listInternalPackages(targetPackageManifest, packagesRegistry, {\n includeDevDependencies: resolvedConfig.includeDevDependencies,\n });\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,eAAsB,wBACpB,QACmB;CACnB,MAAM,iBAAiB,cAAc,OAAO;CAC5C,MAAM,EAAE,kBAAkB,qBACxB,sBAAsB,eAAe;AAEvC,sBAAqB,iBAAiB;AAWtC,QAAO,qBATuB,MAAM,cAClC,KAAK,KAAK,kBAAkB,eAAe,CAC5C,EAEwB,MAAM,uBAC7B,kBACA,eAAe,kBAChB,EAEoE,EACnE,wBAAwB,eAAe,wBACxC,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/get-internal-package-names.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { IsolateConfig } from \"./lib/config\";\nimport { resolveConfig, resolveWorkspacePaths } from \"./lib/config\";\nimport { detectPackageManager } from \"./lib/package-manager\";\nimport { createPackagesRegistry, listInternalPackages } from \"./lib/registry\";\nimport type { PackageManifest } from \"./lib/types\";\nimport { readTypedJson } from \"./lib/utils\";\n\n/**\n * Get the names of all internal workspace packages that the target package\n * depends on. This is useful for tools like tsup that need a list of internal\n * packages to include in `noExternal`.\n *\n * If no config is passed, it reads from `isolate.config.{ts,js,json}` in the\n * current working directory.\n */\nexport async function getInternalPackageNames(\n config?: IsolateConfig,\n): Promise<string[]> {\n const resolvedConfig = resolveConfig(config);\n const { targetPackageDir, workspaceRootDir } =\n resolveWorkspacePaths(resolvedConfig);\n\n detectPackageManager(workspaceRootDir);\n\n const targetPackageManifest = await readTypedJson<PackageManifest>(\n path.join(targetPackageDir, \"package.json\"),\n );\n\n const packagesRegistry = await createPackagesRegistry(\n workspaceRootDir,\n resolvedConfig.workspacePackages,\n );\n\n return listInternalPackages(targetPackageManifest, packagesRegistry, {\n includeDevDependencies: resolvedConfig.includeDevDependencies,\n });\n}\n"],"mappings":";;;;;;;;;;;AAgBA,eAAsB,wBACpB,QACmB;CACnB,MAAM,iBAAiB,cAAc,OAAO;CAC5C,MAAM,EAAE,kBAAkB,qBACxB,sBAAsB,eAAe;AAEvC,sBAAqB,iBAAiB;AAWtC,QAAO,qBATuB,MAAM,cAClC,KAAK,KAAK,kBAAkB,eAAe,CAC5C,EAEwB,MAAM,uBAC7B,kBACA,eAAe,kBAChB,EAEoE,EACnE,wBAAwB,eAAe,wBACxC,CAAC"}
@@ -4,6 +4,7 @@ import assert from "node:assert";
4
4
  import path, { join } from "node:path";
5
5
  import { isEmpty, omit, pick, unique } from "remeda";
6
6
  import { exec, execFileSync, execSync } from "node:child_process";
7
+ import { detectMonorepo } from "detect-monorepo";
7
8
  import { pathToFileURL } from "node:url";
8
9
  import { createConsola } from "consola";
9
10
  import { fileURLToPath } from "url";
@@ -24,7 +25,6 @@ import path$1 from "path";
24
25
  import { getTsconfig } from "get-tsconfig";
25
26
  import outdent$1 from "outdent";
26
27
  import { globSync } from "glob";
27
-
28
28
  //#region src/lib/logger.ts
29
29
  /**
30
30
  * Map our log levels to consola's numeric levels. Consola levels:
@@ -56,13 +56,11 @@ function setLogLevel(logLevel) {
56
56
  function useLogger() {
57
57
  return _logger;
58
58
  }
59
-
60
59
  //#endregion
61
60
  //#region src/lib/utils/filter-object-undefined.ts
62
61
  function filterObjectUndefined(object) {
63
62
  return Object.fromEntries(Object.entries(object).filter(([_, value]) => value !== void 0));
64
63
  }
65
-
66
64
  //#endregion
67
65
  //#region src/lib/utils/get-package-name.ts
68
66
  /**
@@ -74,7 +72,6 @@ function getPackageName(packageSpec) {
74
72
  /** Regular packages: package@version -> package */
75
73
  return packageSpec.split("@")[0] ?? "";
76
74
  }
77
-
78
75
  //#endregion
79
76
  //#region src/lib/utils/filter-patched-dependencies.ts
80
77
  /**
@@ -115,7 +112,6 @@ function filterPatchedDependencies({ patchedDependencies, targetPackageManifest,
115
112
  log.debug(`Filtered patches: ${includedCount} included, ${excludedCount} excluded`);
116
113
  return Object.keys(filteredPatches).length > 0 ? filteredPatches : void 0;
117
114
  }
118
-
119
115
  //#endregion
120
116
  //#region src/lib/utils/get-dirname.ts
121
117
  /**
@@ -125,7 +121,6 @@ function filterPatchedDependencies({ patchedDependencies, targetPackageManifest,
125
121
  function getDirname(importMetaUrl) {
126
122
  return fileURLToPath(new URL(".", importMetaUrl));
127
123
  }
128
-
129
124
  //#endregion
130
125
  //#region src/lib/utils/get-error-message.ts
131
126
  function getErrorMessage(error) {
@@ -146,23 +141,26 @@ function toErrorWithMessage(maybeError) {
146
141
  return new Error(String(maybeError));
147
142
  }
148
143
  }
149
-
150
144
  //#endregion
151
145
  //#region src/lib/utils/inspect-value.ts
152
146
  function inspectValue(value) {
153
147
  return inspect(value, false, 16, true);
154
148
  }
155
-
156
149
  //#endregion
157
150
  //#region src/lib/utils/is-rush-workspace.ts
158
151
  /**
159
152
  * Detect if this is a Rush monorepo. They use a very different structure so
160
153
  * there are multiple places where we need to make exceptions based on this.
154
+ *
155
+ * This intentionally only checks the passed-in directory. Using the upward
156
+ * walk of `detectMonorepo` here would break callers that pass a subdirectory
157
+ * of the actual Rush root, because downstream code builds paths (like
158
+ * `common/config/rush`) and lockfile importer ids relative to the same
159
+ * directory it gets.
161
160
  */
162
161
  function isRushWorkspace(workspaceRootDir) {
163
162
  return fs$1.existsSync(path.join(workspaceRootDir, "rush.json"));
164
163
  }
165
-
166
164
  //#endregion
167
165
  //#region src/lib/utils/json.ts
168
166
  /** @todo Pass in zod schema and validate */
@@ -182,7 +180,6 @@ async function readTypedJson(filePath) {
182
180
  throw new Error(`Failed to read JSON from ${filePath}: ${getErrorMessage(err)}`, { cause: err });
183
181
  }
184
182
  }
185
-
186
183
  //#endregion
187
184
  //#region src/lib/utils/log-paths.ts
188
185
  function getRootRelativeLogPath(path, rootPath) {
@@ -191,13 +188,11 @@ function getRootRelativeLogPath(path, rootPath) {
191
188
  function getIsolateRelativeLogPath(path, isolatePath) {
192
189
  return join("(isolate)", path.replace(isolatePath, ""));
193
190
  }
194
-
195
191
  //#endregion
196
192
  //#region src/lib/utils/get-major-version.ts
197
193
  function getMajorVersion(version) {
198
194
  return parseInt(version.split(".").at(0) ?? "0", 10);
199
195
  }
200
-
201
196
  //#endregion
202
197
  //#region src/lib/package-manager/names.ts
203
198
  const supportedPackageManagerNames = [
@@ -214,7 +209,6 @@ function getLockfileFileName(name) {
214
209
  case "npm": return "package-lock.json";
215
210
  }
216
211
  }
217
-
218
212
  //#endregion
219
213
  //#region src/lib/package-manager/helpers/infer-from-files.ts
220
214
  function inferFromFiles(workspaceRoot) {
@@ -245,7 +239,6 @@ function inferFromFiles(workspaceRoot) {
245
239
  function getVersion(packageManagerName) {
246
240
  return execSync(`${packageManagerName} --version`).toString().trim();
247
241
  }
248
-
249
242
  //#endregion
250
243
  //#region src/lib/package-manager/helpers/infer-from-manifest.ts
251
244
  function inferFromManifest(workspaceRoot) {
@@ -266,7 +259,6 @@ function inferFromManifest(workspaceRoot) {
266
259
  packageManagerString
267
260
  };
268
261
  }
269
-
270
262
  //#endregion
271
263
  //#region src/lib/package-manager/index.ts
272
264
  let packageManager;
@@ -293,7 +285,6 @@ function shouldUsePnpmPack() {
293
285
  const { name, majorVersion } = usePackageManager();
294
286
  return name === "pnpm" && majorVersion >= 8;
295
287
  }
296
-
297
288
  //#endregion
298
289
  //#region src/lib/utils/pack.ts
299
290
  async function pack(srcDir, dstDir) {
@@ -334,7 +325,6 @@ async function pack(srcDir, dstDir) {
334
325
  */
335
326
  return filePath;
336
327
  }
337
-
338
328
  //#endregion
339
329
  //#region src/lib/utils/unpack.ts
340
330
  async function unpack(filePath, unpackDir) {
@@ -342,7 +332,6 @@ async function unpack(filePath, unpackDir) {
342
332
  fs.createReadStream(filePath).pipe(createGunzip()).pipe(tar.extract(unpackDir)).on("finish", () => resolve()).on("error", (err) => reject(err));
343
333
  });
344
334
  }
345
-
346
335
  //#endregion
347
336
  //#region src/lib/utils/yaml.ts
348
337
  function readTypedYamlSync(filePath) {
@@ -358,7 +347,6 @@ function writeTypedYamlSync(filePath, content) {
358
347
  /** @todo Add some zod validation maybe */
359
348
  fs.writeFileSync(filePath, yaml.stringify(content), "utf-8");
360
349
  }
361
-
362
350
  //#endregion
363
351
  //#region src/lib/config.ts
364
352
  const configDefaults = {
@@ -369,7 +357,7 @@ const configDefaults = {
369
357
  targetPackagePath: void 0,
370
358
  tsconfigPath: "./tsconfig.json",
371
359
  workspacePackages: void 0,
372
- workspaceRoot: "../..",
360
+ workspaceRoot: void 0,
373
361
  forceNpm: false,
374
362
  pickFromScripts: void 0,
375
363
  omitFromScripts: void 0,
@@ -451,12 +439,25 @@ function validateConfig(config) {
451
439
  * Resolve the target package directory and workspace root directory from the
452
440
  * configuration. When targetPackagePath is set, the config is assumed to live
453
441
  * at the workspace root. Otherwise it lives in the target package directory.
442
+ *
443
+ * When `workspaceRoot` is not explicitly set, auto-detect the monorepo root by
444
+ * walking upward from the target package directory.
454
445
  */
455
446
  function resolveWorkspacePaths(config) {
456
447
  const targetPackageDir = config.targetPackagePath ? path.join(process.cwd(), config.targetPackagePath) : process.cwd();
448
+ if (config.targetPackagePath) return {
449
+ targetPackageDir,
450
+ workspaceRootDir: process.cwd()
451
+ };
452
+ if (config.workspaceRoot !== void 0) return {
453
+ targetPackageDir,
454
+ workspaceRootDir: path.join(targetPackageDir, config.workspaceRoot)
455
+ };
456
+ const detected = detectMonorepo(targetPackageDir);
457
+ if (!detected) throw new Error(`Failed to auto-detect monorepo workspace root from ${targetPackageDir}. Set the 'workspaceRoot' config option explicitly.`);
457
458
  return {
458
459
  targetPackageDir,
459
- workspaceRootDir: config.targetPackagePath ? process.cwd() : path.join(targetPackageDir, config.workspaceRoot)
460
+ workspaceRootDir: detected.rootDir
460
461
  };
461
462
  }
462
463
  function resolveConfig(initialConfig) {
@@ -474,7 +475,6 @@ function resolveConfig(initialConfig) {
474
475
  log.debug("Using configuration:", inspectValue(config));
475
476
  return config;
476
477
  }
477
-
478
478
  //#endregion
479
479
  //#region src/lib/lockfile/helpers/generate-bun-lockfile.ts
480
480
  /**
@@ -578,14 +578,16 @@ async function generateBunLockfile({ workspaceRootDir, targetPackageDir, isolate
578
578
  const targetWorkspaceKey = path.relative(workspaceRootDir, targetPackageDir).split(path.sep).join(path.posix.sep);
579
579
  const internalDepWorkspaceKeys = /* @__PURE__ */ new Map();
580
580
  for (const name of internalDepPackageNames) {
581
- const pkg = got(packagesRegistry, name);
582
- internalDepWorkspaceKeys.set(name, pkg.rootRelativeDir);
581
+ /** Normalize to POSIX separators for matching bun.lock workspace keys */
582
+ const workspaceKey = got(packagesRegistry, name).rootRelativeDir.split(path.sep).join(path.posix.sep);
583
+ internalDepWorkspaceKeys.set(name, workspaceKey);
583
584
  }
584
585
  /** Build the filtered workspaces object */
585
586
  const filteredWorkspaces = {};
586
587
  /** Remap the target workspace to root ("") */
587
588
  const targetEntry = lockfile.workspaces[targetWorkspaceKey];
588
- if (targetEntry) {
589
+ if (!targetEntry) throw new Error(`Target workspace "${targetWorkspaceKey}" not found in bun.lock. Available workspaces: ${Object.keys(lockfile.workspaces).join(", ")}`);
590
+ {
589
591
  const entry = { ...targetEntry };
590
592
  if (!includeDevDependencies) delete entry.devDependencies;
591
593
  filteredWorkspaces[""] = entry;
@@ -645,14 +647,14 @@ async function generateBunLockfile({ workspaceRootDir, targetPackageDir, isolate
645
647
  if (Object.keys(outputPatches).length > 0) outputLockfile.patchedDependencies = outputPatches;
646
648
  }
647
649
  const outputPath = path.join(isolateDir, "bun.lock");
648
- await fs.writeFile(outputPath, serializeWithTrailingCommas(outputLockfile));
650
+ /** Append trailing newline to match Bun's native output format */
651
+ await fs.writeFile(outputPath, serializeWithTrailingCommas(outputLockfile) + "\n");
649
652
  log.debug("Created lockfile at", outputPath);
650
653
  } catch (err) {
651
654
  log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);
652
655
  throw err;
653
656
  }
654
657
  }
655
-
656
658
  //#endregion
657
659
  //#region src/lib/lockfile/helpers/load-npm-config.ts
658
660
  async function loadNpmConfig({ npmPath }) {
@@ -665,7 +667,6 @@ async function loadNpmConfig({ npmPath }) {
665
667
  await config.load();
666
668
  return config;
667
669
  }
668
-
669
670
  //#endregion
670
671
  //#region src/lib/lockfile/helpers/generate-npm-lockfile.ts
671
672
  /**
@@ -692,7 +693,6 @@ async function generateNpmLockfile({ workspaceRootDir, isolateDir }) {
692
693
  throw err;
693
694
  }
694
695
  }
695
-
696
696
  //#endregion
697
697
  //#region src/lib/lockfile/helpers/pnpm-map-importer.ts
698
698
  /** Convert dependency links */
@@ -723,7 +723,6 @@ function pnpmMapDependenciesLinks(importerPath, def, directoryByPackageName) {
723
723
  return [[key, relativePath.startsWith(".") ? `link:${relativePath}` : `link:./${relativePath}`]];
724
724
  }));
725
725
  }
726
-
727
726
  //#endregion
728
727
  //#region src/lib/lockfile/helpers/generate-pnpm-lockfile.ts
729
728
  async function generatePnpmLockfile({ workspaceRootDir, targetPackageDir, isolateDir, internalDepPackageNames, packagesRegistry, targetPackageManifest, majorVersion, includeDevDependencies, patchedDependencies }) {
@@ -794,7 +793,6 @@ async function generatePnpmLockfile({ workspaceRootDir, targetPackageDir, isolat
794
793
  throw err;
795
794
  }
796
795
  }
797
-
798
796
  //#endregion
799
797
  //#region src/lib/lockfile/helpers/generate-yarn-lockfile.ts
800
798
  /**
@@ -823,7 +821,6 @@ async function generateYarnLockfile({ workspaceRootDir, isolateDir }) {
823
821
  throw err;
824
822
  }
825
823
  }
826
-
827
824
  //#endregion
828
825
  //#region src/lib/lockfile/process-lockfile.ts
829
826
  /**
@@ -899,7 +896,6 @@ async function processLockfile({ workspaceRootDir, packagesRegistry, isolateDir,
899
896
  }
900
897
  return usedFallbackToNpm;
901
898
  }
902
-
903
899
  //#endregion
904
900
  //#region src/lib/manifest/io.ts
905
901
  async function readManifest(packageDir) {
@@ -908,7 +904,6 @@ async function readManifest(packageDir) {
908
904
  async function writeManifest(outputDir, manifest) {
909
905
  await fs.writeFile(path.join(outputDir, "package.json"), JSON.stringify(manifest, null, 2));
910
906
  }
911
-
912
907
  //#endregion
913
908
  //#region src/lib/manifest/helpers/patch-internal-entries.ts
914
909
  function patchInternalEntries(dependencies, packagesRegistry, parentRootRelativeDir) {
@@ -923,7 +918,6 @@ function patchInternalEntries(dependencies, packagesRegistry, parentRootRelative
923
918
  } else return [key, value];
924
919
  }));
925
920
  }
926
-
927
921
  //#endregion
928
922
  //#region src/lib/manifest/helpers/adapt-manifest-internal-deps.ts
929
923
  /**
@@ -939,7 +933,6 @@ function adaptManifestInternalDeps({ manifest, packagesRegistry, parentRootRelat
939
933
  devDependencies: devDependencies ? patchInternalEntries(devDependencies, packagesRegistry, parentRootRelativeDir) : void 0
940
934
  };
941
935
  }
942
-
943
936
  //#endregion
944
937
  //#region src/lib/manifest/helpers/resolve-catalog-dependencies.ts
945
938
  /**
@@ -973,7 +966,6 @@ async function resolveCatalogDependencies(dependencies, workspaceRootDir) {
973
966
  }
974
967
  return resolved;
975
968
  }
976
-
977
969
  //#endregion
978
970
  //#region src/lib/manifest/helpers/adapt-internal-package-manifests.ts
979
971
  /**
@@ -985,14 +977,22 @@ async function adaptInternalPackageManifests({ internalPackageNames, packagesReg
985
977
  const packageManager = usePackageManager();
986
978
  await Promise.all(internalPackageNames.map(async (packageName) => {
987
979
  const { manifest, rootRelativeDir } = got(packagesRegistry, packageName);
988
- /** Dev dependencies and scripts are never included for internal deps */
989
- const strippedManifest = omit(manifest, ["scripts", "devDependencies"]);
980
+ /** Dev dependencies are never included for internal deps */
981
+ const strippedManifest = omit(manifest, ["devDependencies"]);
982
+ /**
983
+ * Strip the `prepare` script because it runs during `pnpm install` and
984
+ * typically depends on devDependency binaries (e.g. tsdown, del-cli)
985
+ * which are not available in the isolated output. Other lifecycle
986
+ * scripts like `postinstall` are preserved because they handle runtime
987
+ * setup (e.g. Prisma client generation).
988
+ */
989
+ if (strippedManifest.scripts) strippedManifest.scripts = omit(strippedManifest.scripts, ["prepare"]);
990
990
  /** Resolve catalog dependencies before adapting internal deps */
991
991
  const manifestWithResolvedCatalogs = {
992
992
  ...strippedManifest,
993
993
  dependencies: await resolveCatalogDependencies(strippedManifest.dependencies, workspaceRootDir)
994
994
  };
995
- const outputManifest = packageManager.name === "pnpm" && !forceNpm ? manifestWithResolvedCatalogs : adaptManifestInternalDeps({
995
+ const outputManifest = (packageManager.name === "pnpm" || packageManager.name === "bun") && !forceNpm ? manifestWithResolvedCatalogs : adaptManifestInternalDeps({
996
996
  manifest: manifestWithResolvedCatalogs,
997
997
  packagesRegistry,
998
998
  parentRootRelativeDir: rootRelativeDir
@@ -1000,17 +1000,36 @@ async function adaptInternalPackageManifests({ internalPackageNames, packagesReg
1000
1000
  await writeManifest(path.join(isolateDir, rootRelativeDir), outputManifest);
1001
1001
  }));
1002
1002
  }
1003
-
1004
1003
  //#endregion
1005
1004
  //#region src/lib/manifest/helpers/adopt-pnpm-fields-from-root.ts
1006
1005
  /**
1007
- * Adopts the `pnpm` fields from the root package manifest. Currently it takes
1008
- * overrides, onlyBuiltDependencies, and ignoredBuiltDependencies, because these
1009
- * are typically workspace-level configuration settings.
1006
+ * Adopts workspace-level fields from the root package manifest. For pnpm this
1007
+ * reads overrides, onlyBuiltDependencies, and ignoredBuiltDependencies from the
1008
+ * `pnpm` key. For Bun it reads `overrides` from the top level.
1010
1009
  */
1011
1010
  async function adoptPnpmFieldsFromRoot(targetPackageManifest, workspaceRootDir) {
1012
1011
  if (isRushWorkspace(workspaceRootDir)) return targetPackageManifest;
1013
- const { overrides, onlyBuiltDependencies, ignoredBuiltDependencies } = (await readTypedJson(path$1.join(workspaceRootDir, "package.json"))).pnpm || {};
1012
+ const rootPackageManifest = await readTypedJson(path$1.join(workspaceRootDir, "package.json"));
1013
+ if (usePackageManager().name === "bun") return adoptBunFieldsFromRoot(targetPackageManifest, rootPackageManifest);
1014
+ return adoptPnpmFieldsOnly(targetPackageManifest, rootPackageManifest);
1015
+ }
1016
+ /** Adopt Bun's top-level overrides from the root manifest */
1017
+ function adoptBunFieldsFromRoot(targetPackageManifest, rootPackageManifest) {
1018
+ /**
1019
+ * Bun supports `overrides` at the top level of package.json (same as npm).
1020
+ * Read from the root manifest and set them on the output manifest so that
1021
+ * `bun install --frozen-lockfile` succeeds.
1022
+ */
1023
+ const overrides = rootPackageManifest["overrides"];
1024
+ if (!overrides) return targetPackageManifest;
1025
+ return {
1026
+ ...targetPackageManifest,
1027
+ overrides
1028
+ };
1029
+ }
1030
+ /** Adopt pnpm-specific fields from the root manifest */
1031
+ function adoptPnpmFieldsOnly(targetPackageManifest, rootPackageManifest) {
1032
+ const { overrides, onlyBuiltDependencies, ignoredBuiltDependencies } = rootPackageManifest.pnpm || {};
1014
1033
  /** If no pnpm fields are present, return the original manifest */
1015
1034
  if (!overrides && !onlyBuiltDependencies && !ignoredBuiltDependencies) return targetPackageManifest;
1016
1035
  const pnpmConfig = {};
@@ -1022,7 +1041,6 @@ async function adoptPnpmFieldsFromRoot(targetPackageManifest, workspaceRootDir)
1022
1041
  pnpm: pnpmConfig
1023
1042
  };
1024
1043
  }
1025
-
1026
1044
  //#endregion
1027
1045
  //#region src/lib/manifest/adapt-target-package-manifest.ts
1028
1046
  /**
@@ -1051,9 +1069,13 @@ async function adaptTargetPackageManifest({ manifest, packagesRegistry, workspac
1051
1069
  scripts: pickFromScripts ? pick(manifest.scripts ?? {}, pickFromScripts) : omitFromScripts ? omit(manifest.scripts ?? {}, omitFromScripts) : {}
1052
1070
  };
1053
1071
  }
1054
-
1055
1072
  //#endregion
1056
1073
  //#region src/lib/manifest/validate-manifest.ts
1074
+ /** Maps field names to their documentation URLs */
1075
+ const fieldDocUrls = {
1076
+ version: "https://isolate-package.codecompose.dev/getting-started#define-version-field-in-each-package-manifest",
1077
+ files: "https://isolate-package.codecompose.dev/getting-started#define-files-field-in-each-package-manifest"
1078
+ };
1057
1079
  /**
1058
1080
  * Validate that mandatory fields are present in the package manifest. These
1059
1081
  * fields are required for the isolate process to work properly.
@@ -1075,13 +1097,13 @@ function validateManifestMandatoryFields(manifest, packagePath, requireFilesFiel
1075
1097
  */
1076
1098
  if (requireFilesField && (!manifest.files || !Array.isArray(manifest.files) || manifest.files.length === 0)) missingFields.push("files");
1077
1099
  if (missingFields.length > 0) {
1078
- const errorMessage = `Package at ${packagePath} is missing mandatory fields: ${missingFields.join(", ")}. See the documentation for more details.`;
1100
+ const field = missingFields[0];
1101
+ const errorMessage = missingFields.length === 1 ? `Package at ${packagePath} is missing the "${field}" field in its package.json. See ${fieldDocUrls[field] ?? "https://isolate-package.codecompose.dev/getting-started#prerequisites"}` : `Package at ${packagePath} is missing mandatory fields in its package.json: ${missingFields.join(", ")}. See https://isolate-package.codecompose.dev/getting-started#prerequisites`;
1079
1102
  log.error(errorMessage);
1080
1103
  throw new Error(errorMessage);
1081
1104
  }
1082
1105
  log.debug(`Validated mandatory fields for package at ${packagePath}`);
1083
1106
  }
1084
-
1085
1107
  //#endregion
1086
1108
  //#region src/lib/output/get-build-output-dir.ts
1087
1109
  async function getBuildOutputDir({ targetPackageDir, buildDirName, tsconfigPath }) {
@@ -1106,7 +1128,6 @@ async function getBuildOutputDir({ targetPackageDir, buildDirName, tsconfigPath
1106
1128
  `);
1107
1129
  }
1108
1130
  }
1109
-
1110
1131
  //#endregion
1111
1132
  //#region src/lib/output/pack-dependencies.ts
1112
1133
  /**
@@ -1134,7 +1155,6 @@ async function packDependencies({ packagesRegistry, internalPackageNames, packDe
1134
1155
  }
1135
1156
  return packedFileByName;
1136
1157
  }
1137
-
1138
1158
  //#endregion
1139
1159
  //#region src/lib/output/process-build-output-files.ts
1140
1160
  const TIMEOUT_MS = 5e3;
@@ -1152,7 +1172,6 @@ async function processBuildOutputFiles({ targetPackageDir, tmpDir, isolateDir })
1152
1172
  await unpack(packedFilePath, unpackDir);
1153
1173
  await fs.copy(path.join(unpackDir, "package"), isolateDir);
1154
1174
  }
1155
-
1156
1175
  //#endregion
1157
1176
  //#region src/lib/output/unpack-dependencies.ts
1158
1177
  async function unpackDependencies(packedFilesByName, packagesRegistry, tmpDir, isolateDir) {
@@ -1168,19 +1187,32 @@ async function unpackDependencies(packedFilesByName, packagesRegistry, tmpDir, i
1168
1187
  log.debug(`Moved package files to ${getIsolateRelativeLogPath(destinationDir, isolateDir)}`);
1169
1188
  }));
1170
1189
  }
1171
-
1172
1190
  //#endregion
1173
1191
  //#region src/lib/patches/copy-patches.ts
1174
1192
  async function copyPatches({ workspaceRootDir, targetPackageManifest, isolateDir, includeDevDependencies }) {
1175
1193
  const log = useLogger();
1176
- let workspaceRootManifest;
1177
- try {
1178
- workspaceRootManifest = await readTypedJson(path.join(workspaceRootDir, "package.json"));
1194
+ const { name: packageManagerName } = usePackageManager();
1195
+ let patchedDependencies;
1196
+ /**
1197
+ * Only try reading pnpm-workspace.yaml for pnpm workspaces. Bun workspaces
1198
+ * don't have this file and the warning would be noisy.
1199
+ */
1200
+ if (packageManagerName === "pnpm") try {
1201
+ patchedDependencies = readTypedYamlSync(path.join(workspaceRootDir, "pnpm-workspace.yaml"))?.patchedDependencies;
1179
1202
  } catch (error) {
1180
- log.warn(`Could not read workspace root package.json: ${error instanceof Error ? error.message : String(error)}`);
1181
- return {};
1203
+ log.warn(`Could not read pnpm-workspace.yaml: ${error instanceof Error ? error.message : String(error)}`);
1204
+ }
1205
+ if (!patchedDependencies || Object.keys(patchedDependencies).length === 0) {
1206
+ if (packageManagerName === "pnpm") log.debug("No patched dependencies found in pnpm-workspace.yaml; Falling back to workspace root package.json");
1207
+ else log.debug("Reading patched dependencies from workspace root package.json");
1208
+ try {
1209
+ const workspaceRootManifest = await readTypedJson(path.join(workspaceRootDir, "package.json"));
1210
+ /** PNPM stores patches under pnpm.patchedDependencies, Bun at the top level */
1211
+ patchedDependencies = workspaceRootManifest?.pnpm?.patchedDependencies ?? workspaceRootManifest?.patchedDependencies;
1212
+ } catch (error) {
1213
+ log.warn(`Could not read workspace root package.json: ${error instanceof Error ? error.message : String(error)}`);
1214
+ }
1182
1215
  }
1183
- const patchedDependencies = workspaceRootManifest.pnpm?.patchedDependencies;
1184
1216
  if (!patchedDependencies || Object.keys(patchedDependencies).length === 0) {
1185
1217
  log.debug("No patched dependencies found in workspace root package.json");
1186
1218
  return {};
@@ -1192,8 +1224,11 @@ async function copyPatches({ workspaceRootDir, targetPackageManifest, isolateDir
1192
1224
  includeDevDependencies
1193
1225
  });
1194
1226
  if (!filteredPatches) return {};
1195
- /** Read the lockfile to get the hashes for each patch */
1196
- const lockfilePatchedDependencies = await readLockfilePatchedDependencies(workspaceRootDir);
1227
+ /**
1228
+ * Read the pnpm lockfile to get patch hashes. Bun doesn't store hashes in
1229
+ * its lockfile so we skip this for Bun.
1230
+ */
1231
+ const lockfilePatchedDependencies = packageManagerName === "pnpm" ? await readLockfilePatchedDependencies(workspaceRootDir) : void 0;
1197
1232
  const copiedPatches = {};
1198
1233
  for (const [packageSpec, patchPath] of Object.entries(filteredPatches)) {
1199
1234
  const sourcePatchPath = path.resolve(workspaceRootDir, patchPath);
@@ -1207,7 +1242,7 @@ async function copyPatches({ workspaceRootDir, targetPackageManifest, isolateDir
1207
1242
  await fs.copy(sourcePatchPath, targetPatchPath);
1208
1243
  log.debug(`Copied patch for ${packageSpec}: ${patchPath}`);
1209
1244
  const hash = (lockfilePatchedDependencies?.[packageSpec])?.hash ?? "";
1210
- if (!hash) log.warn(`No hash found for patch ${packageSpec} in lockfile`);
1245
+ if (packageManagerName === "pnpm" && !hash) log.warn(`No hash found for patch ${packageSpec} in lockfile`);
1211
1246
  copiedPatches[packageSpec] = {
1212
1247
  path: patchPath,
1213
1248
  hash
@@ -1231,7 +1266,6 @@ async function readLockfilePatchedDependencies(workspaceRootDir) {
1231
1266
  return;
1232
1267
  }
1233
1268
  }
1234
-
1235
1269
  //#endregion
1236
1270
  //#region src/lib/registry/helpers/find-packages-globs.ts
1237
1271
  /**
@@ -1270,7 +1304,6 @@ function findPackagesGlobs(workspaceRootDir) {
1270
1304
  }
1271
1305
  }
1272
1306
  }
1273
-
1274
1307
  //#endregion
1275
1308
  //#region src/lib/registry/create-packages-registry.ts
1276
1309
  /**
@@ -1305,7 +1338,6 @@ function listWorkspacePackages(workspacePackagesOverride, workspaceRootDir) {
1305
1338
  if (isRushWorkspace(workspaceRootDir)) return readTypedJsonSync(path.join(workspaceRootDir, "rush.json")).projects.map(({ projectFolder }) => projectFolder);
1306
1339
  else return (workspacePackagesOverride ?? findPackagesGlobs(workspaceRootDir)).flatMap((glob) => globSync(glob, { cwd: workspaceRootDir })).filter((dir) => fs.lstatSync(path.join(workspaceRootDir, dir)).isDirectory());
1307
1340
  }
1308
-
1309
1341
  //#endregion
1310
1342
  //#region src/lib/registry/list-internal-packages.ts
1311
1343
  /**
@@ -1350,7 +1382,6 @@ function listInternalPackages(manifest, packagesRegistry, { includeDevDependenci
1350
1382
  const result = collectInternalPackages(manifest, packagesRegistry, includeDevDependencies, /* @__PURE__ */ new Set(), new Set(manifest.name ? [manifest.name] : []));
1351
1383
  return [...new Set(result)];
1352
1384
  }
1353
-
1354
1385
  //#endregion
1355
1386
  //#region src/isolate.ts
1356
1387
  const __dirname = getDirname(import.meta.url);
@@ -1403,6 +1434,21 @@ function createIsolator(config) {
1403
1434
  const isProductionDependency = productionInternalPackageNames.includes(packageName);
1404
1435
  validateManifestMandatoryFields(packageDef.manifest, getRootRelativeLogPath(packageDef.absoluteDir, workspaceRootDir), isProductionDependency);
1405
1436
  }
1437
+ /**
1438
+ * Validate that workspace dev dependencies of all packages being packed
1439
+ * have a version field. Even when dev dependencies are not included in the
1440
+ * isolation output, pnpm pack resolves workspace:* specifiers and requires
1441
+ * the version field to be present.
1442
+ */
1443
+ const validatedPackageNames = new Set(internalPackageNames);
1444
+ const manifestsToPack = [targetPackageManifest, ...internalPackageNames.map((name) => got(packagesRegistry, name).manifest)];
1445
+ for (const manifest of manifestsToPack) for (const depName of Object.keys(manifest.devDependencies ?? {})) {
1446
+ if (validatedPackageNames.has(depName)) continue;
1447
+ const packageDef = packagesRegistry[depName];
1448
+ if (!packageDef) continue;
1449
+ validateManifestMandatoryFields(packageDef.manifest, getRootRelativeLogPath(packageDef.absoluteDir, workspaceRootDir), false);
1450
+ validatedPackageNames.add(depName);
1451
+ }
1406
1452
  await unpackDependencies(await packDependencies({
1407
1453
  internalPackageNames,
1408
1454
  packagesRegistry,
@@ -1456,12 +1502,17 @@ function createIsolator(config) {
1456
1502
  if (hasCopiedPatches || usedFallbackToNpm) {
1457
1503
  const manifest = await readManifest(isolateDir);
1458
1504
  if (hasCopiedPatches) {
1459
- if (!manifest.pnpm) manifest.pnpm = {};
1460
1505
  /**
1461
1506
  * Extract just the paths for the manifest (lockfile needs full
1462
- * PatchFile)
1507
+ * PatchFile). PNPM stores patches under pnpm.patchedDependencies, Bun
1508
+ * at the top level.
1463
1509
  */
1464
- manifest.pnpm.patchedDependencies = Object.fromEntries(Object.entries(copiedPatches).map(([spec, patchFile]) => [spec, patchFile.path]));
1510
+ const patchEntries = Object.fromEntries(Object.entries(copiedPatches).map(([spec, patchFile]) => [spec, patchFile.path]));
1511
+ if (packageManager.name === "bun") manifest.patchedDependencies = patchEntries;
1512
+ else {
1513
+ if (!manifest.pnpm) manifest.pnpm = {};
1514
+ manifest.pnpm.patchedDependencies = patchEntries;
1515
+ }
1465
1516
  log.debug(`Added ${Object.keys(copiedPatches).length} patches to isolated package.json`);
1466
1517
  }
1467
1518
  if (usedFallbackToNpm) manifest.packageManager = `npm@${getVersion("npm")}`;
@@ -1521,7 +1572,7 @@ function createIsolator(config) {
1521
1572
  async function isolate(config) {
1522
1573
  return createIsolator(config)();
1523
1574
  }
1524
-
1525
1575
  //#endregion
1526
1576
  export { loadConfigFromFile as a, detectPackageManager as c, defineConfig as i, readTypedJson as l, listInternalPackages as n, resolveConfig as o, createPackagesRegistry as r, resolveWorkspacePaths as s, isolate as t, filterObjectUndefined as u };
1527
- //# sourceMappingURL=isolate-BZjQHi0U.mjs.map
1577
+
1578
+ //# sourceMappingURL=isolate-DtNAHzfa.mjs.map