@railway/cli 5.30.3 → 5.30.4

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/bin/railway.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { execFileSync } from "child_process";
3
+ import { constants } from "os";
3
4
  import path from "path";
4
5
  import { exit } from "process";
5
6
  import { fileURLToPath } from "url";
@@ -7,10 +8,38 @@ import { fileURLToPath } from "url";
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = path.dirname(__filename);
9
10
  const binName = process.platform === "win32" ? "railway.exe" : "railway";
11
+ const binPath = path.resolve(__dirname, binName);
12
+
10
13
  try {
11
- execFileSync(path.resolve(`${__dirname}/${binName}`), process.argv.slice(2), {
12
- stdio: "inherit",
13
- });
14
+ execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
14
15
  } catch (e) {
15
- exit(1);
16
+ // The binary is downloaded by npm-install/postinstall.js. If that step was
17
+ // skipped (--ignore-scripts) or failed (unsupported platform, network), the
18
+ // spawn fails with ENOENT — say so instead of exiting 1 with no output.
19
+ if (e.code === "ENOENT") {
20
+ console.error(
21
+ `railway: could not find the CLI binary at ${binPath}\n` +
22
+ `The @railway/cli install step did not complete. Try:\n` +
23
+ ` npm install -g @railway/cli --foreground-scripts\n` +
24
+ `or install the CLI directly:\n` +
25
+ ` curl -fsSL https://railway.com/install.sh | sh`,
26
+ );
27
+ exit(127);
28
+ }
29
+
30
+ // Propagate the real exit status. Without this every failure collapses to 1,
31
+ // which hides usage errors (clap exits 2), breaks `set -e` callers that
32
+ // inspect the code, and masks crashes as ordinary failures.
33
+ if (typeof e.status === "number") {
34
+ exit(e.status);
35
+ }
36
+
37
+ // Killed by a signal: report it the way a shell does (128 + signal number)
38
+ // so a segfault surfaces as 139 rather than a generic 1.
39
+ if (e.signal) {
40
+ const signum = constants.signals[e.signal];
41
+ exit(signum ? 128 + signum : 1);
42
+ }
43
+
44
+ exit(1);
16
45
  }
@@ -1,48 +1,114 @@
1
- import triples from "@napi-rs/triples";
2
1
  import { createWriteStream } from "fs";
3
2
  import * as fs from "fs/promises";
4
3
  import fetch from "node-fetch";
4
+ import path from "path";
5
5
  import { pipeline } from "stream/promises";
6
+ import { fileURLToPath } from "url";
6
7
  import tar from "tar";
7
8
 
8
9
  import { CONFIG } from "./config.js";
9
10
 
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ const PACKAGE_ROOT = path.resolve(__dirname, "..");
13
+
14
+ // process.platform/arch -> release target triple.
15
+ //
16
+ // This is deliberately hand-maintained rather than derived from a generic table
17
+ // (we previously used @napi-rs/triples): the generic answer for Linux is always
18
+ // `*-unknown-linux-gnu`, and we do not publish gnu builds for any Linux arch
19
+ // except x86_64. That silently broke `npm i -g @railway/cli` on arm64/arm/ia32
20
+ // Linux with "Failed fetching the binary: Not Found".
21
+ //
22
+ // Every entry below must correspond to an asset produced by
23
+ // .github/workflows/release.yml. Linux uses the statically linked musl builds
24
+ // for the same reason install.sh does: one binary that runs regardless of the
25
+ // host's libc.
26
+ const TARGETS = {
27
+ linux: {
28
+ x64: "x86_64-unknown-linux-musl",
29
+ arm64: "aarch64-unknown-linux-musl",
30
+ ia32: "i686-unknown-linux-musl",
31
+ arm: "arm-unknown-linux-musleabihf",
32
+ },
33
+ darwin: {
34
+ x64: "x86_64-apple-darwin",
35
+ arm64: "aarch64-apple-darwin",
36
+ },
37
+ win32: {
38
+ x64: "x86_64-pc-windows-gnu",
39
+ ia32: "i686-pc-windows-gnu",
40
+ arm64: "aarch64-pc-windows-msvc",
41
+ },
42
+ };
43
+
44
+ function resolveTarget() {
45
+ const { platform, arch } = process;
46
+ const triple = TARGETS[platform]?.[arch];
47
+
48
+ if (!triple) {
49
+ const supported = Object.entries(TARGETS)
50
+ .flatMap(([p, arches]) => Object.keys(arches).map((a) => `${p}-${a}`))
51
+ .join(", ");
52
+ throw new Error(
53
+ `Railway CLI does not ship a prebuilt binary for ${platform}-${arch}.\n` +
54
+ `Supported: ${supported}\n` +
55
+ `Request a build at https://github.com/railwayapp/cli/issues/new, ` +
56
+ `or build from source with \`cargo install railwayapp\`.`,
57
+ );
58
+ }
59
+
60
+ return triple;
61
+ }
62
+
10
63
  async function install() {
11
- const packageJson = await fs.readFile("package.json").then(JSON.parse);
12
- let version = packageJson.version;
13
-
14
- if (typeof version !== "string") {
15
- throw new Error("Missing version in package.json");
16
- }
17
-
18
- if (version[0] === "v") version = version.slice(1);
19
-
20
- // Fetch Static Config
21
- let { name: binName, path: binPath, url } = CONFIG;
22
- let triple = triples.platformArchTriples[process.platform][process.arch][0];
23
-
24
- url = url.replace(/{{triple}}/g, triple.raw);
25
- url = url.replace(/{{version}}/g, version);
26
- url = url.replace(/{{bin_name}}/g, binName);
27
- console.log(url);
28
- const response = await fetch(url);
29
- if (!response.ok) {
30
- throw new Error("Failed fetching the binary: " + response.statusText);
31
- }
32
-
33
- const tarFile = "downloaded.tar.gz";
34
-
35
- await fs.mkdir(binPath, { recursive: true });
36
- await pipeline(response.body, createWriteStream(tarFile));
37
- await tar.x({ file: tarFile, cwd: binPath });
38
- await fs.rm(tarFile);
64
+ const packageJson = await fs
65
+ .readFile(path.join(PACKAGE_ROOT, "package.json"), "utf8")
66
+ .then(JSON.parse);
67
+ let version = packageJson.version;
68
+
69
+ if (typeof version !== "string") {
70
+ throw new Error("Missing version in package.json");
71
+ }
72
+
73
+ if (version[0] === "v") version = version.slice(1);
74
+
75
+ const { name: binName, path: binPath, url } = CONFIG;
76
+ const triple = resolveTarget();
77
+
78
+ const downloadUrl = url
79
+ .replace(/{{triple}}/g, triple)
80
+ .replace(/{{version}}/g, version)
81
+ .replace(/{{bin_name}}/g, binName);
82
+
83
+ console.log(downloadUrl);
84
+ const response = await fetch(downloadUrl);
85
+ if (!response.ok) {
86
+ throw new Error(
87
+ `Failed fetching the binary (${response.status} ${response.statusText}): ${downloadUrl}`,
88
+ );
89
+ }
90
+
91
+ const destDir = path.resolve(PACKAGE_ROOT, binPath);
92
+ const tarFile = path.join(PACKAGE_ROOT, "downloaded.tar.gz");
93
+
94
+ await fs.mkdir(destDir, { recursive: true });
95
+ await pipeline(response.body, createWriteStream(tarFile));
96
+ await tar.x({ file: tarFile, cwd: destDir });
97
+ await fs.rm(tarFile);
98
+
99
+ // Fail loudly here rather than leaving a package whose `railway` shim exits
100
+ // with a confusing ENOENT on first use.
101
+ const expected = path.join(destDir, process.platform === "win32" ? "railway.exe" : "railway");
102
+ await fs.access(expected).catch(() => {
103
+ throw new Error(`Archive did not contain the expected binary at ${expected}`);
104
+ });
39
105
  }
40
106
 
41
107
  install()
42
- .then(async () => {
43
- process.exit(0);
44
- })
45
- .catch(async (err) => {
46
- console.error(err);
47
- process.exit(1);
48
- });
108
+ .then(async () => {
109
+ process.exit(0);
110
+ })
111
+ .catch(async (err) => {
112
+ console.error(err.message ?? err);
113
+ process.exit(1);
114
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@railway/cli",
3
- "version": "5.30.3",
3
+ "version": "5.30.4",
4
4
  "description": "Develop and deploy code with zero configuration",
5
5
  "type": "module",
6
6
  "author": "Jake Runzer",
@@ -24,7 +24,6 @@
24
24
  "README.md"
25
25
  ],
26
26
  "dependencies": {
27
- "@napi-rs/triples": "^1.1.0",
28
27
  "node-fetch": "^3.1.0",
29
28
  "tar": "^6.1.11"
30
29
  }