api-switch-cc 0.2.3 → 0.2.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.
Files changed (2) hide show
  1. package/install.js +73 -34
  2. package/package.json +1 -1
package/install.js CHANGED
@@ -3,8 +3,10 @@
3
3
  /**
4
4
  * API-Switch — binary downloader & launcher
5
5
  *
6
- * On postinstall, downloads the correct pre-built binary for the
7
- * current platform from GitHub Releases and caches it locally.
6
+ * On postinstall, installs the api-switch binary.
7
+ * Tries multiple methods in order:
8
+ * 1. go install (works behind GFW with goproxy.cn)
9
+ * 2. Download pre-built binary from GitHub Releases
8
10
  *
9
11
  * Usage: npx api-switch-cc <command>
10
12
  * npm install -g api-switch-cc && api-switch serve
@@ -12,17 +14,15 @@
12
14
 
13
15
  "use strict";
14
16
 
15
- const { existsSync, mkdirSync, chmodSync, unlinkSync } = require("fs");
17
+ const { existsSync, mkdirSync, chmodSync, copyFileSync } = require("fs");
16
18
  const { join } = require("path");
17
19
  const { execSync } = require("child_process");
18
20
 
19
21
  const PKG = require("./package.json");
20
- // Download version — points to the GitHub release tag independent of npm version
21
22
  const DOWNLOAD_VERSION = "v0.2.0";
22
- const BASE = `https://github.com/hxz0727/API-Switch/releases/download/${DOWNLOAD_VERSION}`;
23
+ const GH_RELEASE = `https://github.com/hxz0727/API-Switch/releases/download/${DOWNLOAD_VERSION}`;
23
24
  const BIN_DIR = join(__dirname, "bin");
24
25
 
25
- // ── Platform detection ──────────────────────────────
26
26
  function platform() {
27
27
  const map = {
28
28
  "darwin-x64": "darwin-amd64",
@@ -39,48 +39,90 @@ function platform() {
39
39
  return map[key];
40
40
  }
41
41
 
42
- function binaryName() {
43
- if (process.platform === "win32") return "api-switch.exe";
44
- return "api-switch";
42
+ function binName() {
43
+ return process.platform === "win32" ? "api-switch.exe" : "api-switch";
45
44
  }
46
45
 
47
- function archivedBinaryName() {
48
- return `api-switch-${platform()}${process.platform === "win32" ? ".exe" : ""}`;
49
- }
50
-
51
- // ── Download & extract ──────────────────────────────
52
46
  function install() {
53
- const binName = binaryName();
54
- const binPath = join(BIN_DIR, binName);
47
+ const name = binName();
48
+ const binPath = join(BIN_DIR, name);
55
49
 
56
- // Skip if binary exists and is fresh
57
- if (existsSync(binPath)) {
58
- return;
59
- }
50
+ if (existsSync(binPath)) return;
60
51
 
61
52
  mkdirSync(BIN_DIR, { recursive: true });
62
53
 
54
+ // ── Method 1: go install via goproxy.cn (works in China) ──
55
+ if (tryGoInstall(binPath, name)) return;
56
+
57
+ // ── Method 2: Download from GitHub Releases ──
58
+ if (tryGitHubDownload(binPath, name)) return;
59
+
60
+ // ── All methods failed ──
61
+ console.error();
62
+ console.error("Installation failed. Try one of these:");
63
+ console.error();
64
+ console.error(" # Option A: Install via Go (quickest)");
65
+ console.error(" GOPROXY=https://goproxy.cn,direct go install github.com/hxz0727/API-Switch/cmd/api-switch@v0.2.0");
66
+ console.error(" sudo cp ~/go/bin/api-switch /usr/local/bin/");
67
+ console.error();
68
+ console.error(" # Option B: Download binary directly");
69
+ const plat = platform();
70
+ const isWin = process.platform === "win32";
71
+ const archive = `api-switch-${plat}${isWin ? ".zip" : ".tar.gz"}`;
72
+ console.error(` curl -sSL "${GH_RELEASE}/${archive}" | tar xz`);
73
+ console.error(` sudo cp api-switch-${plat} /usr/local/bin/api-switch`);
74
+ console.error();
75
+ console.error(" # Option C: Build from source");
76
+ console.error(" git clone https://github.com/hxz0727/API-Switch.git");
77
+ console.error(" cd API-Switch && make build && sudo make install");
78
+ process.exit(1);
79
+ }
80
+
81
+ function tryGoInstall(binPath, name) {
82
+ try {
83
+ console.log("Trying go install (works behind GFW)...");
84
+ // Use goproxy.cn for Chinese users, fallback to default for others
85
+ execSync(
86
+ `go install github.com/hxz0727/API-Switch/cmd/api-switch@${DOWNLOAD_VERSION}`,
87
+ { stdio: "pipe", timeout: 120000 }
88
+ );
89
+ // go install puts binary in GOPATH/bin or ~/go/bin
90
+ const goPath = (execSync("go env GOPATH", { encoding: "utf8" }) || "~/go").trim();
91
+ const goBin = join(goPath, "bin", name);
92
+ if (existsSync(goBin)) {
93
+ copyFileSync(goBin, binPath);
94
+ chmodSync(binPath, 0o755);
95
+ console.log(`Installed to ${binPath}`);
96
+ return true;
97
+ }
98
+ } catch (_) {
99
+ // go not installed or install failed — try next method
100
+ }
101
+ return false;
102
+ }
103
+
104
+ function tryGitHubDownload(binPath, name) {
63
105
  const plat = platform();
64
106
  const isWin = process.platform === "win32";
65
107
  const archive = `api-switch-${plat}${isWin ? ".zip" : ".tar.gz"}`;
66
- const url = `${BASE}/${archive}`;
108
+ const url = `${GH_RELEASE}/${archive}`;
67
109
  const tmp = join(__dirname, `_${archive}`);
68
110
 
69
111
  console.log(`Downloading ${DOWNLOAD_VERSION} for ${plat} ...`);
70
112
 
71
113
  try {
72
- // Download
73
- execSync(`curl -sSL "${url}" -o "${tmp}"`, { stdio: "pipe" });
114
+ execSync(
115
+ `curl -sSL --connect-timeout 10 --max-time 120 --retry 2 "${url}" -o "${tmp}"`,
116
+ { stdio: "pipe", timeout: 180000 }
117
+ );
74
118
 
75
- // Extract (archive contains binary named api-switch-<plat>)
76
- const archiveBin = archivedBinaryName();
119
+ const archiveBin = `api-switch-${plat}${isWin ? ".exe" : ""}`;
77
120
  if (isWin) {
78
121
  execSync(`unzip -o "${tmp}" "${archiveBin}" -d "${BIN_DIR}"`, { stdio: "pipe" });
79
122
  } else {
80
123
  execSync(`tar xzf "${tmp}" -C "${BIN_DIR}" "${archiveBin}"`, { stdio: "pipe" });
81
124
  }
82
125
 
83
- // Rename to simple binary name (e.g. api-switch-linux-amd64 → api-switch)
84
126
  const extractedPath = join(BIN_DIR, archiveBin);
85
127
  if (extractedPath !== binPath) {
86
128
  execSync(`mv "${extractedPath}" "${binPath}"`, { stdio: "pipe" });
@@ -88,15 +130,12 @@ function install() {
88
130
 
89
131
  chmodSync(binPath, 0o755);
90
132
  unlinkSync(tmp);
91
-
92
133
  console.log(`Installed to ${binPath}`);
134
+ return true;
93
135
  } catch (err) {
94
- console.error(`Download failed: ${err.message}`);
95
- console.log("Falling back to source build (requires Go)...");
96
- execSync(
97
- `cd ${join(__dirname, "..")} && go build -ldflags="-s -w" -o "${binPath}" ./cmd/api-switch/`,
98
- { stdio: "inherit" }
99
- );
136
+ console.error(` Download failed: ${err.message.split('\n')[0]}`);
137
+ try { unlinkSync(tmp); } catch (_) {}
138
+ return false;
100
139
  }
101
140
  }
102
141
 
@@ -107,7 +146,7 @@ if (process.argv[2] === "postinstall") {
107
146
  }
108
147
 
109
148
  // When run as CLI: execute the binary
110
- const binPath = join(BIN_DIR, binaryName());
149
+ const binPath = join(BIN_DIR, binName());
111
150
  const result = require("child_process").spawnSync(binPath, process.argv.slice(2), {
112
151
  stdio: "inherit",
113
152
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-switch-cc",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Claude Code 多模型代理 — 一键切换 DeepSeek、Qwen、GLM、Moonshot 等国产大模型,协议自动转换,零配置即用。LLM API proxy for Claude Code with DeepSeek, Qwen, Anthropic, OpenAI support.",
5
5
  "bin": {
6
6
  "api-switch": "bin/api-switch"