agc-api-cli 1.0.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/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # AGC API CLI
2
+
3
+ 这是一个用于调用 AppGallery Connect (AGC) REST API 的 Node.js 命令行工具(CLI)。
4
+ 同时,核心的 API 请求被封装在独立的服务类中,可以轻松地被其他 Node.js 项目或 AI Agent (如 MCP Server、Agent Skills) 引入和复用。
5
+
6
+ ## 特性
7
+
8
+ * **解耦设计**:网络层、鉴权层与业务层分离,CLI 仅作为表现层。
9
+ * **自动鉴权**:支持配置 Client ID 和 Client Secret 后,自动获取和缓存 Access Token,并在请求中自动附加。
10
+ * **功能封装**:
11
+ * **Publishing API**:查询 AppID、查询应用信息。
12
+ * **Provisioning API**:查询证书列表。
13
+ * **Upload Management API**:智能封装了单文件与大文件(分片)上传的完整流程。
14
+ * **良好的类型支持**:使用 TypeScript 编写,核心请求与响应均定义了完整的接口。
15
+
16
+ ## 快速开始
17
+
18
+ ### 安装依赖
19
+
20
+ ```bash
21
+ npm install
22
+ npm run build
23
+ ```
24
+
25
+ 可以使用 `npm link` 将命令注册到全局:
26
+
27
+ ```bash
28
+ npm link
29
+ ```
30
+
31
+ ### 配置鉴权
32
+
33
+ 在项目根目录下创建一个 `.env` 文件,或者将以下变量设置到环境变量中:
34
+
35
+ ```env
36
+ AGC_CLIENT_ID=你的_CLIENT_ID
37
+ AGC_CLIENT_SECRET=你的_CLIENT_SECRET
38
+ # 可选,默认使用中国区域名
39
+ # AGC_DOMAIN=connect-api.cloud.huawei.com
40
+ ```
41
+
42
+ ### 使用 CLI
43
+
44
+ 如果执行了 `npm link`,可以直接使用 `agc-cli` 命令;否则可以使用 `npx tsx src/cli/index.ts` 或 `node dist/cli.js` 执行。
45
+
46
+ #### 1. 登录 (缓存 Token)
47
+
48
+ ```bash
49
+ agc-cli auth login
50
+ ```
51
+
52
+ #### 2. Publishing API
53
+
54
+ * 根据包名获取 AppID:
55
+
56
+ ```bash
57
+ agc-cli publish app-id -p com.example.app
58
+ ```
59
+
60
+ * 根据 AppID 查询应用信息:
61
+
62
+ ```bash
63
+ agc-cli publish app-info -a 你的AppID -l zh-CN
64
+ ```
65
+
66
+ #### 3. Upload Management API
67
+
68
+ * 上传文件 (自动根据大小选择分片或单文件上传):
69
+
70
+ ```bash
71
+ agc-cli upload file -a 你的AppID -f ./app.hap -r 1
72
+ ```
73
+
74
+ #### 4. Provisioning API
75
+
76
+ * 获取证书列表:
77
+
78
+ ```bash
79
+ agc-cli provision cert-list
80
+ ```
81
+
82
+ ## 在 MCP / Agent Skills 中使用
83
+
84
+ 本项目的核心服务已在 `src/index.ts` 中导出,可以直接作为依赖使用:
85
+
86
+ ```typescript
87
+ import { PublishService, UploadService, ProvisionService, AuthManager } from 'agc-api-cli';
88
+
89
+ // 确保已配置环境变量 AGC_CLIENT_ID / AGC_CLIENT_SECRET
90
+ // 所有的请求都会自动走拦截器补充 Authorization 头部
91
+
92
+ async function test() {
93
+ const info = await PublishService.getAppInfo('10xxxxxx57');
94
+ console.log(info);
95
+ }
96
+ ```
97
+
98
+ ## 当前支持的接口
99
+
100
+ * `POST /api/oauth2/v1/token` - 获取Token
101
+ * `GET /api/publish/v2/appid-list` - 查询应用包名对应的appid
102
+ * `GET /api/publish/v3/app-info` - 查询应用信息
103
+ * `GET /api/publish/v2/upload-url/for-obs` - 获取文件上传地址
104
+ * `PUT {上传地址}` - 上传单文件/上传分片实体
105
+ * `POST /api/publish/v2/upload/multipart/init` - 分片上传初始化
106
+ * `POST /api/publish/v2/upload/multipart/parts` - 获取分片上传地址
107
+ * `POST /api/publish/v2/upload/multipart/compose` - 合并分片
108
+ * `POST /api/publish/v3/cert` - 申请证书
109
+ * `POST /api/publish/v3/cert/list` - 查询证书
@@ -0,0 +1,411 @@
1
+ // src/config/index.ts
2
+ import * as dotenv from "dotenv";
3
+ import path from "path";
4
+ import fs from "fs";
5
+ var envPath = path.resolve(process.cwd(), ".env");
6
+ if (fs.existsSync(envPath)) {
7
+ dotenv.config({ path: envPath });
8
+ } else {
9
+ dotenv.config();
10
+ }
11
+ function getConfig() {
12
+ const clientId = process.env.AGC_CLIENT_ID;
13
+ const clientSecret = process.env.AGC_CLIENT_SECRET;
14
+ if (!clientId || !clientSecret) {
15
+ throw new Error("Missing AGC credentials. Please set AGC_CLIENT_ID and AGC_CLIENT_SECRET environment variables.");
16
+ }
17
+ return {
18
+ clientId,
19
+ clientSecret,
20
+ domain: process.env.AGC_DOMAIN || "connect-api.cloud.huawei.com"
21
+ };
22
+ }
23
+
24
+ // src/services/auth.ts
25
+ import axios from "axios";
26
+ var AuthService = class {
27
+ /**
28
+ * 获取访问API的Token
29
+ */
30
+ static async getToken() {
31
+ const config2 = getConfig();
32
+ const url = `https://${config2.domain}/api/oauth2/v1/token`;
33
+ const payload = {
34
+ grant_type: "client_credentials",
35
+ client_id: config2.clientId,
36
+ client_secret: config2.clientSecret
37
+ };
38
+ const response = await axios.post(url, payload, {
39
+ headers: {
40
+ "Content-Type": "application/json"
41
+ }
42
+ });
43
+ return response.data;
44
+ }
45
+ };
46
+
47
+ // src/core/auth-mgr.ts
48
+ import fs2 from "fs";
49
+ import path2 from "path";
50
+ import os from "os";
51
+ var AuthManager = class {
52
+ static cacheFile = path2.join(os.homedir(), ".agc-cli-token.json");
53
+ static async getAccessToken() {
54
+ const cache = this.readCache();
55
+ if (cache && cache.expiresAt > Date.now() + 5 * 60 * 1e3) {
56
+ return cache.accessToken;
57
+ }
58
+ const res = await AuthService.getToken();
59
+ if (res.access_token && res.expires_in) {
60
+ const expiresAt = Date.now() + res.expires_in * 1e3;
61
+ this.writeCache({ accessToken: res.access_token, expiresAt });
62
+ return res.access_token;
63
+ }
64
+ throw new Error(`Failed to get token: ${JSON.stringify(res.ret)}`);
65
+ }
66
+ static readCache() {
67
+ try {
68
+ if (fs2.existsSync(this.cacheFile)) {
69
+ const data = fs2.readFileSync(this.cacheFile, "utf8");
70
+ return JSON.parse(data);
71
+ }
72
+ } catch (e) {
73
+ }
74
+ return null;
75
+ }
76
+ static writeCache(cache) {
77
+ try {
78
+ fs2.writeFileSync(this.cacheFile, JSON.stringify(cache, null, 2), "utf8");
79
+ } catch (e) {
80
+ }
81
+ }
82
+ /**
83
+ * 清除缓存的 Token(登出)
84
+ */
85
+ static clearCache() {
86
+ try {
87
+ if (fs2.existsSync(this.cacheFile)) {
88
+ fs2.unlinkSync(this.cacheFile);
89
+ return true;
90
+ }
91
+ return false;
92
+ } catch (e) {
93
+ return false;
94
+ }
95
+ }
96
+ };
97
+
98
+ // src/core/http.ts
99
+ import axios2 from "axios";
100
+ var agcClient = axios2.create();
101
+ agcClient.interceptors.request.use(async (config2) => {
102
+ const cfg = getConfig();
103
+ if (!config2.baseURL) {
104
+ config2.baseURL = `https://${cfg.domain}`;
105
+ }
106
+ const token = await AuthManager.getAccessToken();
107
+ if (!config2.headers) {
108
+ config2.headers = {};
109
+ }
110
+ if (!config2.headers.Authorization) {
111
+ config2.headers.Authorization = `Bearer ${token}`;
112
+ }
113
+ if (!config2.headers.client_id) {
114
+ config2.headers.client_id = cfg.clientId;
115
+ }
116
+ if (config2.data !== void 0 && !config2.headers["Content-Type"]) {
117
+ config2.headers["Content-Type"] = "application/json";
118
+ }
119
+ return config2;
120
+ }, (error) => {
121
+ return Promise.reject(error);
122
+ });
123
+ agcClient.interceptors.response.use(
124
+ (res) => res,
125
+ (err) => {
126
+ if (err.response?.status === 403) {
127
+ const body = err.response?.data;
128
+ const msg = typeof body === "object" ? JSON.stringify(body, null, 2) : body;
129
+ err.message = err.message + (msg ? `
130
+ API \u54CD\u5E94: ${msg}` : "");
131
+ }
132
+ return Promise.reject(err);
133
+ }
134
+ );
135
+
136
+ // src/services/publish.ts
137
+ var PublishService = class {
138
+ /**
139
+ * 查询应用包名对应的appid
140
+ * @param packageName 需要查询的应用包名,多个包名以逗号分隔,最多支持50个
141
+ */
142
+ static async getAppIdList(packageName) {
143
+ const response = await agcClient.get("/api/publish/v2/appid-list", {
144
+ params: { packageName }
145
+ });
146
+ return response.data;
147
+ }
148
+ /**
149
+ * 查询应用信息
150
+ * @param appId 需要查询的应用ID
151
+ * @param lang 需要查询的语言 (例如: 'zh-CN'),不传则查询全部语言
152
+ */
153
+ static async getAppInfo(appId, lang) {
154
+ const params = { appId };
155
+ if (lang) {
156
+ params.lang = lang;
157
+ }
158
+ const response = await agcClient.get("/api/publish/v3/app-info", {
159
+ params
160
+ });
161
+ return response.data;
162
+ }
163
+ };
164
+
165
+ // src/services/upload.ts
166
+ import axios3 from "axios";
167
+ import fs3 from "fs";
168
+ var UploadService = class {
169
+ // ================= Raw APIs =================
170
+ static async getUploadUrl(req) {
171
+ const response = await agcClient.get("/api/publish/v2/upload-url/for-obs", {
172
+ params: req
173
+ });
174
+ return response.data;
175
+ }
176
+ static async initMultipart(req) {
177
+ const response = await agcClient.post("/api/publish/v2/upload/multipart/init", null, {
178
+ params: req
179
+ });
180
+ return response.data;
181
+ }
182
+ static async getMultipartParts(req) {
183
+ const { objectId, nspUploadId, parts } = req;
184
+ const response = await agcClient.post("/api/publish/v2/upload/multipart/parts", parts, {
185
+ params: { objectId, nspUploadId }
186
+ });
187
+ return response.data;
188
+ }
189
+ static async composeMultipart(req) {
190
+ const { objectId, nspUploadId, parts } = req;
191
+ const response = await agcClient.post("/api/publish/v2/upload/multipart/compose", parts, {
192
+ params: { objectId, nspUploadId }
193
+ });
194
+ return response.data;
195
+ }
196
+ // ================= High-level Operations =================
197
+ /**
198
+ * 封装好的上传文件核心流程(支持根据文件大小自动单文件或分片上传)
199
+ * 文件大小 < 5MB 时使用单文件上传,否则使用分片上传
200
+ */
201
+ static async uploadFile(options) {
202
+ const stat = fs3.statSync(options.filePath);
203
+ const fileName = options.filePath.split("/").pop() || "unknown";
204
+ if (stat.size < 5 * 1024 * 1024) {
205
+ await this.uploadSingleFile(options, fileName, stat.size);
206
+ } else {
207
+ await this.uploadMultipartFile(options, fileName, stat.size);
208
+ }
209
+ }
210
+ /**
211
+ * 单文件上传流程
212
+ */
213
+ static async uploadSingleFile(options, fileName, contentLength) {
214
+ const urlRes = await this.getUploadUrl({
215
+ appId: options.appId,
216
+ fileName,
217
+ contentLength,
218
+ releaseType: options.releaseType,
219
+ chineseMainlandFlag: options.chineseMainlandFlag
220
+ });
221
+ if (!urlRes.urlInfo) {
222
+ throw new Error(`Failed to get upload URL: ${JSON.stringify(urlRes.ret)}`);
223
+ }
224
+ const { url, headers } = urlRes.urlInfo;
225
+ const fileStream = fs3.createReadStream(options.filePath);
226
+ await axios3.put(url, fileStream, {
227
+ headers: {
228
+ ...headers,
229
+ "Content-Type": "application/octet-stream"
230
+ },
231
+ maxBodyLength: Infinity,
232
+ maxContentLength: Infinity
233
+ });
234
+ }
235
+ /**
236
+ * 分片上传流程
237
+ */
238
+ static async uploadMultipartFile(options, fileName, fileSize) {
239
+ const initRes = await this.initMultipart({
240
+ appId: options.appId,
241
+ fileName,
242
+ releaseType: options.releaseType,
243
+ chineseMainlandFlag: options.chineseMainlandFlag
244
+ });
245
+ const { objectId, nspUploadId, nspPartMinSize = 5242880 } = initRes;
246
+ if (!objectId || !nspUploadId) {
247
+ throw new Error(`Failed to init multipart upload: ${JSON.stringify(initRes.ret)}`);
248
+ }
249
+ const partSize = Number(nspPartMinSize);
250
+ const partsCount = Math.ceil(fileSize / partSize);
251
+ const partsReqBody = {};
252
+ for (let i = 1; i <= partsCount; i++) {
253
+ const start = (i - 1) * partSize;
254
+ const end = Math.min(start + partSize, fileSize);
255
+ partsReqBody[`additionalProp${i}`] = {
256
+ length: end - start
257
+ };
258
+ }
259
+ const partsRes = await this.getMultipartParts({
260
+ objectId,
261
+ nspUploadId,
262
+ parts: partsReqBody
263
+ });
264
+ const uploadInfoMap = partsRes.uploadInfoMap;
265
+ if (!uploadInfoMap) {
266
+ throw new Error(`Failed to get parts upload URL: ${JSON.stringify(partsRes.ret)}`);
267
+ }
268
+ const fd = fs3.openSync(options.filePath, "r");
269
+ const composeReqBody = {};
270
+ for (let i = 1; i <= partsCount; i++) {
271
+ const propKey = `additionalProp${i}`;
272
+ const uploadInfo = uploadInfoMap[propKey];
273
+ const start = (i - 1) * partSize;
274
+ const end = Math.min(start + partSize, fileSize);
275
+ const length = end - start;
276
+ const buffer = Buffer.alloc(length);
277
+ fs3.readSync(fd, buffer, 0, length, start);
278
+ const res = await axios3.put(uploadInfo.url, buffer, {
279
+ headers: {
280
+ ...uploadInfo.headers,
281
+ "Content-Type": "application/octet-stream"
282
+ },
283
+ maxBodyLength: Infinity,
284
+ maxContentLength: Infinity
285
+ });
286
+ const etag = res.headers["etag"];
287
+ composeReqBody[propKey] = {
288
+ partObjectId: uploadInfo.partObjectId || "",
289
+ etag
290
+ };
291
+ }
292
+ fs3.closeSync(fd);
293
+ await this.composeMultipart({
294
+ objectId,
295
+ nspUploadId,
296
+ parts: composeReqBody
297
+ });
298
+ }
299
+ };
300
+
301
+ // src/services/provision.ts
302
+ var ProvisionService = class {
303
+ // ================= Certificates =================
304
+ static async createCert(req) {
305
+ const response = await agcClient.post("/api/publish/v3/cert", req);
306
+ return response.data;
307
+ }
308
+ static async getCertList(req) {
309
+ const response = await agcClient.post("/api/publish/v3/cert/list", req);
310
+ return response.data;
311
+ }
312
+ static async deleteCert(req) {
313
+ const response = await agcClient.post("/api/publish/v2/cert/delete", req);
314
+ return response.data;
315
+ }
316
+ // ================= Devices =================
317
+ static async addDevice(req) {
318
+ const response = await agcClient.post("/api/publish/v2/device", req);
319
+ return response.data;
320
+ }
321
+ static async getDeviceList(req) {
322
+ const params = new URLSearchParams();
323
+ if (req.deviceName) params.append("deviceName", req.deviceName);
324
+ if (req.fromRecCount) params.append("fromRecCount", String(req.fromRecCount));
325
+ if (req.maxReqCount) params.append("maxReqCount", String(req.maxReqCount));
326
+ if (req.order) params.append("order", String(req.order));
327
+ const url = `/api/publish/v2/device/list?${params.toString()}`;
328
+ const response = await agcClient.get(url);
329
+ return response.data;
330
+ }
331
+ static async deleteDevice(req) {
332
+ const response = await agcClient.post("/api/publish/v2/device/delete", req);
333
+ return response.data;
334
+ }
335
+ // ================= Profile / Provision =================
336
+ static async createProvision(req) {
337
+ const response = await agcClient.post("/api/publish/v3/provision", req);
338
+ return response.data;
339
+ }
340
+ static async getProvisionList(req) {
341
+ const params = new URLSearchParams();
342
+ if (req.fromRecCount) params.append("fromRecCount", String(req.fromRecCount));
343
+ if (req.maxReqCount) params.append("maxReqCount", String(req.maxReqCount));
344
+ const headers = {
345
+ appId: req.appId
346
+ };
347
+ if (req.provisionId) {
348
+ headers.provisionId = req.provisionId;
349
+ }
350
+ const url = `/api/publish/v3/provision/list?${params.toString()}`;
351
+ const response = await agcClient.get(url, { headers });
352
+ return response.data;
353
+ }
354
+ static async updateProvision(req) {
355
+ const response = await agcClient.put("/api/publish/v3/provision", req);
356
+ return response.data;
357
+ }
358
+ static async deleteProvision(req) {
359
+ const params = new URLSearchParams();
360
+ if (req.id) params.append("id", req.id);
361
+ const url = `/api/publish/v2/provision?${params.toString()}`;
362
+ const response = await agcClient.delete(url);
363
+ return response.data;
364
+ }
365
+ // ================= Fingerprint =================
366
+ static async addFingerprint(req) {
367
+ const { appId, ...body } = req;
368
+ const headers = { appId };
369
+ const response = await agcClient.post("/api/provision/v1/fingerprints", body, { headers });
370
+ return response.data;
371
+ }
372
+ static async getFingerprintList(req) {
373
+ const headers = { appId: req.appId };
374
+ const response = await agcClient.get("/api/provision/v1/fingerprints", { headers });
375
+ return response.data;
376
+ }
377
+ static async deleteFingerprint(req) {
378
+ const { appId, ...body } = req;
379
+ const headers = { appId };
380
+ const response = await agcClient.delete("/api/provision/v1/fingerprints", { headers, data: body });
381
+ return response.data;
382
+ }
383
+ // ================= ACL Permission =================
384
+ static async applyACL(req) {
385
+ const { appId, ...body } = req;
386
+ const headers = { appId };
387
+ const response = await agcClient.post("/api/provision/v1/user/permission/apply", body, { headers });
388
+ return response.data;
389
+ }
390
+ static async getACLStatus(req) {
391
+ const headers = { appId: req.appId };
392
+ const response = await agcClient.get("/api/provision/v1/user/permission/apply/status", { headers });
393
+ return response.data;
394
+ }
395
+ static async getACLQuery(req) {
396
+ const headers = { appId: req.appId };
397
+ const response = await agcClient.get("/api/provision/v1/user/permission", { headers });
398
+ return response.data;
399
+ }
400
+ };
401
+
402
+ export {
403
+ getConfig,
404
+ AuthService,
405
+ AuthManager,
406
+ agcClient,
407
+ PublishService,
408
+ UploadService,
409
+ ProvisionService
410
+ };
411
+ //# sourceMappingURL=chunk-CSXIZ7GI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/index.ts","../src/services/auth.ts","../src/core/auth-mgr.ts","../src/core/http.ts","../src/services/publish.ts","../src/services/upload.ts","../src/services/provision.ts"],"sourcesContent":["import * as dotenv from 'dotenv';\nimport path from 'path';\nimport fs from 'fs';\n\n// 尝试从当前目录加载 .env\nconst envPath = path.resolve(process.cwd(), '.env');\nif (fs.existsSync(envPath)) {\n dotenv.config({ path: envPath });\n} else {\n dotenv.config();\n}\n\nexport interface AgcConfig {\n clientId: string;\n clientSecret: string;\n domain: string;\n}\n\nexport function getConfig(): AgcConfig {\n const clientId = process.env.AGC_CLIENT_ID;\n const clientSecret = process.env.AGC_CLIENT_SECRET;\n \n if (!clientId || !clientSecret) {\n throw new Error('Missing AGC credentials. Please set AGC_CLIENT_ID and AGC_CLIENT_SECRET environment variables.');\n }\n\n return {\n clientId,\n clientSecret,\n domain: process.env.AGC_DOMAIN || 'connect-api.cloud.huawei.com',\n };\n}\n","import axios from 'axios';\nimport { TokenRequest, TokenResponse } from '../types/auth';\nimport { getConfig } from '../config';\n\nexport class AuthService {\n /**\n * 获取访问API的Token\n */\n static async getToken(): Promise<TokenResponse> {\n const config = getConfig();\n const url = `https://${config.domain}/api/oauth2/v1/token`;\n \n const payload: TokenRequest = {\n grant_type: 'client_credentials',\n client_id: config.clientId,\n client_secret: config.clientSecret,\n };\n\n const response = await axios.post<TokenResponse>(url, payload, {\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n return response.data;\n }\n}\n","import { AuthService } from '../services/auth';\nimport fs from 'fs';\nimport path from 'path';\nimport os from 'os';\n\nexport interface TokenCache {\n accessToken: string;\n expiresAt: number;\n}\n\nexport class AuthManager {\n private static cacheFile = path.join(os.homedir(), '.agc-cli-token.json');\n\n static async getAccessToken(): Promise<string> {\n const cache = this.readCache();\n // 提前5分钟判断过期,避免临界情况\n if (cache && cache.expiresAt > Date.now() + 5 * 60 * 1000) {\n return cache.accessToken;\n }\n\n // Token不存在或已过期,重新获取\n const res = await AuthService.getToken();\n if (res.access_token && res.expires_in) {\n const expiresAt = Date.now() + res.expires_in * 1000;\n this.writeCache({ accessToken: res.access_token, expiresAt });\n return res.access_token;\n }\n\n throw new Error(`Failed to get token: ${JSON.stringify(res.ret)}`);\n }\n\n private static readCache(): TokenCache | null {\n try {\n if (fs.existsSync(this.cacheFile)) {\n const data = fs.readFileSync(this.cacheFile, 'utf8');\n return JSON.parse(data);\n }\n } catch (e) {\n // 忽略读取错误\n }\n return null;\n }\n\n private static writeCache(cache: TokenCache) {\n try {\n fs.writeFileSync(this.cacheFile, JSON.stringify(cache, null, 2), 'utf8');\n } catch (e) {\n // 忽略写入错误\n }\n }\n\n /**\n * 清除缓存的 Token(登出)\n */\n static clearCache(): boolean {\n try {\n if (fs.existsSync(this.cacheFile)) {\n fs.unlinkSync(this.cacheFile);\n return true;\n }\n return false;\n } catch (e) {\n return false;\n }\n }\n}\n","import axios from 'axios';\nimport { AuthManager } from './auth-mgr';\nimport { getConfig } from '../config';\n\nexport const agcClient = axios.create();\n\n// 请求拦截器:自动补充BaseURL、鉴权Token和client_id\nagcClient.interceptors.request.use(async (config) => {\n const cfg = getConfig();\n \n if (!config.baseURL) {\n config.baseURL = `https://${cfg.domain}`;\n }\n \n const token = await AuthManager.getAccessToken();\n \n if (!config.headers) {\n config.headers = {} as any;\n }\n \n if (!config.headers.Authorization) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n \n if (!config.headers.client_id) {\n config.headers.client_id = cfg.clientId;\n }\n\n // POST/PUT 等带 Body 的请求需显式设置 Content-Type(文档要求)\n if (config.data !== undefined && !config.headers['Content-Type']) {\n config.headers['Content-Type'] = 'application/json';\n }\n\n return config;\n}, (error) => {\n return Promise.reject(error);\n});\n\n// 响应拦截器:403 时输出完整错误信息便于调试\nagcClient.interceptors.response.use(\n (res) => res,\n (err) => {\n if (err.response?.status === 403) {\n const body = err.response?.data;\n const msg = typeof body === 'object' ? JSON.stringify(body, null, 2) : body;\n err.message = err.message + (msg ? `\\nAPI 响应: ${msg}` : '');\n }\n return Promise.reject(err);\n }\n);\n","import { agcClient } from '../core/http';\nimport { AppIdListResponse, AppInfoResponse } from '../types/publish';\n\nexport class PublishService {\n /**\n * 查询应用包名对应的appid\n * @param packageName 需要查询的应用包名,多个包名以逗号分隔,最多支持50个\n */\n static async getAppIdList(packageName: string): Promise<AppIdListResponse> {\n const response = await agcClient.get<AppIdListResponse>('/api/publish/v2/appid-list', {\n params: { packageName }\n });\n return response.data;\n }\n\n /**\n * 查询应用信息\n * @param appId 需要查询的应用ID\n * @param lang 需要查询的语言 (例如: 'zh-CN'),不传则查询全部语言\n */\n static async getAppInfo(appId: string, lang?: string): Promise<AppInfoResponse> {\n const params: any = { appId };\n if (lang) {\n params.lang = lang;\n }\n \n const response = await agcClient.get<AppInfoResponse>('/api/publish/v3/app-info', {\n params\n });\n return response.data;\n }\n}\n","import { agcClient } from '../core/http';\nimport axios from 'axios';\nimport fs from 'fs';\nimport {\n UploadUrlRequest, UploadUrlResponse,\n MultipartInitRequest, MultipartInitResponse,\n MultipartPartsRequest, MultipartPartsResponse,\n MultipartComposeRequest, MultipartComposeResponse,\n UploadFileOptions\n} from '../types/upload';\n\nexport class UploadService {\n // ================= Raw APIs =================\n\n static async getUploadUrl(req: UploadUrlRequest): Promise<UploadUrlResponse> {\n const response = await agcClient.get<UploadUrlResponse>('/api/publish/v2/upload-url/for-obs', {\n params: req\n });\n return response.data;\n }\n\n static async initMultipart(req: MultipartInitRequest): Promise<MultipartInitResponse> {\n const response = await agcClient.post<MultipartInitResponse>('/api/publish/v2/upload/multipart/init', null, {\n params: req\n });\n return response.data;\n }\n\n static async getMultipartParts(req: MultipartPartsRequest): Promise<MultipartPartsResponse> {\n const { objectId, nspUploadId, parts } = req;\n const response = await agcClient.post<MultipartPartsResponse>('/api/publish/v2/upload/multipart/parts', parts, {\n params: { objectId, nspUploadId }\n });\n return response.data;\n }\n\n static async composeMultipart(req: MultipartComposeRequest): Promise<MultipartComposeResponse> {\n const { objectId, nspUploadId, parts } = req;\n const response = await agcClient.post<MultipartComposeResponse>('/api/publish/v2/upload/multipart/compose', parts, {\n params: { objectId, nspUploadId }\n });\n return response.data;\n }\n\n // ================= High-level Operations =================\n\n /**\n * 封装好的上传文件核心流程(支持根据文件大小自动单文件或分片上传)\n * 文件大小 < 5MB 时使用单文件上传,否则使用分片上传\n */\n static async uploadFile(options: UploadFileOptions): Promise<void> {\n const stat = fs.statSync(options.filePath);\n const fileName = options.filePath.split('/').pop() || 'unknown';\n \n // 如果小于 5MB,可以直接使用单文件上传\n if (stat.size < 5 * 1024 * 1024) {\n await this.uploadSingleFile(options, fileName, stat.size);\n } else {\n await this.uploadMultipartFile(options, fileName, stat.size);\n }\n }\n\n /**\n * 单文件上传流程\n */\n private static async uploadSingleFile(\n options: UploadFileOptions,\n fileName: string,\n contentLength: number\n ): Promise<void> {\n // 1. 获取上传文件地址\n const urlRes = await this.getUploadUrl({\n appId: options.appId,\n fileName,\n contentLength,\n releaseType: options.releaseType,\n chineseMainlandFlag: options.chineseMainlandFlag\n });\n\n if (!urlRes.urlInfo) {\n throw new Error(`Failed to get upload URL: ${JSON.stringify(urlRes.ret)}`);\n }\n\n const { url, headers } = urlRes.urlInfo;\n\n // 2. 上传文件\n const fileStream = fs.createReadStream(options.filePath);\n await axios.put(url, fileStream, {\n headers: {\n ...headers,\n 'Content-Type': 'application/octet-stream',\n },\n maxBodyLength: Infinity,\n maxContentLength: Infinity\n });\n }\n\n /**\n * 分片上传流程\n */\n private static async uploadMultipartFile(\n options: UploadFileOptions,\n fileName: string,\n fileSize: number\n ): Promise<void> {\n // 1. 初始化分片上传\n const initRes = await this.initMultipart({\n appId: options.appId,\n fileName,\n releaseType: options.releaseType,\n chineseMainlandFlag: options.chineseMainlandFlag\n });\n\n const { objectId, nspUploadId, nspPartMinSize = 5242880 } = initRes;\n if (!objectId || !nspUploadId) {\n throw new Error(`Failed to init multipart upload: ${JSON.stringify(initRes.ret)}`);\n }\n\n const partSize = Number(nspPartMinSize);\n const partsCount = Math.ceil(fileSize / partSize);\n\n // 2. 构造分片请求信息以获取各分片的上传地址\n const partsReqBody: Record<string, { length: number }> = {};\n for (let i = 1; i <= partsCount; i++) {\n const start = (i - 1) * partSize;\n const end = Math.min(start + partSize, fileSize);\n partsReqBody[`additionalProp${i}`] = {\n length: end - start\n };\n }\n\n const partsRes = await this.getMultipartParts({\n objectId,\n nspUploadId,\n parts: partsReqBody\n });\n\n const uploadInfoMap = partsRes.uploadInfoMap;\n if (!uploadInfoMap) {\n throw new Error(`Failed to get parts upload URL: ${JSON.stringify(partsRes.ret)}`);\n }\n\n // 3. 上传各分片\n const fd = fs.openSync(options.filePath, 'r');\n const composeReqBody: Record<string, { partObjectId: string; etag: string }> = {};\n\n for (let i = 1; i <= partsCount; i++) {\n const propKey = `additionalProp${i}`;\n const uploadInfo = uploadInfoMap[propKey];\n \n const start = (i - 1) * partSize;\n const end = Math.min(start + partSize, fileSize);\n const length = end - start;\n const buffer = Buffer.alloc(length);\n fs.readSync(fd, buffer, 0, length, start);\n\n const res = await axios.put(uploadInfo.url, buffer, {\n headers: {\n ...uploadInfo.headers,\n 'Content-Type': 'application/octet-stream'\n },\n maxBodyLength: Infinity,\n maxContentLength: Infinity\n });\n\n // 记录ETag供合并分片使用\n const etag = res.headers['etag'];\n composeReqBody[propKey] = {\n partObjectId: uploadInfo.partObjectId || \"\",\n etag: etag\n };\n }\n fs.closeSync(fd);\n\n // 4. 合并分片\n await this.composeMultipart({\n objectId,\n nspUploadId,\n parts: composeReqBody\n });\n }\n}\n","import { agcClient } from '../core/http';\nimport {\n CertCreateRequest, CertCreateResponse,\n CertListRequest, CertListResponse,\n CertDeleteRequest, CertDeleteResponse,\n DeviceAddRequest, DeviceAddResponse,\n DeviceListRequest, DeviceListResponse,\n DeviceDeleteRequest, DeviceDeleteResponse,\n ProvisionCreateRequest, ProvisionCreateResponse,\n ProvisionListRequest, ProvisionListResponse,\n ProvisionUpdateRequest, ProvisionUpdateResponse,\n ProvisionDeleteRequest, ProvisionDeleteResponse,\n FingerprintAddRequest, FingerprintAddResponse,\n FingerprintListRequest, FingerprintListResponse,\n FingerprintDeleteRequest, FingerprintDeleteResponse,\n ACLApplyRequest, ACLApplyResponse,\n ACLStatusRequest, ACLStatusResponse,\n ACLQueryRequest, ACLQueryResponse\n} from '../types/provision';\n\nexport class ProvisionService {\n // ================= Certificates =================\n static async createCert(req: CertCreateRequest): Promise<CertCreateResponse> {\n const response = await agcClient.post<CertCreateResponse>('/api/publish/v3/cert', req);\n return response.data;\n }\n\n static async getCertList(req: CertListRequest): Promise<CertListResponse> {\n const response = await agcClient.post<CertListResponse>('/api/publish/v3/cert/list', req);\n return response.data;\n }\n\n static async deleteCert(req: CertDeleteRequest): Promise<CertDeleteResponse> {\n const response = await agcClient.post<CertDeleteResponse>('/api/publish/v2/cert/delete', req);\n return response.data;\n }\n\n // ================= Devices =================\n static async addDevice(req: DeviceAddRequest): Promise<DeviceAddResponse> {\n const response = await agcClient.post<DeviceAddResponse>('/api/publish/v2/device', req);\n return response.data;\n }\n\n static async getDeviceList(req: DeviceListRequest): Promise<DeviceListResponse> {\n const params = new URLSearchParams();\n if (req.deviceName) params.append('deviceName', req.deviceName);\n if (req.fromRecCount) params.append('fromRecCount', String(req.fromRecCount));\n if (req.maxReqCount) params.append('maxReqCount', String(req.maxReqCount));\n if (req.order) params.append('order', String(req.order));\n \n const url = `/api/publish/v2/device/list?${params.toString()}`;\n const response = await agcClient.get<DeviceListResponse>(url);\n return response.data;\n }\n\n static async deleteDevice(req: DeviceDeleteRequest): Promise<DeviceDeleteResponse> {\n const response = await agcClient.post<DeviceDeleteResponse>('/api/publish/v2/device/delete', req);\n return response.data;\n }\n\n // ================= Profile / Provision =================\n static async createProvision(req: ProvisionCreateRequest): Promise<ProvisionCreateResponse> {\n const response = await agcClient.post<ProvisionCreateResponse>('/api/publish/v3/provision', req);\n return response.data;\n }\n\n static async getProvisionList(req: ProvisionListRequest): Promise<ProvisionListResponse> {\n const params = new URLSearchParams();\n if (req.fromRecCount) params.append('fromRecCount', String(req.fromRecCount));\n if (req.maxReqCount) params.append('maxReqCount', String(req.maxReqCount));\n \n // Some parameters like appId and provisionId are sent via headers in the API, we need to pass them in config\n const headers: Record<string, string> = {\n appId: req.appId\n };\n if (req.provisionId) {\n headers.provisionId = req.provisionId;\n }\n\n const url = `/api/publish/v3/provision/list?${params.toString()}`;\n const response = await agcClient.get<ProvisionListResponse>(url, { headers });\n return response.data;\n }\n\n static async updateProvision(req: ProvisionUpdateRequest): Promise<ProvisionUpdateResponse> {\n const response = await agcClient.put<ProvisionUpdateResponse>('/api/publish/v3/provision', req);\n return response.data;\n }\n\n static async deleteProvision(req: ProvisionDeleteRequest): Promise<ProvisionDeleteResponse> {\n const params = new URLSearchParams();\n if (req.id) params.append('id', req.id);\n const url = `/api/publish/v2/provision?${params.toString()}`;\n const response = await agcClient.delete<ProvisionDeleteResponse>(url);\n return response.data;\n }\n\n // ================= Fingerprint =================\n static async addFingerprint(req: FingerprintAddRequest): Promise<FingerprintAddResponse> {\n const { appId, ...body } = req;\n const headers = { appId };\n const response = await agcClient.post<FingerprintAddResponse>('/api/provision/v1/fingerprints', body, { headers });\n return response.data;\n }\n\n static async getFingerprintList(req: FingerprintListRequest): Promise<FingerprintListResponse> {\n const headers = { appId: req.appId };\n const response = await agcClient.get<FingerprintListResponse>('/api/provision/v1/fingerprints', { headers });\n return response.data;\n }\n\n static async deleteFingerprint(req: FingerprintDeleteRequest): Promise<FingerprintDeleteResponse> {\n const { appId, ...body } = req;\n const headers = { appId };\n // Axios delete with body requires 'data' config property\n const response = await agcClient.delete<FingerprintDeleteResponse>('/api/provision/v1/fingerprints', { headers, data: body });\n return response.data;\n }\n\n // ================= ACL Permission =================\n static async applyACL(req: ACLApplyRequest): Promise<ACLApplyResponse> {\n const { appId, ...body } = req;\n const headers = { appId };\n const response = await agcClient.post<ACLApplyResponse>('/api/provision/v1/user/permission/apply', body, { headers });\n return response.data;\n }\n\n static async getACLStatus(req: ACLStatusRequest): Promise<ACLStatusResponse> {\n const headers = { appId: req.appId };\n const response = await agcClient.get<ACLStatusResponse>('/api/provision/v1/user/permission/apply/status', { headers });\n return response.data;\n }\n\n static async getACLQuery(req: ACLQueryRequest): Promise<ACLQueryResponse> {\n const headers = { appId: req.appId };\n const response = await agcClient.get<ACLQueryResponse>('/api/provision/v1/user/permission', { headers });\n return response.data;\n }\n}\n"],"mappings":";AAAA,YAAY,YAAY;AACxB,OAAO,UAAU;AACjB,OAAO,QAAQ;AAGf,IAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM;AAClD,IAAI,GAAG,WAAW,OAAO,GAAG;AAC1B,EAAO,cAAO,EAAE,MAAM,QAAQ,CAAC;AACjC,OAAO;AACL,EAAO,cAAO;AAChB;AAQO,SAAS,YAAuB;AACrC,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,eAAe,QAAQ,IAAI;AAEjC,MAAI,CAAC,YAAY,CAAC,cAAc;AAC9B,UAAM,IAAI,MAAM,gGAAgG;AAAA,EAClH;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,QAAQ,QAAQ,IAAI,cAAc;AAAA,EACpC;AACF;;;AC/BA,OAAO,WAAW;AAIX,IAAM,cAAN,MAAkB;AAAA;AAAA;AAAA;AAAA,EAIvB,aAAa,WAAmC;AAC9C,UAAMA,UAAS,UAAU;AACzB,UAAM,MAAM,WAAWA,QAAO,MAAM;AAEpC,UAAM,UAAwB;AAAA,MAC5B,YAAY;AAAA,MACZ,WAAWA,QAAO;AAAA,MAClB,eAAeA,QAAO;AAAA,IACxB;AAEA,UAAM,WAAW,MAAM,MAAM,KAAoB,KAAK,SAAS;AAAA,MAC7D,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AAED,WAAO,SAAS;AAAA,EAClB;AACF;;;ACzBA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAO,QAAQ;AAOR,IAAM,cAAN,MAAkB;AAAA,EACvB,OAAe,YAAYA,MAAK,KAAK,GAAG,QAAQ,GAAG,qBAAqB;AAAA,EAExE,aAAa,iBAAkC;AAC7C,UAAM,QAAQ,KAAK,UAAU;AAE7B,QAAI,SAAS,MAAM,YAAY,KAAK,IAAI,IAAI,IAAI,KAAK,KAAM;AACzD,aAAO,MAAM;AAAA,IACf;AAGA,UAAM,MAAM,MAAM,YAAY,SAAS;AACvC,QAAI,IAAI,gBAAgB,IAAI,YAAY;AACtC,YAAM,YAAY,KAAK,IAAI,IAAI,IAAI,aAAa;AAChD,WAAK,WAAW,EAAE,aAAa,IAAI,cAAc,UAAU,CAAC;AAC5D,aAAO,IAAI;AAAA,IACb;AAEA,UAAM,IAAI,MAAM,wBAAwB,KAAK,UAAU,IAAI,GAAG,CAAC,EAAE;AAAA,EACnE;AAAA,EAEA,OAAe,YAA+B;AAC5C,QAAI;AACF,UAAID,IAAG,WAAW,KAAK,SAAS,GAAG;AACjC,cAAM,OAAOA,IAAG,aAAa,KAAK,WAAW,MAAM;AACnD,eAAO,KAAK,MAAM,IAAI;AAAA,MACxB;AAAA,IACF,SAAS,GAAG;AAAA,IAEZ;AACA,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,WAAW,OAAmB;AAC3C,QAAI;AACF,MAAAA,IAAG,cAAc,KAAK,WAAW,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,MAAM;AAAA,IACzE,SAAS,GAAG;AAAA,IAEZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,aAAsB;AAC3B,QAAI;AACF,UAAIA,IAAG,WAAW,KAAK,SAAS,GAAG;AACjC,QAAAA,IAAG,WAAW,KAAK,SAAS;AAC5B,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT,SAAS,GAAG;AACV,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACjEA,OAAOE,YAAW;AAIX,IAAM,YAAYC,OAAM,OAAO;AAGtC,UAAU,aAAa,QAAQ,IAAI,OAAOC,YAAW;AACnD,QAAM,MAAM,UAAU;AAEtB,MAAI,CAACA,QAAO,SAAS;AACnB,IAAAA,QAAO,UAAU,WAAW,IAAI,MAAM;AAAA,EACxC;AAEA,QAAM,QAAQ,MAAM,YAAY,eAAe;AAE/C,MAAI,CAACA,QAAO,SAAS;AACnB,IAAAA,QAAO,UAAU,CAAC;AAAA,EACpB;AAEA,MAAI,CAACA,QAAO,QAAQ,eAAe;AACjC,IAAAA,QAAO,QAAQ,gBAAgB,UAAU,KAAK;AAAA,EAChD;AAEA,MAAI,CAACA,QAAO,QAAQ,WAAW;AAC7B,IAAAA,QAAO,QAAQ,YAAY,IAAI;AAAA,EACjC;AAGA,MAAIA,QAAO,SAAS,UAAa,CAACA,QAAO,QAAQ,cAAc,GAAG;AAChE,IAAAA,QAAO,QAAQ,cAAc,IAAI;AAAA,EACnC;AAEA,SAAOA;AACT,GAAG,CAAC,UAAU;AACZ,SAAO,QAAQ,OAAO,KAAK;AAC7B,CAAC;AAGD,UAAU,aAAa,SAAS;AAAA,EAC9B,CAAC,QAAQ;AAAA,EACT,CAAC,QAAQ;AACP,QAAI,IAAI,UAAU,WAAW,KAAK;AAChC,YAAM,OAAO,IAAI,UAAU;AAC3B,YAAM,MAAM,OAAO,SAAS,WAAW,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI;AACvE,UAAI,UAAU,IAAI,WAAW,MAAM;AAAA,oBAAa,GAAG,KAAK;AAAA,IAC1D;AACA,WAAO,QAAQ,OAAO,GAAG;AAAA,EAC3B;AACF;;;AC9CO,IAAM,iBAAN,MAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK1B,aAAa,aAAa,aAAiD;AACzE,UAAM,WAAW,MAAM,UAAU,IAAuB,8BAA8B;AAAA,MACpF,QAAQ,EAAE,YAAY;AAAA,IACxB,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,WAAW,OAAe,MAAyC;AAC9E,UAAM,SAAc,EAAE,MAAM;AAC5B,QAAI,MAAM;AACR,aAAO,OAAO;AAAA,IAChB;AAEA,UAAM,WAAW,MAAM,UAAU,IAAqB,4BAA4B;AAAA,MAChF;AAAA,IACF,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AACF;;;AC9BA,OAAOC,YAAW;AAClB,OAAOC,SAAQ;AASR,IAAM,gBAAN,MAAoB;AAAA;AAAA,EAGzB,aAAa,aAAa,KAAmD;AAC3E,UAAM,WAAW,MAAM,UAAU,IAAuB,sCAAsC;AAAA,MAC5F,QAAQ;AAAA,IACV,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,cAAc,KAA2D;AACpF,UAAM,WAAW,MAAM,UAAU,KAA4B,yCAAyC,MAAM;AAAA,MAC1G,QAAQ;AAAA,IACV,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,kBAAkB,KAA6D;AAC1F,UAAM,EAAE,UAAU,aAAa,MAAM,IAAI;AACzC,UAAM,WAAW,MAAM,UAAU,KAA6B,0CAA0C,OAAO;AAAA,MAC7G,QAAQ,EAAE,UAAU,YAAY;AAAA,IAClC,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,iBAAiB,KAAiE;AAC7F,UAAM,EAAE,UAAU,aAAa,MAAM,IAAI;AACzC,UAAM,WAAW,MAAM,UAAU,KAA+B,4CAA4C,OAAO;AAAA,MACjH,QAAQ,EAAE,UAAU,YAAY;AAAA,IAClC,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,WAAW,SAA2C;AACjE,UAAM,OAAOA,IAAG,SAAS,QAAQ,QAAQ;AACzC,UAAM,WAAW,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAGtD,QAAI,KAAK,OAAO,IAAI,OAAO,MAAM;AAC/B,YAAM,KAAK,iBAAiB,SAAS,UAAU,KAAK,IAAI;AAAA,IAC1D,OAAO;AACL,YAAM,KAAK,oBAAoB,SAAS,UAAU,KAAK,IAAI;AAAA,IAC7D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAqB,iBACnB,SACA,UACA,eACe;AAEf,UAAM,SAAS,MAAM,KAAK,aAAa;AAAA,MACrC,OAAO,QAAQ;AAAA,MACf;AAAA,MACA;AAAA,MACA,aAAa,QAAQ;AAAA,MACrB,qBAAqB,QAAQ;AAAA,IAC/B,CAAC;AAED,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,MAAM,6BAA6B,KAAK,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IAC3E;AAEA,UAAM,EAAE,KAAK,QAAQ,IAAI,OAAO;AAGhC,UAAM,aAAaA,IAAG,iBAAiB,QAAQ,QAAQ;AACvD,UAAMD,OAAM,IAAI,KAAK,YAAY;AAAA,MAC/B,SAAS;AAAA,QACP,GAAG;AAAA,QACH,gBAAgB;AAAA,MAClB;AAAA,MACA,eAAe;AAAA,MACf,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAqB,oBACnB,SACA,UACA,UACe;AAEf,UAAM,UAAU,MAAM,KAAK,cAAc;AAAA,MACvC,OAAO,QAAQ;AAAA,MACf;AAAA,MACA,aAAa,QAAQ;AAAA,MACrB,qBAAqB,QAAQ;AAAA,IAC/B,CAAC;AAED,UAAM,EAAE,UAAU,aAAa,iBAAiB,QAAQ,IAAI;AAC5D,QAAI,CAAC,YAAY,CAAC,aAAa;AAC7B,YAAM,IAAI,MAAM,oCAAoC,KAAK,UAAU,QAAQ,GAAG,CAAC,EAAE;AAAA,IACnF;AAEA,UAAM,WAAW,OAAO,cAAc;AACtC,UAAM,aAAa,KAAK,KAAK,WAAW,QAAQ;AAGhD,UAAM,eAAmD,CAAC;AAC1D,aAAS,IAAI,GAAG,KAAK,YAAY,KAAK;AACpC,YAAM,SAAS,IAAI,KAAK;AACxB,YAAM,MAAM,KAAK,IAAI,QAAQ,UAAU,QAAQ;AAC/C,mBAAa,iBAAiB,CAAC,EAAE,IAAI;AAAA,QACnC,QAAQ,MAAM;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,KAAK,kBAAkB;AAAA,MAC5C;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAED,UAAM,gBAAgB,SAAS;AAC/B,QAAI,CAAC,eAAe;AAClB,YAAM,IAAI,MAAM,mCAAmC,KAAK,UAAU,SAAS,GAAG,CAAC,EAAE;AAAA,IACnF;AAGA,UAAM,KAAKC,IAAG,SAAS,QAAQ,UAAU,GAAG;AAC5C,UAAM,iBAAyE,CAAC;AAEhF,aAAS,IAAI,GAAG,KAAK,YAAY,KAAK;AACpC,YAAM,UAAU,iBAAiB,CAAC;AAClC,YAAM,aAAa,cAAc,OAAO;AAExC,YAAM,SAAS,IAAI,KAAK;AACxB,YAAM,MAAM,KAAK,IAAI,QAAQ,UAAU,QAAQ;AAC/C,YAAM,SAAS,MAAM;AACrB,YAAM,SAAS,OAAO,MAAM,MAAM;AAClC,MAAAA,IAAG,SAAS,IAAI,QAAQ,GAAG,QAAQ,KAAK;AAExC,YAAM,MAAM,MAAMD,OAAM,IAAI,WAAW,KAAK,QAAQ;AAAA,QAClD,SAAS;AAAA,UACP,GAAG,WAAW;AAAA,UACd,gBAAgB;AAAA,QAClB;AAAA,QACA,eAAe;AAAA,QACf,kBAAkB;AAAA,MACpB,CAAC;AAGD,YAAM,OAAO,IAAI,QAAQ,MAAM;AAC/B,qBAAe,OAAO,IAAI;AAAA,QACxB,cAAc,WAAW,gBAAgB;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AACA,IAAAC,IAAG,UAAU,EAAE;AAGf,UAAM,KAAK,iBAAiB;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;;;ACjKO,IAAM,mBAAN,MAAuB;AAAA;AAAA,EAE5B,aAAa,WAAW,KAAqD;AAC3E,UAAM,WAAW,MAAM,UAAU,KAAyB,wBAAwB,GAAG;AACrF,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,YAAY,KAAiD;AACxE,UAAM,WAAW,MAAM,UAAU,KAAuB,6BAA6B,GAAG;AACxF,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,WAAW,KAAqD;AAC3E,UAAM,WAAW,MAAM,UAAU,KAAyB,+BAA+B,GAAG;AAC5F,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,aAAa,UAAU,KAAmD;AACxE,UAAM,WAAW,MAAM,UAAU,KAAwB,0BAA0B,GAAG;AACtF,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,cAAc,KAAqD;AAC9E,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,IAAI,WAAY,QAAO,OAAO,cAAc,IAAI,UAAU;AAC9D,QAAI,IAAI,aAAc,QAAO,OAAO,gBAAgB,OAAO,IAAI,YAAY,CAAC;AAC5E,QAAI,IAAI,YAAa,QAAO,OAAO,eAAe,OAAO,IAAI,WAAW,CAAC;AACzE,QAAI,IAAI,MAAO,QAAO,OAAO,SAAS,OAAO,IAAI,KAAK,CAAC;AAEvD,UAAM,MAAM,+BAA+B,OAAO,SAAS,CAAC;AAC5D,UAAM,WAAW,MAAM,UAAU,IAAwB,GAAG;AAC5D,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,aAAa,KAAyD;AACjF,UAAM,WAAW,MAAM,UAAU,KAA2B,iCAAiC,GAAG;AAChG,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,aAAa,gBAAgB,KAA+D;AAC1F,UAAM,WAAW,MAAM,UAAU,KAA8B,6BAA6B,GAAG;AAC/F,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,iBAAiB,KAA2D;AACvF,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,IAAI,aAAc,QAAO,OAAO,gBAAgB,OAAO,IAAI,YAAY,CAAC;AAC5E,QAAI,IAAI,YAAa,QAAO,OAAO,eAAe,OAAO,IAAI,WAAW,CAAC;AAGzE,UAAM,UAAkC;AAAA,MACtC,OAAO,IAAI;AAAA,IACb;AACA,QAAI,IAAI,aAAa;AACnB,cAAQ,cAAc,IAAI;AAAA,IAC5B;AAEA,UAAM,MAAM,kCAAkC,OAAO,SAAS,CAAC;AAC/D,UAAM,WAAW,MAAM,UAAU,IAA2B,KAAK,EAAE,QAAQ,CAAC;AAC5E,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,gBAAgB,KAA+D;AAC1F,UAAM,WAAW,MAAM,UAAU,IAA6B,6BAA6B,GAAG;AAC9F,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,gBAAgB,KAA+D;AAC1F,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,IAAI,GAAI,QAAO,OAAO,MAAM,IAAI,EAAE;AACtC,UAAM,MAAM,6BAA6B,OAAO,SAAS,CAAC;AAC1D,UAAM,WAAW,MAAM,UAAU,OAAgC,GAAG;AACpE,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,aAAa,eAAe,KAA6D;AACvF,UAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,UAAM,UAAU,EAAE,MAAM;AACxB,UAAM,WAAW,MAAM,UAAU,KAA6B,kCAAkC,MAAM,EAAE,QAAQ,CAAC;AACjH,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,mBAAmB,KAA+D;AAC7F,UAAM,UAAU,EAAE,OAAO,IAAI,MAAM;AACnC,UAAM,WAAW,MAAM,UAAU,IAA6B,kCAAkC,EAAE,QAAQ,CAAC;AAC3G,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,kBAAkB,KAAmE;AAChG,UAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,UAAM,UAAU,EAAE,MAAM;AAExB,UAAM,WAAW,MAAM,UAAU,OAAkC,kCAAkC,EAAE,SAAS,MAAM,KAAK,CAAC;AAC5H,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,aAAa,SAAS,KAAiD;AACrE,UAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,UAAM,UAAU,EAAE,MAAM;AACxB,UAAM,WAAW,MAAM,UAAU,KAAuB,2CAA2C,MAAM,EAAE,QAAQ,CAAC;AACpH,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,aAAa,KAAmD;AAC3E,UAAM,UAAU,EAAE,OAAO,IAAI,MAAM;AACnC,UAAM,WAAW,MAAM,UAAU,IAAuB,kDAAkD,EAAE,QAAQ,CAAC;AACrH,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,aAAa,YAAY,KAAiD;AACxE,UAAM,UAAU,EAAE,OAAO,IAAI,MAAM;AACnC,UAAM,WAAW,MAAM,UAAU,IAAsB,qCAAqC,EAAE,QAAQ,CAAC;AACvG,WAAO,SAAS;AAAA,EAClB;AACF;","names":["config","fs","path","axios","axios","config","axios","fs"]}
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node