@tsdown/exe 0.21.0-beta.4 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -5,10 +5,15 @@ interface ExeTarget {
5
5
  platform: ExePlatform;
6
6
  arch: ExeArch;
7
7
  /**
8
- * Node.js version to use for the executable. Should be a valid Node.js version string (e.g., "25.7.0").
8
+ * Node.js version to use for the executable.
9
+ *
10
+ * Accepts a valid semver string (e.g., `"25.7.0"`), or the special values
11
+ * `"latest"` / `"latest-lts"` which resolve the version automatically from
12
+ * {@link https://nodejs.org/dist/index.json}.
13
+ *
9
14
  * The minimum required version is 25.7.0, which is when SEA support was added to Node.js.
10
15
  */
11
- nodeVersion: string;
16
+ nodeVersion: (string & {}) | "latest" | "latest-lts" | `${string}.${string}.${string}`;
12
17
  }
13
18
  interface ExeExtensionOptions {
14
19
  /**
package/dist/index.mjs CHANGED
@@ -5,9 +5,8 @@ import { Buffer } from "node:buffer";
5
5
  import { access, chmod, mkdir, rename, rm, writeFile } from "node:fs/promises";
6
6
  import { createDebug } from "obug";
7
7
  import { x } from "tinyexec";
8
- import semver from "semver";
9
8
  import satisfies from "semver/functions/satisfies.js";
10
-
9
+ import valid from "semver/functions/valid.js";
11
10
  //#region src/cache.ts
12
11
  function getCacheDir() {
13
12
  const home = os.homedir();
@@ -24,7 +23,6 @@ function getCachedBinaryPath(target) {
24
23
  const binName = target.platform === "win" ? "node.exe" : "node";
25
24
  return path.join(cacheDir, "node", `v${target.nodeVersion}`, `${target.platform}-${target.arch}`, binName);
26
25
  }
27
-
28
26
  //#endregion
29
27
  //#region ../../src/utils/fs.ts
30
28
  function fsExists(path) {
@@ -36,10 +34,8 @@ function fsRemove(path) {
36
34
  recursive: true
37
35
  }).catch(() => {});
38
36
  }
39
-
40
37
  //#endregion
41
38
  //#region src/platform.ts
42
- const SEA_VERSION_RANGE = ">=25.7.0";
43
39
  function getArchiveExtension(platform) {
44
40
  if (platform === "win") return "zip";
45
41
  if (platform === "linux") return "tar.xz";
@@ -55,22 +51,30 @@ function getBinaryPathInArchive(target) {
55
51
  if (platform === "win") return `${dirName}/node.exe`;
56
52
  return `${dirName}/bin/node`;
57
53
  }
58
- function normalizeNodeVersion(target) {
59
- const version = semver.valid(target.nodeVersion);
60
- if (!version) throw new Error(`Invalid Node.js version: ${target.nodeVersion}. Please provide a valid version string (e.g., "25.7.0").`);
61
- if (!satisfies(version, SEA_VERSION_RANGE)) throw new Error(`Node.js ${version} does not support SEA (Single Executable Applications). Required: ${SEA_VERSION_RANGE}`);
54
+ const NODE_DIST_INDEX_URL = "https://nodejs.org/dist/index.json";
55
+ async function resolveNodeVersion(nodeVersion) {
56
+ if (nodeVersion === "latest" || nodeVersion === "latest-lts") {
57
+ const response = await fetch(NODE_DIST_INDEX_URL);
58
+ if (!response.ok) throw new Error(`Failed to fetch Node.js releases: HTTP ${response.status} from ${NODE_DIST_INDEX_URL}`);
59
+ const releases = await response.json();
60
+ const release = nodeVersion === "latest" ? releases[0] : releases.find((r) => r.lts !== false);
61
+ if (!release) throw new Error(`No matching Node.js release found for "${nodeVersion}".`);
62
+ nodeVersion = release.version.replace(/^v/, "");
63
+ }
64
+ const version = valid(nodeVersion);
65
+ if (!version) throw new Error(`Invalid Node.js version: ${nodeVersion}. Please provide a valid version string (e.g., "25.7.0").`);
66
+ if (!satisfies(version, ">=25.7.0")) throw new Error(`Node.js ${version} does not support SEA (Single Executable Applications). Required minimum version is 25.7.0. Please update the nodeVersion in your target configuration.`);
62
67
  return version;
63
68
  }
64
69
  function getTargetSuffix(target) {
65
70
  return `-${target.platform}-${target.arch}`;
66
71
  }
67
-
68
72
  //#endregion
69
73
  //#region src/download.ts
70
74
  const debug = createDebug("tsdown:exe:download");
71
75
  async function resolveNodeBinary(target, logger) {
72
76
  debug("Resolving Node.js binary for target: %O", target);
73
- target.nodeVersion = normalizeNodeVersion(target);
77
+ target.nodeVersion = await resolveNodeVersion(target.nodeVersion);
74
78
  const cachedPath = getCachedBinaryPath(target);
75
79
  debug("Cache path: %s", cachedPath);
76
80
  if (await fsExists(cachedPath)) {
@@ -129,6 +133,5 @@ async function extractBinary(archivePath, targetBinaryPath, target) {
129
133
  const extractedPath = path.join(outDir, extractedName);
130
134
  if (extractedPath !== targetBinaryPath) await rename(extractedPath, targetBinaryPath);
131
135
  }
132
-
133
136
  //#endregion
134
- export { getCacheDir, getCachedBinaryPath, getTargetSuffix, resolveNodeBinary };
137
+ export { getCacheDir, getCachedBinaryPath, getTargetSuffix, resolveNodeBinary };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tsdown/exe",
3
3
  "type": "module",
4
- "version": "0.21.0-beta.4",
4
+ "version": "0.21.0",
5
5
  "description": "Cross-platform executable building for tsdown",
6
6
  "author": "Kevin Deng <sxzz@sxzz.moe>",
7
7
  "license": "MIT",