@node-cli/bundlecheck 1.6.3 → 1.6.5

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/bundler.js CHANGED
@@ -223,15 +223,59 @@ let usePnpm = null;
223
223
  *
224
224
  * Tested against esbuild 0.27.x error format.
225
225
  *
226
- */ function parseUnresolvedModules(error) {
226
+ */ /**
227
+ * Node.js built-in modules that indicate a package is meant for Node.js.
228
+ * When these fail to resolve during browser bundling, we auto-retry with
229
+ * platform: "node".
230
+ */ const NODE_BUILTIN_MODULES = new Set([
231
+ "assert",
232
+ "buffer",
233
+ "child_process",
234
+ "cluster",
235
+ "crypto",
236
+ "dgram",
237
+ "dns",
238
+ "events",
239
+ "fs",
240
+ "http",
241
+ "http2",
242
+ "https",
243
+ "module",
244
+ "net",
245
+ "os",
246
+ "path",
247
+ "perf_hooks",
248
+ "process",
249
+ "querystring",
250
+ "readline",
251
+ "stream",
252
+ "string_decoder",
253
+ "tls",
254
+ "tty",
255
+ "url",
256
+ "util",
257
+ "v8",
258
+ "vm",
259
+ "worker_threads",
260
+ "zlib"
261
+ ]);
262
+ function parseUnresolvedModules(error) {
227
263
  const result = {
228
264
  hasUnresolvedReact: false,
229
- hasUnresolvedReactDom: false
265
+ hasUnresolvedReactDom: false,
266
+ hasUnresolvedNodeBuiltins: false
230
267
  };
231
268
  /**
232
269
  * Pattern to extract module path from "Could not resolve X" errors. Matches:
233
270
  * Could not resolve "module-name" or Could not resolve 'module-name'.
234
271
  */ const resolveErrorPattern = /Could not resolve ["']([^"']+)["']/;
272
+ /**
273
+ * Check if a module path is a Node.js built-in (with or without "node:" prefix).
274
+ */ const isNodeBuiltin = (modulePath)=>{
275
+ const withoutPrefix = modulePath.startsWith("node:") ? modulePath.slice(5) : modulePath;
276
+ const [root] = withoutPrefix.split("/");
277
+ return NODE_BUILTIN_MODULES.has(root);
278
+ };
235
279
  if (isEsbuildBuildFailure(error)) {
236
280
  // Use structured error objects from esbuild BuildFailure.
237
281
  for (const err of error.errors){
@@ -245,6 +289,9 @@ let usePnpm = null;
245
289
  if (modulePath === "react-dom" || modulePath.startsWith("react-dom/")) {
246
290
  result.hasUnresolvedReactDom = true;
247
291
  }
292
+ if (isNodeBuiltin(modulePath)) {
293
+ result.hasUnresolvedNodeBuiltins = true;
294
+ }
248
295
  }
249
296
  }
250
297
  } else {
@@ -259,6 +306,9 @@ let usePnpm = null;
259
306
  if (modulePath === "react-dom" || modulePath.startsWith("react-dom/")) {
260
307
  result.hasUnresolvedReactDom = true;
261
308
  }
309
+ if (isNodeBuiltin(modulePath)) {
310
+ result.hasUnresolvedNodeBuiltins = true;
311
+ }
262
312
  }
263
313
  }
264
314
  return result;
@@ -561,30 +611,51 @@ let usePnpm = null;
561
611
  * 2. If it fails due to unresolved react imports, auto-add react to externals and retry
562
612
  * This handles packages that don't properly declare react as a peer
563
613
  * dependency.
564
- */ let result;
614
+ */ /**
615
+ * Common esbuild options shared across all build attempts.
616
+ * Native .node addons cannot be bundled by esbuild, so we treat them
617
+ * as empty files to avoid loader errors.
618
+ */ const commonBuildOptions = {
619
+ entryPoints: [
620
+ entryFile
621
+ ],
622
+ bundle: true,
623
+ write: false,
624
+ format: "esm",
625
+ target,
626
+ minify: true,
627
+ treeShaking: true,
628
+ metafile: true,
629
+ loader: {
630
+ ".node": "empty"
631
+ }
632
+ };
633
+ let result;
565
634
  try {
566
635
  result = await esbuild.build({
567
- entryPoints: [
568
- entryFile
569
- ],
570
- bundle: true,
571
- write: false,
572
- format: "esm",
636
+ ...commonBuildOptions,
573
637
  platform,
574
- target,
575
- minify: true,
576
- treeShaking: true,
577
638
  external: esbuildExternals,
578
- metafile: true,
579
639
  logLevel: "silent"
580
640
  });
581
641
  } catch (error) {
582
642
  /**
583
643
  * Parse unresolved module errors using esbuild's structured error format.
584
644
  * This handles packages that don't properly declare react as a peer
585
- * dependency.
586
- */ const { hasUnresolvedReact, hasUnresolvedReactDom } = parseUnresolvedModules(error);
587
- if (!noExternal && (hasUnresolvedReact || hasUnresolvedReactDom)) {
645
+ * dependency, and Node.js packages incorrectly bundled for the browser.
646
+ */ const { hasUnresolvedReact, hasUnresolvedReactDom, hasUnresolvedNodeBuiltins } = parseUnresolvedModules(error);
647
+ if (hasUnresolvedNodeBuiltins && platform === "browser" && !explicitPlatform) {
648
+ /**
649
+ * Node.js built-in modules failed to resolve during browser bundling.
650
+ * This means the package is a Node.js package that wasn't detected by
651
+ * the engines-based auto-detection. Retry with platform: "node".
652
+ */ platform = "node";
653
+ result = await esbuild.build({
654
+ ...commonBuildOptions,
655
+ platform,
656
+ external: esbuildExternals
657
+ });
658
+ } else if (!noExternal && (hasUnresolvedReact || hasUnresolvedReactDom)) {
588
659
  // Auto-add react and/or react-dom to externals and retry.
589
660
  const autoExternals = [];
590
661
  if (hasUnresolvedReact && !externals.includes("react")) {
@@ -600,18 +671,9 @@ let usePnpm = null;
600
671
  ];
601
672
  esbuildExternals = expandExternalsForEsbuild(externals);
602
673
  result = await esbuild.build({
603
- entryPoints: [
604
- entryFile
605
- ],
606
- bundle: true,
607
- write: false,
608
- format: "esm",
674
+ ...commonBuildOptions,
609
675
  platform,
610
- target,
611
- minify: true,
612
- treeShaking: true,
613
- external: esbuildExternals,
614
- metafile: true
676
+ external: esbuildExternals
615
677
  });
616
678
  } else {
617
679
  throw error;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bundler.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport zlib from \"node:zlib\";\nimport * as esbuild from \"esbuild\";\nimport {\n\tBROWSER_FRAMEWORK_DEPS,\n\tDEFAULT_EXTERNALS,\n\tDEFAULT_TARGET,\n\tEXTERNAL_SUBPATHS,\n} from \"./defaults.js\";\nimport { getNamedExports } from \"./exports.js\";\n\nconst gzipAsync = promisify(zlib.gzip);\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegExp(str: string): string {\n\treturn str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport type ParsedPackage = {\n\tname: string;\n\tversion: string;\n\tsubpath?: string;\n};\n\n/**\n * Parse a package specifier to extract name, version, and subpath.\n * Handles:\n * - @scope/package@1.0.0\n * - @scope/package/subpath@1.0.0\n * - @scope/package/subpath\n * - package/subpath@1.0.0\n */\nexport function parsePackageSpecifier(specifier: string): ParsedPackage {\n\tlet workingSpec = specifier;\n\tlet version = \"latest\";\n\n\t// Handle scoped packages (@scope/name...)\n\tif (workingSpec.startsWith(\"@\")) {\n\t\t// Find the second @ which would separate version.\n\t\tconst secondAtIndex = workingSpec.indexOf(\"@\", 1);\n\t\tif (secondAtIndex !== -1) {\n\t\t\tversion = workingSpec.substring(secondAtIndex + 1);\n\t\t\tworkingSpec = workingSpec.substring(0, secondAtIndex);\n\t\t}\n\n\t\t/**\n\t\t * Now workingSpec is like @scope/name or @scope/name/subpath Split by / and\n\t\t * check if there are more than 2 parts.\n\t\t */\n\t\tconst parts = workingSpec.split(\"/\");\n\t\tif (parts.length > 2) {\n\t\t\t// Has subpath: @scope/name/subpath/more.\n\t\t\tconst name = `${parts[0]}/${parts[1]}`;\n\t\t\tconst subpath = parts.slice(2).join(\"/\");\n\t\t\treturn { name, version, subpath };\n\t\t}\n\t\t// No subpath: @scope/name.\n\t\treturn { name: workingSpec, version };\n\t}\n\n\t// Handle non-scoped packages (name@version or name/subpath@version).\n\tconst atIndex = workingSpec.indexOf(\"@\");\n\tif (atIndex !== -1) {\n\t\tversion = workingSpec.substring(atIndex + 1);\n\t\tworkingSpec = workingSpec.substring(0, atIndex);\n\t}\n\n\t// Check for subpath in non-scoped packages.\n\tconst slashIndex = workingSpec.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst name = workingSpec.substring(0, slashIndex);\n\t\tconst subpath = workingSpec.substring(slashIndex + 1);\n\t\treturn { name, version, subpath };\n\t}\n\n\treturn { name: workingSpec, version };\n}\n\nexport type BundleOptions = {\n\tpackageName: string;\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tregistry?: string;\n\t/**\n\t * Target platform. If undefined, auto-detects from package.json engines.\n\t */\n\tplatform?: \"browser\" | \"node\";\n\t/**\n\t * esbuild target (e.g., \"es2022\", \"es2020\"). Defaults to \"es2022\".\n\t */\n\ttarget?: string;\n};\n\nexport type BundleResult = {\n\tpackageName: string;\n\tpackageVersion: string;\n\texports: string[];\n\trawSize: number;\n\t/**\n\t * Gzip size in bytes, or null for node platform (gzip not applicable).\n\t */\n\tgzipSize: number | null;\n\tgzipLevel: number;\n\texternals: string[];\n\tdependencies: string[];\n\tplatform: \"browser\" | \"node\";\n\t/**\n\t * Total number of named exports in the package (when analyzing entire\n\t * package).\n\t */\n\tnamedExportCount: number;\n};\n\n/**\n * Format bytes to human-readable string.\n */\nexport function formatBytes(bytes: number): string {\n\tif (bytes === 0) {\n\t\treturn \"0 B\";\n\t}\n\tconst k = 1024;\n\tconst sizes = [\"B\", \"kB\", \"MB\", \"GB\"];\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\treturn `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;\n}\n\n/**\n * Create a temporary directory for bundling.\n */\nfunction createTempDir(): string {\n\tconst tmpDir = path.join(os.tmpdir(), `bundlecheck-${Date.now()}`);\n\tfs.mkdirSync(tmpDir, { recursive: true });\n\treturn tmpDir;\n}\n\n/**\n * Clean up temporary directory.\n */\nfunction cleanupTempDir(tmpDir: string): void {\n\ttry {\n\t\tfs.rmSync(tmpDir, { recursive: true, force: true });\n\t} catch {\n\t\t// Ignore cleanup errors.\n\t}\n}\n\n/**\n * Check if pnpm is available.\n */\nfunction isPnpmAvailable(): boolean {\n\ttry {\n\t\texecSync(\"pnpm --version\", { stdio: \"pipe\" });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Cache the result of pnpm availability check.\nlet usePnpm: boolean | null = null;\n\n/**\n * Validate and sanitize a registry URL to prevent command injection.\n * @param registry - The registry URL to validate\n * @returns The sanitized URL or undefined if invalid\n * @throws Error if the URL is invalid or contains potentially malicious characters\n */\nfunction validateRegistryUrl(registry: string): string {\n\t// Parse as URL to validate format.\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(registry);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL: ${registry}. Must be a valid URL (e.g., https://registry.example.com)`,\n\t\t);\n\t}\n\n\t// Only allow http and https protocols.\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL protocol: ${url.protocol}. Only http: and https: are allowed`,\n\t\t);\n\t}\n\n\t// Return the sanitized URL (URL constructor normalizes it).\n\treturn url.toString();\n}\n\n/**\n * Get the install command (pnpm preferred, npm fallback).\n * @param registry - Optional custom npm registry URL\n */\nfunction getInstallCommand(registry?: string): string {\n\tif (usePnpm === null) {\n\t\tusePnpm = isPnpmAvailable();\n\t}\n\n\tlet registryArg = \"\";\n\tif (registry) {\n\t\t// Validate and sanitize the registry URL to prevent command injection.\n\t\tconst sanitizedRegistry = validateRegistryUrl(registry);\n\t\t// Quote the URL to handle any special characters safely.\n\t\tregistryArg = ` --registry \"${sanitizedRegistry}\"`;\n\t}\n\n\tif (usePnpm) {\n\t\treturn `pnpm install --ignore-scripts --no-frozen-lockfile${registryArg}`;\n\t}\n\treturn `npm install --legacy-peer-deps --ignore-scripts${registryArg}`;\n}\n\nexport type EntryContentOptions = {\n\tpackageName: string;\n\tsubpath?: string;\n\texports?: string[];\n\tallSubpaths?: string[];\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Generate the entry file content based on package, subpath, and exports.\n */\nfunction generateEntryContent(options: EntryContentOptions): string {\n\tconst { packageName, subpath, exports, allSubpaths, exportToSubpath } =\n\t\toptions;\n\n\t// If we have exports mapped to different subpaths.\n\tif (exportToSubpath && exportToSubpath.size > 0) {\n\t\t// Group exports by subpath.\n\t\tconst subpathToExports = new Map<string, string[]>();\n\t\tfor (const [exportName, sp] of exportToSubpath) {\n\t\t\tconst existing = subpathToExports.get(sp) || [];\n\t\t\texisting.push(exportName);\n\t\t\tsubpathToExports.set(sp, existing);\n\t\t}\n\n\t\t// Generate imports for each subpath.\n\t\tconst lines: string[] = [];\n\t\tconst allExportNames: string[] = [];\n\n\t\tfor (const [sp, exportNames] of subpathToExports) {\n\t\t\tconst importPath = `${packageName}/${sp}`;\n\t\t\tconst names = exportNames.join(\", \");\n\t\t\tlines.push(`import { ${names} } from \"${importPath}\";`);\n\t\t\tallExportNames.push(...exportNames);\n\t\t}\n\n\t\tlines.push(`export { ${allExportNames.join(\", \")} };`);\n\t\treturn lines.join(\"\\n\") + \"\\n\";\n\t}\n\n\t// If we have specific exports to import.\n\tif (exports && exports.length > 0) {\n\t\t// Determine the import path.\n\t\tconst importPath = subpath ? `${packageName}/${subpath}` : packageName;\n\t\tconst importNames = exports.join(\", \");\n\t\treturn `import { ${importNames} } from \"${importPath}\";\\nexport { ${importNames} };\\n`;\n\t}\n\n\t// If we have a specific subpath (but no specific exports).\n\tif (subpath) {\n\t\tconst importPath = `${packageName}/${subpath}`;\n\t\treturn `import * as pkg from \"${importPath}\";\\nexport default pkg;\\n`;\n\t}\n\n\t// If package has subpath exports only (no main entry), import all subpaths.\n\tif (allSubpaths && allSubpaths.length > 0) {\n\t\tconst imports = allSubpaths\n\t\t\t.map(\n\t\t\t\t(sp, i) =>\n\t\t\t\t\t`import * as sub${i} from \"${packageName}/${sp}\";\\nexport { sub${i} };`,\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t\treturn imports + \"\\n\";\n\t}\n\n\t// Default: import everything from main entry.\n\treturn `import * as pkg from \"${packageName}\";\\nexport default pkg;\\n`;\n}\n\n/**\n * Check if an error is an esbuild BuildFailure. BuildFailure has an `errors`\n * array with structured error objects.\n */\nfunction isEsbuildBuildFailure(\n\terror: unknown,\n): error is { errors: Array<{ text: string; location?: unknown }> } {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t\"errors\" in error &&\n\t\tArray.isArray((error as { errors: unknown }).errors)\n\t);\n}\n\n/**\n * Extract unresolved module paths from an esbuild BuildFailure error. Returns\n * an object indicating which react-related modules failed to resolve.\n *\n * Uses esbuild's structured error objects (errors array) for reliable parsing.\n * Falls back to string matching if the error format is unexpected.\n *\n * Tested against esbuild 0.27.x error format.\n *\n */\nfunction parseUnresolvedModules(error: unknown): {\n\thasUnresolvedReact: boolean;\n\thasUnresolvedReactDom: boolean;\n} {\n\tconst result = { hasUnresolvedReact: false, hasUnresolvedReactDom: false };\n\n\t/**\n\t * Pattern to extract module path from \"Could not resolve X\" errors. Matches:\n\t * Could not resolve \"module-name\" or Could not resolve 'module-name'.\n\t */\n\tconst resolveErrorPattern = /Could not resolve [\"']([^\"']+)[\"']/;\n\n\tif (isEsbuildBuildFailure(error)) {\n\t\t// Use structured error objects from esbuild BuildFailure.\n\t\tfor (const err of error.errors) {\n\t\t\tconst match = resolveErrorPattern.exec(err.text);\n\t\t\tif (match) {\n\t\t\t\tconst modulePath = match[1];\n\t\t\t\t// Check if it's a react or react-dom import (including subpaths).\n\t\t\t\tif (modulePath === \"react\" || modulePath.startsWith(\"react/\")) {\n\t\t\t\t\tresult.hasUnresolvedReact = true;\n\t\t\t\t}\n\t\t\t\tif (modulePath === \"react-dom\" || modulePath.startsWith(\"react-dom/\")) {\n\t\t\t\t\tresult.hasUnresolvedReactDom = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Fallback: parse error message string (less reliable).\n\t\tconst errorMessage = String(error);\n\t\tconst matches = errorMessage.matchAll(\n\t\t\t/Could not resolve [\"']([^\"']+)[\"']/g,\n\t\t);\n\t\tfor (const match of matches) {\n\t\t\tconst modulePath = match[1];\n\t\t\tif (modulePath === \"react\" || modulePath.startsWith(\"react/\")) {\n\t\t\t\tresult.hasUnresolvedReact = true;\n\t\t\t}\n\t\t\tif (modulePath === \"react-dom\" || modulePath.startsWith(\"react-dom/\")) {\n\t\t\t\tresult.hasUnresolvedReactDom = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Get externals list based on options and package dependencies. react and\n * react-dom are only marked as external if they are declared in the package's\n * dependencies or peerDependencies.\n *\n * Returns the base package names (e.g., [\"react\", \"react-dom\"]) for display\n * purposes.\n *\n */\nexport function getExternals(\n\tpackageName: string,\n\texternals?: string[],\n\tnoExternal?: boolean,\n\tpackageDependencies?: string[],\n): string[] {\n\tif (noExternal) {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Start with empty result - we'll only add react/react-dom if they're in\n\t * package deps.\n\t */\n\tlet result: string[] = [];\n\n\t/**\n\t * Only include react/react-dom if they're in the package's dependencies or\n\t * peerDependencies.\n\t */\n\tif (packageDependencies && packageDependencies.length > 0) {\n\t\tfor (const dep of DEFAULT_EXTERNALS) {\n\t\t\t// Don't mark as external if we're checking the package itself.\n\t\t\tif (dep === packageName) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (packageDependencies.includes(dep)) {\n\t\t\t\tresult.push(dep);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add any additional externals.\n\tif (externals && externals.length > 0) {\n\t\tresult = [...new Set([...result, ...externals])];\n\t}\n\n\treturn result;\n}\n\n/**\n * Expand externals to include subpaths for esbuild. For example, \"react\"\n * expands to [\"react\", \"react/jsx-runtime\", \"react/jsx-dev-runtime\"]. This is\n * needed because esbuild doesn't automatically externalize subpaths.\n */\nexport function expandExternalsForEsbuild(externals: string[]): string[] {\n\tconst expanded: string[] = [];\n\n\tfor (const ext of externals) {\n\t\texpanded.push(ext);\n\t\t// Add subpaths if this is a known package with subpath exports.\n\t\tconst subpaths = EXTERNAL_SUBPATHS[ext];\n\t\tif (subpaths) {\n\t\t\texpanded.push(...subpaths);\n\t\t}\n\t}\n\n\treturn [...new Set(expanded)];\n}\n\nexport type PackageExports = Record<\n\tstring,\n\tstring | { import?: string; types?: string }\n>;\n\nexport type PackageInfo = {\n\tversion: string;\n\tdependencies: Record<string, string>;\n\tpeerDependencies: Record<string, string>;\n\texports: PackageExports | null;\n\thasMainEntry: boolean;\n\tengines: Record<string, string> | null;\n};\n\n/**\n * Get version, dependencies, peer dependencies, and exports from an installed\n * package.\n */\nfunction getPackageInfo(tmpDir: string, packageName: string): PackageInfo {\n\ttry {\n\t\t// Handle scoped packages - the package name in node_modules.\n\t\tconst pkgJsonPath = path.join(\n\t\t\ttmpDir,\n\t\t\t\"node_modules\",\n\t\t\tpackageName,\n\t\t\t\"package.json\",\n\t\t);\n\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\tconst pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\n\t\t\t// Check if package has a main entry point.\n\t\t\tconst hasMainEntry = Boolean(\n\t\t\t\tpkgJson.main ||\n\t\t\t\t\tpkgJson.module ||\n\t\t\t\t\tpkgJson.exports?.[\".\"] ||\n\t\t\t\t\tpkgJson.exports?.[\"./index\"] ||\n\t\t\t\t\t(!pkgJson.exports && !pkgJson.main && !pkgJson.module),\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tversion: pkgJson.version || \"unknown\",\n\t\t\t\tdependencies: pkgJson.dependencies || {},\n\t\t\t\tpeerDependencies: pkgJson.peerDependencies || {},\n\t\t\t\texports: pkgJson.exports || null,\n\t\t\t\thasMainEntry,\n\t\t\t\tengines: pkgJson.engines || null,\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// Ignore errors reading package info.\n\t}\n\treturn {\n\t\tversion: \"unknown\",\n\t\tdependencies: {},\n\t\tpeerDependencies: {},\n\t\texports: null,\n\t\thasMainEntry: true,\n\t\tengines: null,\n\t};\n}\n\n/**\n * Extract subpath export names from package exports field Returns array of\n * subpaths like [\"header\", \"body\", \"datagrid\"].\n */\nfunction getSubpathExports(exports: PackageExports | null): string[] {\n\tif (!exports) {\n\t\treturn [];\n\t}\n\n\tconst subpaths: string[] = [];\n\tfor (const key of Object.keys(exports)) {\n\t\t// Skip the main entry point and package.json.\n\t\tif (key === \".\" || key === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\t\t// Remove leading \"./\" to get subpath name.\n\t\tif (key.startsWith(\"./\")) {\n\t\t\tsubpaths.push(key.substring(2));\n\t\t}\n\t}\n\treturn subpaths;\n}\n\n/**\n * Result of finding subpaths for exports.\n */\ntype SubpathMapping = {\n\t// Single subpath if all exports are from the same subpath.\n\tsingleSubpath?: string;\n\t// Map of export name to subpath for multiple subpaths.\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Find which subpath(s) export the given component names Reads type definition\n * files or JS files to find the exports.\n */\nfunction findSubpathsForExports(\n\ttmpDir: string,\n\tpackageName: string,\n\texports: PackageExports,\n\tcomponentNames: string[],\n): SubpathMapping {\n\tconst packageDir = path.join(tmpDir, \"node_modules\", packageName);\n\tconst exportToSubpath = new Map<string, string>();\n\n\tfor (const [subpathKey, subpathValue] of Object.entries(exports)) {\n\t\t// Skip main entry and package.json.\n\t\tif (subpathKey === \".\" || subpathKey === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Get the types or import path.\n\t\tlet filePath: string | undefined;\n\t\tif (typeof subpathValue === \"object\" && subpathValue !== null) {\n\t\t\t// Prefer types file for more accurate export detection.\n\t\t\tfilePath = subpathValue.types || subpathValue.import;\n\t\t} else if (typeof subpathValue === \"string\") {\n\t\t\tfilePath = subpathValue;\n\t\t}\n\n\t\tif (!filePath) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve the file path.\n\t\tconst fullPath = path.join(packageDir, filePath);\n\n\t\ttry {\n\t\t\tif (fs.existsSync(fullPath)) {\n\t\t\t\tconst content = fs.readFileSync(fullPath, \"utf-8\");\n\t\t\t\tconst subpath = subpathKey.startsWith(\"./\")\n\t\t\t\t\t? subpathKey.substring(2)\n\t\t\t\t\t: subpathKey;\n\n\t\t\t\t// Check each component name.\n\t\t\t\tfor (const name of componentNames) {\n\t\t\t\t\t// Skip if already found.\n\t\t\t\t\tif (exportToSubpath.has(name)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Escape regex special characters in the name to prevent injection.\n\t\t\t\t\tconst escapedName = escapeRegExp(name);\n\n\t\t\t\t\t// Look for various export patterns.\n\t\t\t\t\tconst patterns = [\n\t\t\t\t\t\tnew RegExp(`export\\\\s*\\\\{[^}]*\\\\b${escapedName}\\\\b[^}]*\\\\}`, \"m\"),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+declare\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t];\n\n\t\t\t\t\tif (patterns.some((pattern) => pattern.test(content))) {\n\t\t\t\t\t\texportToSubpath.set(name, subpath);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors, continue to next subpath.\n\t\t}\n\t}\n\n\t// Check if all exports were found.\n\tif (exportToSubpath.size !== componentNames.length) {\n\t\treturn {}; // Not all exports found\n\t}\n\n\t// Check if all exports are from the same subpath.\n\tconst subpaths = new Set(exportToSubpath.values());\n\tif (subpaths.size === 1) {\n\t\treturn { singleSubpath: [...subpaths][0] };\n\t}\n\n\t// Multiple subpaths needed.\n\treturn { exportToSubpath };\n}\n\n/**\n * Check the bundle size of an npm package.\n */\nexport async function checkBundleSize(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tpackageName: packageSpecifier,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel = 5,\n\t\tregistry,\n\t\tplatform: explicitPlatform,\n\t\ttarget = DEFAULT_TARGET,\n\t} = options;\n\n\t// Parse the package specifier to extract name, version, and subpath.\n\tconst {\n\t\tname: packageName,\n\t\tversion: requestedVersion,\n\t\tsubpath,\n\t} = parsePackageSpecifier(packageSpecifier);\n\n\tconst tmpDir = createTempDir();\n\n\ttry {\n\t\t// Create initial package.json.\n\t\tconst packageJson: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\ttype: string;\n\t\t\tdependencies: Record<string, string>;\n\t\t} = {\n\t\t\tname: \"bundlecheck-temp\",\n\t\t\tversion: \"1.0.0\",\n\t\t\ttype: \"module\",\n\t\t\tdependencies: {\n\t\t\t\t[packageName]: requestedVersion,\n\t\t\t},\n\t\t};\n\n\t\tfs.writeFileSync(\n\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t);\n\n\t\t// Install the main package (try pnpm first, fallback to npm).\n\t\tconst installCmd = getInstallCommand(registry);\n\t\texecSync(installCmd, {\n\t\t\tcwd: tmpDir,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\n\t\t/**\n\t\t * Get package info (version, dependencies, peer dependencies, exports,\n\t\t * engines).\n\t\t */\n\t\tconst pkgInfo = getPackageInfo(tmpDir, packageName);\n\t\tconst peerDepKeys = Object.keys(pkgInfo.peerDependencies);\n\n\t\t/**\n\t\t * Determine platform: use explicit value if provided, otherwise auto-detect\n\t\t * from engines.\n\t\t */\n\t\tlet platform: \"browser\" | \"node\" = \"browser\";\n\t\tif (explicitPlatform) {\n\t\t\tplatform = explicitPlatform;\n\t\t} else if (pkgInfo.engines?.node && !pkgInfo.engines?.browser) {\n\t\t\t/**\n\t\t\t * Package specifies node engine without browser - potentially a Node.js\n\t\t\t * package. However, many browser packages also specify engines.node for\n\t\t\t * build tooling or SSR compatibility (e.g., @clerk/clerk-react). Check\n\t\t\t * if the package has browser-framework dependencies which indicate it's\n\t\t\t * a browser package despite having engines.node.\n\t\t\t */\n\t\t\tconst allDepNames = [\n\t\t\t\t...Object.keys(pkgInfo.dependencies),\n\t\t\t\t...Object.keys(pkgInfo.peerDependencies),\n\t\t\t];\n\t\t\tconst hasBrowserFrameworkDep = allDepNames.some((dep) =>\n\t\t\t\tBROWSER_FRAMEWORK_DEPS.includes(dep),\n\t\t\t);\n\t\t\tif (!hasBrowserFrameworkDep) {\n\t\t\t\tplatform = \"node\";\n\t\t\t}\n\t\t}\n\n\t\t// Collect all dependency names (prod + peer).\n\t\tconst allDependencies = [\n\t\t\t...new Set([...Object.keys(pkgInfo.dependencies), ...peerDepKeys]),\n\t\t].sort();\n\n\t\tif (peerDepKeys.length > 0) {\n\t\t\t// Add peer dependencies to package.json.\n\t\t\tfor (const dep of peerDepKeys) {\n\t\t\t\t// Use the version range from peer dependencies.\n\t\t\t\tpackageJson.dependencies[dep] = pkgInfo.peerDependencies[dep];\n\t\t\t}\n\n\t\t\t// Update package.json and reinstall.\n\t\t\tfs.writeFileSync(\n\t\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t\t);\n\n\t\t\texecSync(installCmd, {\n\t\t\t\tcwd: tmpDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * Determine if we need to use all subpath exports or find the right\n\t\t * subpath(s).\n\t\t */\n\t\tlet allSubpaths: string[] | undefined;\n\t\tlet resolvedSubpath = subpath;\n\t\tlet exportToSubpath: Map<string, string> | undefined;\n\n\t\tif (!subpath && !pkgInfo.hasMainEntry && pkgInfo.exports) {\n\t\t\tif (exports && exports.length > 0) {\n\t\t\t\t// User specified exports but no subpath - try to find the right subpath(s).\n\t\t\t\tconst mapping = findSubpathsForExports(\n\t\t\t\t\ttmpDir,\n\t\t\t\t\tpackageName,\n\t\t\t\t\tpkgInfo.exports,\n\t\t\t\t\texports,\n\t\t\t\t);\n\n\t\t\t\tif (mapping.singleSubpath) {\n\t\t\t\t\t// All exports from the same subpath.\n\t\t\t\t\tresolvedSubpath = mapping.singleSubpath;\n\t\t\t\t} else if (mapping.exportToSubpath) {\n\t\t\t\t\t// Exports from multiple subpaths.\n\t\t\t\t\texportToSubpath = mapping.exportToSubpath;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If still no subpath resolved and no mapping, bundle all subpaths.\n\t\t\tif (!resolvedSubpath && !exportToSubpath) {\n\t\t\t\tallSubpaths = getSubpathExports(pkgInfo.exports);\n\t\t\t}\n\t\t}\n\n\t\t// Create entry file with appropriate content.\n\t\tconst entryContent = generateEntryContent({\n\t\t\tpackageName,\n\t\t\tsubpath: resolvedSubpath,\n\t\t\texports,\n\t\t\tallSubpaths,\n\t\t\texportToSubpath,\n\t\t});\n\t\tconst entryFile = path.join(tmpDir, \"entry.js\");\n\t\tfs.writeFileSync(entryFile, entryContent);\n\n\t\t/**\n\t\t * Get externals based on package dependencies. Only include react/react-dom\n\t\t * if they're in the package's dependencies or peerDependencies.\n\t\t */\n\t\tlet externals = getExternals(\n\t\t\tpackageName,\n\t\t\tadditionalExternals,\n\t\t\tnoExternal,\n\t\t\tallDependencies,\n\t\t);\n\n\t\t/**\n\t\t * Expand externals to include subpaths for esbuild.\n\t\t * e.g., \"react\" -> [\"react\", \"react/jsx-runtime\", \"react/jsx-dev-runtime\"]\n\t\t */\n\t\tlet esbuildExternals = expandExternalsForEsbuild(externals);\n\n\t\t/**\n\t\t * Bundle with esbuild. We use a two-phase approach:\n\t\t * 1. First attempt with logLevel: \"silent\" to suppress errors\n\t\t * 2. If it fails due to unresolved react imports, auto-add react to externals and retry\n\t\t * This handles packages that don't properly declare react as a peer\n\t\t * dependency.\n\t\t */\n\t\tlet result: esbuild.BuildResult<{ write: false; metafile: true }>;\n\t\ttry {\n\t\t\tresult = await esbuild.build({\n\t\t\t\tentryPoints: [entryFile],\n\t\t\t\tbundle: true,\n\t\t\t\twrite: false,\n\t\t\t\tformat: \"esm\",\n\t\t\t\tplatform,\n\t\t\t\ttarget,\n\t\t\t\tminify: true,\n\t\t\t\ttreeShaking: true,\n\t\t\t\texternal: esbuildExternals,\n\t\t\t\tmetafile: true,\n\t\t\t\tlogLevel: \"silent\", // Suppress errors on first attempt (will retry if needed)\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t/**\n\t\t\t * Parse unresolved module errors using esbuild's structured error format.\n\t\t\t * This handles packages that don't properly declare react as a peer\n\t\t\t * dependency.\n\t\t\t */\n\t\t\tconst { hasUnresolvedReact, hasUnresolvedReactDom } =\n\t\t\t\tparseUnresolvedModules(error);\n\n\t\t\tif (!noExternal && (hasUnresolvedReact || hasUnresolvedReactDom)) {\n\t\t\t\t// Auto-add react and/or react-dom to externals and retry.\n\t\t\t\tconst autoExternals: string[] = [];\n\t\t\t\tif (hasUnresolvedReact && !externals.includes(\"react\")) {\n\t\t\t\t\tautoExternals.push(\"react\");\n\t\t\t\t}\n\t\t\t\tif (hasUnresolvedReactDom && !externals.includes(\"react-dom\")) {\n\t\t\t\t\tautoExternals.push(\"react-dom\");\n\t\t\t\t}\n\n\t\t\t\tif (autoExternals.length > 0) {\n\t\t\t\t\texternals = [...externals, ...autoExternals];\n\t\t\t\t\tesbuildExternals = expandExternalsForEsbuild(externals);\n\n\t\t\t\t\tresult = await esbuild.build({\n\t\t\t\t\t\tentryPoints: [entryFile],\n\t\t\t\t\t\tbundle: true,\n\t\t\t\t\t\twrite: false,\n\t\t\t\t\t\tformat: \"esm\",\n\t\t\t\t\t\tplatform,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tminify: true,\n\t\t\t\t\t\ttreeShaking: true,\n\t\t\t\t\t\texternal: esbuildExternals,\n\t\t\t\t\t\tmetafile: true,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// Get raw size.\n\t\tconst bundleContent = result.outputFiles[0].contents;\n\t\tconst rawSize = bundleContent.length;\n\n\t\t// Gzip the bundle (only for browser platform - not relevant for Node.js).\n\t\tlet gzipSize: number | null = null;\n\t\tif (platform === \"browser\") {\n\t\t\tconst gzipped = await gzipAsync(Buffer.from(bundleContent), {\n\t\t\t\tlevel: gzipLevel,\n\t\t\t});\n\t\t\tgzipSize = gzipped.length;\n\t\t}\n\n\t\t// Determine the display name.\n\t\tlet displayName = packageName;\n\t\tif (resolvedSubpath) {\n\t\t\tdisplayName = `${packageName}/${resolvedSubpath}`;\n\t\t} else if (exportToSubpath && exportToSubpath.size > 0) {\n\t\t\t// Multiple subpaths - show them all.\n\t\t\tconst uniqueSubpaths = [...new Set(exportToSubpath.values())].sort();\n\t\t\tdisplayName = `${packageName}/{${uniqueSubpaths.join(\", \")}}`;\n\t\t}\n\n\t\t/**\n\t\t * Get named export count from the package's type definitions. Use\n\t\t * runtimeCount to exclude type-only exports (types, interfaces).\n\t\t */\n\t\tconst { runtimeCount: namedExportCount } = getNamedExports(\n\t\t\ttmpDir,\n\t\t\tpackageName,\n\t\t);\n\n\t\treturn {\n\t\t\tpackageName: displayName,\n\t\t\tpackageVersion: pkgInfo.version,\n\t\t\texports: exports || [],\n\t\t\trawSize,\n\t\t\tgzipSize,\n\t\t\tgzipLevel,\n\t\t\texternals,\n\t\t\tdependencies: allDependencies,\n\t\t\tplatform,\n\t\t\tnamedExportCount,\n\t\t};\n\t} finally {\n\t\tcleanupTempDir(tmpDir);\n\t}\n}\n"],"names":["execSync","fs","os","path","promisify","zlib","esbuild","BROWSER_FRAMEWORK_DEPS","DEFAULT_EXTERNALS","DEFAULT_TARGET","EXTERNAL_SUBPATHS","getNamedExports","gzipAsync","gzip","escapeRegExp","str","replace","parsePackageSpecifier","specifier","workingSpec","version","startsWith","secondAtIndex","indexOf","substring","parts","split","length","name","subpath","slice","join","atIndex","slashIndex","formatBytes","bytes","k","sizes","i","Math","floor","log","Number","parseFloat","toFixed","createTempDir","tmpDir","tmpdir","Date","now","mkdirSync","recursive","cleanupTempDir","rmSync","force","isPnpmAvailable","stdio","usePnpm","validateRegistryUrl","registry","url","URL","Error","protocol","toString","getInstallCommand","registryArg","sanitizedRegistry","generateEntryContent","options","packageName","exports","allSubpaths","exportToSubpath","size","subpathToExports","Map","exportName","sp","existing","get","push","set","lines","allExportNames","exportNames","importPath","names","importNames","imports","map","isEsbuildBuildFailure","error","Array","isArray","errors","parseUnresolvedModules","result","hasUnresolvedReact","hasUnresolvedReactDom","resolveErrorPattern","err","match","exec","text","modulePath","errorMessage","String","matches","matchAll","getExternals","externals","noExternal","packageDependencies","dep","includes","Set","expandExternalsForEsbuild","expanded","ext","subpaths","getPackageInfo","pkgJsonPath","existsSync","pkgJson","JSON","parse","readFileSync","hasMainEntry","Boolean","main","module","dependencies","peerDependencies","engines","getSubpathExports","key","Object","keys","findSubpathsForExports","componentNames","packageDir","subpathKey","subpathValue","entries","filePath","types","import","fullPath","content","has","escapedName","patterns","RegExp","some","pattern","test","values","singleSubpath","checkBundleSize","packageSpecifier","additionalExternals","gzipLevel","platform","explicitPlatform","target","requestedVersion","packageJson","type","writeFileSync","stringify","installCmd","cwd","pkgInfo","peerDepKeys","node","browser","allDepNames","hasBrowserFrameworkDep","allDependencies","sort","resolvedSubpath","mapping","entryContent","entryFile","esbuildExternals","build","entryPoints","bundle","write","format","minify","treeShaking","external","metafile","logLevel","autoExternals","bundleContent","outputFiles","contents","rawSize","gzipSize","gzipped","Buffer","from","level","displayName","uniqueSubpaths","runtimeCount","namedExportCount","packageVersion"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/bundler.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport zlib from \"node:zlib\";\nimport * as esbuild from \"esbuild\";\nimport {\n\tBROWSER_FRAMEWORK_DEPS,\n\tDEFAULT_EXTERNALS,\n\tDEFAULT_TARGET,\n\tEXTERNAL_SUBPATHS,\n} from \"./defaults.js\";\nimport { getNamedExports } from \"./exports.js\";\n\nconst gzipAsync = promisify(zlib.gzip);\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegExp(str: string): string {\n\treturn str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport type ParsedPackage = {\n\tname: string;\n\tversion: string;\n\tsubpath?: string;\n};\n\n/**\n * Parse a package specifier to extract name, version, and subpath.\n * Handles:\n * - @scope/package@1.0.0\n * - @scope/package/subpath@1.0.0\n * - @scope/package/subpath\n * - package/subpath@1.0.0\n */\nexport function parsePackageSpecifier(specifier: string): ParsedPackage {\n\tlet workingSpec = specifier;\n\tlet version = \"latest\";\n\n\t// Handle scoped packages (@scope/name...)\n\tif (workingSpec.startsWith(\"@\")) {\n\t\t// Find the second @ which would separate version.\n\t\tconst secondAtIndex = workingSpec.indexOf(\"@\", 1);\n\t\tif (secondAtIndex !== -1) {\n\t\t\tversion = workingSpec.substring(secondAtIndex + 1);\n\t\t\tworkingSpec = workingSpec.substring(0, secondAtIndex);\n\t\t}\n\n\t\t/**\n\t\t * Now workingSpec is like @scope/name or @scope/name/subpath Split by / and\n\t\t * check if there are more than 2 parts.\n\t\t */\n\t\tconst parts = workingSpec.split(\"/\");\n\t\tif (parts.length > 2) {\n\t\t\t// Has subpath: @scope/name/subpath/more.\n\t\t\tconst name = `${parts[0]}/${parts[1]}`;\n\t\t\tconst subpath = parts.slice(2).join(\"/\");\n\t\t\treturn { name, version, subpath };\n\t\t}\n\t\t// No subpath: @scope/name.\n\t\treturn { name: workingSpec, version };\n\t}\n\n\t// Handle non-scoped packages (name@version or name/subpath@version).\n\tconst atIndex = workingSpec.indexOf(\"@\");\n\tif (atIndex !== -1) {\n\t\tversion = workingSpec.substring(atIndex + 1);\n\t\tworkingSpec = workingSpec.substring(0, atIndex);\n\t}\n\n\t// Check for subpath in non-scoped packages.\n\tconst slashIndex = workingSpec.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst name = workingSpec.substring(0, slashIndex);\n\t\tconst subpath = workingSpec.substring(slashIndex + 1);\n\t\treturn { name, version, subpath };\n\t}\n\n\treturn { name: workingSpec, version };\n}\n\nexport type BundleOptions = {\n\tpackageName: string;\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tregistry?: string;\n\t/**\n\t * Target platform. If undefined, auto-detects from package.json engines.\n\t */\n\tplatform?: \"browser\" | \"node\";\n\t/**\n\t * esbuild target (e.g., \"es2022\", \"es2020\"). Defaults to \"es2022\".\n\t */\n\ttarget?: string;\n};\n\nexport type BundleResult = {\n\tpackageName: string;\n\tpackageVersion: string;\n\texports: string[];\n\trawSize: number;\n\t/**\n\t * Gzip size in bytes, or null for node platform (gzip not applicable).\n\t */\n\tgzipSize: number | null;\n\tgzipLevel: number;\n\texternals: string[];\n\tdependencies: string[];\n\tplatform: \"browser\" | \"node\";\n\t/**\n\t * Total number of named exports in the package (when analyzing entire\n\t * package).\n\t */\n\tnamedExportCount: number;\n};\n\n/**\n * Format bytes to human-readable string.\n */\nexport function formatBytes(bytes: number): string {\n\tif (bytes === 0) {\n\t\treturn \"0 B\";\n\t}\n\tconst k = 1024;\n\tconst sizes = [\"B\", \"kB\", \"MB\", \"GB\"];\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\treturn `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;\n}\n\n/**\n * Create a temporary directory for bundling.\n */\nfunction createTempDir(): string {\n\tconst tmpDir = path.join(os.tmpdir(), `bundlecheck-${Date.now()}`);\n\tfs.mkdirSync(tmpDir, { recursive: true });\n\treturn tmpDir;\n}\n\n/**\n * Clean up temporary directory.\n */\nfunction cleanupTempDir(tmpDir: string): void {\n\ttry {\n\t\tfs.rmSync(tmpDir, { recursive: true, force: true });\n\t} catch {\n\t\t// Ignore cleanup errors.\n\t}\n}\n\n/**\n * Check if pnpm is available.\n */\nfunction isPnpmAvailable(): boolean {\n\ttry {\n\t\texecSync(\"pnpm --version\", { stdio: \"pipe\" });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Cache the result of pnpm availability check.\nlet usePnpm: boolean | null = null;\n\n/**\n * Validate and sanitize a registry URL to prevent command injection.\n * @param registry - The registry URL to validate\n * @returns The sanitized URL or undefined if invalid\n * @throws Error if the URL is invalid or contains potentially malicious characters\n */\nfunction validateRegistryUrl(registry: string): string {\n\t// Parse as URL to validate format.\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(registry);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL: ${registry}. Must be a valid URL (e.g., https://registry.example.com)`,\n\t\t);\n\t}\n\n\t// Only allow http and https protocols.\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL protocol: ${url.protocol}. Only http: and https: are allowed`,\n\t\t);\n\t}\n\n\t// Return the sanitized URL (URL constructor normalizes it).\n\treturn url.toString();\n}\n\n/**\n * Get the install command (pnpm preferred, npm fallback).\n * @param registry - Optional custom npm registry URL\n */\nfunction getInstallCommand(registry?: string): string {\n\tif (usePnpm === null) {\n\t\tusePnpm = isPnpmAvailable();\n\t}\n\n\tlet registryArg = \"\";\n\tif (registry) {\n\t\t// Validate and sanitize the registry URL to prevent command injection.\n\t\tconst sanitizedRegistry = validateRegistryUrl(registry);\n\t\t// Quote the URL to handle any special characters safely.\n\t\tregistryArg = ` --registry \"${sanitizedRegistry}\"`;\n\t}\n\n\tif (usePnpm) {\n\t\treturn `pnpm install --ignore-scripts --no-frozen-lockfile${registryArg}`;\n\t}\n\treturn `npm install --legacy-peer-deps --ignore-scripts${registryArg}`;\n}\n\nexport type EntryContentOptions = {\n\tpackageName: string;\n\tsubpath?: string;\n\texports?: string[];\n\tallSubpaths?: string[];\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Generate the entry file content based on package, subpath, and exports.\n */\nfunction generateEntryContent(options: EntryContentOptions): string {\n\tconst { packageName, subpath, exports, allSubpaths, exportToSubpath } =\n\t\toptions;\n\n\t// If we have exports mapped to different subpaths.\n\tif (exportToSubpath && exportToSubpath.size > 0) {\n\t\t// Group exports by subpath.\n\t\tconst subpathToExports = new Map<string, string[]>();\n\t\tfor (const [exportName, sp] of exportToSubpath) {\n\t\t\tconst existing = subpathToExports.get(sp) || [];\n\t\t\texisting.push(exportName);\n\t\t\tsubpathToExports.set(sp, existing);\n\t\t}\n\n\t\t// Generate imports for each subpath.\n\t\tconst lines: string[] = [];\n\t\tconst allExportNames: string[] = [];\n\n\t\tfor (const [sp, exportNames] of subpathToExports) {\n\t\t\tconst importPath = `${packageName}/${sp}`;\n\t\t\tconst names = exportNames.join(\", \");\n\t\t\tlines.push(`import { ${names} } from \"${importPath}\";`);\n\t\t\tallExportNames.push(...exportNames);\n\t\t}\n\n\t\tlines.push(`export { ${allExportNames.join(\", \")} };`);\n\t\treturn lines.join(\"\\n\") + \"\\n\";\n\t}\n\n\t// If we have specific exports to import.\n\tif (exports && exports.length > 0) {\n\t\t// Determine the import path.\n\t\tconst importPath = subpath ? `${packageName}/${subpath}` : packageName;\n\t\tconst importNames = exports.join(\", \");\n\t\treturn `import { ${importNames} } from \"${importPath}\";\\nexport { ${importNames} };\\n`;\n\t}\n\n\t// If we have a specific subpath (but no specific exports).\n\tif (subpath) {\n\t\tconst importPath = `${packageName}/${subpath}`;\n\t\treturn `import * as pkg from \"${importPath}\";\\nexport default pkg;\\n`;\n\t}\n\n\t// If package has subpath exports only (no main entry), import all subpaths.\n\tif (allSubpaths && allSubpaths.length > 0) {\n\t\tconst imports = allSubpaths\n\t\t\t.map(\n\t\t\t\t(sp, i) =>\n\t\t\t\t\t`import * as sub${i} from \"${packageName}/${sp}\";\\nexport { sub${i} };`,\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t\treturn imports + \"\\n\";\n\t}\n\n\t// Default: import everything from main entry.\n\treturn `import * as pkg from \"${packageName}\";\\nexport default pkg;\\n`;\n}\n\n/**\n * Check if an error is an esbuild BuildFailure. BuildFailure has an `errors`\n * array with structured error objects.\n */\nfunction isEsbuildBuildFailure(\n\terror: unknown,\n): error is { errors: Array<{ text: string; location?: unknown }> } {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t\"errors\" in error &&\n\t\tArray.isArray((error as { errors: unknown }).errors)\n\t);\n}\n\n/**\n * Extract unresolved module paths from an esbuild BuildFailure error. Returns\n * an object indicating which react-related modules failed to resolve.\n *\n * Uses esbuild's structured error objects (errors array) for reliable parsing.\n * Falls back to string matching if the error format is unexpected.\n *\n * Tested against esbuild 0.27.x error format.\n *\n */\n/**\n * Node.js built-in modules that indicate a package is meant for Node.js.\n * When these fail to resolve during browser bundling, we auto-retry with\n * platform: \"node\".\n */\nconst NODE_BUILTIN_MODULES = new Set([\n\t\"assert\",\n\t\"buffer\",\n\t\"child_process\",\n\t\"cluster\",\n\t\"crypto\",\n\t\"dgram\",\n\t\"dns\",\n\t\"events\",\n\t\"fs\",\n\t\"http\",\n\t\"http2\",\n\t\"https\",\n\t\"module\",\n\t\"net\",\n\t\"os\",\n\t\"path\",\n\t\"perf_hooks\",\n\t\"process\",\n\t\"querystring\",\n\t\"readline\",\n\t\"stream\",\n\t\"string_decoder\",\n\t\"tls\",\n\t\"tty\",\n\t\"url\",\n\t\"util\",\n\t\"v8\",\n\t\"vm\",\n\t\"worker_threads\",\n\t\"zlib\",\n]);\n\nfunction parseUnresolvedModules(error: unknown): {\n\thasUnresolvedReact: boolean;\n\thasUnresolvedReactDom: boolean;\n\thasUnresolvedNodeBuiltins: boolean;\n} {\n\tconst result = {\n\t\thasUnresolvedReact: false,\n\t\thasUnresolvedReactDom: false,\n\t\thasUnresolvedNodeBuiltins: false,\n\t};\n\n\t/**\n\t * Pattern to extract module path from \"Could not resolve X\" errors. Matches:\n\t * Could not resolve \"module-name\" or Could not resolve 'module-name'.\n\t */\n\tconst resolveErrorPattern = /Could not resolve [\"']([^\"']+)[\"']/;\n\n\t/**\n\t * Check if a module path is a Node.js built-in (with or without \"node:\" prefix).\n\t */\n\tconst isNodeBuiltin = (modulePath: string): boolean => {\n\t\tconst withoutPrefix = modulePath.startsWith(\"node:\")\n\t\t\t? modulePath.slice(5)\n\t\t\t: modulePath;\n\t\tconst [root] = withoutPrefix.split(\"/\");\n\t\treturn NODE_BUILTIN_MODULES.has(root);\n\t};\n\n\tif (isEsbuildBuildFailure(error)) {\n\t\t// Use structured error objects from esbuild BuildFailure.\n\t\tfor (const err of error.errors) {\n\t\t\tconst match = resolveErrorPattern.exec(err.text);\n\t\t\tif (match) {\n\t\t\t\tconst modulePath = match[1];\n\t\t\t\t// Check if it's a react or react-dom import (including subpaths).\n\t\t\t\tif (modulePath === \"react\" || modulePath.startsWith(\"react/\")) {\n\t\t\t\t\tresult.hasUnresolvedReact = true;\n\t\t\t\t}\n\t\t\t\tif (modulePath === \"react-dom\" || modulePath.startsWith(\"react-dom/\")) {\n\t\t\t\t\tresult.hasUnresolvedReactDom = true;\n\t\t\t\t}\n\t\t\t\tif (isNodeBuiltin(modulePath)) {\n\t\t\t\t\tresult.hasUnresolvedNodeBuiltins = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Fallback: parse error message string (less reliable).\n\t\tconst errorMessage = String(error);\n\t\tconst matches = errorMessage.matchAll(\n\t\t\t/Could not resolve [\"']([^\"']+)[\"']/g,\n\t\t);\n\t\tfor (const match of matches) {\n\t\t\tconst modulePath = match[1];\n\t\t\tif (modulePath === \"react\" || modulePath.startsWith(\"react/\")) {\n\t\t\t\tresult.hasUnresolvedReact = true;\n\t\t\t}\n\t\t\tif (modulePath === \"react-dom\" || modulePath.startsWith(\"react-dom/\")) {\n\t\t\t\tresult.hasUnresolvedReactDom = true;\n\t\t\t}\n\t\t\tif (isNodeBuiltin(modulePath)) {\n\t\t\t\tresult.hasUnresolvedNodeBuiltins = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Get externals list based on options and package dependencies. react and\n * react-dom are only marked as external if they are declared in the package's\n * dependencies or peerDependencies.\n *\n * Returns the base package names (e.g., [\"react\", \"react-dom\"]) for display\n * purposes.\n *\n */\nexport function getExternals(\n\tpackageName: string,\n\texternals?: string[],\n\tnoExternal?: boolean,\n\tpackageDependencies?: string[],\n): string[] {\n\tif (noExternal) {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Start with empty result - we'll only add react/react-dom if they're in\n\t * package deps.\n\t */\n\tlet result: string[] = [];\n\n\t/**\n\t * Only include react/react-dom if they're in the package's dependencies or\n\t * peerDependencies.\n\t */\n\tif (packageDependencies && packageDependencies.length > 0) {\n\t\tfor (const dep of DEFAULT_EXTERNALS) {\n\t\t\t// Don't mark as external if we're checking the package itself.\n\t\t\tif (dep === packageName) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (packageDependencies.includes(dep)) {\n\t\t\t\tresult.push(dep);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add any additional externals.\n\tif (externals && externals.length > 0) {\n\t\tresult = [...new Set([...result, ...externals])];\n\t}\n\n\treturn result;\n}\n\n/**\n * Expand externals to include subpaths for esbuild. For example, \"react\"\n * expands to [\"react\", \"react/jsx-runtime\", \"react/jsx-dev-runtime\"]. This is\n * needed because esbuild doesn't automatically externalize subpaths.\n */\nexport function expandExternalsForEsbuild(externals: string[]): string[] {\n\tconst expanded: string[] = [];\n\n\tfor (const ext of externals) {\n\t\texpanded.push(ext);\n\t\t// Add subpaths if this is a known package with subpath exports.\n\t\tconst subpaths = EXTERNAL_SUBPATHS[ext];\n\t\tif (subpaths) {\n\t\t\texpanded.push(...subpaths);\n\t\t}\n\t}\n\n\treturn [...new Set(expanded)];\n}\n\nexport type PackageExports = Record<\n\tstring,\n\tstring | { import?: string; types?: string }\n>;\n\nexport type PackageInfo = {\n\tversion: string;\n\tdependencies: Record<string, string>;\n\tpeerDependencies: Record<string, string>;\n\texports: PackageExports | null;\n\thasMainEntry: boolean;\n\tengines: Record<string, string> | null;\n};\n\n/**\n * Get version, dependencies, peer dependencies, and exports from an installed\n * package.\n */\nfunction getPackageInfo(tmpDir: string, packageName: string): PackageInfo {\n\ttry {\n\t\t// Handle scoped packages - the package name in node_modules.\n\t\tconst pkgJsonPath = path.join(\n\t\t\ttmpDir,\n\t\t\t\"node_modules\",\n\t\t\tpackageName,\n\t\t\t\"package.json\",\n\t\t);\n\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\tconst pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\n\t\t\t// Check if package has a main entry point.\n\t\t\tconst hasMainEntry = Boolean(\n\t\t\t\tpkgJson.main ||\n\t\t\t\t\tpkgJson.module ||\n\t\t\t\t\tpkgJson.exports?.[\".\"] ||\n\t\t\t\t\tpkgJson.exports?.[\"./index\"] ||\n\t\t\t\t\t(!pkgJson.exports && !pkgJson.main && !pkgJson.module),\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tversion: pkgJson.version || \"unknown\",\n\t\t\t\tdependencies: pkgJson.dependencies || {},\n\t\t\t\tpeerDependencies: pkgJson.peerDependencies || {},\n\t\t\t\texports: pkgJson.exports || null,\n\t\t\t\thasMainEntry,\n\t\t\t\tengines: pkgJson.engines || null,\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// Ignore errors reading package info.\n\t}\n\treturn {\n\t\tversion: \"unknown\",\n\t\tdependencies: {},\n\t\tpeerDependencies: {},\n\t\texports: null,\n\t\thasMainEntry: true,\n\t\tengines: null,\n\t};\n}\n\n/**\n * Extract subpath export names from package exports field Returns array of\n * subpaths like [\"header\", \"body\", \"datagrid\"].\n */\nfunction getSubpathExports(exports: PackageExports | null): string[] {\n\tif (!exports) {\n\t\treturn [];\n\t}\n\n\tconst subpaths: string[] = [];\n\tfor (const key of Object.keys(exports)) {\n\t\t// Skip the main entry point and package.json.\n\t\tif (key === \".\" || key === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\t\t// Remove leading \"./\" to get subpath name.\n\t\tif (key.startsWith(\"./\")) {\n\t\t\tsubpaths.push(key.substring(2));\n\t\t}\n\t}\n\treturn subpaths;\n}\n\n/**\n * Result of finding subpaths for exports.\n */\ntype SubpathMapping = {\n\t// Single subpath if all exports are from the same subpath.\n\tsingleSubpath?: string;\n\t// Map of export name to subpath for multiple subpaths.\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Find which subpath(s) export the given component names Reads type definition\n * files or JS files to find the exports.\n */\nfunction findSubpathsForExports(\n\ttmpDir: string,\n\tpackageName: string,\n\texports: PackageExports,\n\tcomponentNames: string[],\n): SubpathMapping {\n\tconst packageDir = path.join(tmpDir, \"node_modules\", packageName);\n\tconst exportToSubpath = new Map<string, string>();\n\n\tfor (const [subpathKey, subpathValue] of Object.entries(exports)) {\n\t\t// Skip main entry and package.json.\n\t\tif (subpathKey === \".\" || subpathKey === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Get the types or import path.\n\t\tlet filePath: string | undefined;\n\t\tif (typeof subpathValue === \"object\" && subpathValue !== null) {\n\t\t\t// Prefer types file for more accurate export detection.\n\t\t\tfilePath = subpathValue.types || subpathValue.import;\n\t\t} else if (typeof subpathValue === \"string\") {\n\t\t\tfilePath = subpathValue;\n\t\t}\n\n\t\tif (!filePath) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve the file path.\n\t\tconst fullPath = path.join(packageDir, filePath);\n\n\t\ttry {\n\t\t\tif (fs.existsSync(fullPath)) {\n\t\t\t\tconst content = fs.readFileSync(fullPath, \"utf-8\");\n\t\t\t\tconst subpath = subpathKey.startsWith(\"./\")\n\t\t\t\t\t? subpathKey.substring(2)\n\t\t\t\t\t: subpathKey;\n\n\t\t\t\t// Check each component name.\n\t\t\t\tfor (const name of componentNames) {\n\t\t\t\t\t// Skip if already found.\n\t\t\t\t\tif (exportToSubpath.has(name)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Escape regex special characters in the name to prevent injection.\n\t\t\t\t\tconst escapedName = escapeRegExp(name);\n\n\t\t\t\t\t// Look for various export patterns.\n\t\t\t\t\tconst patterns = [\n\t\t\t\t\t\tnew RegExp(`export\\\\s*\\\\{[^}]*\\\\b${escapedName}\\\\b[^}]*\\\\}`, \"m\"),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+declare\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t];\n\n\t\t\t\t\tif (patterns.some((pattern) => pattern.test(content))) {\n\t\t\t\t\t\texportToSubpath.set(name, subpath);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors, continue to next subpath.\n\t\t}\n\t}\n\n\t// Check if all exports were found.\n\tif (exportToSubpath.size !== componentNames.length) {\n\t\treturn {}; // Not all exports found\n\t}\n\n\t// Check if all exports are from the same subpath.\n\tconst subpaths = new Set(exportToSubpath.values());\n\tif (subpaths.size === 1) {\n\t\treturn { singleSubpath: [...subpaths][0] };\n\t}\n\n\t// Multiple subpaths needed.\n\treturn { exportToSubpath };\n}\n\n/**\n * Check the bundle size of an npm package.\n */\nexport async function checkBundleSize(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tpackageName: packageSpecifier,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel = 5,\n\t\tregistry,\n\t\tplatform: explicitPlatform,\n\t\ttarget = DEFAULT_TARGET,\n\t} = options;\n\n\t// Parse the package specifier to extract name, version, and subpath.\n\tconst {\n\t\tname: packageName,\n\t\tversion: requestedVersion,\n\t\tsubpath,\n\t} = parsePackageSpecifier(packageSpecifier);\n\n\tconst tmpDir = createTempDir();\n\n\ttry {\n\t\t// Create initial package.json.\n\t\tconst packageJson: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\ttype: string;\n\t\t\tdependencies: Record<string, string>;\n\t\t} = {\n\t\t\tname: \"bundlecheck-temp\",\n\t\t\tversion: \"1.0.0\",\n\t\t\ttype: \"module\",\n\t\t\tdependencies: {\n\t\t\t\t[packageName]: requestedVersion,\n\t\t\t},\n\t\t};\n\n\t\tfs.writeFileSync(\n\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t);\n\n\t\t// Install the main package (try pnpm first, fallback to npm).\n\t\tconst installCmd = getInstallCommand(registry);\n\t\texecSync(installCmd, {\n\t\t\tcwd: tmpDir,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\n\t\t/**\n\t\t * Get package info (version, dependencies, peer dependencies, exports,\n\t\t * engines).\n\t\t */\n\t\tconst pkgInfo = getPackageInfo(tmpDir, packageName);\n\t\tconst peerDepKeys = Object.keys(pkgInfo.peerDependencies);\n\n\t\t/**\n\t\t * Determine platform: use explicit value if provided, otherwise auto-detect\n\t\t * from engines.\n\t\t */\n\t\tlet platform: \"browser\" | \"node\" = \"browser\";\n\t\tif (explicitPlatform) {\n\t\t\tplatform = explicitPlatform;\n\t\t} else if (pkgInfo.engines?.node && !pkgInfo.engines?.browser) {\n\t\t\t/**\n\t\t\t * Package specifies node engine without browser - potentially a Node.js\n\t\t\t * package. However, many browser packages also specify engines.node for\n\t\t\t * build tooling or SSR compatibility (e.g., @clerk/clerk-react). Check\n\t\t\t * if the package has browser-framework dependencies which indicate it's\n\t\t\t * a browser package despite having engines.node.\n\t\t\t */\n\t\t\tconst allDepNames = [\n\t\t\t\t...Object.keys(pkgInfo.dependencies),\n\t\t\t\t...Object.keys(pkgInfo.peerDependencies),\n\t\t\t];\n\t\t\tconst hasBrowserFrameworkDep = allDepNames.some((dep) =>\n\t\t\t\tBROWSER_FRAMEWORK_DEPS.includes(dep),\n\t\t\t);\n\t\t\tif (!hasBrowserFrameworkDep) {\n\t\t\t\tplatform = \"node\";\n\t\t\t}\n\t\t}\n\n\t\t// Collect all dependency names (prod + peer).\n\t\tconst allDependencies = [\n\t\t\t...new Set([...Object.keys(pkgInfo.dependencies), ...peerDepKeys]),\n\t\t].sort();\n\n\t\tif (peerDepKeys.length > 0) {\n\t\t\t// Add peer dependencies to package.json.\n\t\t\tfor (const dep of peerDepKeys) {\n\t\t\t\t// Use the version range from peer dependencies.\n\t\t\t\tpackageJson.dependencies[dep] = pkgInfo.peerDependencies[dep];\n\t\t\t}\n\n\t\t\t// Update package.json and reinstall.\n\t\t\tfs.writeFileSync(\n\t\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t\t);\n\n\t\t\texecSync(installCmd, {\n\t\t\t\tcwd: tmpDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * Determine if we need to use all subpath exports or find the right\n\t\t * subpath(s).\n\t\t */\n\t\tlet allSubpaths: string[] | undefined;\n\t\tlet resolvedSubpath = subpath;\n\t\tlet exportToSubpath: Map<string, string> | undefined;\n\n\t\tif (!subpath && !pkgInfo.hasMainEntry && pkgInfo.exports) {\n\t\t\tif (exports && exports.length > 0) {\n\t\t\t\t// User specified exports but no subpath - try to find the right subpath(s).\n\t\t\t\tconst mapping = findSubpathsForExports(\n\t\t\t\t\ttmpDir,\n\t\t\t\t\tpackageName,\n\t\t\t\t\tpkgInfo.exports,\n\t\t\t\t\texports,\n\t\t\t\t);\n\n\t\t\t\tif (mapping.singleSubpath) {\n\t\t\t\t\t// All exports from the same subpath.\n\t\t\t\t\tresolvedSubpath = mapping.singleSubpath;\n\t\t\t\t} else if (mapping.exportToSubpath) {\n\t\t\t\t\t// Exports from multiple subpaths.\n\t\t\t\t\texportToSubpath = mapping.exportToSubpath;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If still no subpath resolved and no mapping, bundle all subpaths.\n\t\t\tif (!resolvedSubpath && !exportToSubpath) {\n\t\t\t\tallSubpaths = getSubpathExports(pkgInfo.exports);\n\t\t\t}\n\t\t}\n\n\t\t// Create entry file with appropriate content.\n\t\tconst entryContent = generateEntryContent({\n\t\t\tpackageName,\n\t\t\tsubpath: resolvedSubpath,\n\t\t\texports,\n\t\t\tallSubpaths,\n\t\t\texportToSubpath,\n\t\t});\n\t\tconst entryFile = path.join(tmpDir, \"entry.js\");\n\t\tfs.writeFileSync(entryFile, entryContent);\n\n\t\t/**\n\t\t * Get externals based on package dependencies. Only include react/react-dom\n\t\t * if they're in the package's dependencies or peerDependencies.\n\t\t */\n\t\tlet externals = getExternals(\n\t\t\tpackageName,\n\t\t\tadditionalExternals,\n\t\t\tnoExternal,\n\t\t\tallDependencies,\n\t\t);\n\n\t\t/**\n\t\t * Expand externals to include subpaths for esbuild.\n\t\t * e.g., \"react\" -> [\"react\", \"react/jsx-runtime\", \"react/jsx-dev-runtime\"]\n\t\t */\n\t\tlet esbuildExternals = expandExternalsForEsbuild(externals);\n\n\t\t/**\n\t\t * Bundle with esbuild. We use a two-phase approach:\n\t\t * 1. First attempt with logLevel: \"silent\" to suppress errors\n\t\t * 2. If it fails due to unresolved react imports, auto-add react to externals and retry\n\t\t * This handles packages that don't properly declare react as a peer\n\t\t * dependency.\n\t\t */\n\t\t/**\n\t\t * Common esbuild options shared across all build attempts.\n\t\t * Native .node addons cannot be bundled by esbuild, so we treat them\n\t\t * as empty files to avoid loader errors.\n\t\t */\n\t\tconst commonBuildOptions = {\n\t\t\tentryPoints: [entryFile],\n\t\t\tbundle: true,\n\t\t\twrite: false as const,\n\t\t\tformat: \"esm\" as const,\n\t\t\ttarget,\n\t\t\tminify: true,\n\t\t\ttreeShaking: true,\n\t\t\tmetafile: true as const,\n\t\t\tloader: { \".node\": \"empty\" as const },\n\t\t};\n\n\t\tlet result: esbuild.BuildResult<{ write: false; metafile: true }>;\n\t\ttry {\n\t\t\tresult = await esbuild.build({\n\t\t\t\t...commonBuildOptions,\n\t\t\t\tplatform,\n\t\t\t\texternal: esbuildExternals,\n\t\t\t\tlogLevel: \"silent\", // Suppress errors on first attempt (will retry if needed)\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t/**\n\t\t\t * Parse unresolved module errors using esbuild's structured error format.\n\t\t\t * This handles packages that don't properly declare react as a peer\n\t\t\t * dependency, and Node.js packages incorrectly bundled for the browser.\n\t\t\t */\n\t\t\tconst {\n\t\t\t\thasUnresolvedReact,\n\t\t\t\thasUnresolvedReactDom,\n\t\t\t\thasUnresolvedNodeBuiltins,\n\t\t\t} = parseUnresolvedModules(error);\n\n\t\t\tif (\n\t\t\t\thasUnresolvedNodeBuiltins &&\n\t\t\t\tplatform === \"browser\" &&\n\t\t\t\t!explicitPlatform\n\t\t\t) {\n\t\t\t\t/**\n\t\t\t\t * Node.js built-in modules failed to resolve during browser bundling.\n\t\t\t\t * This means the package is a Node.js package that wasn't detected by\n\t\t\t\t * the engines-based auto-detection. Retry with platform: \"node\".\n\t\t\t\t */\n\t\t\t\tplatform = \"node\";\n\t\t\t\tresult = await esbuild.build({\n\t\t\t\t\t...commonBuildOptions,\n\t\t\t\t\tplatform,\n\t\t\t\t\texternal: esbuildExternals,\n\t\t\t\t});\n\t\t\t} else if (!noExternal && (hasUnresolvedReact || hasUnresolvedReactDom)) {\n\t\t\t\t// Auto-add react and/or react-dom to externals and retry.\n\t\t\t\tconst autoExternals: string[] = [];\n\t\t\t\tif (hasUnresolvedReact && !externals.includes(\"react\")) {\n\t\t\t\t\tautoExternals.push(\"react\");\n\t\t\t\t}\n\t\t\t\tif (hasUnresolvedReactDom && !externals.includes(\"react-dom\")) {\n\t\t\t\t\tautoExternals.push(\"react-dom\");\n\t\t\t\t}\n\n\t\t\t\tif (autoExternals.length > 0) {\n\t\t\t\t\texternals = [...externals, ...autoExternals];\n\t\t\t\t\tesbuildExternals = expandExternalsForEsbuild(externals);\n\n\t\t\t\t\tresult = await esbuild.build({\n\t\t\t\t\t\t...commonBuildOptions,\n\t\t\t\t\t\tplatform,\n\t\t\t\t\t\texternal: esbuildExternals,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// Get raw size.\n\t\tconst bundleContent = result.outputFiles[0].contents;\n\t\tconst rawSize = bundleContent.length;\n\n\t\t// Gzip the bundle (only for browser platform - not relevant for Node.js).\n\t\tlet gzipSize: number | null = null;\n\t\tif (platform === \"browser\") {\n\t\t\tconst gzipped = await gzipAsync(Buffer.from(bundleContent), {\n\t\t\t\tlevel: gzipLevel,\n\t\t\t});\n\t\t\tgzipSize = gzipped.length;\n\t\t}\n\n\t\t// Determine the display name.\n\t\tlet displayName = packageName;\n\t\tif (resolvedSubpath) {\n\t\t\tdisplayName = `${packageName}/${resolvedSubpath}`;\n\t\t} else if (exportToSubpath && exportToSubpath.size > 0) {\n\t\t\t// Multiple subpaths - show them all.\n\t\t\tconst uniqueSubpaths = [...new Set(exportToSubpath.values())].sort();\n\t\t\tdisplayName = `${packageName}/{${uniqueSubpaths.join(\", \")}}`;\n\t\t}\n\n\t\t/**\n\t\t * Get named export count from the package's type definitions. Use\n\t\t * runtimeCount to exclude type-only exports (types, interfaces).\n\t\t */\n\t\tconst { runtimeCount: namedExportCount } = getNamedExports(\n\t\t\ttmpDir,\n\t\t\tpackageName,\n\t\t);\n\n\t\treturn {\n\t\t\tpackageName: displayName,\n\t\t\tpackageVersion: pkgInfo.version,\n\t\t\texports: exports || [],\n\t\t\trawSize,\n\t\t\tgzipSize,\n\t\t\tgzipLevel,\n\t\t\texternals,\n\t\t\tdependencies: allDependencies,\n\t\t\tplatform,\n\t\t\tnamedExportCount,\n\t\t};\n\t} finally {\n\t\tcleanupTempDir(tmpDir);\n\t}\n}\n"],"names":["execSync","fs","os","path","promisify","zlib","esbuild","BROWSER_FRAMEWORK_DEPS","DEFAULT_EXTERNALS","DEFAULT_TARGET","EXTERNAL_SUBPATHS","getNamedExports","gzipAsync","gzip","escapeRegExp","str","replace","parsePackageSpecifier","specifier","workingSpec","version","startsWith","secondAtIndex","indexOf","substring","parts","split","length","name","subpath","slice","join","atIndex","slashIndex","formatBytes","bytes","k","sizes","i","Math","floor","log","Number","parseFloat","toFixed","createTempDir","tmpDir","tmpdir","Date","now","mkdirSync","recursive","cleanupTempDir","rmSync","force","isPnpmAvailable","stdio","usePnpm","validateRegistryUrl","registry","url","URL","Error","protocol","toString","getInstallCommand","registryArg","sanitizedRegistry","generateEntryContent","options","packageName","exports","allSubpaths","exportToSubpath","size","subpathToExports","Map","exportName","sp","existing","get","push","set","lines","allExportNames","exportNames","importPath","names","importNames","imports","map","isEsbuildBuildFailure","error","Array","isArray","errors","NODE_BUILTIN_MODULES","Set","parseUnresolvedModules","result","hasUnresolvedReact","hasUnresolvedReactDom","hasUnresolvedNodeBuiltins","resolveErrorPattern","isNodeBuiltin","modulePath","withoutPrefix","root","has","err","match","exec","text","errorMessage","String","matches","matchAll","getExternals","externals","noExternal","packageDependencies","dep","includes","expandExternalsForEsbuild","expanded","ext","subpaths","getPackageInfo","pkgJsonPath","existsSync","pkgJson","JSON","parse","readFileSync","hasMainEntry","Boolean","main","module","dependencies","peerDependencies","engines","getSubpathExports","key","Object","keys","findSubpathsForExports","componentNames","packageDir","subpathKey","subpathValue","entries","filePath","types","import","fullPath","content","escapedName","patterns","RegExp","some","pattern","test","values","singleSubpath","checkBundleSize","packageSpecifier","additionalExternals","gzipLevel","platform","explicitPlatform","target","requestedVersion","packageJson","type","writeFileSync","stringify","installCmd","cwd","pkgInfo","peerDepKeys","node","browser","allDepNames","hasBrowserFrameworkDep","allDependencies","sort","resolvedSubpath","mapping","entryContent","entryFile","esbuildExternals","commonBuildOptions","entryPoints","bundle","write","format","minify","treeShaking","metafile","loader","build","external","logLevel","autoExternals","bundleContent","outputFiles","contents","rawSize","gzipSize","gzipped","Buffer","from","level","displayName","uniqueSubpaths","runtimeCount","namedExportCount","packageVersion"],"mappings":"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"}
package/dist/cache.js CHANGED
@@ -70,6 +70,15 @@ let db = null;
70
70
  } catch {
71
71
  // Column already exists, ignore error.
72
72
  }
73
+ /**
74
+ * Migration: Add actual_platform column if it doesn't exist (for existing
75
+ * databases). Stores the real platform from BundleResult, which may differ
76
+ * from the cache key platform (e.g., "auto" key but "node" actual).
77
+ */ try {
78
+ db.exec(`ALTER TABLE bundle_cache ADD COLUMN actual_platform TEXT`);
79
+ } catch {
80
+ // Column already exists, ignore error.
81
+ }
73
82
  return db;
74
83
  }
75
84
  /**
@@ -126,7 +135,19 @@ let db = null;
126
135
  * Convert row to BundleResult. Use actual_externals (computed externals
127
136
  * including auto-detected react/react-dom) if available, otherwise fall back
128
137
  * to externals (for old cache entries).
138
+ *
139
+ * Use actual_platform if available (stores the real detected platform),
140
+ * otherwise fall back to the cache key platform. For old entries where
141
+ * platform is "auto" and no actual_platform exists, default to "browser".
129
142
  */ const externalsStr = row.actual_externals || row.externals;
143
+ let platform;
144
+ if (row.actual_platform === "browser" || row.actual_platform === "node") {
145
+ platform = row.actual_platform;
146
+ } else if (row.platform === "browser" || row.platform === "node") {
147
+ platform = row.platform;
148
+ } else {
149
+ platform = "browser";
150
+ }
130
151
  return {
131
152
  packageName: row.display_name,
132
153
  packageVersion: row.version,
@@ -136,7 +157,7 @@ let db = null;
136
157
  gzipLevel: row.gzip_level,
137
158
  externals: externalsStr ? externalsStr.split(",").filter(Boolean) : [],
138
159
  dependencies,
139
- platform: row.platform,
160
+ platform,
140
161
  namedExportCount: row.named_export_count ?? 0
141
162
  };
142
163
  } catch {
@@ -158,10 +179,11 @@ let db = null;
158
179
  */ const stmt = database.prepare(`
159
180
  INSERT OR REPLACE INTO bundle_cache (
160
181
  package_name, version, exports, platform, gzip_level, externals, no_external,
161
- raw_size, gzip_size, dependencies, display_name, created_at, named_export_count, actual_externals
162
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
182
+ raw_size, gzip_size, dependencies, display_name, created_at, named_export_count, actual_externals,
183
+ actual_platform
184
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
163
185
  `);
164
- stmt.run(key.packageName, key.version, key.exports, key.platform, key.gzipLevel, key.externals, key.noExternal, result.rawSize, result.gzipSize, JSON.stringify(result.dependencies), result.packageName, Date.now(), result.namedExportCount, result.externals.slice().sort().join(","));
186
+ stmt.run(key.packageName, key.version, key.exports, key.platform, key.gzipLevel, key.externals, key.noExternal, result.rawSize, result.gzipSize, JSON.stringify(result.dependencies), result.packageName, Date.now(), result.namedExportCount, result.externals.slice().sort().join(","), result.platform);
165
187
  // Enforce max entries (LRU-style eviction based on created_at).
166
188
  enforceMaxEntries(database);
167
189
  } catch {
package/dist/cache.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cache.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { BundleResult } from \"./bundler.js\";\n\nconst MAX_CACHE_ENTRIES = 1000;\n\n/**\n * Get the cache directory path (computed lazily to support testing).\n */\nfunction getCacheDir(): string {\n\treturn path.join(os.homedir(), \".bundlecheck\");\n}\n\n/**\n * Get the cache database path (computed lazily to support testing).\n */\nfunction getCacheDbPath(): string {\n\treturn path.join(getCacheDir(), \"cache.db\");\n}\n\nexport type CacheKey = {\n\tpackageName: string;\n\tversion: string;\n\texports: string;\n\t/**\n\t * Platform: \"browser\", \"node\", or \"auto\" (for auto-detection).\n\t */\n\tplatform: \"browser\" | \"node\" | \"auto\";\n\tgzipLevel: number;\n\texternals: string;\n\tnoExternal: number;\n};\n\nexport type CachedBundleResult = BundleResult;\n\ntype CacheRow = {\n\tid: number;\n\tpackage_name: string;\n\tversion: string;\n\texports: string;\n\tplatform: string;\n\tgzip_level: number;\n\texternals: string;\n\tno_external: number;\n\traw_size: number;\n\tgzip_size: number | null;\n\tdependencies: string;\n\tdisplay_name: string;\n\tcreated_at: number;\n\tnamed_export_count: number | null;\n\tactual_externals: string;\n};\n\nlet db: Database.Database | null = null;\n\n/**\n * Initialize the cache database with proper pragmas and schema.\n */\nexport function initCache(): Database.Database {\n\tif (db) {\n\t\treturn db;\n\t}\n\n\t// Ensure cache directory exists.\n\tconst cacheDir = getCacheDir();\n\tif (!fs.existsSync(cacheDir)) {\n\t\tfs.mkdirSync(cacheDir, { recursive: true });\n\t}\n\n\tdb = new Database(getCacheDbPath());\n\n\t// Apply pragmas for better CLI performance.\n\tdb.pragma(\"journal_mode = WAL\");\n\tdb.pragma(\"foreign_keys = ON\");\n\n\t// Create table if not exists.\n\tdb.exec(`\n\t\tCREATE TABLE IF NOT EXISTS bundle_cache (\n\t\t\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\t\t\tpackage_name TEXT NOT NULL,\n\t\t\tversion TEXT NOT NULL,\n\t\t\texports TEXT NOT NULL DEFAULT '',\n\t\t\tplatform TEXT NOT NULL,\n\t\t\tgzip_level INTEGER NOT NULL,\n\t\t\texternals TEXT NOT NULL DEFAULT '',\n\t\t\tno_external INTEGER NOT NULL DEFAULT 0,\n\t\t\traw_size INTEGER NOT NULL,\n\t\t\tgzip_size INTEGER,\n\t\t\tdependencies TEXT NOT NULL DEFAULT '[]',\n\t\t\tdisplay_name TEXT NOT NULL,\n\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\tnamed_export_count INTEGER DEFAULT 0,\n\t\t\tactual_externals TEXT NOT NULL DEFAULT '',\n\t\t\tUNIQUE(package_name, version, exports, platform, gzip_level, externals, no_external)\n\t\t);\n\n\t\tCREATE INDEX IF NOT EXISTS idx_created_at ON bundle_cache(created_at);\n\t`);\n\n\t/**\n\t * Migration: Add named_export_count column if it doesn't exist (for existing\n\t * databases).\n\t */\n\ttry {\n\t\tdb.exec(\n\t\t\t`ALTER TABLE bundle_cache ADD COLUMN named_export_count INTEGER DEFAULT 0`,\n\t\t);\n\t} catch {\n\t\t// Column already exists, ignore error.\n\t}\n\n\t/**\n\t * Migration: Add actual_externals column if it doesn't exist (for existing\n\t * databases).\n\t */\n\ttry {\n\t\tdb.exec(\n\t\t\t`ALTER TABLE bundle_cache ADD COLUMN actual_externals TEXT NOT NULL DEFAULT ''`,\n\t\t);\n\t} catch {\n\t\t// Column already exists, ignore error.\n\t}\n\n\treturn db;\n}\n\n/**\n * Normalize cache key options to a consistent format Sorts exports and\n * externals to ensure consistent cache hits.\n *\n * NOTE: platform can be \"browser\", \"node\", or \"auto\" (when user doesn't specify).\n * Using \"auto\" in the cache key ensures that auto-detected results are cached\n * separately from explicitly specified platform results.\n *\n */\nexport function normalizeCacheKey(options: {\n\tpackageName: string;\n\tversion: string;\n\texports?: string[];\n\t/**\n\t * Platform: \"browser\", \"node\", or undefined (treated as \"auto\").\n\t */\n\tplatform: \"browser\" | \"node\" | undefined;\n\tgzipLevel: number;\n\texternals: string[];\n\tnoExternal: boolean;\n}): CacheKey {\n\treturn {\n\t\tpackageName: options.packageName,\n\t\tversion: options.version,\n\t\texports: (options.exports || []).slice().sort().join(\",\"),\n\t\t/**\n\t\t * Use \"auto\" when platform is undefined to distinguish from explicit\n\t\t * platform.\n\t\t */\n\t\tplatform: options.platform ?? \"auto\",\n\t\tgzipLevel: options.gzipLevel,\n\t\texternals: options.externals.slice().sort().join(\",\"),\n\t\tnoExternal: options.noExternal ? 1 : 0,\n\t};\n}\n\n/**\n * Get a cached result if it exists Returns null if not found or if an error\n * occurs (graceful degradation).\n */\nexport function getCachedResult(key: CacheKey): CachedBundleResult | null {\n\ttry {\n\t\tconst database = initCache();\n\n\t\tconst stmt = database.prepare<\n\t\t\t[string, string, string, string, number, string, number]\n\t\t>(`\n\t\t\tSELECT * FROM bundle_cache\n\t\t\tWHERE package_name = ?\n\t\t\tAND version = ?\n\t\t\tAND exports = ?\n\t\t\tAND platform = ?\n\t\t\tAND gzip_level = ?\n\t\t\tAND externals = ?\n\t\t\tAND no_external = ?\n\t\t`);\n\n\t\tconst row = stmt.get(\n\t\t\tkey.packageName,\n\t\t\tkey.version,\n\t\t\tkey.exports,\n\t\t\tkey.platform,\n\t\t\tkey.gzipLevel,\n\t\t\tkey.externals,\n\t\t\tkey.noExternal,\n\t\t) as CacheRow | undefined;\n\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Parse dependencies with error handling for corrupted data.\n\t\tlet dependencies: string[] = [];\n\t\ttry {\n\t\t\tdependencies = JSON.parse(row.dependencies) as string[];\n\t\t} catch {\n\t\t\t// If JSON is corrupted, use empty array.\n\t\t\tdependencies = [];\n\t\t}\n\n\t\t/**\n\t\t * Convert row to BundleResult. Use actual_externals (computed externals\n\t\t * including auto-detected react/react-dom) if available, otherwise fall back\n\t\t * to externals (for old cache entries).\n\t\t */\n\t\tconst externalsStr = row.actual_externals || row.externals;\n\t\treturn {\n\t\t\tpackageName: row.display_name,\n\t\t\tpackageVersion: row.version,\n\t\t\texports: row.exports ? row.exports.split(\",\").filter(Boolean) : [],\n\t\t\trawSize: row.raw_size,\n\t\t\tgzipSize: row.gzip_size,\n\t\t\tgzipLevel: row.gzip_level,\n\t\t\texternals: externalsStr ? externalsStr.split(\",\").filter(Boolean) : [],\n\t\t\tdependencies,\n\t\t\tplatform: row.platform as \"browser\" | \"node\",\n\t\t\tnamedExportCount: row.named_export_count ?? 0,\n\t\t};\n\t} catch {\n\t\t/**\n\t\t * On any database error, return null (graceful degradation - continue without\n\t\t * cache).\n\t\t */\n\t\treturn null;\n\t}\n}\n\n/**\n * Store a result in the cache Silently fails on errors (graceful degradation -\n * CLI continues without caching).\n */\nexport function setCachedResult(key: CacheKey, result: BundleResult): void {\n\ttry {\n\t\tconst database = initCache();\n\n\t\t/**\n\t\t * Use INSERT OR REPLACE to handle duplicates.\n\t\t * NOTE: This updates created_at on replace, making this LRU-style eviction.\n\t\t */\n\t\tconst stmt = database.prepare(`\n\t\t\tINSERT OR REPLACE INTO bundle_cache (\n\t\t\t\tpackage_name, version, exports, platform, gzip_level, externals, no_external,\n\t\t\t\traw_size, gzip_size, dependencies, display_name, created_at, named_export_count, actual_externals\n\t\t\t) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n\t\t`);\n\n\t\tstmt.run(\n\t\t\tkey.packageName,\n\t\t\tkey.version,\n\t\t\tkey.exports,\n\t\t\tkey.platform,\n\t\t\tkey.gzipLevel,\n\t\t\tkey.externals,\n\t\t\tkey.noExternal,\n\t\t\tresult.rawSize,\n\t\t\tresult.gzipSize,\n\t\t\tJSON.stringify(result.dependencies),\n\t\t\tresult.packageName,\n\t\t\tDate.now(),\n\t\t\tresult.namedExportCount,\n\t\t\tresult.externals.slice().sort().join(\",\"),\n\t\t);\n\n\t\t// Enforce max entries (LRU-style eviction based on created_at).\n\t\tenforceMaxEntries(database);\n\t} catch {\n\t\t// On any database error, silently continue (graceful degradation).\n\t}\n}\n\n/**\n * Enforce maximum cache entries by removing entries with oldest timestamps Uses\n * LRU-style eviction: entries that are re-checked get updated timestamps and\n * move to the end of the eviction queue.\n */\nfunction enforceMaxEntries(database: Database.Database): void {\n\tconst countResult = database\n\t\t.prepare(\"SELECT COUNT(*) as count FROM bundle_cache\")\n\t\t.get() as { count: number };\n\n\tif (countResult.count > MAX_CACHE_ENTRIES) {\n\t\tconst toDelete = countResult.count - MAX_CACHE_ENTRIES;\n\t\tdatabase\n\t\t\t.prepare(\n\t\t\t\t`\n\t\t\tDELETE FROM bundle_cache\n\t\t\tWHERE id IN (\n\t\t\t\tSELECT id FROM bundle_cache\n\t\t\t\tORDER BY created_at ASC\n\t\t\t\tLIMIT ?\n\t\t\t)\n\t\t`,\n\t\t\t)\n\t\t\t.run(toDelete);\n\t}\n}\n\n/**\n * Clear all cache entries Silently fails on errors.\n */\nexport function clearCache(): void {\n\ttry {\n\t\tconst database = initCache();\n\t\tdatabase.prepare(\"DELETE FROM bundle_cache\").run();\n\t} catch {\n\t\t// Silently ignore errors.\n\t}\n}\n\n/**\n * Get the number of cached entries Returns 0 on error.\n */\nexport function getCacheCount(): number {\n\ttry {\n\t\tconst database = initCache();\n\t\tconst result = database\n\t\t\t.prepare(\"SELECT COUNT(*) as count FROM bundle_cache\")\n\t\t\t.get() as { count: number };\n\t\treturn result.count;\n\t} catch {\n\t\treturn 0;\n\t}\n}\n\n/**\n * Close the database connection (useful for testing).\n */\nexport function closeCache(): void {\n\tif (db) {\n\t\tdb.close();\n\t\tdb = null;\n\t}\n}\n"],"names":["fs","os","path","Database","MAX_CACHE_ENTRIES","getCacheDir","join","homedir","getCacheDbPath","db","initCache","cacheDir","existsSync","mkdirSync","recursive","pragma","exec","normalizeCacheKey","options","packageName","version","exports","slice","sort","platform","gzipLevel","externals","noExternal","getCachedResult","key","database","stmt","prepare","row","get","dependencies","JSON","parse","externalsStr","actual_externals","display_name","packageVersion","split","filter","Boolean","rawSize","raw_size","gzipSize","gzip_size","gzip_level","namedExportCount","named_export_count","setCachedResult","result","run","stringify","Date","now","enforceMaxEntries","countResult","count","toDelete","clearCache","getCacheCount","closeCache","close"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/cache.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { BundleResult } from \"./bundler.js\";\n\nconst MAX_CACHE_ENTRIES = 1000;\n\n/**\n * Get the cache directory path (computed lazily to support testing).\n */\nfunction getCacheDir(): string {\n\treturn path.join(os.homedir(), \".bundlecheck\");\n}\n\n/**\n * Get the cache database path (computed lazily to support testing).\n */\nfunction getCacheDbPath(): string {\n\treturn path.join(getCacheDir(), \"cache.db\");\n}\n\nexport type CacheKey = {\n\tpackageName: string;\n\tversion: string;\n\texports: string;\n\t/**\n\t * Platform: \"browser\", \"node\", or \"auto\" (for auto-detection).\n\t */\n\tplatform: \"browser\" | \"node\" | \"auto\";\n\tgzipLevel: number;\n\texternals: string;\n\tnoExternal: number;\n};\n\nexport type CachedBundleResult = BundleResult;\n\ntype CacheRow = {\n\tid: number;\n\tpackage_name: string;\n\tversion: string;\n\texports: string;\n\tplatform: string;\n\tgzip_level: number;\n\texternals: string;\n\tno_external: number;\n\traw_size: number;\n\tgzip_size: number | null;\n\tdependencies: string;\n\tdisplay_name: string;\n\tcreated_at: number;\n\tnamed_export_count: number | null;\n\tactual_externals: string;\n\tactual_platform: string | null;\n};\n\nlet db: Database.Database | null = null;\n\n/**\n * Initialize the cache database with proper pragmas and schema.\n */\nexport function initCache(): Database.Database {\n\tif (db) {\n\t\treturn db;\n\t}\n\n\t// Ensure cache directory exists.\n\tconst cacheDir = getCacheDir();\n\tif (!fs.existsSync(cacheDir)) {\n\t\tfs.mkdirSync(cacheDir, { recursive: true });\n\t}\n\n\tdb = new Database(getCacheDbPath());\n\n\t// Apply pragmas for better CLI performance.\n\tdb.pragma(\"journal_mode = WAL\");\n\tdb.pragma(\"foreign_keys = ON\");\n\n\t// Create table if not exists.\n\tdb.exec(`\n\t\tCREATE TABLE IF NOT EXISTS bundle_cache (\n\t\t\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\t\t\tpackage_name TEXT NOT NULL,\n\t\t\tversion TEXT NOT NULL,\n\t\t\texports TEXT NOT NULL DEFAULT '',\n\t\t\tplatform TEXT NOT NULL,\n\t\t\tgzip_level INTEGER NOT NULL,\n\t\t\texternals TEXT NOT NULL DEFAULT '',\n\t\t\tno_external INTEGER NOT NULL DEFAULT 0,\n\t\t\traw_size INTEGER NOT NULL,\n\t\t\tgzip_size INTEGER,\n\t\t\tdependencies TEXT NOT NULL DEFAULT '[]',\n\t\t\tdisplay_name TEXT NOT NULL,\n\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\tnamed_export_count INTEGER DEFAULT 0,\n\t\t\tactual_externals TEXT NOT NULL DEFAULT '',\n\t\t\tUNIQUE(package_name, version, exports, platform, gzip_level, externals, no_external)\n\t\t);\n\n\t\tCREATE INDEX IF NOT EXISTS idx_created_at ON bundle_cache(created_at);\n\t`);\n\n\t/**\n\t * Migration: Add named_export_count column if it doesn't exist (for existing\n\t * databases).\n\t */\n\ttry {\n\t\tdb.exec(\n\t\t\t`ALTER TABLE bundle_cache ADD COLUMN named_export_count INTEGER DEFAULT 0`,\n\t\t);\n\t} catch {\n\t\t// Column already exists, ignore error.\n\t}\n\n\t/**\n\t * Migration: Add actual_externals column if it doesn't exist (for existing\n\t * databases).\n\t */\n\ttry {\n\t\tdb.exec(\n\t\t\t`ALTER TABLE bundle_cache ADD COLUMN actual_externals TEXT NOT NULL DEFAULT ''`,\n\t\t);\n\t} catch {\n\t\t// Column already exists, ignore error.\n\t}\n\n\t/**\n\t * Migration: Add actual_platform column if it doesn't exist (for existing\n\t * databases). Stores the real platform from BundleResult, which may differ\n\t * from the cache key platform (e.g., \"auto\" key but \"node\" actual).\n\t */\n\ttry {\n\t\tdb.exec(`ALTER TABLE bundle_cache ADD COLUMN actual_platform TEXT`);\n\t} catch {\n\t\t// Column already exists, ignore error.\n\t}\n\n\treturn db;\n}\n\n/**\n * Normalize cache key options to a consistent format Sorts exports and\n * externals to ensure consistent cache hits.\n *\n * NOTE: platform can be \"browser\", \"node\", or \"auto\" (when user doesn't specify).\n * Using \"auto\" in the cache key ensures that auto-detected results are cached\n * separately from explicitly specified platform results.\n *\n */\nexport function normalizeCacheKey(options: {\n\tpackageName: string;\n\tversion: string;\n\texports?: string[];\n\t/**\n\t * Platform: \"browser\", \"node\", or undefined (treated as \"auto\").\n\t */\n\tplatform: \"browser\" | \"node\" | undefined;\n\tgzipLevel: number;\n\texternals: string[];\n\tnoExternal: boolean;\n}): CacheKey {\n\treturn {\n\t\tpackageName: options.packageName,\n\t\tversion: options.version,\n\t\texports: (options.exports || []).slice().sort().join(\",\"),\n\t\t/**\n\t\t * Use \"auto\" when platform is undefined to distinguish from explicit\n\t\t * platform.\n\t\t */\n\t\tplatform: options.platform ?? \"auto\",\n\t\tgzipLevel: options.gzipLevel,\n\t\texternals: options.externals.slice().sort().join(\",\"),\n\t\tnoExternal: options.noExternal ? 1 : 0,\n\t};\n}\n\n/**\n * Get a cached result if it exists Returns null if not found or if an error\n * occurs (graceful degradation).\n */\nexport function getCachedResult(key: CacheKey): CachedBundleResult | null {\n\ttry {\n\t\tconst database = initCache();\n\n\t\tconst stmt = database.prepare<\n\t\t\t[string, string, string, string, number, string, number]\n\t\t>(`\n\t\t\tSELECT * FROM bundle_cache\n\t\t\tWHERE package_name = ?\n\t\t\tAND version = ?\n\t\t\tAND exports = ?\n\t\t\tAND platform = ?\n\t\t\tAND gzip_level = ?\n\t\t\tAND externals = ?\n\t\t\tAND no_external = ?\n\t\t`);\n\n\t\tconst row = stmt.get(\n\t\t\tkey.packageName,\n\t\t\tkey.version,\n\t\t\tkey.exports,\n\t\t\tkey.platform,\n\t\t\tkey.gzipLevel,\n\t\t\tkey.externals,\n\t\t\tkey.noExternal,\n\t\t) as CacheRow | undefined;\n\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Parse dependencies with error handling for corrupted data.\n\t\tlet dependencies: string[] = [];\n\t\ttry {\n\t\t\tdependencies = JSON.parse(row.dependencies) as string[];\n\t\t} catch {\n\t\t\t// If JSON is corrupted, use empty array.\n\t\t\tdependencies = [];\n\t\t}\n\n\t\t/**\n\t\t * Convert row to BundleResult. Use actual_externals (computed externals\n\t\t * including auto-detected react/react-dom) if available, otherwise fall back\n\t\t * to externals (for old cache entries).\n\t\t *\n\t\t * Use actual_platform if available (stores the real detected platform),\n\t\t * otherwise fall back to the cache key platform. For old entries where\n\t\t * platform is \"auto\" and no actual_platform exists, default to \"browser\".\n\t\t */\n\t\tconst externalsStr = row.actual_externals || row.externals;\n\t\tlet platform: \"browser\" | \"node\";\n\t\tif (row.actual_platform === \"browser\" || row.actual_platform === \"node\") {\n\t\t\tplatform = row.actual_platform;\n\t\t} else if (row.platform === \"browser\" || row.platform === \"node\") {\n\t\t\tplatform = row.platform;\n\t\t} else {\n\t\t\tplatform = \"browser\";\n\t\t}\n\t\treturn {\n\t\t\tpackageName: row.display_name,\n\t\t\tpackageVersion: row.version,\n\t\t\texports: row.exports ? row.exports.split(\",\").filter(Boolean) : [],\n\t\t\trawSize: row.raw_size,\n\t\t\tgzipSize: row.gzip_size,\n\t\t\tgzipLevel: row.gzip_level,\n\t\t\texternals: externalsStr ? externalsStr.split(\",\").filter(Boolean) : [],\n\t\t\tdependencies,\n\t\t\tplatform,\n\t\t\tnamedExportCount: row.named_export_count ?? 0,\n\t\t};\n\t} catch {\n\t\t/**\n\t\t * On any database error, return null (graceful degradation - continue without\n\t\t * cache).\n\t\t */\n\t\treturn null;\n\t}\n}\n\n/**\n * Store a result in the cache Silently fails on errors (graceful degradation -\n * CLI continues without caching).\n */\nexport function setCachedResult(key: CacheKey, result: BundleResult): void {\n\ttry {\n\t\tconst database = initCache();\n\n\t\t/**\n\t\t * Use INSERT OR REPLACE to handle duplicates.\n\t\t * NOTE: This updates created_at on replace, making this LRU-style eviction.\n\t\t */\n\t\tconst stmt = database.prepare(`\n\t\t\tINSERT OR REPLACE INTO bundle_cache (\n\t\t\t\tpackage_name, version, exports, platform, gzip_level, externals, no_external,\n\t\t\t\traw_size, gzip_size, dependencies, display_name, created_at, named_export_count, actual_externals,\n\t\t\t\tactual_platform\n\t\t\t) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n\t\t`);\n\n\t\tstmt.run(\n\t\t\tkey.packageName,\n\t\t\tkey.version,\n\t\t\tkey.exports,\n\t\t\tkey.platform,\n\t\t\tkey.gzipLevel,\n\t\t\tkey.externals,\n\t\t\tkey.noExternal,\n\t\t\tresult.rawSize,\n\t\t\tresult.gzipSize,\n\t\t\tJSON.stringify(result.dependencies),\n\t\t\tresult.packageName,\n\t\t\tDate.now(),\n\t\t\tresult.namedExportCount,\n\t\t\tresult.externals.slice().sort().join(\",\"),\n\t\t\tresult.platform,\n\t\t);\n\n\t\t// Enforce max entries (LRU-style eviction based on created_at).\n\t\tenforceMaxEntries(database);\n\t} catch {\n\t\t// On any database error, silently continue (graceful degradation).\n\t}\n}\n\n/**\n * Enforce maximum cache entries by removing entries with oldest timestamps Uses\n * LRU-style eviction: entries that are re-checked get updated timestamps and\n * move to the end of the eviction queue.\n */\nfunction enforceMaxEntries(database: Database.Database): void {\n\tconst countResult = database\n\t\t.prepare(\"SELECT COUNT(*) as count FROM bundle_cache\")\n\t\t.get() as { count: number };\n\n\tif (countResult.count > MAX_CACHE_ENTRIES) {\n\t\tconst toDelete = countResult.count - MAX_CACHE_ENTRIES;\n\t\tdatabase\n\t\t\t.prepare(\n\t\t\t\t`\n\t\t\tDELETE FROM bundle_cache\n\t\t\tWHERE id IN (\n\t\t\t\tSELECT id FROM bundle_cache\n\t\t\t\tORDER BY created_at ASC\n\t\t\t\tLIMIT ?\n\t\t\t)\n\t\t`,\n\t\t\t)\n\t\t\t.run(toDelete);\n\t}\n}\n\n/**\n * Clear all cache entries Silently fails on errors.\n */\nexport function clearCache(): void {\n\ttry {\n\t\tconst database = initCache();\n\t\tdatabase.prepare(\"DELETE FROM bundle_cache\").run();\n\t} catch {\n\t\t// Silently ignore errors.\n\t}\n}\n\n/**\n * Get the number of cached entries Returns 0 on error.\n */\nexport function getCacheCount(): number {\n\ttry {\n\t\tconst database = initCache();\n\t\tconst result = database\n\t\t\t.prepare(\"SELECT COUNT(*) as count FROM bundle_cache\")\n\t\t\t.get() as { count: number };\n\t\treturn result.count;\n\t} catch {\n\t\treturn 0;\n\t}\n}\n\n/**\n * Close the database connection (useful for testing).\n */\nexport function closeCache(): void {\n\tif (db) {\n\t\tdb.close();\n\t\tdb = null;\n\t}\n}\n"],"names":["fs","os","path","Database","MAX_CACHE_ENTRIES","getCacheDir","join","homedir","getCacheDbPath","db","initCache","cacheDir","existsSync","mkdirSync","recursive","pragma","exec","normalizeCacheKey","options","packageName","version","exports","slice","sort","platform","gzipLevel","externals","noExternal","getCachedResult","key","database","stmt","prepare","row","get","dependencies","JSON","parse","externalsStr","actual_externals","actual_platform","display_name","packageVersion","split","filter","Boolean","rawSize","raw_size","gzipSize","gzip_size","gzip_level","namedExportCount","named_export_count","setCachedResult","result","run","stringify","Date","now","enforceMaxEntries","countResult","count","toDelete","clearCache","getCacheCount","closeCache","close"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-cli/bundlecheck",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "description": "CLI tool to check the bundle size of npm packages (like bundlephobia)",
@@ -33,11 +33,11 @@
33
33
  "watch": "swc --strip-leading-paths --watch --out-dir dist src"
34
34
  },
35
35
  "dependencies": {
36
- "@inquirer/select": "5.1.0",
37
- "@node-cli/logger": "1.3.5",
38
- "@node-cli/parser": "2.4.6",
39
- "better-sqlite3": "12.6.2",
40
- "esbuild": "0.27.3",
36
+ "@inquirer/select": "5.1.2",
37
+ "@node-cli/logger": "1.3.6",
38
+ "@node-cli/parser": "2.4.7",
39
+ "better-sqlite3": "12.8.0",
40
+ "esbuild": "0.27.4",
41
41
  "kleur": "4.1.5",
42
42
  "semver": "7.7.4"
43
43
  },
@@ -46,8 +46,8 @@
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/better-sqlite3": "7.6.13",
49
- "@vitest/coverage-v8": "4.0.18",
50
- "vitest": "4.0.18"
49
+ "@vitest/coverage-v8": "4.1.1",
50
+ "vitest": "4.1.1"
51
51
  },
52
- "gitHead": "9196e7eb6e51d3db5ed0e13fce7d6c9803d34383"
52
+ "gitHead": "7ddcbe04d1eff21d7e379ce5cb33a17540d4cb75"
53
53
  }