keyapi-cli 0.0.0-stage → 1.0.1

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/README.md CHANGED
@@ -1,3 +1,277 @@
1
- # Temporary Holding Version
1
+ # KeyAPI CLI
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ---
4
+
5
+ [Chinese](https://github.com/EchoSell/keyapi-cli/blob/main/README.zh.md) | [English](https://github.com/EchoSell/keyapi-cli/blob/main/README.md)
6
+
7
+ KeyAPI CLI is a lightweight command line client for the [KeyAPI](https://keyapi.ai) platform. It helps you configure authentication, discover supported API platforms, inspect endpoint schemas, and call APIs without writing request code.
8
+
9
+ ## Why KeyAPI CLI?
10
+
11
+ KeyAPI provides many APIs across platforms such as Google, TikTok, Instagram, and more. When a project uses many endpoints, manually writing and maintaining request code can become repetitive.
12
+
13
+ KeyAPI CLI provides one consistent entry point:
14
+
15
+ - configure your API token once
16
+ - list supported platforms
17
+ - list endpoints under each platform
18
+ - inspect endpoint methods, paths, descriptions, parameters, and request body fields
19
+ - execute API requests from the terminal
20
+ - save large responses to files
21
+
22
+ The CLI reads the latest KeyAPI OpenAPI documentation when endpoint details are requested, so endpoint descriptions and schemas stay aligned with the current KeyAPI API documentation.
23
+
24
+ ## Features
25
+
26
+ - Simple configuration commands: `keyapi set`, `keyapi get`, `keyapi show`, `keyapi clear`
27
+ - API discovery commands: `keyapi spec list-platforms`, `keyapi spec list-endpoints`, `keyapi schema`
28
+ - One request command: `keyapi call`
29
+ - JSON output by default for `spec` and `call`
30
+ - Built-in `--help` output designed for humans, scripts, and agents
31
+ - `--dry-run` support before sending requests
32
+ - `--output "path"` support for large responses
33
+
34
+ ## Installation
35
+
36
+ ### Install with npm
37
+
38
+ Requires Node.js 18 or later. The npm package installs the matching KeyAPI
39
+ binary for your operating system from GitHub Releases:
40
+
41
+ ```bash
42
+ npm install -g @echosell/keyapi-cli
43
+ keyapi --help
44
+ ```
45
+
46
+ If you already have a KeyAPI binary, set `KEYAPI_CLI_BINARY` to its path before
47
+ running `keyapi`.
48
+
49
+ ### Install from Release
50
+
51
+ 1. Open the [GitHub Releases](https://github.com/EchoSell/keyapi-cli/releases) page.
52
+ 2. Download the binary for your operating system.
53
+ ```powershell
54
+ cd ~/keyapi-cli
55
+ keyapi --help
56
+ ```
57
+
58
+ Copy this prompt into an AI assistant such as Claude Code, Codex, Cursor, or Trae if you want it to install the release binary for you:
59
+
60
+ ```text
61
+ Install the latest KeyAPI CLI from https://github.com/EchoSell/keyapi-cli/releases by downloading the binary for the current platform, configuring it so the `keyapi` command is available from the terminal, and verifying the installation with `keyapi --version`.
62
+ ```
63
+
64
+ ### Build from Source
65
+
66
+ Requires Go `v1.22` or later.
67
+
68
+ Clone the repository and build the executable:
69
+
70
+ ```powershell
71
+ git clone https://github.com/EchoSell/keyapi-cli.git
72
+ cd keyapi-cli
73
+ go build -buildvcs=false -o keyapi.exe .
74
+ ```
75
+
76
+ On Linux or macOS, build with:
77
+
78
+ ```bash
79
+ git clone https://github.com/EchoSell/keyapi-cli.git
80
+ cd keyapi-cli
81
+ go build -buildvcs=false -o keyapi .
82
+ ```
83
+
84
+
85
+ Copy this prompt into an AI assistant such as Claude Code, Codex, Cursor, or Trae if you want it to build the project from source:
86
+
87
+ ```text
88
+ Install KeyAPI CLI from source: https://github.com/EchoSell/keyapi-cli.git. Build an executable for the current system, configure it so the `keyapi` command is available from the terminal, and verify the installation by running `keyapi --version`.
89
+ ```
90
+
91
+ After building, continue with the PATH setup section below.
92
+
93
+ ### Make keyapi available on PATH
94
+
95
+ After installing or building the binary, place it in a directory that is available on `PATH`.
96
+
97
+ Windows example:
98
+
99
+ ```powershell
100
+ # Example: keyapi.exe is stored in C:\Tools\keyapi
101
+ $env:Path += ";C:\Tools\keyapi"
102
+ keyapi --help
103
+ ```
104
+
105
+ The command above only updates the current PowerShell session. For permanent use, add the directory to the system or user `PATH` environment variable.
106
+
107
+ Linux or macOS example:
108
+
109
+ ```bash
110
+ chmod +x keyapi
111
+ sudo mv keyapi /usr/local/bin/keyapi
112
+ keyapi --help
113
+ ```
114
+
115
+ ## Quick Start
116
+
117
+ Configure your KeyAPI token:
118
+
119
+ ```powershell
120
+ keyapi set token sk_xxx
121
+ ```
122
+
123
+ Check the current configuration:
124
+
125
+ ```powershell
126
+ keyapi show
127
+ ```
128
+
129
+ List supported platforms:
130
+
131
+ ```powershell
132
+ keyapi spec list-platforms
133
+ ```
134
+
135
+ List endpoints for a platform:
136
+
137
+ ```powershell
138
+ keyapi spec list-endpoints google
139
+ ```
140
+
141
+ Inspect an endpoint before calling it:
142
+
143
+ ```powershell
144
+ keyapi schema google/search
145
+ ```
146
+
147
+ Dry-run a request:
148
+
149
+ ```powershell
150
+ keyapi call "/v1/google/search?q=openai&gl=us&hl=en" --dry-run
151
+ ```
152
+
153
+ Execute the request:
154
+
155
+ ```powershell
156
+ keyapi call "/v1/google/search?q=openai&gl=us&hl=en"
157
+ ```
158
+
159
+ Save a large response:
160
+
161
+ ```powershell
162
+ keyapi call "/v1/google/search?q=openai&gl=us&hl=en" --output "google-search.json"
163
+ ```
164
+
165
+ Clear the saved token when needed:
166
+
167
+ ```powershell
168
+ keyapi clear token
169
+ ```
170
+
171
+ ## Commands
172
+
173
+ | Command | Purpose |
174
+ | --- | --- |
175
+ | `keyapi --help` | Show the main help, recommended order, and command help entry points. |
176
+ | `keyapi set token <value>` | Save the API token locally. |
177
+ | `keyapi set language <en\|zh>` | Set OpenAPI documentation language for endpoint descriptions. |
178
+ | `keyapi get <key>` | Read one local configuration value. |
179
+ | `keyapi show` | Show current local configuration. |
180
+ | `keyapi clear <key>` | Clear one local configuration value. |
181
+ | `keyapi spec list-platforms` | Return a JSON array of supported platforms. |
182
+ | `keyapi spec list-endpoints <platform...\|all>` | Return endpoint summaries for one or more platforms. |
183
+ | `keyapi spec get-endpoint <endpoint-or-path>` | Return method, path, description, parameters, and body fields for one endpoint. |
184
+ | `keyapi schema <endpoint-or-path>` | Short alias for `keyapi spec get-endpoint`. |
185
+ | `keyapi call <endpoint-or-path>` | Execute a KeyAPI request. |
186
+
187
+ Every command supports `--help`:
188
+
189
+ ```powershell
190
+ keyapi --help
191
+ keyapi set --help
192
+ keyapi spec --help
193
+ keyapi spec list-platforms --help
194
+ keyapi spec list-endpoints --help
195
+ keyapi spec get-endpoint --help
196
+ keyapi schema --help
197
+ keyapi call --help
198
+ ```
199
+
200
+ ## Advanced Usage
201
+
202
+ ### JSON Output
203
+
204
+ `spec` and `call` commands return JSON by default.
205
+
206
+ `keyapi spec list-platforms`:
207
+
208
+ ```json
209
+ ["google", "tiktok"]
210
+ ```
211
+
212
+ `keyapi spec list-endpoints tiktok`:
213
+
214
+ ```json
215
+ {
216
+ "tiktok": [
217
+ {
218
+ "method": "GET",
219
+ "path": "/v1/tiktok/influencer/detail",
220
+ "summary": "User detail",
221
+ "description": "Get TikTok user detail."
222
+ }
223
+ ]
224
+ }
225
+ ```
226
+
227
+ ### Save Large Responses
228
+
229
+ Some endpoints return large JSON responses, such as product details, images, SKU lists, or description fields. Use `--output "path"` to write the full response body to a file instead of printing it in the terminal:
230
+
231
+ ```powershell
232
+ keyapi call "/v1/google/search?q=openai&gl=us" --output "outputs/google-search.json"
233
+ ```
234
+
235
+ Relative output paths are resolved from the current working directory.
236
+
237
+ ### Dry Run
238
+
239
+ Use `--dry-run` to print the request without sending it:
240
+
241
+ ```powershell
242
+ keyapi call "/v1/google/search?q=openai&gl=us" --dry-run
243
+ ```
244
+
245
+ ### Request Body
246
+
247
+ Use `--body-json` for JSON request bodies:
248
+
249
+ ```powershell
250
+ keyapi call "/v1/example/post-endpoint" --method POST --body-json '{"page":1,"verified":true}'
251
+ ```
252
+
253
+ Use `--body-raw` for raw text request bodies:
254
+
255
+ ```powershell
256
+ keyapi call "/v1/example/text-endpoint" --method POST --body-raw "plain text"
257
+ ```
258
+
259
+ For GET endpoints, prefer putting query parameters directly in the endpoint path:
260
+
261
+ ```powershell
262
+ keyapi call "/v1/google/search?q=openai&gl=us"
263
+ ```
264
+
265
+ Use `--params "k=v"` or `--query "k=v"` when query parameters are easier to append programmatically.
266
+
267
+ ## Documentation
268
+
269
+ `docs/` contains usage documentation for installing, configuring, and using the CLI. The CLI help output is the primary built-in reference for command usage.
270
+
271
+ | File | Purpose |
272
+ | --- | --- |
273
+ | [docs/index.md](docs/index.md) | Documentation entry point. |
274
+ | [docs/commands.md](docs/commands.md) | Full command and parameter reference. |
275
+ | [docs/config.md](docs/config.md) | Config file and environment variables. |
276
+ | [README.zh.md](README.zh.md) | Chinese README. |
277
+ | [docs/zh/index.md](docs/zh/index.md) | Chinese documentation entry point. |
package/README.zh.md ADDED
@@ -0,0 +1,277 @@
1
+ # KeyAPI CLI
2
+
3
+ ---
4
+
5
+ [中文版](https://github.com/EchoSell/keyapi-cli/blob/main/README.zh.md) | [English](https://github.com/EchoSell/keyapi-cli/blob/main/README.md)
6
+
7
+ KeyAPI CLI 是 [KeyAPI](https://keyapi.ai) 平台的轻量级命令行客户端。它可以帮助你配置认证信息、发现支持的 API 平台、查看接口 schema,并在不编写请求代码的情况下调用 API。
8
+
9
+ ## 为什么选择 KeyAPI CLI?
10
+
11
+ KeyAPI 提供了 Google、TikTok、Instagram 等多个平台的接口。当项目中需要使用大量接口时,手写和维护请求代码会变得重复且容易出错。
12
+
13
+ KeyAPI CLI 提供一个统一的命令行入口:
14
+
15
+ - 配置一次 API token
16
+ - 查看支持的平台
17
+ - 查看每个平台下的接口
18
+ - 查看接口方法、路径、描述、参数和请求体字段
19
+ - 从终端直接执行 API 请求
20
+ - 将大响应保存到文件
21
+
22
+ CLI 会在请求接口详情时读取最新的 KeyAPI OpenAPI 文档,使接口描述和 schema 与当前 KeyAPI API 文档保持一致。
23
+
24
+ ## 功能
25
+
26
+ - 简单的配置命令:`keyapi set`、`keyapi get`、`keyapi show`、`keyapi clear`
27
+ - API 查看命令:`keyapi spec list-platforms`、`keyapi spec list-endpoints`、`keyapi schema`
28
+ - 一个请求命令:`keyapi call`
29
+ - `spec` 和 `call` 默认返回 JSON
30
+ - 内置 `--help` 输出,适合人类用户、脚本和 Agent 阅读
31
+ - 支持 `--dry-run`,发送请求前先查看请求内容
32
+ - 支持 `--output "path"`,保存大响应
33
+
34
+ ## 安装
35
+
36
+ ### 使用 npm 安装
37
+
38
+ 需要 Node.js 18 或更高版本。npm 包会从 GitHub Releases 下载适合当前
39
+ 操作系统的 KeyAPI 二进制文件:
40
+
41
+ ```bash
42
+ npm install -g @echosell/keyapi-cli
43
+ keyapi --help
44
+ ```
45
+
46
+ 如果你已经有可用的 KeyAPI 二进制文件,可以在运行 `keyapi` 前设置
47
+ `KEYAPI_CLI_BINARY` 指向该文件路径。
48
+
49
+ ### 从 Release 安装
50
+
51
+ 1. 打开 [GitHub Releases](https://github.com/EchoSell/keyapi-cli/releases) 页面。
52
+ 2. 下载适合当前系统的二进制文件。
53
+ ```powershell
54
+ cd ~/keyapi-cli
55
+ keyapi --help
56
+ ```
57
+
58
+ 如果你希望 AI 助手帮你安装 release 二进制文件,可以将下面的提示词复制给 Claude Code、Codex、Cursor、Trae 等工具:
59
+
60
+ ```text
61
+ 请从 https://github.com/EchoSell/keyapi-cli/releases 下载并安装适用于当前系统的最新 KeyAPI CLI,完成可执行文件配置,使其可通过 `keyapi` 命令直接调用,并执行 `keyapi --version` 验证安装是否成功。
62
+ ```
63
+
64
+ ### 从源码构建
65
+
66
+ 需要 Go `v1.22` 或更高版本。
67
+
68
+ 克隆仓库并构建可执行文件:
69
+
70
+ ```powershell
71
+ git clone https://github.com/EchoSell/keyapi-cli.git
72
+ cd keyapi-cli
73
+ go build -buildvcs=false -o keyapi.exe .
74
+ ```
75
+
76
+ Linux 或 macOS 使用:
77
+
78
+ ```bash
79
+ git clone https://github.com/EchoSell/keyapi-cli.git
80
+ cd keyapi-cli
81
+ go build -buildvcs=false -o keyapi .
82
+ ```
83
+
84
+
85
+ 如果你希望 AI 助手帮你从源码构建,可以将下面的提示词复制给 Claude Code、Codex、Cursor、Trae 等工具:
86
+
87
+ ```text
88
+ 请从源码安装 KeyAPI CLI:https://github.com/EchoSell/keyapi-cli.git,编译生成适用于当前系统的可执行文件,并配置为可通过 `keyapi` 命令直接调用,最后执行 `keyapi --version` 验证安装结果。
89
+ ```
90
+
91
+ 构建完成后,继续查看下面的 PATH 配置说明。
92
+
93
+ ### 将 keyapi 加入 PATH
94
+
95
+ 安装或构建完成后,可以将二进制文件放到已加入 `PATH` 的目录中。
96
+
97
+ Windows 示例:
98
+
99
+ ```powershell
100
+ # 示例:keyapi.exe 存放在 C:\Tools\keyapi
101
+ $env:Path += ";C:\Tools\keyapi"
102
+ keyapi --help
103
+ ```
104
+
105
+ 上面的命令只会影响当前 PowerShell 会话。长期使用时,请将该目录添加到系统或用户的 `PATH` 环境变量中。
106
+
107
+ Linux 或 macOS 示例:
108
+
109
+ ```bash
110
+ chmod +x keyapi
111
+ sudo mv keyapi /usr/local/bin/keyapi
112
+ keyapi --help
113
+ ```
114
+
115
+ ## 快速开始
116
+
117
+ 配置 KeyAPI token:
118
+
119
+ ```powershell
120
+ keyapi set token sk_xxx
121
+ ```
122
+
123
+ 查看当前配置:
124
+
125
+ ```powershell
126
+ keyapi show
127
+ ```
128
+
129
+ 列出支持的平台:
130
+
131
+ ```powershell
132
+ keyapi spec list-platforms
133
+ ```
134
+
135
+ 列出某个平台的接口:
136
+
137
+ ```powershell
138
+ keyapi spec list-endpoints google
139
+ ```
140
+
141
+ 调用前查看接口详情:
142
+
143
+ ```powershell
144
+ keyapi schema google/search
145
+ ```
146
+
147
+ 先 dry-run 查看请求:
148
+
149
+ ```powershell
150
+ keyapi call "/v1/google/search?q=openai&gl=us&hl=en" --dry-run
151
+ ```
152
+
153
+ 执行请求:
154
+
155
+ ```powershell
156
+ keyapi call "/v1/google/search?q=openai&gl=us&hl=en"
157
+ ```
158
+
159
+ 保存大响应:
160
+
161
+ ```powershell
162
+ keyapi call "/v1/google/search?q=openai&gl=us&hl=en" --output "google-search.json"
163
+ ```
164
+
165
+ 需要时清除已保存的 token:
166
+
167
+ ```powershell
168
+ keyapi clear token
169
+ ```
170
+
171
+ ## 命令
172
+
173
+ | 命令 | 作用 |
174
+ | --- | --- |
175
+ | `keyapi --help` | 查看主帮助、推荐顺序和子命令帮助入口。 |
176
+ | `keyapi set token <value>` | 保存 API token 到本地。 |
177
+ | `keyapi set language <en\|zh>` | 设置接口描述使用的 OpenAPI 文档语言。 |
178
+ | `keyapi get <key>` | 读取一个本地配置值。 |
179
+ | `keyapi show` | 查看当前本地配置。 |
180
+ | `keyapi clear <key>` | 清除一个本地配置值。 |
181
+ | `keyapi spec list-platforms` | 返回支持的平台 JSON 数组。 |
182
+ | `keyapi spec list-endpoints <platform...\|all>` | 返回一个或多个平台的接口摘要。 |
183
+ | `keyapi spec get-endpoint <endpoint-or-path>` | 返回单个接口的方法、路径、描述、参数和 body 字段。 |
184
+ | `keyapi schema <endpoint-or-path>` | `keyapi spec get-endpoint` 的简短别名。 |
185
+ | `keyapi call <endpoint-or-path>` | 执行 KeyAPI 请求。 |
186
+
187
+ 每个命令都支持 `--help`:
188
+
189
+ ```powershell
190
+ keyapi --help
191
+ keyapi set --help
192
+ keyapi spec --help
193
+ keyapi spec list-platforms --help
194
+ keyapi spec list-endpoints --help
195
+ keyapi spec get-endpoint --help
196
+ keyapi schema --help
197
+ keyapi call --help
198
+ ```
199
+
200
+ ## 进阶用法
201
+
202
+ ### JSON 输出
203
+
204
+ `spec` 和 `call` 命令默认返回 JSON。
205
+
206
+ `keyapi spec list-platforms`:
207
+
208
+ ```json
209
+ ["google", "tiktok"]
210
+ ```
211
+
212
+ `keyapi spec list-endpoints tiktok`:
213
+
214
+ ```json
215
+ {
216
+ "tiktok": [
217
+ {
218
+ "method": "GET",
219
+ "path": "/v1/tiktok/influencer/detail",
220
+ "summary": "User detail",
221
+ "description": "Get TikTok user detail."
222
+ }
223
+ ]
224
+ }
225
+ ```
226
+
227
+ ### 保存大响应
228
+
229
+ 部分接口会返回较大的 JSON,例如商品详情、图片列表、SKU 列表或描述字段。建议使用 `--output "path"` 将完整响应体写入文件,避免直接在终端中输出大量内容:
230
+
231
+ ```powershell
232
+ keyapi call "/v1/google/search?q=openai&gl=us" --output "outputs/google-search.json"
233
+ ```
234
+
235
+ 相对路径会基于当前工作目录解析。
236
+
237
+ ### Dry Run
238
+
239
+ 使用 `--dry-run` 打印请求但不发送:
240
+
241
+ ```powershell
242
+ keyapi call "/v1/google/search?q=openai&gl=us" --dry-run
243
+ ```
244
+
245
+ ### 请求体
246
+
247
+ JSON 请求体使用 `--body-json`:
248
+
249
+ ```powershell
250
+ keyapi call "/v1/example/post-endpoint" --method POST --body-json '{"page":1,"verified":true}'
251
+ ```
252
+
253
+ 原始文本请求体使用 `--body-raw`:
254
+
255
+ ```powershell
256
+ keyapi call "/v1/example/text-endpoint" --method POST --body-raw "plain text"
257
+ ```
258
+
259
+ 对于 GET 接口,推荐直接把 query 参数写在接口路径中:
260
+
261
+ ```powershell
262
+ keyapi call "/v1/google/search?q=openai&gl=us"
263
+ ```
264
+
265
+ 需要用程序追加 query 参数时,可以使用 `--params "k=v"` 或 `--query "k=v"`。
266
+
267
+ ## 文档
268
+
269
+ `docs/` 包含 CLI 的安装、配置和使用文档。CLI 的 help 输出是内置的命令使用参考。
270
+
271
+ | 文件 | 作用 |
272
+ | --- | --- |
273
+ | [docs/index.md](docs/index.md) | 文档入口。 |
274
+ | [docs/commands.md](docs/commands.md) | 完整命令和参数参考。 |
275
+ | [docs/config.md](docs/config.md) | 配置文件和环境变量说明。 |
276
+ | [README.md](README.md) | 英文 README。 |
277
+ | [docs/zh/index.md](docs/zh/index.md) | 中文文档入口。 |
package/npm/keyapi.js ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ const { spawnSync } = require('node:child_process');
3
+ const path = require('node:path');
4
+
5
+ const { binaryNameForPlatform } = require('../scripts/platform');
6
+
7
+ function resolveBinaryPath(options = {}) {
8
+ const env = options.env || process.env;
9
+ const platform = options.platform || process.platform;
10
+
11
+ if (env.KEYAPI_CLI_BINARY) {
12
+ return env.KEYAPI_CLI_BINARY;
13
+ }
14
+
15
+ return path.join(__dirname, 'native', binaryNameForPlatform({ platform }));
16
+ }
17
+
18
+ function main() {
19
+ const binaryPath = resolveBinaryPath();
20
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
21
+ stdio: 'inherit',
22
+ });
23
+
24
+ if (result.error) {
25
+ console.error(`Failed to start KeyAPI CLI: ${result.error.message}`);
26
+ console.error('Try reinstalling the npm package, or set KEYAPI_CLI_BINARY.');
27
+ process.exit(1);
28
+ }
29
+
30
+ if (result.signal) {
31
+ process.kill(process.pid, result.signal);
32
+ return;
33
+ }
34
+
35
+ process.exit(result.status ?? 1);
36
+ }
37
+
38
+ if (require.main === module) {
39
+ main();
40
+ }
41
+
42
+ module.exports = {
43
+ resolveBinaryPath,
44
+ };
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "keyapi-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "KeyAPI CLI for discovering endpoint schemas and calling KeyAPI APIs.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/EchoSell/keyapi-cli.git"
9
+ },
10
+ "bin": {
11
+ "keyapi": "npm/keyapi.js"
12
+ },
13
+ "files": [
14
+ "npm",
15
+ "scripts",
16
+ "README.md",
17
+ "README.zh.md"
18
+ ],
19
+ "scripts": {
20
+ "postinstall": "node scripts/install.js",
21
+ "test": "node --test test/*.test.js"
22
+ },
23
+ "keywords": [
24
+ "keyapi",
25
+ "cli",
26
+ "api",
27
+ "openapi"
28
+ ],
29
+ "engines": {
30
+ "node": ">=18"
31
+ }
32
+ }
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('node:fs');
3
+ const https = require('node:https');
4
+ const path = require('node:path');
5
+
6
+ const { assetNameForPlatform, binaryNameForPlatform } = require('./platform');
7
+
8
+ const rootDir = path.resolve(__dirname, '..');
9
+ const packageJson = require(path.join(rootDir, 'package.json'));
10
+
11
+ function download(url, destination, redirects = 0) {
12
+ return new Promise((resolve, reject) => {
13
+ const request = https.get(
14
+ url,
15
+ {
16
+ headers: {
17
+ 'User-Agent': '@echosell/keyapi-cli installer',
18
+ },
19
+ },
20
+ (response) => {
21
+ const location = response.headers.location;
22
+ if (
23
+ response.statusCode >= 300 &&
24
+ response.statusCode < 400 &&
25
+ location
26
+ ) {
27
+ response.resume();
28
+ if (redirects >= 5) {
29
+ reject(new Error('too many redirects while downloading KeyAPI CLI'));
30
+ return;
31
+ }
32
+ download(new URL(location, url).toString(), destination, redirects + 1)
33
+ .then(resolve, reject);
34
+ return;
35
+ }
36
+
37
+ if (response.statusCode !== 200) {
38
+ response.resume();
39
+ reject(new Error(`download failed with HTTP ${response.statusCode}`));
40
+ return;
41
+ }
42
+
43
+ const file = fs.createWriteStream(destination, { mode: 0o755 });
44
+ response.pipe(file);
45
+ file.on('finish', () => {
46
+ file.close(resolve);
47
+ });
48
+ file.on('error', reject);
49
+ },
50
+ );
51
+
52
+ request.on('error', reject);
53
+ });
54
+ }
55
+
56
+ function getInstallPlan(options = {}) {
57
+ const env = options.env || process.env;
58
+ const baseDir = options.rootDir || rootDir;
59
+ const version = options.version || packageJson.version;
60
+
61
+ if (env.KEYAPI_CLI_BINARY) {
62
+ return { skip: true };
63
+ }
64
+
65
+ const assetName = assetNameForPlatform({
66
+ version,
67
+ platform: options.platform,
68
+ arch: options.arch,
69
+ });
70
+ const repo = env.KEYAPI_CLI_REPOSITORY || 'EchoSell/keyapi-cli';
71
+ const tag = env.KEYAPI_CLI_RELEASE_TAG || `v${version}`;
72
+ const url =
73
+ env.KEYAPI_CLI_DOWNLOAD_URL ||
74
+ `https://github.com/${repo}/releases/download/${tag}/${assetName}`;
75
+
76
+ const nativeDir = path.join(baseDir, 'npm', 'native');
77
+ const binaryPath = path.join(
78
+ nativeDir,
79
+ binaryNameForPlatform({ platform: options.platform }),
80
+ );
81
+ const tempPath = `${binaryPath}.download`;
82
+
83
+ return {
84
+ binaryPath,
85
+ nativeDir,
86
+ skip: false,
87
+ tempPath,
88
+ url,
89
+ };
90
+ }
91
+
92
+ async function install(options = {}) {
93
+ const plan = getInstallPlan(options);
94
+ if (plan.skip) {
95
+ return;
96
+ }
97
+
98
+ fs.mkdirSync(plan.nativeDir, { recursive: true });
99
+ if (fs.existsSync(plan.tempPath)) {
100
+ fs.rmSync(plan.tempPath, { force: true });
101
+ }
102
+ if (fs.existsSync(plan.binaryPath)) {
103
+ fs.rmSync(plan.binaryPath, { force: true });
104
+ }
105
+
106
+ await download(plan.url, plan.tempPath);
107
+ fs.renameSync(plan.tempPath, plan.binaryPath);
108
+ fs.chmodSync(plan.binaryPath, 0o755);
109
+ }
110
+
111
+ if (require.main === module) {
112
+ install().catch((error) => {
113
+ console.error(`Failed to install KeyAPI CLI binary: ${error.message}`);
114
+ console.error('Set KEYAPI_CLI_BINARY to an existing keyapi binary to skip download.');
115
+ process.exit(1);
116
+ });
117
+ }
118
+
119
+ module.exports = {
120
+ getInstallPlan,
121
+ install,
122
+ };
@@ -0,0 +1,44 @@
1
+ const osByPlatform = {
2
+ win32: 'windows',
3
+ darwin: 'darwin',
4
+ linux: 'linux',
5
+ };
6
+
7
+ const archByArch = {
8
+ x64: 'amd64',
9
+ arm64: 'arm64',
10
+ };
11
+
12
+ function targetForPlatform(options = {}) {
13
+ const platform = options.platform || process.platform;
14
+ const arch = options.arch || process.arch;
15
+ const os = osByPlatform[platform];
16
+ const goarch = archByArch[arch];
17
+
18
+ if (!os || !goarch) {
19
+ throw new Error(`Unsupported platform: ${platform}/${arch}`);
20
+ }
21
+
22
+ return { os, arch: goarch };
23
+ }
24
+
25
+ function assetNameForPlatform(options = {}) {
26
+ if (!options.version) {
27
+ throw new Error('version is required');
28
+ }
29
+
30
+ const target = targetForPlatform(options);
31
+ const suffix = target.os === 'windows' ? '.exe' : '';
32
+ return `keyapi_${options.version}_${target.os}_${target.arch}${suffix}`;
33
+ }
34
+
35
+ function binaryNameForPlatform(options = {}) {
36
+ const platform = options.platform || process.platform;
37
+ return platform === 'win32' ? 'keyapi.exe' : 'keyapi';
38
+ }
39
+
40
+ module.exports = {
41
+ assetNameForPlatform,
42
+ binaryNameForPlatform,
43
+ targetForPlatform,
44
+ };