@b9g/libuild 0.1.11 → 0.1.13

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/src/libuild.js CHANGED
@@ -1,4 +1,12 @@
1
1
  /// <reference types="./libuild.d.ts" />
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined")
6
+ return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
2
10
  // src/libuild.ts
3
11
  import * as FS3 from "fs/promises";
4
12
  import * as Path3 from "path";
@@ -67,6 +75,21 @@ function externalEntrypointsPlugin(options) {
67
75
  };
68
76
  }
69
77
  });
78
+ build3.onResolve({ filter: /^\.\.\/(?:src|bin)\// }, (args) => {
79
+ const withoutExt = args.path.replace(/\.(ts|js)$/, "");
80
+ const match = withoutExt.match(/^\.\.\/(?:src|bin)\/(.+)$/);
81
+ if (match) {
82
+ const entryName = match[1];
83
+ if (externalEntries.includes(entryName)) {
84
+ const dir = withoutExt.match(/^(\.\.\/(?:src|bin))\//)?.[1];
85
+ return {
86
+ path: `${dir}/${entryName}${outputExtension}`,
87
+ external: true
88
+ };
89
+ }
90
+ }
91
+ return void 0;
92
+ });
70
93
  }
71
94
  };
72
95
  }
@@ -92,27 +115,34 @@ function dtsPlugin(options) {
92
115
  let TS;
93
116
  try {
94
117
  TS = await import("typescript");
95
- } catch {
118
+ } catch (error) {
96
119
  return;
97
120
  }
98
121
  const tsFiles = entryFiles.filter((file) => {
99
122
  if (!file.endsWith(".ts"))
100
123
  return false;
101
124
  return options.entryPoints.some((entryPoint) => {
102
- const normalizedEntry = Path2.resolve(entryPoint);
103
- const normalizedFile = Path2.resolve(file);
104
- return normalizedEntry === normalizedFile;
125
+ try {
126
+ const fs = __require("fs");
127
+ const normalizedEntry = fs.realpathSync(Path2.resolve(entryPoint));
128
+ const normalizedFile = fs.realpathSync(Path2.resolve(file));
129
+ return normalizedEntry === normalizedFile;
130
+ } catch {
131
+ const normalizedEntry = Path2.resolve(entryPoint);
132
+ const normalizedFile = Path2.resolve(file);
133
+ return normalizedEntry === normalizedFile;
134
+ }
105
135
  });
106
136
  });
107
137
  if (tsFiles.length === 0) {
108
138
  return;
109
139
  }
110
140
  try {
141
+ await FS2.mkdir(options.outDir, { recursive: true });
111
142
  const compilerOptions = {
112
143
  declaration: true,
113
144
  emitDeclarationOnly: true,
114
145
  outDir: options.outDir,
115
- rootDir: options.rootDir,
116
146
  skipLibCheck: true,
117
147
  esModuleInterop: true,
118
148
  target: TS.ScriptTarget.ES2020,
@@ -187,6 +217,38 @@ ${content}`;
187
217
  }
188
218
 
189
219
  // src/libuild.ts
220
+ function generateRuntimeBanner(pkg) {
221
+ const prefersBun = pkg.engines?.bun !== void 0;
222
+ if (prefersBun) {
223
+ return '//bin/true; exec "$({ [ "${npm_config_user_agent#bun/}" != "$npm_config_user_agent" ] || true; } && command -v bun || command -v node)" "$0" "$@"';
224
+ } else {
225
+ return '//bin/true; exec "$([ "${npm_config_user_agent#bun/}" != "$npm_config_user_agent" ] && command -v bun || command -v node)" "$0" "$@"';
226
+ }
227
+ }
228
+ async function processJavaScriptExecutable(filePath, runtimeBanner) {
229
+ try {
230
+ const contents = await FS3.readFile(filePath, "utf8");
231
+ const lines = contents.split("\n");
232
+ let modified = false;
233
+ if (lines[0]?.startsWith("#!")) {
234
+ const existingShebang = lines[0];
235
+ if (existingShebang.includes("python") || existingShebang.includes("bash") || !existingShebang.includes("node") && !existingShebang.includes("bun") && !existingShebang.includes("sh")) {
236
+ console.warn(`\u26A0\uFE0F WARNING: ${filePath} has non-JavaScript shebang but is a JS file. Adding dual runtime support.`);
237
+ }
238
+ lines[0] = "#!/usr/bin/env sh";
239
+ lines.splice(1, 0, runtimeBanner);
240
+ modified = true;
241
+ } else {
242
+ lines.unshift("#!/usr/bin/env sh", runtimeBanner);
243
+ modified = true;
244
+ }
245
+ if (modified) {
246
+ await FS3.writeFile(filePath, lines.join("\n"));
247
+ }
248
+ } catch (error) {
249
+ console.warn(`\u26A0\uFE0F WARNING: Could not process executable ${filePath}: ${error.message}`);
250
+ }
251
+ }
190
252
  function isValidEntrypoint(filename) {
191
253
  if (!filename.endsWith(".ts") && !filename.endsWith(".js"))
192
254
  return false;
@@ -213,6 +275,22 @@ async function findEntrypoints(srcDir) {
213
275
  return isValidEntrypoint(dirent.name);
214
276
  }).map((dirent) => Path3.basename(dirent.name, Path3.extname(dirent.name))).sort();
215
277
  }
278
+ async function findBinEntrypoints(binDir) {
279
+ try {
280
+ const files = await FS3.readdir(binDir, { withFileTypes: true });
281
+ return files.filter((dirent) => {
282
+ if (dirent.isDirectory()) {
283
+ return false;
284
+ }
285
+ return isValidEntrypoint(dirent.name);
286
+ }).map((dirent) => Path3.basename(dirent.name, Path3.extname(dirent.name))).sort();
287
+ } catch (error) {
288
+ if (error.code === "ENOENT") {
289
+ return [];
290
+ }
291
+ throw error;
292
+ }
293
+ }
216
294
  function detectMainEntry(pkg, entries) {
217
295
  function extractEntryFromPath(path) {
218
296
  const match = path.match(/\.\/src\/([^.]+)/);
@@ -310,18 +388,38 @@ function checkIfExportIsStale(exportKey, exportValue, entries) {
310
388
  }
311
389
  return entryName ? !entries.includes(entryName) : false;
312
390
  }
313
- function generateExports(entries, mainEntry, options, existingExports = {}) {
391
+ async function generateExports(entries, mainEntry, options, existingExports = {}, distDir, allBinEntries = []) {
314
392
  const exports = {};
315
393
  const staleExports = [];
316
- function createExportEntry(entry) {
317
- const exportEntry = {
318
- types: `./src/${entry}.d.ts`,
319
- import: `./src/${entry}.js`
320
- };
321
- if (options.formats.cjs) {
322
- exportEntry.require = `./src/${entry}.cjs`;
394
+ async function createExportEntry(entry) {
395
+ if (entry.startsWith("bin/")) {
396
+ const binEntry = entry.replace("bin/", "");
397
+ const exportEntry = {
398
+ import: `./bin/${binEntry}.js`
399
+ };
400
+ if (distDir) {
401
+ const dtsPath = Path3.join(distDir, "bin", `${binEntry}.d.ts`);
402
+ if (await fileExists(dtsPath)) {
403
+ exportEntry.types = `./bin/${binEntry}.d.ts`;
404
+ }
405
+ }
406
+ return exportEntry;
407
+ } else {
408
+ const exportEntry = {
409
+ import: `./src/${entry}.js`
410
+ };
411
+ if (distDir) {
412
+ const dtsPath = Path3.join(distDir, "src", `${entry}.d.ts`);
413
+ const exists = await fileExists(dtsPath);
414
+ if (exists) {
415
+ exportEntry.types = `./src/${entry}.d.ts`;
416
+ }
417
+ }
418
+ if (options.formats.cjs) {
419
+ exportEntry.require = `./src/${entry}.cjs`;
420
+ }
421
+ return exportEntry;
323
422
  }
324
- return exportEntry;
325
423
  }
326
424
  function expandExistingExport(existing, entryFromPath) {
327
425
  if (typeof existing === "string") {
@@ -395,7 +493,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
395
493
  }
396
494
  }
397
495
  if (!exports["."]) {
398
- exports["."] = createExportEntry(mainEntry);
496
+ exports["."] = await createExportEntry(mainEntry);
399
497
  } else {
400
498
  exports["."] = expandExistingExport(exports["."], mainEntry);
401
499
  }
@@ -404,7 +502,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
404
502
  continue;
405
503
  const key = `./${entry}`;
406
504
  if (!exports[key]) {
407
- exports[key] = createExportEntry(entry);
505
+ exports[key] = await createExportEntry(entry);
408
506
  } else {
409
507
  exports[key] = expandExistingExport(exports[key], entry);
410
508
  }
@@ -457,13 +555,30 @@ async function validateSingleBinPath(binPath, fieldName, cwd, save) {
457
555
  if (save) {
458
556
  return;
459
557
  }
460
- if (binPath.startsWith("dist/src/") || binPath.startsWith("./dist/src/")) {
558
+ if (binPath.startsWith("dist/src/") || binPath.startsWith("./dist/src/") || binPath.startsWith("dist/bin/") || binPath.startsWith("./dist/bin/")) {
461
559
  const fullPath2 = Path3.join(cwd, binPath);
462
560
  const distExists = await fileExists(fullPath2);
463
561
  if (distExists) {
464
562
  return;
465
563
  }
466
- const srcPath = binPath.startsWith("./dist/src/") ? binPath.replace("./dist/src/", "src/") : binPath.replace("dist/src/", "src/");
564
+ let srcPath;
565
+ let sourceDir;
566
+ if (binPath.startsWith("./dist/src/")) {
567
+ srcPath = binPath.replace("./dist/src/", "src/");
568
+ sourceDir = "src";
569
+ } else if (binPath.startsWith("dist/src/")) {
570
+ srcPath = binPath.replace("dist/src/", "src/");
571
+ sourceDir = "src";
572
+ } else if (binPath.startsWith("./dist/bin/")) {
573
+ srcPath = binPath.replace("./dist/bin/", "bin/");
574
+ sourceDir = "bin";
575
+ } else if (binPath.startsWith("dist/bin/")) {
576
+ srcPath = binPath.replace("dist/bin/", "bin/");
577
+ sourceDir = "bin";
578
+ } else {
579
+ srcPath = binPath;
580
+ sourceDir = "src";
581
+ }
467
582
  const basePath = srcPath.replace(/\.(js|cjs|mjs)$/, "");
468
583
  const tsPath = Path3.join(cwd, basePath + ".ts");
469
584
  const jsPath = Path3.join(cwd, basePath + ".js");
@@ -490,7 +605,16 @@ async function validateSingleBinPath(binPath, fieldName, cwd, save) {
490
605
  if (pathExists) {
491
606
  return;
492
607
  }
493
- if (binPath.startsWith("src/") || binPath.startsWith("./src/")) {
608
+ if (binPath.startsWith("src/") || binPath.startsWith("./src/") || binPath.startsWith("bin/") || binPath.startsWith("./bin/")) {
609
+ let normalizedPath = binPath.startsWith("./") ? binPath.slice(2) : binPath;
610
+ if (normalizedPath.startsWith("src/")) {
611
+ const srcRelativePath = normalizedPath.replace("src/", "");
612
+ if (srcRelativePath.includes("/")) {
613
+ console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which is in a subdirectory of src/.`);
614
+ console.warn(` libuild only auto-detects top-level src/ files as entrypoints.`);
615
+ console.warn(` Consider moving the file to the top-level src/ directory or use the bin/ directory for executables.`);
616
+ }
617
+ }
494
618
  const basePath = fullPath.replace(/\.(js|cjs|mjs)$/, "");
495
619
  const tsPath = basePath + ".ts";
496
620
  const jsPath = basePath + ".js";
@@ -515,10 +639,19 @@ function transformBinPaths(value) {
515
639
  if (value.startsWith("dist/src/")) {
516
640
  return value.replace("dist/", "");
517
641
  }
642
+ if (value.startsWith("./dist/bin/")) {
643
+ return value.replace("./dist/", "");
644
+ }
645
+ if (value.startsWith("dist/bin/")) {
646
+ return value.replace("dist/", "");
647
+ }
518
648
  if (value.startsWith("./src/")) {
519
649
  return value.replace("./", "");
520
650
  }
521
- if (value.startsWith("src/") || value === "src") {
651
+ if (value.startsWith("./bin/")) {
652
+ return value.replace("./", "");
653
+ }
654
+ if (value.startsWith("src/") || value === "src" || value.startsWith("bin/") || value === "bin") {
522
655
  return value;
523
656
  }
524
657
  return value;
@@ -563,6 +696,60 @@ function fixExportsForDist(obj) {
563
696
  }
564
697
  return obj;
565
698
  }
699
+ async function setExecutablePermissions(filePath) {
700
+ try {
701
+ await FS3.chmod(filePath, 493);
702
+ } catch (error) {
703
+ console.warn(`\u26A0\uFE0F WARNING: Could not set executable permissions for ${filePath}: ${error.message}`);
704
+ }
705
+ }
706
+ async function makeFilesExecutable(pkg, cwd, allBinEntries, runtimeBanner) {
707
+ const filesToMakeExecutable = [];
708
+ const filesToProcessForDualRuntime = [];
709
+ const distDir = Path3.join(cwd, "dist");
710
+ if (pkg.bin) {
711
+ if (typeof pkg.bin === "string") {
712
+ const fullPath = Path3.join(distDir, pkg.bin);
713
+ filesToMakeExecutable.push(fullPath);
714
+ if (pkg.bin.endsWith(".js")) {
715
+ filesToProcessForDualRuntime.push(fullPath);
716
+ }
717
+ } else if (typeof pkg.bin === "object") {
718
+ for (const binPath of Object.values(pkg.bin)) {
719
+ if (typeof binPath === "string") {
720
+ const fullPath = Path3.join(distDir, binPath);
721
+ filesToMakeExecutable.push(fullPath);
722
+ if (binPath.endsWith(".js")) {
723
+ filesToProcessForDualRuntime.push(fullPath);
724
+ }
725
+ }
726
+ }
727
+ }
728
+ }
729
+ const binDirFiles = /* @__PURE__ */ new Set();
730
+ for (const binEntryInfo of allBinEntries) {
731
+ const baseDir = binEntryInfo.source === "src" ? "dist/src/bin" : "dist/bin";
732
+ const jsPath = Path3.join(cwd, baseDir, `${binEntryInfo.name}.js`);
733
+ const cjsPath = Path3.join(cwd, baseDir, `${binEntryInfo.name}.cjs`);
734
+ binDirFiles.add(jsPath);
735
+ if (!filesToMakeExecutable.includes(jsPath)) {
736
+ filesToMakeExecutable.push(jsPath);
737
+ }
738
+ if (!filesToMakeExecutable.includes(cjsPath)) {
739
+ filesToMakeExecutable.push(cjsPath);
740
+ }
741
+ }
742
+ for (const filePath of filesToProcessForDualRuntime) {
743
+ if (await fileExists(filePath) && !binDirFiles.has(filePath)) {
744
+ await processJavaScriptExecutable(filePath, runtimeBanner);
745
+ }
746
+ }
747
+ for (const filePath of filesToMakeExecutable) {
748
+ if (await fileExists(filePath)) {
749
+ await setExecutablePermissions(filePath);
750
+ }
751
+ }
752
+ }
566
753
  async function resolveWorkspaceDependencies(dependencies, cwd) {
567
754
  if (!dependencies)
568
755
  return void 0;
@@ -622,7 +809,7 @@ async function resolveWorkspaceVersion(packageName, workspaceSpec, cwd) {
622
809
  return workspaceSpec;
623
810
  }
624
811
  }
625
- async function cleanPackageJSON(pkg, mainEntry, options, cwd) {
812
+ async function cleanPackageJSON(pkg, mainEntry, options, cwd, distDir) {
626
813
  const cleaned = {
627
814
  name: pkg.name,
628
815
  version: pkg.version
@@ -687,7 +874,13 @@ async function cleanPackageJSON(pkg, mainEntry, options, cwd) {
687
874
  cleaned.main = `src/${mainEntry}.cjs`;
688
875
  }
689
876
  cleaned.module = `src/${mainEntry}.js`;
690
- cleaned.types = `src/${mainEntry}.d.ts`;
877
+ if (distDir) {
878
+ const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
879
+ const exists = await fileExists(dtsPath);
880
+ if (exists) {
881
+ cleaned.types = `src/${mainEntry}.d.ts`;
882
+ }
883
+ }
691
884
  return cleaned;
692
885
  }
693
886
  async function fileExists(filePath) {
@@ -739,9 +932,19 @@ async function build2(cwd, save = false) {
739
932
  console.warn(" Add 'dist/' to your .gitignore file");
740
933
  }
741
934
  }
742
- const entries = await findEntrypoints(srcDir);
743
- if (entries.length === 0) {
744
- throw new Error("No entry points found in src/");
935
+ const binDir = Path3.join(cwd, "bin");
936
+ const srcEntries = await findEntrypoints(srcDir);
937
+ const binEntries = await findBinEntrypoints(binDir);
938
+ const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
939
+ const entries = [
940
+ ...srcEntries,
941
+ ...allBinEntries.map((entry) => `bin/${entry.name}`)
942
+ ];
943
+ if (srcEntries.length === 0 && allBinEntries.length === 0) {
944
+ throw new Error("No entry points found in src/ or bin/");
945
+ }
946
+ if (allBinEntries.length > 0) {
947
+ console.info(` Found bin entries: ${allBinEntries.map((entry) => entry.name).join(", ")}`);
745
948
  }
746
949
  const options = {
747
950
  formats: {
@@ -752,7 +955,7 @@ async function build2(cwd, save = false) {
752
955
  umd: entries.includes("umd")
753
956
  }
754
957
  };
755
- const mainEntry = detectMainEntry(pkg, entries);
958
+ const mainEntry = detectMainEntry(pkg, srcEntries);
756
959
  console.info(" Found entries:", entries.join(", "));
757
960
  console.info(" Main entry:", mainEntry);
758
961
  if (options.formats.cjs) {
@@ -783,11 +986,29 @@ async function build2(cwd, save = false) {
783
986
  const entryPoints = [];
784
987
  const umdEntries = [];
785
988
  for (const entry of entries) {
786
- const entryPath = Path3.join(srcDir, `${entry}.ts`);
787
- const jsEntryPath = Path3.join(srcDir, `${entry}.js`);
989
+ let entryPath;
990
+ let jsEntryPath;
991
+ let sourceDir;
992
+ if (entry.startsWith("bin/")) {
993
+ const binEntryName = entry.replace("bin/", "");
994
+ const binEntryInfo = allBinEntries.find((binEntry) => binEntry.name === binEntryName);
995
+ if (binEntryInfo?.source === "src") {
996
+ entryPath = Path3.join(srcDir, "bin", `${binEntryName}.ts`);
997
+ jsEntryPath = Path3.join(srcDir, "bin", `${binEntryName}.js`);
998
+ sourceDir = "src/bin/";
999
+ } else {
1000
+ entryPath = Path3.join(binDir, `${binEntryName}.ts`);
1001
+ jsEntryPath = Path3.join(binDir, `${binEntryName}.js`);
1002
+ sourceDir = "bin/";
1003
+ }
1004
+ } else {
1005
+ entryPath = Path3.join(srcDir, `${entry}.ts`);
1006
+ jsEntryPath = Path3.join(srcDir, `${entry}.js`);
1007
+ sourceDir = "src/";
1008
+ }
788
1009
  const actualPath = await fileExists(entryPath) ? entryPath : jsEntryPath;
789
1010
  if (!await fileExists(actualPath)) {
790
- throw new Error(`Entry point file not found: ${actualPath}. Expected ${entry}.ts or ${entry}.js in src/ directory.`);
1011
+ throw new Error(`Entry point file not found: ${actualPath}. Expected ${entry.replace("bin/", "")}.ts or ${entry.replace("bin/", "")}.js in ${sourceDir} directory.`);
791
1012
  }
792
1013
  if (entry === "umd") {
793
1014
  umdEntries.push(actualPath);
@@ -795,58 +1016,107 @@ async function build2(cwd, save = false) {
795
1016
  entryPoints.push(actualPath);
796
1017
  }
797
1018
  }
1019
+ const srcEntryPoints = entryPoints.filter((path) => path.includes(srcDir));
1020
+ const binEntryPoints = entryPoints.filter((path) => path.includes(binDir));
1021
+ const distBinDir = Path3.join(distDir, "bin");
1022
+ if (binEntryPoints.length > 0) {
1023
+ await FS3.mkdir(distBinDir, { recursive: true });
1024
+ }
798
1025
  if (entryPoints.length > 0) {
799
- const entryNames = entryPoints.map((path) => {
1026
+ console.info(` Building ${entryPoints.length} entries (ESM)...`);
1027
+ const srcEntryNames = srcEntryPoints.map((path) => {
800
1028
  const name = Path3.basename(path, Path3.extname(path));
801
1029
  return name;
802
1030
  });
803
- console.info(` Building ${entryPoints.length} entries (ESM)...`);
804
- await ESBuild.build({
805
- entryPoints,
806
- outdir: distSrcDir,
807
- format: "esm",
808
- outExtension: { ".js": ".js" },
809
- bundle: true,
810
- minify: false,
811
- sourcemap: false,
812
- external: externalDeps,
813
- platform: "node",
814
- target: "node18",
815
- packages: "external",
816
- supported: { "import-attributes": true },
817
- plugins: [
818
- externalEntrypointsPlugin({
819
- entryNames,
820
- outputExtension: ".js"
821
- }),
822
- dtsPlugin({
823
- outDir: distSrcDir,
824
- rootDir: srcDir,
825
- entryPoints
826
- })
827
- ]
1031
+ const binEntryNames = binEntryPoints.map((path) => {
1032
+ const name = Path3.basename(path, Path3.extname(path));
1033
+ return name;
828
1034
  });
829
- if (options.formats.cjs) {
830
- console.info(` Building ${entryPoints.length} entries (CJS)...`);
1035
+ const allESMEntryPoints = [...srcEntryPoints, ...binEntryPoints];
1036
+ const allEntryNames = [...srcEntryNames, ...binEntryNames];
1037
+ if (allESMEntryPoints.length > 0) {
831
1038
  await ESBuild.build({
832
- entryPoints,
833
- outdir: distSrcDir,
834
- format: "cjs",
835
- outExtension: { ".js": ".cjs" },
1039
+ entryPoints: allESMEntryPoints,
1040
+ outdir: distDir,
1041
+ outbase: cwd,
1042
+ // Preserve src/ and bin/ directory structure
1043
+ format: "esm",
1044
+ outExtension: { ".js": ".js" },
836
1045
  bundle: true,
837
1046
  minify: false,
838
1047
  sourcemap: false,
839
1048
  external: externalDeps,
840
1049
  platform: "node",
841
1050
  target: "node18",
1051
+ packages: "external",
842
1052
  supported: { "import-attributes": true },
843
1053
  plugins: [
844
1054
  externalEntrypointsPlugin({
845
- entryNames,
846
- outputExtension: ".cjs"
847
- })
1055
+ entryNames: allEntryNames,
1056
+ outputExtension: ".js"
1057
+ }),
1058
+ // Generate TypeScript declarations for src entries
1059
+ ...srcEntryPoints.length > 0 ? [dtsPlugin({
1060
+ outDir: distSrcDir,
1061
+ rootDir: srcDir,
1062
+ entryPoints: srcEntryPoints
1063
+ })] : [],
1064
+ // Generate TypeScript declarations for bin entries
1065
+ ...binEntryPoints.length > 0 ? [dtsPlugin({
1066
+ outDir: distBinDir,
1067
+ rootDir: binDir,
1068
+ entryPoints: binEntryPoints
1069
+ })] : []
848
1070
  ]
849
1071
  });
1072
+ if (binEntryPoints.length > 0) {
1073
+ const runtimeBanner = generateRuntimeBanner(pkg);
1074
+ for (const binEntryName of binEntryNames) {
1075
+ const outputPath = Path3.join(distBinDir, `${binEntryName}.js`);
1076
+ await processJavaScriptExecutable(outputPath, runtimeBanner);
1077
+ }
1078
+ }
1079
+ }
1080
+ if (options.formats.cjs) {
1081
+ console.info(` Building ${entryPoints.length} entries (CJS)...`);
1082
+ if (srcEntryPoints.length > 0) {
1083
+ try {
1084
+ await ESBuild.build({
1085
+ entryPoints: srcEntryPoints,
1086
+ outdir: distSrcDir,
1087
+ format: "cjs",
1088
+ outExtension: { ".js": ".cjs" },
1089
+ bundle: true,
1090
+ minify: false,
1091
+ sourcemap: false,
1092
+ external: externalDeps,
1093
+ platform: "node",
1094
+ target: "node18",
1095
+ supported: { "import-attributes": true },
1096
+ plugins: [
1097
+ externalEntrypointsPlugin({
1098
+ entryNames: srcEntryNames,
1099
+ outputExtension: ".cjs"
1100
+ })
1101
+ ]
1102
+ });
1103
+ } catch (error) {
1104
+ const errorMessage = error.message || "";
1105
+ const hasErrorsArray = error.errors && Array.isArray(error.errors);
1106
+ const isTLAError = errorMessage.includes('Top-level await is currently not supported with the "cjs" output format') || hasErrorsArray && error.errors.some((e) => e.text && e.text.includes('Top-level await is currently not supported with the "cjs" output format'));
1107
+ if (isTLAError) {
1108
+ console.info(`
1109
+ \u26A0\uFE0F Top-level await detected - CommonJS generation disabled`);
1110
+ console.info(` Top-level await is incompatible with CommonJS format`);
1111
+ console.info(` Building ESM-only (Node.js 14+ and modern bundlers supported)`);
1112
+ console.info(` To permanently disable CJS: remove "main" field from package.json
1113
+ `);
1114
+ options.formats.cjs = false;
1115
+ } else {
1116
+ throw error;
1117
+ }
1118
+ }
1119
+ }
850
1120
  }
851
1121
  }
852
1122
  for (const umdPath of umdEntries) {
@@ -869,8 +1139,8 @@ async function build2(cwd, save = false) {
869
1139
  }
870
1140
  const autoDiscoveredFiles = [];
871
1141
  console.info(" Generating package.json...");
872
- const cleanedPkg = await cleanPackageJSON(pkg, mainEntry, options, cwd);
873
- const exportsResult = generateExports(entries, mainEntry, options, pkg.exports);
1142
+ const cleanedPkg = await cleanPackageJSON(pkg, mainEntry, options, cwd, distDir);
1143
+ const exportsResult = await generateExports(entries, mainEntry, options, pkg.exports, distDir, allBinEntries);
874
1144
  cleanedPkg.exports = fixExportsForDist(exportsResult.exports);
875
1145
  if (exportsResult.staleExports.length > 0) {
876
1146
  console.warn(`\u26A0\uFE0F WARNING: Found ${exportsResult.staleExports.length} stale export(s) pointing to missing src/ files:`);
@@ -971,7 +1241,10 @@ async function build2(cwd, save = false) {
971
1241
  rootPkg2.main = `./dist/src/${mainEntry}.cjs`;
972
1242
  }
973
1243
  rootPkg2.module = `./dist/src/${mainEntry}.js`;
974
- rootPkg2.types = `./dist/src/${mainEntry}.d.ts`;
1244
+ const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
1245
+ if (await fileExists(dtsPath)) {
1246
+ rootPkg2.types = `./dist/src/${mainEntry}.d.ts`;
1247
+ }
975
1248
  if (rootPkg2.typings && typeof rootPkg2.typings === "string") {
976
1249
  rootPkg2.typings = rootPkg2.typings.startsWith("./dist/") ? rootPkg2.typings : "./" + Path3.join("dist", rootPkg2.typings);
977
1250
  }
@@ -1002,6 +1275,27 @@ async function build2(cwd, save = false) {
1002
1275
  }
1003
1276
  }
1004
1277
  rootPkg2.exports = rootExports;
1278
+ if (allBinEntries.length > 0) {
1279
+ const generatedBin = {};
1280
+ for (const binEntryInfo of allBinEntries) {
1281
+ const binPath = binEntryInfo.source === "src" ? `./dist/src/bin/${binEntryInfo.name}.js` : `./dist/bin/${binEntryInfo.name}.js`;
1282
+ const fullPath = Path3.join(cwd, binPath);
1283
+ if (await fileExists(fullPath)) {
1284
+ generatedBin[binEntryInfo.name] = binPath;
1285
+ }
1286
+ }
1287
+ if (Object.keys(generatedBin).length > 0) {
1288
+ if (rootPkg2.bin) {
1289
+ if (typeof rootPkg2.bin === "string") {
1290
+ const existingName = pkg.name?.split("/").pop() || "cli";
1291
+ rootPkg2.bin = { [existingName]: rootPkg2.bin };
1292
+ }
1293
+ rootPkg2.bin = { ...rootPkg2.bin, ...generatedBin };
1294
+ } else {
1295
+ rootPkg2.bin = generatedBin;
1296
+ }
1297
+ }
1298
+ }
1005
1299
  if (rootPkg2.bin) {
1006
1300
  if (typeof rootPkg2.bin === "string") {
1007
1301
  const distPath = rootPkg2.bin.startsWith("./dist/") ? rootPkg2.bin : rootPkg2.bin.startsWith("dist/") ? "./" + rootPkg2.bin : "./" + Path3.join("dist", rootPkg2.bin);
@@ -1064,6 +1358,10 @@ async function build2(cwd, save = false) {
1064
1358
  if (save) {
1065
1359
  rootPkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
1066
1360
  }
1361
+ if (allBinEntries.length > 0 || fixedDistPkg.bin) {
1362
+ const runtimeBanner = generateRuntimeBanner(pkg);
1363
+ await makeFilesExecutable(fixedDistPkg, cwd, allBinEntries, runtimeBanner);
1364
+ }
1067
1365
  return { distPkg: fixedDistPkg, rootPkg };
1068
1366
  }
1069
1367
  async function publish(cwd, save = true, extraArgs = []) {