bailian-cli-core 0.0.0-beta-ca77c77-20260605
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/LICENSE +202 -0
- package/README.md +14 -0
- package/dist/index.d.mts +994 -0
- package/dist/index.mjs +2102 -0
- package/package.json +47 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2102 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { basename, join } from "path";
|
|
5
|
+
import { stringify } from "yaml";
|
|
6
|
+
import { createHash, createHmac, randomUUID } from "crypto";
|
|
7
|
+
//#region \0rolldown/runtime.js
|
|
8
|
+
var __create = Object.create;
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
+
key = keys[i];
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
19
|
+
get: ((k) => from[k]).bind(null, key),
|
|
20
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
26
|
+
value: mod,
|
|
27
|
+
enumerable: true
|
|
28
|
+
}) : target, mod));
|
|
29
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/errors/codes.ts
|
|
32
|
+
const ExitCode = {
|
|
33
|
+
SUCCESS: 0,
|
|
34
|
+
GENERAL: 1,
|
|
35
|
+
USAGE: 2,
|
|
36
|
+
AUTH: 3,
|
|
37
|
+
QUOTA: 4,
|
|
38
|
+
TIMEOUT: 5,
|
|
39
|
+
NETWORK: 6,
|
|
40
|
+
CONTENT_FILTER: 10
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/errors/base.ts
|
|
44
|
+
var BailianError = class extends Error {
|
|
45
|
+
exitCode;
|
|
46
|
+
hint;
|
|
47
|
+
api;
|
|
48
|
+
constructor(message, exitCode = ExitCode.GENERAL, hint, options) {
|
|
49
|
+
super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
50
|
+
this.name = "BailianError";
|
|
51
|
+
this.exitCode = exitCode;
|
|
52
|
+
this.hint = hint;
|
|
53
|
+
this.api = options?.api;
|
|
54
|
+
}
|
|
55
|
+
toJSON() {
|
|
56
|
+
const causeJson = serializeCause(this.cause);
|
|
57
|
+
return { error: {
|
|
58
|
+
code: this.exitCode,
|
|
59
|
+
message: this.message,
|
|
60
|
+
...this.hint ? { hint: this.hint } : {},
|
|
61
|
+
...this.api?.httpStatus !== void 0 ? { http_status: this.api.httpStatus } : {},
|
|
62
|
+
...this.api?.apiCode ? { api_code: this.api.apiCode } : {},
|
|
63
|
+
...this.api?.requestId ? { request_id: this.api.requestId } : {},
|
|
64
|
+
...causeJson ? { cause: causeJson } : {}
|
|
65
|
+
} };
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function serializeCause(cause) {
|
|
69
|
+
if (cause == null) return void 0;
|
|
70
|
+
if (cause instanceof Error) {
|
|
71
|
+
const out = { message: cause.message };
|
|
72
|
+
const code = cause.code;
|
|
73
|
+
if (code) out.code = code;
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
if (typeof cause === "string" || typeof cause === "number" || typeof cause === "boolean") return { message: String(cause) };
|
|
77
|
+
try {
|
|
78
|
+
return { message: JSON.stringify(cause) };
|
|
79
|
+
} catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/errors/api.ts
|
|
85
|
+
function mapApiError(status, body, _url) {
|
|
86
|
+
const apiMsg = body.error?.message || body.message || `HTTP ${status}`;
|
|
87
|
+
const rawCode = body.error?.type ?? body.code;
|
|
88
|
+
const apiCode = typeof rawCode === "string" ? rawCode : typeof rawCode === "number" ? String(rawCode) : void 0;
|
|
89
|
+
return new BailianError(apiMsg, ExitCode.GENERAL, void 0, { api: {
|
|
90
|
+
httpStatus: status,
|
|
91
|
+
apiCode,
|
|
92
|
+
requestId: body.request_id
|
|
93
|
+
} });
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/config/schema.ts
|
|
97
|
+
const REGIONS = {
|
|
98
|
+
cn: "https://dashscope.aliyuncs.com",
|
|
99
|
+
us: "https://dashscope-us.aliyuncs.com",
|
|
100
|
+
intl: "https://dashscope-intl.aliyuncs.com"
|
|
101
|
+
};
|
|
102
|
+
const DOCS_HOSTS = {
|
|
103
|
+
cn: "https://help.aliyun.com/zh/model-studio",
|
|
104
|
+
us: "https://help.aliyun.com/zh/model-studio",
|
|
105
|
+
intl: "https://help.aliyun.com/zh/model-studio"
|
|
106
|
+
};
|
|
107
|
+
const BAILIAN_HOST = "https://bailian.cn-beijing.aliyuncs.com";
|
|
108
|
+
const VALID_REGIONS = new Set([
|
|
109
|
+
"cn",
|
|
110
|
+
"us",
|
|
111
|
+
"intl"
|
|
112
|
+
]);
|
|
113
|
+
const VALID_OUTPUTS = new Set(["text", "json"]);
|
|
114
|
+
/**
|
|
115
|
+
* A syntactically valid absolute http(s) URL. Used to validate `base_url` and
|
|
116
|
+
* `console_gateway_url` from the config file: the credential-bearing client
|
|
117
|
+
* sends the Bearer token to these origins, so a bare `startsWith("http")` check
|
|
118
|
+
* (which also accepts e.g. "httpfoo://…") is too loose.
|
|
119
|
+
*/
|
|
120
|
+
function isHttpUrl(value) {
|
|
121
|
+
try {
|
|
122
|
+
const u = new URL(value);
|
|
123
|
+
return u.protocol === "http:" || u.protocol === "https:";
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function parseConfigFile(raw) {
|
|
129
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
130
|
+
const obj = raw;
|
|
131
|
+
const out = {};
|
|
132
|
+
if (typeof obj.api_key === "string") out.api_key = obj.api_key;
|
|
133
|
+
if (typeof obj.access_token === "string" && obj.access_token.length > 0) out.access_token = obj.access_token;
|
|
134
|
+
else if (typeof obj.accessToken === "string" && obj.accessToken.length > 0) out.access_token = obj.accessToken;
|
|
135
|
+
if (typeof obj.region === "string" && VALID_REGIONS.has(obj.region)) out.region = obj.region;
|
|
136
|
+
if (typeof obj.base_url === "string" && isHttpUrl(obj.base_url)) out.base_url = obj.base_url;
|
|
137
|
+
if (typeof obj.output === "string" && VALID_OUTPUTS.has(obj.output)) out.output = obj.output;
|
|
138
|
+
if (typeof obj.output_dir === "string" && obj.output_dir.length > 0) out.output_dir = obj.output_dir;
|
|
139
|
+
if (typeof obj.timeout === "number" && obj.timeout > 0) out.timeout = obj.timeout;
|
|
140
|
+
if (typeof obj.default_text_model === "string" && obj.default_text_model.length > 0) out.default_text_model = obj.default_text_model;
|
|
141
|
+
if (typeof obj.default_video_model === "string" && obj.default_video_model.length > 0) out.default_video_model = obj.default_video_model;
|
|
142
|
+
if (typeof obj.default_image_model === "string" && obj.default_image_model.length > 0) out.default_image_model = obj.default_image_model;
|
|
143
|
+
if (typeof obj.default_speech_model === "string" && obj.default_speech_model.length > 0) out.default_speech_model = obj.default_speech_model;
|
|
144
|
+
if (typeof obj.default_omni_model === "string" && obj.default_omni_model.length > 0) out.default_omni_model = obj.default_omni_model;
|
|
145
|
+
if (typeof obj.access_key_id === "string" && obj.access_key_id.length > 0) out.access_key_id = obj.access_key_id;
|
|
146
|
+
if (typeof obj.access_key_secret === "string" && obj.access_key_secret.length > 0) out.access_key_secret = obj.access_key_secret;
|
|
147
|
+
if (typeof obj.workspace_id === "string" && obj.workspace_id.length > 0) out.workspace_id = obj.workspace_id;
|
|
148
|
+
if (typeof obj.console_gateway_url === "string" && isHttpUrl(obj.console_gateway_url)) out.console_gateway_url = obj.console_gateway_url;
|
|
149
|
+
if (typeof obj.telemetry === "boolean") out.telemetry = obj.telemetry;
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/config/paths.ts
|
|
154
|
+
const CONFIG_DIR_NAME = ".bailian";
|
|
155
|
+
function getConfigDir() {
|
|
156
|
+
if (process.env.BAILIAN_CONFIG_DIR) return process.env.BAILIAN_CONFIG_DIR;
|
|
157
|
+
return join(homedir(), CONFIG_DIR_NAME);
|
|
158
|
+
}
|
|
159
|
+
function getConfigPath() {
|
|
160
|
+
return join(getConfigDir(), "config.json");
|
|
161
|
+
}
|
|
162
|
+
function getCredentialsPath() {
|
|
163
|
+
return join(getConfigDir(), "credentials.json");
|
|
164
|
+
}
|
|
165
|
+
async function ensureConfigDir() {
|
|
166
|
+
const dir = getConfigDir();
|
|
167
|
+
const fs = await import("fs/promises");
|
|
168
|
+
await fs.mkdir(dir, {
|
|
169
|
+
recursive: true,
|
|
170
|
+
mode: 448
|
|
171
|
+
});
|
|
172
|
+
try {
|
|
173
|
+
await fs.chmod(dir, 448);
|
|
174
|
+
} catch {}
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/output/text.ts
|
|
178
|
+
function formatText(data) {
|
|
179
|
+
return stringify(data).replace(/\n$/, "");
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/output/json.ts
|
|
183
|
+
function formatJson(data) {
|
|
184
|
+
return JSON.stringify(data, null, 2);
|
|
185
|
+
}
|
|
186
|
+
function formatErrorJson(code, message, hint) {
|
|
187
|
+
return JSON.stringify({ error: {
|
|
188
|
+
code,
|
|
189
|
+
message,
|
|
190
|
+
...hint ? { hint } : {}
|
|
191
|
+
} }, null, 2);
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/output/formatter.ts
|
|
195
|
+
function detectOutputFormat(flagValue) {
|
|
196
|
+
if (flagValue === "json" || flagValue === "text") return flagValue;
|
|
197
|
+
if (!process.stdout.isTTY) return "json";
|
|
198
|
+
return "text";
|
|
199
|
+
}
|
|
200
|
+
function formatOutput(data, format) {
|
|
201
|
+
switch (format) {
|
|
202
|
+
case "json": return formatJson(data);
|
|
203
|
+
case "text": return formatText(data);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/config/loader.ts
|
|
208
|
+
function readConfigFile() {
|
|
209
|
+
const path = getConfigPath();
|
|
210
|
+
if (!existsSync(path)) return {};
|
|
211
|
+
try {
|
|
212
|
+
return parseConfigFile(JSON.parse(readFileSync(path, "utf-8")));
|
|
213
|
+
} catch (err) {
|
|
214
|
+
const e = err;
|
|
215
|
+
if (e instanceof SyntaxError || e.message.includes("JSON")) console.warn("Warning: config file is corrupted; using defaults.");
|
|
216
|
+
return {};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function writeConfigFile(data) {
|
|
220
|
+
await ensureConfigDir();
|
|
221
|
+
const path = getConfigPath();
|
|
222
|
+
const tmp = path + ".tmp";
|
|
223
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
|
|
224
|
+
renameSync(tmp, path);
|
|
225
|
+
}
|
|
226
|
+
function loadConfig(flags) {
|
|
227
|
+
const file = readConfigFile();
|
|
228
|
+
const apiKey = flags.apiKey || void 0;
|
|
229
|
+
const fileApiKey = file.api_key;
|
|
230
|
+
const accessTokenEnv = process.env.DASHSCOPE_ACCESS_TOKEN?.trim() || void 0;
|
|
231
|
+
const fileAccessToken = file.access_token?.trim() || void 0;
|
|
232
|
+
const explicitRegion = flags.region || process.env.DASHSCOPE_REGION || void 0;
|
|
233
|
+
const cachedRegion = file.region;
|
|
234
|
+
const region = explicitRegion || cachedRegion || "cn";
|
|
235
|
+
const baseUrl = flags.baseUrl || process.env.DASHSCOPE_BASE_URL || file.base_url || REGIONS[region] || REGIONS.cn;
|
|
236
|
+
const output = detectOutputFormat(flags.output || process.env.DASHSCOPE_OUTPUT || file.output);
|
|
237
|
+
const envTimeout = process.env.DASHSCOPE_TIMEOUT ? Number(process.env.DASHSCOPE_TIMEOUT) : void 0;
|
|
238
|
+
const validEnvTimeout = envTimeout !== void 0 && Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : void 0;
|
|
239
|
+
const timeout = flags.timeout ?? validEnvTimeout ?? file.timeout ?? 300;
|
|
240
|
+
if (!Number.isFinite(timeout) || timeout <= 0) throw new BailianError("Timeout must be a positive finite number.", ExitCode.USAGE);
|
|
241
|
+
return {
|
|
242
|
+
apiKey,
|
|
243
|
+
accessTokenEnv,
|
|
244
|
+
fileAccessToken,
|
|
245
|
+
fileApiKey,
|
|
246
|
+
fileRegion: file.region,
|
|
247
|
+
configPath: getConfigPath(),
|
|
248
|
+
region,
|
|
249
|
+
baseUrl,
|
|
250
|
+
output,
|
|
251
|
+
outputDir: file.output_dir || void 0,
|
|
252
|
+
timeout,
|
|
253
|
+
defaultTextModel: file.default_text_model,
|
|
254
|
+
defaultVideoModel: file.default_video_model,
|
|
255
|
+
defaultImageModel: file.default_image_model,
|
|
256
|
+
defaultSpeechModel: file.default_speech_model,
|
|
257
|
+
defaultOmniModel: file.default_omni_model,
|
|
258
|
+
accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID || file.access_key_id || void 0,
|
|
259
|
+
accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET || file.access_key_secret || void 0,
|
|
260
|
+
workspaceId: process.env.BAILIAN_WORKSPACE_ID || file.workspace_id || void 0,
|
|
261
|
+
consoleGatewayUrl: process.env.BAILIAN_CONSOLE_GATEWAY_URL || file.console_gateway_url || "https://bailian-cs.console.aliyun.com",
|
|
262
|
+
verbose: flags.verbose || process.env.DASHSCOPE_VERBOSE === "1",
|
|
263
|
+
quiet: flags.quiet || false,
|
|
264
|
+
noColor: flags.noColor || process.env.NO_COLOR !== void 0 || !process.stdout.isTTY,
|
|
265
|
+
yes: flags.yes || false,
|
|
266
|
+
dryRun: flags.dryRun || false,
|
|
267
|
+
nonInteractive: flags.nonInteractive || false,
|
|
268
|
+
async: flags.async || false,
|
|
269
|
+
telemetry: process.env.DO_NOT_TRACK === "1" ? false : file.telemetry ?? true
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/auth/credentials.ts
|
|
274
|
+
function loadApiKeyFromConfig() {
|
|
275
|
+
const path = getConfigPath();
|
|
276
|
+
if (!existsSync(path)) return null;
|
|
277
|
+
try {
|
|
278
|
+
const raw = readFileSync(path, "utf-8");
|
|
279
|
+
const data = JSON.parse(raw);
|
|
280
|
+
if (typeof data.api_key === "string" && data.api_key.length > 0) return data.api_key;
|
|
281
|
+
return null;
|
|
282
|
+
} catch {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async function saveApiKeyToConfig(apiKey) {
|
|
287
|
+
await ensureConfigDir();
|
|
288
|
+
const path = getConfigPath();
|
|
289
|
+
let existing = {};
|
|
290
|
+
try {
|
|
291
|
+
existing = JSON.parse(readFileSync(path, "utf-8"));
|
|
292
|
+
} catch {}
|
|
293
|
+
existing.api_key = apiKey;
|
|
294
|
+
const tmp = path + ".tmp";
|
|
295
|
+
writeFileSync(tmp, JSON.stringify(existing, null, 2) + "\n", { mode: 384 });
|
|
296
|
+
renameSync(tmp, path);
|
|
297
|
+
}
|
|
298
|
+
async function clearApiKey() {
|
|
299
|
+
const path = getConfigPath();
|
|
300
|
+
if (!existsSync(path)) return;
|
|
301
|
+
try {
|
|
302
|
+
const existing = JSON.parse(readFileSync(path, "utf-8"));
|
|
303
|
+
delete existing.api_key;
|
|
304
|
+
delete existing.access_token;
|
|
305
|
+
const tmp = path + ".tmp";
|
|
306
|
+
writeFileSync(tmp, JSON.stringify(existing, null, 2) + "\n", { mode: 384 });
|
|
307
|
+
renameSync(tmp, path);
|
|
308
|
+
} catch {}
|
|
309
|
+
}
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/auth/resolver.ts
|
|
312
|
+
async function resolveCredential(config) {
|
|
313
|
+
if (config.apiKey) return {
|
|
314
|
+
token: config.apiKey,
|
|
315
|
+
method: "api-key",
|
|
316
|
+
source: "flag"
|
|
317
|
+
};
|
|
318
|
+
if (config.fileApiKey) return {
|
|
319
|
+
token: config.fileApiKey,
|
|
320
|
+
method: "api-key",
|
|
321
|
+
source: "config.json"
|
|
322
|
+
};
|
|
323
|
+
if (config.accessTokenEnv) return {
|
|
324
|
+
token: config.accessTokenEnv,
|
|
325
|
+
method: "access-token",
|
|
326
|
+
source: "DASHSCOPE_ACCESS_TOKEN"
|
|
327
|
+
};
|
|
328
|
+
if (config.fileAccessToken) return {
|
|
329
|
+
token: config.fileAccessToken,
|
|
330
|
+
method: "access-token",
|
|
331
|
+
source: "config.json"
|
|
332
|
+
};
|
|
333
|
+
if (process.env.DASHSCOPE_API_KEY) return {
|
|
334
|
+
token: process.env.DASHSCOPE_API_KEY,
|
|
335
|
+
method: "api-key",
|
|
336
|
+
source: "DASHSCOPE_API_KEY"
|
|
337
|
+
};
|
|
338
|
+
throw new BailianError("No credentials found.", ExitCode.AUTH, "Set DASHSCOPE_API_KEY environment variable, pass --api-key, or configure a key.");
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Credential for Bailian **console** CLI gateway only (`callConsoleGateway`).
|
|
342
|
+
* DashScope API keys are not valid Bearer tokens for this gateway — use env/file
|
|
343
|
+
* `access_token` even when `api_key` is also present in config.
|
|
344
|
+
*/
|
|
345
|
+
/** Thrown when `callConsoleGateway` has no usable console session token. */
|
|
346
|
+
const CONSOLE_GATEWAY_NO_TOKEN_MESSAGE = "No console access token found.";
|
|
347
|
+
async function resolveConsoleGatewayCredential(config) {
|
|
348
|
+
if (config.accessTokenEnv) return {
|
|
349
|
+
token: config.accessTokenEnv,
|
|
350
|
+
method: "access-token",
|
|
351
|
+
source: "DASHSCOPE_ACCESS_TOKEN"
|
|
352
|
+
};
|
|
353
|
+
if (config.fileAccessToken) return {
|
|
354
|
+
token: config.fileAccessToken,
|
|
355
|
+
method: "access-token",
|
|
356
|
+
source: "config.json"
|
|
357
|
+
};
|
|
358
|
+
throw new BailianError(CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, ExitCode.AUTH, "Run `bl auth login --console` or set DASHSCOPE_ACCESS_TOKEN.");
|
|
359
|
+
}
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/client/ak-sign.ts
|
|
362
|
+
/**
|
|
363
|
+
* Alibaba Cloud V3 Signature (ROA style) for Bailian Cloud API.
|
|
364
|
+
*
|
|
365
|
+
* Used by Knowledge Base Retrieve API which requires AK/SK authentication
|
|
366
|
+
* instead of Bearer token.
|
|
367
|
+
*
|
|
368
|
+
* Reference: https://help.aliyun.com/document_detail/2712195.html
|
|
369
|
+
*/
|
|
370
|
+
function signRequest(cfg) {
|
|
371
|
+
const method = cfg.method ?? "POST";
|
|
372
|
+
const dateISO = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
373
|
+
const nonce = randomUUID();
|
|
374
|
+
const hashedBody = sha256Hex(cfg.body);
|
|
375
|
+
const headers = {
|
|
376
|
+
host: cfg.host,
|
|
377
|
+
"x-acs-action": cfg.action,
|
|
378
|
+
"x-acs-version": cfg.version,
|
|
379
|
+
"x-acs-date": dateISO,
|
|
380
|
+
"x-acs-signature-nonce": nonce,
|
|
381
|
+
"x-acs-content-sha256": hashedBody,
|
|
382
|
+
"content-type": "application/json"
|
|
383
|
+
};
|
|
384
|
+
const signedHeaderKeys = Object.keys(headers).filter((k) => k === "host" || k === "content-type" || k.startsWith("x-acs-")).sort();
|
|
385
|
+
const canonicalHeaders = signedHeaderKeys.map((k) => `${k}:${headers[k]}`).join("\n") + "\n";
|
|
386
|
+
const signedHeadersStr = signedHeaderKeys.join(";");
|
|
387
|
+
const canonicalRequest = [
|
|
388
|
+
method,
|
|
389
|
+
cfg.pathname,
|
|
390
|
+
"",
|
|
391
|
+
canonicalHeaders,
|
|
392
|
+
signedHeadersStr,
|
|
393
|
+
hashedBody
|
|
394
|
+
].join("\n");
|
|
395
|
+
const algorithm = "ACS3-HMAC-SHA256";
|
|
396
|
+
const stringToSign = `${algorithm}\n${sha256Hex(canonicalRequest)}`;
|
|
397
|
+
const signature = hmacSHA256Hex(cfg.accessKeySecret, stringToSign);
|
|
398
|
+
headers["authorization"] = `${algorithm} Credential=${cfg.accessKeyId},SignedHeaders=${signedHeadersStr},Signature=${signature}`;
|
|
399
|
+
return headers;
|
|
400
|
+
}
|
|
401
|
+
function sha256Hex(data) {
|
|
402
|
+
return createHash("sha256").update(data, "utf8").digest("hex");
|
|
403
|
+
}
|
|
404
|
+
function hmacSHA256Hex(key, data) {
|
|
405
|
+
return createHmac("sha256", key).update(data, "utf8").digest("hex");
|
|
406
|
+
}
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region src/client/endpoints.ts
|
|
409
|
+
function chatEndpoint(baseUrl) {
|
|
410
|
+
return `${baseUrl}/compatible-mode/v1/chat/completions`;
|
|
411
|
+
}
|
|
412
|
+
function imageEndpoint(baseUrl) {
|
|
413
|
+
return `${baseUrl}/api/v1/services/aigc/image-generation/generation`;
|
|
414
|
+
}
|
|
415
|
+
function imageSyncEndpoint(baseUrl) {
|
|
416
|
+
return `${baseUrl}/api/v1/services/aigc/multimodal-generation/generation`;
|
|
417
|
+
}
|
|
418
|
+
function videoGenerateEndpoint(baseUrl) {
|
|
419
|
+
return `${baseUrl}/api/v1/services/aigc/video-generation/video-synthesis`;
|
|
420
|
+
}
|
|
421
|
+
function taskEndpoint(baseUrl, taskId) {
|
|
422
|
+
return `${baseUrl}/api/v1/tasks/${encodeURIComponent(taskId)}`;
|
|
423
|
+
}
|
|
424
|
+
function appCompletionEndpoint(baseUrl, appId) {
|
|
425
|
+
return `${baseUrl}/api/v1/apps/${encodeURIComponent(appId)}/completion`;
|
|
426
|
+
}
|
|
427
|
+
function memoryAddEndpoint(baseUrl) {
|
|
428
|
+
return `${baseUrl}/api/v2/apps/memory/add`;
|
|
429
|
+
}
|
|
430
|
+
function memorySearchEndpoint(baseUrl) {
|
|
431
|
+
return `${baseUrl}/api/v2/apps/memory/memory_nodes/search`;
|
|
432
|
+
}
|
|
433
|
+
function memoryListEndpoint(baseUrl) {
|
|
434
|
+
return `${baseUrl}/api/v2/apps/memory/memory_nodes`;
|
|
435
|
+
}
|
|
436
|
+
function memoryNodeEndpoint(baseUrl, nodeId) {
|
|
437
|
+
return `${baseUrl}/api/v2/apps/memory/memory_nodes/${encodeURIComponent(nodeId)}`;
|
|
438
|
+
}
|
|
439
|
+
function speechSynthesizeEndpoint(baseUrl) {
|
|
440
|
+
return `${baseUrl}/api/v1/services/audio/tts/SpeechSynthesizer`;
|
|
441
|
+
}
|
|
442
|
+
function speechRecognizeEndpoint(baseUrl) {
|
|
443
|
+
return `${baseUrl}/api/v1/services/audio/asr/transcription`;
|
|
444
|
+
}
|
|
445
|
+
function profileSchemaEndpoint(baseUrl) {
|
|
446
|
+
return `${baseUrl}/api/v2/apps/memory/profile_schemas`;
|
|
447
|
+
}
|
|
448
|
+
function userProfileEndpoint(baseUrl, schemaId) {
|
|
449
|
+
return `${baseUrl}/api/v2/apps/memory/profile_schemas/${encodeURIComponent(schemaId)}/profiles`;
|
|
450
|
+
}
|
|
451
|
+
function mcpWebSearchEndpoint(baseUrl) {
|
|
452
|
+
return `${baseUrl}/api/v1/mcps/WebSearch/mcp`;
|
|
453
|
+
}
|
|
454
|
+
//#endregion
|
|
455
|
+
//#region src/client/headers.ts
|
|
456
|
+
/**
|
|
457
|
+
* Shared HTTP request headers for all outgoing requests.
|
|
458
|
+
*
|
|
459
|
+
* Centralises the `x-dashscope-source-config` header so every fetch call
|
|
460
|
+
* (both via the central http client and the bypass paths) uses the
|
|
461
|
+
* same values from a single source of truth.
|
|
462
|
+
*/
|
|
463
|
+
const CHANNEL = "bailian-cli";
|
|
464
|
+
const TAGS = {
|
|
465
|
+
t1: "public",
|
|
466
|
+
t2: ""
|
|
467
|
+
};
|
|
468
|
+
const SOURCE_CONFIG = JSON.stringify({
|
|
469
|
+
channel: CHANNEL,
|
|
470
|
+
tags: TAGS
|
|
471
|
+
});
|
|
472
|
+
/** Standard tracking headers required on every outbound request. */
|
|
473
|
+
function trackingHeaders() {
|
|
474
|
+
return { "x-dashscope-source-config": SOURCE_CONFIG };
|
|
475
|
+
}
|
|
476
|
+
//#endregion
|
|
477
|
+
//#region src/utils/token.ts
|
|
478
|
+
function maskToken(token) {
|
|
479
|
+
return token.length > 8 ? `${token.slice(0, 4)}...${token.slice(-4)}` : "***";
|
|
480
|
+
}
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region src/client/http.ts
|
|
483
|
+
/**
|
|
484
|
+
* Bailian requires `X-DashScope-OssResourceResolve: enable` on any request whose body
|
|
485
|
+
* references an `oss://` URL (returned by the upload API). Detected automatically here
|
|
486
|
+
* so callers don't need to track it manually.
|
|
487
|
+
*/
|
|
488
|
+
function bodyReferencesOssUrl(body) {
|
|
489
|
+
if (body == null || typeof body !== "object") return false;
|
|
490
|
+
if (body instanceof FormData) return false;
|
|
491
|
+
return JSON.stringify(body).includes("oss://");
|
|
492
|
+
}
|
|
493
|
+
async function request(config, opts) {
|
|
494
|
+
const isFormData = typeof FormData !== "undefined" && opts.body instanceof FormData;
|
|
495
|
+
const headers = {
|
|
496
|
+
"User-Agent": `${config.clientName ?? "bailian-cli-core"}/${config.clientVersion ?? "0.0.0-dev"}`,
|
|
497
|
+
...trackingHeaders(),
|
|
498
|
+
...opts.headers
|
|
499
|
+
};
|
|
500
|
+
if (!isFormData && !headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
|
501
|
+
if (opts.async) headers["X-DashScope-Async"] = "enable";
|
|
502
|
+
if (bodyReferencesOssUrl(opts.body)) headers["X-DashScope-OssResourceResolve"] = "enable";
|
|
503
|
+
if (!opts.noAuth) {
|
|
504
|
+
const credential = await resolveCredential(config);
|
|
505
|
+
headers["Authorization"] = `Bearer ${credential.token}`;
|
|
506
|
+
if (config.verbose) {
|
|
507
|
+
console.error(`> ${opts.method ?? "GET"} ${opts.url}`);
|
|
508
|
+
console.error(`> Auth: ${maskToken(credential.token)}`);
|
|
509
|
+
console.error(`> x-dashscope-source-config: ${SOURCE_CONFIG}`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const requestSignal = createRequestSignal((opts.timeout ?? config.timeout) * 1e3, opts.signal);
|
|
513
|
+
const res = await fetch(opts.url, {
|
|
514
|
+
method: opts.method ?? "GET",
|
|
515
|
+
headers,
|
|
516
|
+
body: opts.body ? isFormData ? opts.body : JSON.stringify(opts.body) : void 0,
|
|
517
|
+
signal: requestSignal.signal
|
|
518
|
+
}).finally(requestSignal.cleanup);
|
|
519
|
+
if (config.verbose) {
|
|
520
|
+
console.error(`< ${res.status} ${res.statusText}`);
|
|
521
|
+
const reqId = res.headers.get("x-request-id");
|
|
522
|
+
if (reqId) console.error(`request_id: ${reqId}`);
|
|
523
|
+
}
|
|
524
|
+
if (!res.ok) {
|
|
525
|
+
let body = {};
|
|
526
|
+
try {
|
|
527
|
+
body = await res.json();
|
|
528
|
+
} catch {}
|
|
529
|
+
throw mapApiError(res.status, body, opts.url);
|
|
530
|
+
}
|
|
531
|
+
return res;
|
|
532
|
+
}
|
|
533
|
+
function createRequestSignal(timeoutMs, parentSignal) {
|
|
534
|
+
const controller = new AbortController();
|
|
535
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
536
|
+
const abortFromParent = () => controller.abort(parentSignal?.reason);
|
|
537
|
+
const cleanup = () => {
|
|
538
|
+
clearTimeout(timeout);
|
|
539
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
540
|
+
};
|
|
541
|
+
if (parentSignal?.aborted) abortFromParent();
|
|
542
|
+
else parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
543
|
+
controller.signal.addEventListener("abort", cleanup, { once: true });
|
|
544
|
+
return {
|
|
545
|
+
signal: controller.signal,
|
|
546
|
+
cleanup
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
async function requestJson(config, opts) {
|
|
550
|
+
const res = await request(config, opts);
|
|
551
|
+
let data;
|
|
552
|
+
try {
|
|
553
|
+
data = await res.json();
|
|
554
|
+
} catch {
|
|
555
|
+
throw new BailianError(`API returned non-JSON response (${res.headers.get("content-type") || "unknown type"}). Server may be experiencing issues.`, ExitCode.GENERAL);
|
|
556
|
+
}
|
|
557
|
+
if (data.code && typeof data.code === "string" && data.code !== "200" && data.code !== "Success") throw mapApiError(200, { error: {
|
|
558
|
+
message: data.message,
|
|
559
|
+
type: data.code
|
|
560
|
+
} }, opts.url);
|
|
561
|
+
return data;
|
|
562
|
+
}
|
|
563
|
+
//#endregion
|
|
564
|
+
//#region src/client/mcp.ts
|
|
565
|
+
/**
|
|
566
|
+
* Compose the streamable-HTTP MCP endpoint for a Bailian MCP server.
|
|
567
|
+
* The path is `/api/v1/mcps/<serverCode>/mcp`; the `serverCode` is taken
|
|
568
|
+
* verbatim from `bl mcp list` (e.g. `WebSearch`, `market-cmapi00073529`).
|
|
569
|
+
*/
|
|
570
|
+
function bailianMcpUrl(baseUrl, serverCode) {
|
|
571
|
+
return `${baseUrl.replace(/\/$/, "")}/api/v1/mcps/${serverCode}/mcp`;
|
|
572
|
+
}
|
|
573
|
+
var McpClient = class {
|
|
574
|
+
url;
|
|
575
|
+
sessionId;
|
|
576
|
+
nextId = 1;
|
|
577
|
+
config;
|
|
578
|
+
authToken;
|
|
579
|
+
constructor(config, url) {
|
|
580
|
+
this.config = config;
|
|
581
|
+
this.url = url;
|
|
582
|
+
}
|
|
583
|
+
/** Initialize the MCP session. Must be called before any other method. */
|
|
584
|
+
async initialize() {
|
|
585
|
+
const credential = await resolveCredential(this.config);
|
|
586
|
+
this.authToken = credential.token;
|
|
587
|
+
const result = await this.rpc("initialize", {
|
|
588
|
+
protocolVersion: "2025-03-26",
|
|
589
|
+
capabilities: {},
|
|
590
|
+
clientInfo: {
|
|
591
|
+
name: this.config.clientName ?? "bailian-cli-core",
|
|
592
|
+
version: this.config.clientVersion ?? "0.0.0-dev"
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
if (this.config.verbose) {
|
|
596
|
+
console.error(`[MCP] Session initialized: ${this.sessionId ?? "no session"}`);
|
|
597
|
+
console.error(`[MCP] Server: ${JSON.stringify(result)}`);
|
|
598
|
+
}
|
|
599
|
+
await this.notify("notifications/initialized");
|
|
600
|
+
}
|
|
601
|
+
async listTools() {
|
|
602
|
+
return (await this.rpc("tools/list")).tools || [];
|
|
603
|
+
}
|
|
604
|
+
async callTool(name, args) {
|
|
605
|
+
return await this.rpc("tools/call", {
|
|
606
|
+
name,
|
|
607
|
+
arguments: args
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
async rpc(method, params) {
|
|
611
|
+
const body = {
|
|
612
|
+
jsonrpc: "2.0",
|
|
613
|
+
id: this.nextId++,
|
|
614
|
+
method,
|
|
615
|
+
...params ? { params } : {}
|
|
616
|
+
};
|
|
617
|
+
const data = await (await this.send(body)).json();
|
|
618
|
+
if (data.error) throw new BailianError(`MCP error (${data.error.code}): ${data.error.message}`, ExitCode.GENERAL);
|
|
619
|
+
return data.result;
|
|
620
|
+
}
|
|
621
|
+
async notify(method, params) {
|
|
622
|
+
const body = {
|
|
623
|
+
jsonrpc: "2.0",
|
|
624
|
+
method,
|
|
625
|
+
...params ? { params } : {}
|
|
626
|
+
};
|
|
627
|
+
await this.send(body);
|
|
628
|
+
}
|
|
629
|
+
async send(body) {
|
|
630
|
+
const headers = {
|
|
631
|
+
"Content-Type": "application/json",
|
|
632
|
+
Accept: "application/json, text/event-stream",
|
|
633
|
+
"User-Agent": `${this.config.clientName ?? "bailian-cli-core"}/${this.config.clientVersion ?? "0.0.0-dev"}`,
|
|
634
|
+
...trackingHeaders()
|
|
635
|
+
};
|
|
636
|
+
if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
|
|
637
|
+
if (this.sessionId) headers["Mcp-Session-Id"] = this.sessionId;
|
|
638
|
+
if (this.config.verbose) {
|
|
639
|
+
console.error(`> POST ${this.url}`);
|
|
640
|
+
console.error(`> Method: ${body.method}`);
|
|
641
|
+
}
|
|
642
|
+
const timeoutMs = this.config.timeout * 1e3;
|
|
643
|
+
const res = await fetch(this.url, {
|
|
644
|
+
method: "POST",
|
|
645
|
+
headers,
|
|
646
|
+
body: JSON.stringify(body),
|
|
647
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
648
|
+
});
|
|
649
|
+
if (this.config.verbose) console.error(`< ${res.status} ${res.statusText}`);
|
|
650
|
+
const sid = res.headers.get("Mcp-Session-Id") || res.headers.get("mcp-session-id");
|
|
651
|
+
if (sid) this.sessionId = sid;
|
|
652
|
+
if (!res.ok) {
|
|
653
|
+
let errMsg = `MCP request failed: ${res.status} ${res.statusText}`;
|
|
654
|
+
try {
|
|
655
|
+
const errBody = await res.text();
|
|
656
|
+
if (errBody) errMsg += ` - ${errBody.slice(0, 500)}`;
|
|
657
|
+
} catch {}
|
|
658
|
+
throw new BailianError(errMsg, ExitCode.GENERAL);
|
|
659
|
+
}
|
|
660
|
+
return res;
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
//#endregion
|
|
664
|
+
//#region src/client/stream.ts
|
|
665
|
+
async function* parseSSE(response) {
|
|
666
|
+
const reader = response.body?.getReader();
|
|
667
|
+
if (!reader) return;
|
|
668
|
+
const decoder = new TextDecoder();
|
|
669
|
+
let buffer = "";
|
|
670
|
+
const MAX_SSE_BUFFER = 16 * 1024 * 1024;
|
|
671
|
+
try {
|
|
672
|
+
while (true) {
|
|
673
|
+
const { done, value } = await reader.read();
|
|
674
|
+
if (done) break;
|
|
675
|
+
buffer += decoder.decode(value, { stream: true });
|
|
676
|
+
if (buffer.length > MAX_SSE_BUFFER) throw new BailianError("SSE stream exceeded the maximum buffer size.", ExitCode.GENERAL);
|
|
677
|
+
const lines = buffer.split("\n");
|
|
678
|
+
buffer = lines.pop() || "";
|
|
679
|
+
let event = {};
|
|
680
|
+
for (const line of lines) {
|
|
681
|
+
if (line === "") {
|
|
682
|
+
if (event.data !== void 0) yield {
|
|
683
|
+
data: event.data,
|
|
684
|
+
event: event.event,
|
|
685
|
+
id: event.id
|
|
686
|
+
};
|
|
687
|
+
event = {};
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
if (line.startsWith(":")) continue;
|
|
691
|
+
const colonIndex = line.indexOf(":");
|
|
692
|
+
if (colonIndex === -1) continue;
|
|
693
|
+
const field = line.slice(0, colonIndex);
|
|
694
|
+
const value = line.slice(colonIndex + 1).trimStart();
|
|
695
|
+
switch (field) {
|
|
696
|
+
case "data":
|
|
697
|
+
event.data = event.data !== void 0 ? `${event.data}\n${value}` : value;
|
|
698
|
+
if (event.data.length > MAX_SSE_BUFFER) throw new BailianError("SSE event exceeded the maximum buffer size.", ExitCode.GENERAL);
|
|
699
|
+
break;
|
|
700
|
+
case "event":
|
|
701
|
+
event.event = value;
|
|
702
|
+
break;
|
|
703
|
+
case "id":
|
|
704
|
+
event.id = value;
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (buffer.trim() && buffer.includes("data:")) {
|
|
710
|
+
const colonIndex = buffer.indexOf(":");
|
|
711
|
+
if (colonIndex !== -1) yield { data: buffer.slice(colonIndex + 1).trimStart() };
|
|
712
|
+
}
|
|
713
|
+
} finally {
|
|
714
|
+
reader.releaseLock();
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
//#endregion
|
|
718
|
+
//#region src/console/gateway.ts
|
|
719
|
+
const GATEWAY_ACTION = "BroadScopeAspnGateway";
|
|
720
|
+
const GATEWAY_PRODUCT = "sfm_bailian";
|
|
721
|
+
function buildGatewayParams(api, data) {
|
|
722
|
+
return JSON.stringify({
|
|
723
|
+
Api: api,
|
|
724
|
+
V: "1.0",
|
|
725
|
+
Data: {
|
|
726
|
+
...data,
|
|
727
|
+
cornerstoneParam: {
|
|
728
|
+
protocol: "V2",
|
|
729
|
+
console: "ONE_CONSOLE",
|
|
730
|
+
productCode: "p_efm",
|
|
731
|
+
consoleSite: "BAILIAN_ALIYUN",
|
|
732
|
+
...typeof data.cornerstoneParam === "object" && data.cornerstoneParam !== null ? data.cornerstoneParam : {}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Invoke a Bailian **console** OpenAPI via the CLI gateway (`/cli/api.json`).
|
|
739
|
+
* `token` is the console `access_token` (from `bl auth login --console`); when
|
|
740
|
+
* omitted the request is sent without an Authorization header, which works for
|
|
741
|
+
* public console APIs that don't require a login session.
|
|
742
|
+
*/
|
|
743
|
+
async function callConsoleGateway(config, token, { api, data, region = "cn-beijing" }) {
|
|
744
|
+
const params = buildGatewayParams(api, data);
|
|
745
|
+
const body = new URLSearchParams({
|
|
746
|
+
params,
|
|
747
|
+
region
|
|
748
|
+
});
|
|
749
|
+
const timeoutMs = config.timeout * 1e3;
|
|
750
|
+
const gatewayBase = config.consoleGatewayUrl;
|
|
751
|
+
const headers = {
|
|
752
|
+
Accept: "*/*",
|
|
753
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
754
|
+
};
|
|
755
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
756
|
+
const res = await fetch(`${gatewayBase}/cli/api.json?action=${GATEWAY_ACTION}&product=${GATEWAY_PRODUCT}&api=${encodeURIComponent(api)}`, {
|
|
757
|
+
method: "POST",
|
|
758
|
+
headers,
|
|
759
|
+
body: body.toString(),
|
|
760
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
761
|
+
});
|
|
762
|
+
if (!res.ok) {
|
|
763
|
+
const t = await res.text().catch(() => "");
|
|
764
|
+
throw new BailianError(`Console CLI gateway failed: HTTP ${res.status} ${res.statusText}`, ExitCode.GENERAL, t.slice(0, 500));
|
|
765
|
+
}
|
|
766
|
+
return res.json();
|
|
767
|
+
}
|
|
768
|
+
//#endregion
|
|
769
|
+
//#region src/files/upload.ts
|
|
770
|
+
/**
|
|
771
|
+
* Upload local files to DashScope temporary OSS storage.
|
|
772
|
+
*
|
|
773
|
+
* Returns an `oss://` prefixed URL valid for 48 hours.
|
|
774
|
+
* When using this URL in API calls, the request MUST include:
|
|
775
|
+
* X-DashScope-OssResourceResolve: enable
|
|
776
|
+
*/
|
|
777
|
+
const UPLOAD_API = `${REGIONS.cn}/api/v1/uploads`;
|
|
778
|
+
/**
|
|
779
|
+
* Step 1: Fetch the upload policy (presigned credentials) from DashScope.
|
|
780
|
+
*/
|
|
781
|
+
async function getUploadPolicy(apiKey, model, signal) {
|
|
782
|
+
const url = `${UPLOAD_API}?action=getPolicy&model=${encodeURIComponent(model)}`;
|
|
783
|
+
const policySignal = combineWithTimeout(15e3, signal);
|
|
784
|
+
const res = await fetch(url, {
|
|
785
|
+
headers: {
|
|
786
|
+
Authorization: `Bearer ${apiKey}`,
|
|
787
|
+
"Content-Type": "application/json",
|
|
788
|
+
...trackingHeaders()
|
|
789
|
+
},
|
|
790
|
+
signal: policySignal.signal
|
|
791
|
+
}).finally(policySignal.cleanup);
|
|
792
|
+
if (!res.ok) {
|
|
793
|
+
const text = await res.text().catch(() => "");
|
|
794
|
+
throw new BailianError(`Failed to get upload policy (HTTP ${res.status}): ${text}`, ExitCode.GENERAL);
|
|
795
|
+
}
|
|
796
|
+
return (await res.json()).data;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Step 2: Upload the file to OSS using the policy.
|
|
800
|
+
*/
|
|
801
|
+
async function uploadToOSS(policy, filePath, signal) {
|
|
802
|
+
const fileName = basename(filePath);
|
|
803
|
+
const key = `${policy.upload_dir}/${fileName}`;
|
|
804
|
+
const fileData = readFileSync(filePath);
|
|
805
|
+
const form = new FormData();
|
|
806
|
+
form.append("OSSAccessKeyId", policy.oss_access_key_id);
|
|
807
|
+
form.append("Signature", policy.signature);
|
|
808
|
+
form.append("policy", policy.policy);
|
|
809
|
+
form.append("x-oss-object-acl", policy.x_oss_object_acl);
|
|
810
|
+
form.append("x-oss-forbid-overwrite", policy.x_oss_forbid_overwrite);
|
|
811
|
+
form.append("key", key);
|
|
812
|
+
form.append("success_action_status", "200");
|
|
813
|
+
form.append("file", new Blob([fileData]), fileName);
|
|
814
|
+
const uploadSignal = combineWithTimeout(12e4, signal);
|
|
815
|
+
const res = await fetch(policy.upload_host, {
|
|
816
|
+
method: "POST",
|
|
817
|
+
headers: { ...trackingHeaders() },
|
|
818
|
+
body: form,
|
|
819
|
+
signal: uploadSignal.signal
|
|
820
|
+
}).finally(uploadSignal.cleanup);
|
|
821
|
+
if (!res.ok) {
|
|
822
|
+
const text = await res.text().catch(() => "");
|
|
823
|
+
throw new BailianError(`Failed to upload file to OSS (HTTP ${res.status}): ${text}`, ExitCode.GENERAL);
|
|
824
|
+
}
|
|
825
|
+
return `oss://${key}`;
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Upload a local file to DashScope temporary storage and return the oss:// URL.
|
|
829
|
+
* The URL is valid for 48 hours.
|
|
830
|
+
*/
|
|
831
|
+
async function uploadFile(opts) {
|
|
832
|
+
const { apiKey, model, filePath, signal } = opts;
|
|
833
|
+
if (!existsSync(filePath)) throw new BailianError(`File not found: ${filePath}`, ExitCode.USAGE);
|
|
834
|
+
if (!statSync(filePath).isFile()) throw new BailianError(`Not a file: ${filePath}`, ExitCode.USAGE);
|
|
835
|
+
return uploadToOSS(await getUploadPolicy(apiKey, model, signal), filePath, signal);
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Check if a string looks like a local file path (not a URL).
|
|
839
|
+
*/
|
|
840
|
+
function isLocalFile(input) {
|
|
841
|
+
if (input.startsWith("http://") || input.startsWith("https://")) return false;
|
|
842
|
+
if (input.startsWith("oss://")) return false;
|
|
843
|
+
if (input.startsWith("data:")) return false;
|
|
844
|
+
return existsSync(input);
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Resolve a file argument: if it's a local path, upload it and return the oss:// URL.
|
|
848
|
+
* If it's already a URL, return as-is.
|
|
849
|
+
*/
|
|
850
|
+
async function resolveFileUrl(input, apiKey, model, opts = {}) {
|
|
851
|
+
if (!isLocalFile(input)) return input;
|
|
852
|
+
return uploadFile({
|
|
853
|
+
apiKey,
|
|
854
|
+
model,
|
|
855
|
+
filePath: input,
|
|
856
|
+
signal: opts.signal
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
function combineWithTimeout(timeoutMs, parentSignal) {
|
|
860
|
+
const controller = new AbortController();
|
|
861
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
862
|
+
const abortFromParent = () => controller.abort(parentSignal?.reason);
|
|
863
|
+
const cleanup = () => {
|
|
864
|
+
clearTimeout(timeout);
|
|
865
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
866
|
+
};
|
|
867
|
+
if (parentSignal?.aborted) abortFromParent();
|
|
868
|
+
else parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
869
|
+
controller.signal.addEventListener("abort", cleanup, { once: true });
|
|
870
|
+
return {
|
|
871
|
+
signal: controller.signal,
|
|
872
|
+
cleanup
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
//#endregion
|
|
876
|
+
//#region src/types/command.ts
|
|
877
|
+
function defineCommand(spec) {
|
|
878
|
+
return {
|
|
879
|
+
name: spec.name,
|
|
880
|
+
description: spec.description,
|
|
881
|
+
usage: spec.usage,
|
|
882
|
+
options: spec.options,
|
|
883
|
+
examples: spec.examples,
|
|
884
|
+
apiDocs: spec.apiDocs,
|
|
885
|
+
execute: (config, flags) => spec.run(config, flags)
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
/** Global flags shared by all commands — drives the parser's type resolution. */
|
|
889
|
+
const GLOBAL_OPTIONS = [
|
|
890
|
+
{
|
|
891
|
+
flag: "--api-key <key>",
|
|
892
|
+
description: "API key"
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
flag: "--region <region>",
|
|
896
|
+
description: "API region: cn (default), us, intl"
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
flag: "--base-url <url>",
|
|
900
|
+
description: "API base URL"
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
flag: "--output <format>",
|
|
904
|
+
description: "Output format: text, json"
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
flag: "--timeout <seconds>",
|
|
908
|
+
description: "Request timeout",
|
|
909
|
+
type: "number"
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
flag: "--quiet",
|
|
913
|
+
description: "Suppress non-essential output"
|
|
914
|
+
},
|
|
915
|
+
{
|
|
916
|
+
flag: "--verbose",
|
|
917
|
+
description: "Print HTTP request/response details"
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
flag: "--no-color",
|
|
921
|
+
description: "Disable ANSI colors"
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
flag: "--dry-run",
|
|
925
|
+
description: "Dry run mode"
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
flag: "--non-interactive",
|
|
929
|
+
description: "Disable interactive prompts"
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
flag: "--concurrent <n>",
|
|
933
|
+
description: "Run N parallel requests (default: 1)",
|
|
934
|
+
type: "number"
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
flag: "--help",
|
|
938
|
+
description: "Show help"
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
flag: "--version",
|
|
942
|
+
description: "Print version"
|
|
943
|
+
}
|
|
944
|
+
];
|
|
945
|
+
//#endregion
|
|
946
|
+
//#region src/utils/filename.ts
|
|
947
|
+
/**
|
|
948
|
+
* 生成文件名前缀
|
|
949
|
+
* @param prefix prompt的前10个字符
|
|
950
|
+
* @param suffix timestamp
|
|
951
|
+
* @returns
|
|
952
|
+
*/
|
|
953
|
+
function sanitizeFilenamePart(input, fallback) {
|
|
954
|
+
return input.normalize("NFKC").replace(/[\\/:*?"<>|]/g, "_").replace(/\s+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "") || fallback;
|
|
955
|
+
}
|
|
956
|
+
function generateFilename(prefix, prompt) {
|
|
957
|
+
return `${sanitizeFilenamePart(prefix || "image", "image")}_${sanitizeFilenamePart((prompt || "").substring(0, 20), "untitled")}_${Date.now()}`;
|
|
958
|
+
}
|
|
959
|
+
//#endregion
|
|
960
|
+
//#region src/utils/output-dir.ts
|
|
961
|
+
const DEFAULT_OUTPUT_DIR = () => join(homedir(), "bailian-output");
|
|
962
|
+
/**
|
|
963
|
+
* Resolve the output directory for generated files.
|
|
964
|
+
*
|
|
965
|
+
* Priority:
|
|
966
|
+
* 1. User-specified dir (e.g. --out-dir flag)
|
|
967
|
+
* 2. Config file output_dir
|
|
968
|
+
* 3. Default: ~/bailian-output/
|
|
969
|
+
*
|
|
970
|
+
* Optionally appends a subdirectory (e.g. 'images', 'videos', 'speech').
|
|
971
|
+
* Creates the directory if it doesn't exist.
|
|
972
|
+
*/
|
|
973
|
+
function resolveOutputDir(config, options) {
|
|
974
|
+
const base = options?.flagDir || config.outputDir || DEFAULT_OUTPUT_DIR();
|
|
975
|
+
const dir = options?.subDir ? join(base, options.subDir) : base;
|
|
976
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
977
|
+
return dir;
|
|
978
|
+
}
|
|
979
|
+
//#endregion
|
|
980
|
+
//#region src/utils/schema.ts
|
|
981
|
+
/**
|
|
982
|
+
* Parse a CLI flag string (e.g. "--prompt <text>", "--stream") into
|
|
983
|
+
* a parameter name and inferred type.
|
|
984
|
+
*/
|
|
985
|
+
function parseFlag(flag) {
|
|
986
|
+
const match = flag.match(/^--([a-zA-Z0-9-]+)/);
|
|
987
|
+
const kebabName = match ? match[1] : "";
|
|
988
|
+
const name = kebabName.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase());
|
|
989
|
+
let inferredType = "string";
|
|
990
|
+
let isArray = false;
|
|
991
|
+
if (!flag.includes("<") && !flag.includes("[")) inferredType = "boolean";
|
|
992
|
+
else if (flag.includes("<n>") || flag.includes("<hz>") || flag.includes("<bps>") || flag.includes("<count>")) inferredType = "number";
|
|
993
|
+
if (flag.toLowerCase().includes("repeatable")) isArray = true;
|
|
994
|
+
return {
|
|
995
|
+
name,
|
|
996
|
+
kebabName,
|
|
997
|
+
inferredType,
|
|
998
|
+
isArray
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
function generateToolSchema(cmd) {
|
|
1002
|
+
const schema = {
|
|
1003
|
+
name: `bailian_${cmd.name.replace(/ /g, "_")}`,
|
|
1004
|
+
description: cmd.description,
|
|
1005
|
+
input_schema: {
|
|
1006
|
+
type: "object",
|
|
1007
|
+
properties: {},
|
|
1008
|
+
required: []
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
if (cmd.options) for (const opt of cmd.options) {
|
|
1012
|
+
const { name, inferredType, isArray } = parseFlag(opt.flag);
|
|
1013
|
+
if (!name) continue;
|
|
1014
|
+
const explicitType = opt.type;
|
|
1015
|
+
const effectiveType = isArray ? "array" : explicitType ?? inferredType;
|
|
1016
|
+
const propSchema = { description: opt.description };
|
|
1017
|
+
if (effectiveType === "array") {
|
|
1018
|
+
propSchema.type = "array";
|
|
1019
|
+
propSchema.items = { type: "string" };
|
|
1020
|
+
} else propSchema.type = effectiveType;
|
|
1021
|
+
const inputSchema = schema.input_schema;
|
|
1022
|
+
inputSchema.properties[name] = propSchema;
|
|
1023
|
+
if (opt.required) inputSchema.required.push(name);
|
|
1024
|
+
}
|
|
1025
|
+
return schema;
|
|
1026
|
+
}
|
|
1027
|
+
//#endregion
|
|
1028
|
+
//#region src/utils/env.ts
|
|
1029
|
+
/**
|
|
1030
|
+
* Environment detection utilities for bailian-cli.
|
|
1031
|
+
*
|
|
1032
|
+
* Used to determine whether the CLI is running in an interactive terminal
|
|
1033
|
+
* (human user) or in a non-interactive environment (CI, agent, pipe, etc.),
|
|
1034
|
+
* so commands can adjust their behavior accordingly.
|
|
1035
|
+
*/
|
|
1036
|
+
/**
|
|
1037
|
+
* Detects whether the current environment is interactive.
|
|
1038
|
+
*
|
|
1039
|
+
* Returns false when:
|
|
1040
|
+
* - stdout or stdin is not a TTY
|
|
1041
|
+
* - The --non-interactive flag was explicitly set
|
|
1042
|
+
* - The process is running in a known CI environment (CI env var present)
|
|
1043
|
+
*
|
|
1044
|
+
* Returns true when stdout and stdin are both TTYs and --non-interactive
|
|
1045
|
+
* was not passed.
|
|
1046
|
+
*/
|
|
1047
|
+
function isInteractive(options) {
|
|
1048
|
+
if (options?.nonInteractive === true) return false;
|
|
1049
|
+
if (process.env.CI) return false;
|
|
1050
|
+
return process.stdout.isTTY === true && process.stdin.isTTY === true;
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Detects whether the current process is running in a CI environment.
|
|
1054
|
+
*/
|
|
1055
|
+
function isCI() {
|
|
1056
|
+
return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.JENKINS_URL || process.env.TRAVIS || process.env.CIRCLECI);
|
|
1057
|
+
}
|
|
1058
|
+
//#endregion
|
|
1059
|
+
//#region src/utils/object.ts
|
|
1060
|
+
/**
|
|
1061
|
+
* Generic object-cleaning utilities.
|
|
1062
|
+
*/
|
|
1063
|
+
/**
|
|
1064
|
+
* Remove all keys whose value is `undefined` from a plain object (in-place).
|
|
1065
|
+
* Returns the same reference for chaining convenience.
|
|
1066
|
+
*
|
|
1067
|
+
* ```ts
|
|
1068
|
+
* const params = { a: 1, b: undefined };
|
|
1069
|
+
* stripUndefined(params); // { a: 1 }
|
|
1070
|
+
* ```
|
|
1071
|
+
*/
|
|
1072
|
+
function stripUndefined(obj) {
|
|
1073
|
+
for (const key of Object.keys(obj)) if (obj[key] === void 0) delete obj[key];
|
|
1074
|
+
return obj;
|
|
1075
|
+
}
|
|
1076
|
+
//#endregion
|
|
1077
|
+
//#region src/telemetry/event.ts
|
|
1078
|
+
function createTrackingEvent(opts) {
|
|
1079
|
+
const event = {
|
|
1080
|
+
command: opts.command,
|
|
1081
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1082
|
+
durationMs: opts.durationMs,
|
|
1083
|
+
success: opts.success,
|
|
1084
|
+
cliVersion: opts.cliVersion,
|
|
1085
|
+
region: opts.region,
|
|
1086
|
+
nodeVersion: process.version,
|
|
1087
|
+
os: process.platform
|
|
1088
|
+
};
|
|
1089
|
+
if (opts.authMethod) event.authMethod = opts.authMethod;
|
|
1090
|
+
if (!opts.success && opts.error) {
|
|
1091
|
+
if (opts.error.message) event.errorMessage = opts.error.message;
|
|
1092
|
+
if (opts.error.httpStatus !== void 0) event.httpStatus = opts.error.httpStatus;
|
|
1093
|
+
if (opts.error.requestId) event.requestId = opts.error.requestId;
|
|
1094
|
+
}
|
|
1095
|
+
if (opts.params && Object.keys(opts.params).length > 0) event.params = opts.params;
|
|
1096
|
+
return event;
|
|
1097
|
+
}
|
|
1098
|
+
const AEM_TEXT_MAX = 500;
|
|
1099
|
+
function aemText(value) {
|
|
1100
|
+
if (value === void 0 || value === null) return void 0;
|
|
1101
|
+
const s = typeof value === "string" ? value : JSON.stringify(value);
|
|
1102
|
+
return s.length <= AEM_TEXT_MAX ? s : s.slice(0, AEM_TEXT_MAX);
|
|
1103
|
+
}
|
|
1104
|
+
function buildRemoteAemOptions(event) {
|
|
1105
|
+
const { command: _command, params, ...extFields } = event;
|
|
1106
|
+
const opts = {
|
|
1107
|
+
et: "EXP",
|
|
1108
|
+
ext: extFields,
|
|
1109
|
+
c1: params,
|
|
1110
|
+
c2: event.success ? "success" : "failure"
|
|
1111
|
+
};
|
|
1112
|
+
if (event.httpStatus !== void 0) opts.c3 = String(event.httpStatus);
|
|
1113
|
+
if (event.errorMessage) opts.c4 = aemText(event.errorMessage);
|
|
1114
|
+
if (event.requestId) opts.c5 = event.requestId;
|
|
1115
|
+
return opts;
|
|
1116
|
+
}
|
|
1117
|
+
//#endregion
|
|
1118
|
+
//#region src/telemetry/env.ts
|
|
1119
|
+
/**
|
|
1120
|
+
* 判断当前运行环境。任一条件为真即视为 dev,默认 prod。
|
|
1121
|
+
*
|
|
1122
|
+
* 1. NODE_ENV=development — Node 圈通用约定,测试同学/CI 可显式声明
|
|
1123
|
+
* 2. 当前模块文件路径不在 node_modules 里 — 自动识别从源码运行(pnpm dev /
|
|
1124
|
+
* npm link / 直接 node packages/cli/src/main.ts),避免开发者忘记设环境变量
|
|
1125
|
+
* 时仍把数据打到 prod
|
|
1126
|
+
*
|
|
1127
|
+
* 缓存结果,模块加载期算一次就行。
|
|
1128
|
+
*/
|
|
1129
|
+
let cachedEnv;
|
|
1130
|
+
function detectEnv() {
|
|
1131
|
+
if (cachedEnv) return cachedEnv;
|
|
1132
|
+
if (process.env.NODE_ENV === "development") {
|
|
1133
|
+
cachedEnv = "dev";
|
|
1134
|
+
return cachedEnv;
|
|
1135
|
+
}
|
|
1136
|
+
cachedEnv = import.meta.url.includes("/node_modules/") ? "prod" : "dev";
|
|
1137
|
+
return cachedEnv;
|
|
1138
|
+
}
|
|
1139
|
+
//#endregion
|
|
1140
|
+
//#region lib/remote-telemetry/tracker.js
|
|
1141
|
+
var require_tracker = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
1142
|
+
module.exports = (function(e) {
|
|
1143
|
+
var t = {};
|
|
1144
|
+
function n(r) {
|
|
1145
|
+
if (t[r]) return t[r].exports;
|
|
1146
|
+
var o = t[r] = {
|
|
1147
|
+
i: r,
|
|
1148
|
+
l: !1,
|
|
1149
|
+
exports: {}
|
|
1150
|
+
};
|
|
1151
|
+
return e[r].call(o.exports, o, o.exports, n), o.l = !0, o.exports;
|
|
1152
|
+
}
|
|
1153
|
+
return n.m = e, n.c = t, n.d = function(e, t, r) {
|
|
1154
|
+
n.o(e, t) || Object.defineProperty(e, t, {
|
|
1155
|
+
enumerable: !0,
|
|
1156
|
+
get: r
|
|
1157
|
+
});
|
|
1158
|
+
}, n.r = function(e) {
|
|
1159
|
+
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 });
|
|
1160
|
+
}, n.t = function(e, t) {
|
|
1161
|
+
if (1 & t && (e = n(e)), 8 & t) return e;
|
|
1162
|
+
if (4 & t && "object" == typeof e && e && e.__esModule) return e;
|
|
1163
|
+
var r = Object.create(null);
|
|
1164
|
+
if (n.r(r), Object.defineProperty(r, "default", {
|
|
1165
|
+
enumerable: !0,
|
|
1166
|
+
value: e
|
|
1167
|
+
}), 2 & t && "string" != typeof e) for (var o in e) n.d(r, o, function(t) {
|
|
1168
|
+
return e[t];
|
|
1169
|
+
}.bind(null, o));
|
|
1170
|
+
return r;
|
|
1171
|
+
}, n.n = function(e) {
|
|
1172
|
+
var t = e && e.__esModule ? function() {
|
|
1173
|
+
return e.default;
|
|
1174
|
+
} : function() {
|
|
1175
|
+
return e;
|
|
1176
|
+
};
|
|
1177
|
+
return n.d(t, "a", t), t;
|
|
1178
|
+
}, n.o = function(e, t) {
|
|
1179
|
+
return Object.prototype.hasOwnProperty.call(e, t);
|
|
1180
|
+
}, n.p = "", n(n.s = 8);
|
|
1181
|
+
})([
|
|
1182
|
+
function(e, t) {
|
|
1183
|
+
e.exports = __require("os");
|
|
1184
|
+
},
|
|
1185
|
+
function(e, t) {
|
|
1186
|
+
e.exports = globalThis.fetch;
|
|
1187
|
+
},
|
|
1188
|
+
function(e, t, n) {
|
|
1189
|
+
"use strict";
|
|
1190
|
+
e.exports = n(6);
|
|
1191
|
+
},
|
|
1192
|
+
function(e, t) {
|
|
1193
|
+
e.exports = __require("dns");
|
|
1194
|
+
},
|
|
1195
|
+
function(e, t) {
|
|
1196
|
+
e.exports = __require("util");
|
|
1197
|
+
},
|
|
1198
|
+
function(e, t) {
|
|
1199
|
+
e.exports = __require("crypto");
|
|
1200
|
+
},
|
|
1201
|
+
function(e, t, n) {
|
|
1202
|
+
Object.defineProperty(t, Symbol.toStringTag, { value: "Module" });
|
|
1203
|
+
const r = n(7), o = (e, t) => {
|
|
1204
|
+
t.appName = "BaiduSpider", t.appVersion = e.value, t.deviceBrand = "Baidu", t.deviceType = "bot", t.platform = "other";
|
|
1205
|
+
}, i = (e, t) => {
|
|
1206
|
+
t.appName = "360 Spider", t.appVersion = e.value, t.deviceBrand = "360", t.deviceType = "bot", t.platform = "other";
|
|
1207
|
+
}, a = (e, t) => {
|
|
1208
|
+
t.appName = "BingBot", t.appVersion = e.value, t.deviceBrand = "Microsoft", t.deviceType = "bot", t.platform = "other";
|
|
1209
|
+
}, u = (e, t) => {
|
|
1210
|
+
t.appName = "Googlebot", t.appVersion = e.value, t.deviceBrand = "Google", t.deviceType = "bot", t.platform = "other";
|
|
1211
|
+
}, p = (e, t) => {
|
|
1212
|
+
t.appName = "YandexBot", t.appVersion = e.value, t.deviceBrand = "Yandex", t.deviceType = "bot", t.platform = "other";
|
|
1213
|
+
}, l = (e, t) => {
|
|
1214
|
+
"Sogou web spider" === e.getPreviousNTokens(3) && (t.deviceBrand = "Sogou.com", t.appName = "SogouSpider"), t.appVersion = e.value, t.deviceType = "bot";
|
|
1215
|
+
}, s = (e, t) => {
|
|
1216
|
+
t.appName = "DataproviderBot", t.appVersion = e.value, t.deviceBrand = "Dataprovider.com", t.deviceType = "bot", t.platform = "other";
|
|
1217
|
+
}, c = (e, t) => {
|
|
1218
|
+
t.appName = "AhrefsBot", t.appVersion = e.value, t.deviceBrand = "Ahrefs", t.deviceType = "bot", t.platform = "other";
|
|
1219
|
+
}, d = (e, t) => {
|
|
1220
|
+
t.appName = "BitSightBot", t.appVersion = e.value, t.deviceBrand = "Bitsight", t.deviceType = "bot", t.platform = "other";
|
|
1221
|
+
}, f = (e, t) => {
|
|
1222
|
+
t.appName = "oBot", t.appVersion = e.value, t.deviceBrand = "IBM", t.deviceType = "bot", t.platform = "other";
|
|
1223
|
+
}, v = (e, t) => {
|
|
1224
|
+
t.appName = "Cincraw", t.appVersion = e.value, t.deviceBrand = "CINC", t.deviceType = "bot", t.platform = "other";
|
|
1225
|
+
}, g = (e, t) => {
|
|
1226
|
+
t.appName = "DingTalkBot", t.appVersion = e.value, t.deviceBrand = "Alibaba", t.deviceType = "bot", t.platform = "other";
|
|
1227
|
+
}, h = (e, t) => {
|
|
1228
|
+
t.appName = "YisouSpider", t.appVersion = e.value, t.deviceBrand = "Alibaba", t.deviceType = "bot", t.platform = "other";
|
|
1229
|
+
}, m = (e, t) => {
|
|
1230
|
+
t.appName = "ByteSpider", t.appVersion = e.value, t.deviceBrand = "ByteDance", t.deviceType = "bot", t.platform = "other";
|
|
1231
|
+
}, b = (e, t) => {
|
|
1232
|
+
t.appName = "HeadlineCrawler", t.appVersion = e.value, t.deviceBrand = "Headline.com", t.deviceType = "bot", t.platform = "other";
|
|
1233
|
+
}, y = (e, t) => {
|
|
1234
|
+
t.appName = "BitDiscoveryBot", t.appVersion = e.value, t.deviceBrand = "Tenable", t.deviceType = "bot", t.platform = "other";
|
|
1235
|
+
}, _ = (e, t) => {
|
|
1236
|
+
"Screaming Frog SEO Spider" === e.getPreviousNTokens(4) && (t.deviceBrand = "Screaming Frog", t.appName = "Screaming Frog"), t.appVersion = e.value, t.deviceType = "bot";
|
|
1237
|
+
}, B = (e, t) => {
|
|
1238
|
+
t.appName = "Ai2Bot", t.appVersion = e.value, t.deviceBrand = "Ai2", t.deviceType = "bot", t.platform = "other";
|
|
1239
|
+
}, S = (e, t) => {
|
|
1240
|
+
t.appName = "DianjingAdSpider", t.appVersion = e.value, t.deviceBrand = "Dianjing", t.deviceType = "bot", t.platform = "other";
|
|
1241
|
+
}, T = (e, t) => {
|
|
1242
|
+
t.appName = "BaiduSpider", t.appVersion = e.value, t.deviceBrand = "Baidu", t.deviceType = "bot", t.platform = "other";
|
|
1243
|
+
}, j = (e, t) => {
|
|
1244
|
+
t.appName = "360 Spider", t.appVersion = e.value, t.deviceBrand = "360", t.deviceType = "bot", t.platform = "other";
|
|
1245
|
+
}, N = (e, t) => {
|
|
1246
|
+
t.appName = "BingBot", t.appVersion = e.value, t.deviceBrand = "Microsoft", t.deviceType = "bot", t.platform = "other";
|
|
1247
|
+
}, w = (e, t) => {
|
|
1248
|
+
t.appName = "Googlebot", t.appVersion = e.value, t.deviceBrand = "Google", t.deviceType = "bot", t.platform = "other";
|
|
1249
|
+
}, O = (e, t) => {
|
|
1250
|
+
t.appName = "YandexBot", t.appVersion = e.value, t.deviceBrand = "Yandex", t.deviceType = "bot", t.platform = "other";
|
|
1251
|
+
}, V = (e, t) => {
|
|
1252
|
+
"Sogou web spider" === e.getPreviousNTokens(3) && (t.deviceBrand = "Sogou.com", t.appName = "SogouSpider"), t.appVersion = e.value, t.deviceType = "bot";
|
|
1253
|
+
}, A = (e, t) => {
|
|
1254
|
+
t.appName = "DataproviderBot", t.appVersion = e.value, t.deviceBrand = "Dataprovider.com", t.deviceType = "bot", t.platform = "other";
|
|
1255
|
+
}, D = (e, t) => {
|
|
1256
|
+
t.appName = "AhrefsBot", t.appVersion = e.value, t.deviceBrand = "Ahrefs", t.deviceType = "bot", t.platform = "other";
|
|
1257
|
+
}, k = (e, t) => {
|
|
1258
|
+
t.appName = "BitSightBot", t.appVersion = e.value, t.deviceBrand = "Bitsight", t.deviceType = "bot", t.platform = "other";
|
|
1259
|
+
}, P = (e, t) => {
|
|
1260
|
+
t.appName = "oBot", t.appVersion = e.value, t.deviceBrand = "IBM", t.deviceType = "bot", t.platform = "other";
|
|
1261
|
+
}, C = (e, t) => {
|
|
1262
|
+
t.appName = "Cincraw", t.appVersion = e.value, t.deviceBrand = "CINC", t.deviceType = "bot", t.platform = "other";
|
|
1263
|
+
}, E = (e, t) => {
|
|
1264
|
+
t.appName = "DingTalkBot", t.appVersion = e.value, t.deviceBrand = "Alibaba", t.deviceType = "bot", t.platform = "other";
|
|
1265
|
+
}, x = (e, t) => {
|
|
1266
|
+
t.appName = "YisouSpider", t.appVersion = e.value, t.deviceBrand = "Alibaba", t.deviceType = "bot", t.platform = "other";
|
|
1267
|
+
}, M = (e, t) => {
|
|
1268
|
+
t.appName = "ByteSpider", t.appVersion = e.value, t.deviceBrand = "ByteDance", t.deviceType = "bot", t.platform = "other";
|
|
1269
|
+
}, q = (e, t) => {
|
|
1270
|
+
t.appName = "HeadlineCrawler", t.appVersion = e.value, t.deviceBrand = "Headline.com", t.deviceType = "bot", t.platform = "other";
|
|
1271
|
+
}, I = (e, t) => {
|
|
1272
|
+
t.appName = "BitDiscoveryBot", t.appVersion = e.value, t.deviceBrand = "Tenable", t.deviceType = "bot", t.platform = "other";
|
|
1273
|
+
}, H = (e, t) => {
|
|
1274
|
+
"Screaming Frog SEO Spider" === e.getPreviousNTokens(4) && (t.deviceBrand = "Screaming Frog", t.appName = "Screaming Frog"), t.appVersion = e.value, t.deviceType = "bot";
|
|
1275
|
+
}, U = (e, t) => {
|
|
1276
|
+
t.appName = "Ai2Bot", t.appVersion = e.value, t.deviceBrand = "Ai2", t.deviceType = "bot", t.platform = "other";
|
|
1277
|
+
}, L = (e, t) => {
|
|
1278
|
+
t.appName = "DianjingAdSpider", t.appVersion = e.value, t.deviceBrand = "Dianjing", t.deviceType = "bot", t.platform = "other";
|
|
1279
|
+
}, Q = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
|
|
1280
|
+
Q.set("Baiduspider-render", o), Q.set("Baiduspider+", o), Q.set("Baiduspider-image+", o), Q.set("360Spider", i), Q.set("360Spider-Image", i), Q.set("bingbot", a), Q.set("Googlebot", u), Q.set("YandexRenderResourcesBot", p), Q.set("spider", l), Q.set("Dataprovider.com", s), Q.set("AhrefsBot", c), Q.set("BitSightBot", d), Q.set("oBot", f), Q.set("Cincraw", v), Q.set("DingTalkBot-LinkService", g), Q.set("YisouSpider", h), Q.set("Bytespider", m), Q.set("ev-crawler", b), Q.set("bitdiscovery", y), Q.set("Spider", _), Q.set("Ai2Bot-Dolma", B), Q.set("dianjing_ad_spider", S), R.set("Baiduspider-render", T), R.set("Baiduspider+", T), R.set("Baiduspider-image+", T), R.set("360Spider", j), R.set("360Spider-Image", j), R.set("bingbot", N), R.set("Googlebot", w), R.set("YandexRenderResourcesBot", O), R.set("spider", V), R.set("Dataprovider.com", A), R.set("AhrefsBot", D), R.set("BitSightBot", k), R.set("oBot", P), R.set("Cincraw", C), R.set("DingTalkBot-LinkService", E), R.set("YisouSpider", x), R.set("Bytespider", M), R.set("ev-crawler", q), R.set("bitdiscovery", I), R.set("Spider", H), R.set("Ai2Bot-Dolma", U), R.set("dianjing_ad_spider", L);
|
|
1281
|
+
const F = {
|
|
1282
|
+
productHandlerMap: Q,
|
|
1283
|
+
commentHandlerMap: R,
|
|
1284
|
+
getSpecialProductHandler: () => null,
|
|
1285
|
+
getSpecialCommentHandler: () => null,
|
|
1286
|
+
getDefaultModelHandler: () => null
|
|
1287
|
+
};
|
|
1288
|
+
t.isBot = function(e) {
|
|
1289
|
+
const t = r.createUAInfo();
|
|
1290
|
+
return r.runTask(e, t, F), "bot" === t.deviceType;
|
|
1291
|
+
};
|
|
1292
|
+
},
|
|
1293
|
+
function(e, t) {
|
|
1294
|
+
function n(e) {
|
|
1295
|
+
const t = [], n = {
|
|
1296
|
+
parent: e,
|
|
1297
|
+
tokens: t,
|
|
1298
|
+
get firstToken() {
|
|
1299
|
+
return 0 === t.length ? null : t[0];
|
|
1300
|
+
},
|
|
1301
|
+
getNewToken(r) {
|
|
1302
|
+
const o = (function() {
|
|
1303
|
+
const e = [], t = [], n = [];
|
|
1304
|
+
let r = null, o = null, i = null, a = !0, u = !0, p = !0, l = null;
|
|
1305
|
+
const s = {
|
|
1306
|
+
get key() {
|
|
1307
|
+
return a && (r = e.join(""), a = !1), r;
|
|
1308
|
+
},
|
|
1309
|
+
get value() {
|
|
1310
|
+
return u && (o = t.join(""), u = !1), o;
|
|
1311
|
+
},
|
|
1312
|
+
get originValue() {
|
|
1313
|
+
return p && (i = n.join(""), p = !1), i;
|
|
1314
|
+
},
|
|
1315
|
+
previousToken: null,
|
|
1316
|
+
properties: null,
|
|
1317
|
+
appendKey(t) {
|
|
1318
|
+
e.push(t), a = !0;
|
|
1319
|
+
},
|
|
1320
|
+
appendValue(e) {
|
|
1321
|
+
t.push("_" === e ? "." : e), n.push(e), u = !0, p = !0, l = null;
|
|
1322
|
+
},
|
|
1323
|
+
getSplitValue(e) {
|
|
1324
|
+
if (null === l) {
|
|
1325
|
+
const e = s.value;
|
|
1326
|
+
l = "" === e ? [] : e.split("/");
|
|
1327
|
+
}
|
|
1328
|
+
return e >= 0 && e < l.length ? l[e] : null;
|
|
1329
|
+
},
|
|
1330
|
+
getPreviousNTokens(e) {
|
|
1331
|
+
const t = [];
|
|
1332
|
+
let n = s;
|
|
1333
|
+
for (let r = 0; r < e; r++) {
|
|
1334
|
+
if (null == n) return null;
|
|
1335
|
+
t.unshift(n.key), n = n.previousToken;
|
|
1336
|
+
}
|
|
1337
|
+
return t.join(" ");
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
return s;
|
|
1341
|
+
})();
|
|
1342
|
+
return t.push(o), o.previousToken = void 0 !== r ? r : t.length > 1 ? t[t.length - 2] : null, e && (e.properties = n), o;
|
|
1343
|
+
},
|
|
1344
|
+
getLastToken: () => 0 === t.length ? null : t[t.length - 1],
|
|
1345
|
+
getFirstToken: () => 0 === t.length ? null : t[0],
|
|
1346
|
+
isEmpty: () => 0 === t.length
|
|
1347
|
+
};
|
|
1348
|
+
return n;
|
|
1349
|
+
}
|
|
1350
|
+
function r() {
|
|
1351
|
+
return {
|
|
1352
|
+
appName: null,
|
|
1353
|
+
appVersion: null,
|
|
1354
|
+
browserName: null,
|
|
1355
|
+
browserVersion: null,
|
|
1356
|
+
engineName: null,
|
|
1357
|
+
engineVersion: null,
|
|
1358
|
+
deviceBrand: null,
|
|
1359
|
+
deviceModel: null,
|
|
1360
|
+
deviceType: "mobile",
|
|
1361
|
+
osName: null,
|
|
1362
|
+
osVersion: null,
|
|
1363
|
+
platform: "web",
|
|
1364
|
+
tokenGroup: n(null)
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
const o = new Set(" ;,\"'".split("")), i = new Set("/=:".split("")), a = new Set([
|
|
1368
|
+
"Mozilla",
|
|
1369
|
+
"AppleWebKit",
|
|
1370
|
+
"Safari",
|
|
1371
|
+
"Opera",
|
|
1372
|
+
"Dalvik",
|
|
1373
|
+
"com.ss.android.ugc.aweme"
|
|
1374
|
+
]);
|
|
1375
|
+
function u(e) {
|
|
1376
|
+
return 1 === e.length && o.has(e);
|
|
1377
|
+
}
|
|
1378
|
+
function p(e) {
|
|
1379
|
+
return 1 === e.length && i.has(e);
|
|
1380
|
+
}
|
|
1381
|
+
function l(e, t, n, r) {
|
|
1382
|
+
if (null == e) return;
|
|
1383
|
+
const o = t.parent, i = e.key;
|
|
1384
|
+
let u = null;
|
|
1385
|
+
if (null != o) {
|
|
1386
|
+
const e = o.key;
|
|
1387
|
+
var p, l;
|
|
1388
|
+
if (a.has(e)) u = null !== (p = r.commentHandlerMap.get(i)) && void 0 !== p ? p : null, u ??= r.getSpecialCommentHandler(i), null == u && i.endsWith(" Build") && (u = r.getDefaultModelHandler());
|
|
1389
|
+
else u = null !== (l = r.productHandlerMap.get(i)) && void 0 !== l ? l : r.getSpecialProductHandler(i);
|
|
1390
|
+
} else {
|
|
1391
|
+
var s;
|
|
1392
|
+
u = null !== (s = r.productHandlerMap.get(i)) && void 0 !== s ? s : r.getSpecialProductHandler(i);
|
|
1393
|
+
}
|
|
1394
|
+
if (null != u) try {
|
|
1395
|
+
u(e, n);
|
|
1396
|
+
} catch (e) {}
|
|
1397
|
+
}
|
|
1398
|
+
function s(e, t, r) {
|
|
1399
|
+
if (null == e) throw new Error("input can not be null");
|
|
1400
|
+
return (function e(t, r, o, i, a) {
|
|
1401
|
+
let s, c = null, d = null, f = !1;
|
|
1402
|
+
const v = t.length;
|
|
1403
|
+
let g = r > 0 ? t[r - 1] : "\0";
|
|
1404
|
+
for (s = r; s < v; s++) {
|
|
1405
|
+
const h = t[s];
|
|
1406
|
+
if (u(h)) {
|
|
1407
|
+
const e = "\0" !== g && u(g);
|
|
1408
|
+
if (!f && r > 0 && " " === h && !e) {
|
|
1409
|
+
const e = s + 1;
|
|
1410
|
+
if (e < v) {
|
|
1411
|
+
const n = t[e];
|
|
1412
|
+
/\d/.test(n) || "-" === n ? f = !0 : d?.appendKey(h);
|
|
1413
|
+
} else d?.appendKey(h);
|
|
1414
|
+
} else null != d && (c = d, d = null);
|
|
1415
|
+
g = h;
|
|
1416
|
+
} else if ("(" === h) {
|
|
1417
|
+
if ("(" === g) {
|
|
1418
|
+
g = h;
|
|
1419
|
+
continue;
|
|
1420
|
+
}
|
|
1421
|
+
const r = s;
|
|
1422
|
+
s = e(t, s + 1, n(o.getLastToken()), i, a), null != d && (c = d, d = null), g = t[r];
|
|
1423
|
+
} else {
|
|
1424
|
+
if (")" === h) {
|
|
1425
|
+
if (0 === r) {
|
|
1426
|
+
g = h;
|
|
1427
|
+
continue;
|
|
1428
|
+
}
|
|
1429
|
+
break;
|
|
1430
|
+
}
|
|
1431
|
+
d ?? (l(o.getLastToken(), o, i, a), d = o.getNewToken(c), f = !1), p(h) ? (f && d.appendValue(h), f = !0) : f ? d.appendValue(h) : d.appendKey(h), g = h;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
return l(o.getLastToken(), o, i, a), s;
|
|
1435
|
+
})(e, 0, t.tokenGroup, t, r), t;
|
|
1436
|
+
}
|
|
1437
|
+
Object.defineProperty(t, "DEFAULT_MODEL_HANDLER_KEY", {
|
|
1438
|
+
enumerable: !0,
|
|
1439
|
+
get: function() {
|
|
1440
|
+
return "DEFAULT_MODEL_HANDLER";
|
|
1441
|
+
}
|
|
1442
|
+
}), Object.defineProperty(t, "createUAInfo", {
|
|
1443
|
+
enumerable: !0,
|
|
1444
|
+
get: function() {
|
|
1445
|
+
return r;
|
|
1446
|
+
}
|
|
1447
|
+
}), Object.defineProperty(t, "runTask", {
|
|
1448
|
+
enumerable: !0,
|
|
1449
|
+
get: function() {
|
|
1450
|
+
return s;
|
|
1451
|
+
}
|
|
1452
|
+
});
|
|
1453
|
+
},
|
|
1454
|
+
function(e, t, n) {
|
|
1455
|
+
"use strict";
|
|
1456
|
+
n.r(t);
|
|
1457
|
+
var r = n(0), o = n.n(r), i = n(1), a = n.n(i);
|
|
1458
|
+
n(2);
|
|
1459
|
+
function u() {
|
|
1460
|
+
var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 20, t = arguments.length > 1 ? arguments[1] : void 0;
|
|
1461
|
+
return t = t || "", e ? u(--e, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(60 * Math.random())) + t) : t;
|
|
1462
|
+
}
|
|
1463
|
+
function p(e, t) {
|
|
1464
|
+
for (var n in t) e[n] = t[n];
|
|
1465
|
+
return e;
|
|
1466
|
+
}
|
|
1467
|
+
function l(e) {
|
|
1468
|
+
return "[object Object]" === Object.prototype.toString.call(e);
|
|
1469
|
+
}
|
|
1470
|
+
function s(e) {
|
|
1471
|
+
return "undefined" != typeof Promise && e instanceof Promise;
|
|
1472
|
+
}
|
|
1473
|
+
var c = Object.freeze({ __aesBeforeSkip: 1 }), d = function(e) {
|
|
1474
|
+
var t = Object.prototype.toString.call(e);
|
|
1475
|
+
if ("[object String]" === t && e || "[object Number]" === t || "[object Boolean]" === t) return e;
|
|
1476
|
+
if ("[object Object]" === t || "[object Array]" === t) try {
|
|
1477
|
+
return JSON.stringify(e);
|
|
1478
|
+
} catch (e) {}
|
|
1479
|
+
}, f = function(e) {
|
|
1480
|
+
var t = {};
|
|
1481
|
+
for (var n in e) {
|
|
1482
|
+
var r = e[n];
|
|
1483
|
+
void 0 !== r && (t[n] = d(r));
|
|
1484
|
+
}
|
|
1485
|
+
return t;
|
|
1486
|
+
}, v = function(e) {
|
|
1487
|
+
var t = [];
|
|
1488
|
+
for (var n in e) {
|
|
1489
|
+
var r = d(e[n]);
|
|
1490
|
+
void 0 !== r && t.push("".concat(n, "=").concat(encodeURIComponent(r)));
|
|
1491
|
+
}
|
|
1492
|
+
return t.join("&");
|
|
1493
|
+
};
|
|
1494
|
+
function g(e) {
|
|
1495
|
+
return (e.requiredFields || []).concat(["pid"]).some(function(t) {
|
|
1496
|
+
return void 0 === e[t];
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
function h() {
|
|
1500
|
+
var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", t = arguments.length > 1 ? arguments[1] : void 0;
|
|
1501
|
+
"undefined" != typeof console && console.warn("日志解析报错,埋点将被丢弃 => ".concat(e), t);
|
|
1502
|
+
}
|
|
1503
|
+
var m = "AEM_TRACKER_UNIQUE_PVID", b = "undefined" != typeof globalThis && globalThis ? globalThis : "undefined" != typeof window && window ? window : "undefined" != typeof global && global ? global : "undefined" != typeof self && self ? self : (console.error("Unable to locate global object in current environment"), {});
|
|
1504
|
+
function y(e) {
|
|
1505
|
+
this._queue = [], this._reqQueue = [], this._plugins = {}, this._subscribers = { onConfigUpdated: [] }, this._timeout = 0, this._config = {
|
|
1506
|
+
sdk_version: "3.3.18",
|
|
1507
|
+
set pv_id(e) {
|
|
1508
|
+
b[m] = e;
|
|
1509
|
+
},
|
|
1510
|
+
get pv_id() {
|
|
1511
|
+
return b[m] || (b[m] = u()), b[m];
|
|
1512
|
+
},
|
|
1513
|
+
timezone_offset: (/* @__PURE__ */ new Date()).getTimezoneOffset()
|
|
1514
|
+
}, e && (this._config = p(this._config, e));
|
|
1515
|
+
}
|
|
1516
|
+
y.prototype = {
|
|
1517
|
+
constructor: y,
|
|
1518
|
+
_sendAll: function() {
|
|
1519
|
+
if (this._timeout && (clearTimeout(this._timeout), this._timeout = 0), this._queue.length) {
|
|
1520
|
+
var e, t = this._config.maxUrlLength || 3e4, n = this._getSendConfig();
|
|
1521
|
+
try {
|
|
1522
|
+
e = this._processData(this._queue, n);
|
|
1523
|
+
} catch (e) {}
|
|
1524
|
+
if (e && e.length < t) return this._queue = [], void this.send(e);
|
|
1525
|
+
for (var r, o = []; this._queue.length;) {
|
|
1526
|
+
o.push(this._queue.shift());
|
|
1527
|
+
try {
|
|
1528
|
+
r = this._processData(o, n);
|
|
1529
|
+
} catch (e) {
|
|
1530
|
+
var i = o.pop();
|
|
1531
|
+
h(e.message, i);
|
|
1532
|
+
continue;
|
|
1533
|
+
}
|
|
1534
|
+
if (r.length > t) {
|
|
1535
|
+
o.length > 1 && (this._queue.unshift(o.pop()), r = this._processData(o, n));
|
|
1536
|
+
break;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
r && this.send(r), this._queue.length && this._sendAll();
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
_send: function(e, t) {
|
|
1543
|
+
var n = this;
|
|
1544
|
+
if (!1 === t) {
|
|
1545
|
+
var r;
|
|
1546
|
+
try {
|
|
1547
|
+
r = this._processData([e]);
|
|
1548
|
+
} catch (t) {
|
|
1549
|
+
h(t.message, e);
|
|
1550
|
+
}
|
|
1551
|
+
r && this.send(r);
|
|
1552
|
+
} else {
|
|
1553
|
+
this._queue.push(e);
|
|
1554
|
+
var o = this._config.mergeRequestInterval || 500;
|
|
1555
|
+
this._timeout || (this._timeout = setTimeout(function() {
|
|
1556
|
+
n._sendAll();
|
|
1557
|
+
}, o));
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
_getSendConfig: function() {
|
|
1561
|
+
var e = {}, t = this._config;
|
|
1562
|
+
for (var n in t) "requiredFields" !== n && "maxUrlLength" !== n && "queueGlobalName" !== n && "debug" !== n && "excludeCrawlers" !== n && "collectClientHints" !== n && 0 !== n.indexOf("plugin") && "" !== t[n] && null !== t[n] && void 0 !== t[n] && (e[n] = d(t[n]));
|
|
1563
|
+
return e;
|
|
1564
|
+
},
|
|
1565
|
+
_processData: function(e, t) {
|
|
1566
|
+
t = t || this._getSendConfig();
|
|
1567
|
+
var n = v(t);
|
|
1568
|
+
return n += "&msg=" + encodeURIComponent(e.map(function(e) {
|
|
1569
|
+
return v(e);
|
|
1570
|
+
}).join("|"));
|
|
1571
|
+
},
|
|
1572
|
+
setConfig: function(e, t) {
|
|
1573
|
+
var n = this, r = {};
|
|
1574
|
+
void 0 !== t ? r[e] = t : r = e;
|
|
1575
|
+
var o = !(function e(t, n) {
|
|
1576
|
+
if (void 0 === t || void 0 === n) return !1;
|
|
1577
|
+
if (!l(t) || !l(n)) return !1;
|
|
1578
|
+
for (var r in t) if (l(t[r])) {
|
|
1579
|
+
if (!e(t[r], n[r])) return !1;
|
|
1580
|
+
} else if (t[r] !== n[r]) return !1;
|
|
1581
|
+
return !0;
|
|
1582
|
+
})(r, this._config), i = function() {
|
|
1583
|
+
if (o) {
|
|
1584
|
+
for (var e in r) l(r[e]) ? n._config[e] = p(n._config[e] || {}, r[e]) : n._config[e] = r[e];
|
|
1585
|
+
n._execSubscribe("onConfigUpdated", [r, n._config]);
|
|
1586
|
+
}
|
|
1587
|
+
};
|
|
1588
|
+
this._reqQueue.length ? (i(), g(this._config) || (this._reqQueue.forEach(function(e) {
|
|
1589
|
+
n._send.apply(n, e);
|
|
1590
|
+
}), this._reqQueue = [])) : (o && this._sendAll(), i());
|
|
1591
|
+
},
|
|
1592
|
+
getConfig: function(e) {
|
|
1593
|
+
return e ? this._config[e] : this._config;
|
|
1594
|
+
},
|
|
1595
|
+
updatePVID: (function(e, t) {
|
|
1596
|
+
if ("function" != typeof e) throw new TypeError("Expected a function");
|
|
1597
|
+
t = "number" == typeof t && t >= 0 ? t : 100;
|
|
1598
|
+
var n = null;
|
|
1599
|
+
return function() {
|
|
1600
|
+
if (null === n) {
|
|
1601
|
+
var r = this, o = Array.prototype.slice.call(arguments);
|
|
1602
|
+
n = setTimeout(function() {
|
|
1603
|
+
n = null;
|
|
1604
|
+
}, t), e.apply(r, o);
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
1607
|
+
})(function() {
|
|
1608
|
+
b[m] = u();
|
|
1609
|
+
}, 200),
|
|
1610
|
+
log: function(e) {
|
|
1611
|
+
var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {};
|
|
1612
|
+
e && (t.ts = t.ts || (/* @__PURE__ */ new Date()).getTime(), t.type = e, this._print("log", e, t), t = f(t), g(this._config) ? this._reqQueue.length < 1e3 && this._reqQueue.push([t, n.combo]) : this._send(t, n.combo));
|
|
1613
|
+
},
|
|
1614
|
+
before: function(e, t) {
|
|
1615
|
+
var n = this;
|
|
1616
|
+
return function() {
|
|
1617
|
+
var r = arguments, o = t.apply(n, r);
|
|
1618
|
+
o !== c && (s(o) ? o.then(function(t) {
|
|
1619
|
+
t !== c && e.apply(n, t || r);
|
|
1620
|
+
}) : e.apply(n, o || r));
|
|
1621
|
+
};
|
|
1622
|
+
},
|
|
1623
|
+
after: function(e, t) {
|
|
1624
|
+
var n = this;
|
|
1625
|
+
return function() {
|
|
1626
|
+
var r = arguments;
|
|
1627
|
+
e.apply(n, r), t.apply(n, r);
|
|
1628
|
+
};
|
|
1629
|
+
},
|
|
1630
|
+
use: function(e, t) {
|
|
1631
|
+
var n = this;
|
|
1632
|
+
return "[object Array]" === Object.prototype.toString.call(e) ? e.map(function(e) {
|
|
1633
|
+
if ("[object Array]" === Object.prototype.toString.call(e)) {
|
|
1634
|
+
var t = e[0], r = e[1];
|
|
1635
|
+
return n._plugins[t] || (n._plugins[t] = new t(n, r));
|
|
1636
|
+
}
|
|
1637
|
+
return n._plugins[e] || (n._plugins[e] = new e(n));
|
|
1638
|
+
}) : this._plugins[e] || (this._plugins[e] = new e(this, t));
|
|
1639
|
+
},
|
|
1640
|
+
_print: function() {
|
|
1641
|
+
this._config.debug && "undefined" != typeof console && console.log.apply(console, arguments);
|
|
1642
|
+
},
|
|
1643
|
+
onConfigUpdated: function(e) {
|
|
1644
|
+
this._subscribers.onConfigUpdated && this._subscribers.onConfigUpdated.push(e);
|
|
1645
|
+
},
|
|
1646
|
+
_execSubscribe: function(e, t) {
|
|
1647
|
+
this._subscribers[e] && this._subscribers[e].forEach(function(e) {
|
|
1648
|
+
e.apply(this, t);
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
};
|
|
1652
|
+
var _ = y, B = n(3), S = n.n(B), T = n(4), j = n(5), N = n.n(j);
|
|
1653
|
+
function w(e) {
|
|
1654
|
+
return (w = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) {
|
|
1655
|
+
return typeof e;
|
|
1656
|
+
} : function(e) {
|
|
1657
|
+
return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e;
|
|
1658
|
+
})(e);
|
|
1659
|
+
}
|
|
1660
|
+
function O(e, t) {
|
|
1661
|
+
var n = Object.keys(e);
|
|
1662
|
+
if (Object.getOwnPropertySymbols) {
|
|
1663
|
+
var r = Object.getOwnPropertySymbols(e);
|
|
1664
|
+
t && (r = r.filter(function(t) {
|
|
1665
|
+
return Object.getOwnPropertyDescriptor(e, t).enumerable;
|
|
1666
|
+
})), n.push.apply(n, r);
|
|
1667
|
+
}
|
|
1668
|
+
return n;
|
|
1669
|
+
}
|
|
1670
|
+
function V(e) {
|
|
1671
|
+
for (var t = 1; t < arguments.length; t++) {
|
|
1672
|
+
var n = null != arguments[t] ? arguments[t] : {};
|
|
1673
|
+
t % 2 ? O(Object(n), !0).forEach(function(t) {
|
|
1674
|
+
A(e, t, n[t]);
|
|
1675
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : O(Object(n)).forEach(function(t) {
|
|
1676
|
+
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t));
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
return e;
|
|
1680
|
+
}
|
|
1681
|
+
function A(e, t, n) {
|
|
1682
|
+
return (t = (function(e) {
|
|
1683
|
+
var t = (function(e, t) {
|
|
1684
|
+
if ("object" != w(e) || !e) return e;
|
|
1685
|
+
var n = e[Symbol.toPrimitive];
|
|
1686
|
+
if (void 0 !== n) {
|
|
1687
|
+
var r = n.call(e, t || "default");
|
|
1688
|
+
if ("object" != w(r)) return r;
|
|
1689
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
1690
|
+
}
|
|
1691
|
+
return ("string" === t ? String : Number)(e);
|
|
1692
|
+
})(e, "string");
|
|
1693
|
+
return "symbol" == w(t) ? t : t + "";
|
|
1694
|
+
})(t)) in e ? Object.defineProperty(e, t, {
|
|
1695
|
+
value: n,
|
|
1696
|
+
enumerable: !0,
|
|
1697
|
+
configurable: !0,
|
|
1698
|
+
writable: !0
|
|
1699
|
+
}) : e[t] = n, e;
|
|
1700
|
+
}
|
|
1701
|
+
function D(e, t) {
|
|
1702
|
+
var n = "undefined" != typeof Symbol && e[Symbol.iterator] || e["@@iterator"];
|
|
1703
|
+
if (!n) {
|
|
1704
|
+
if (Array.isArray(e) || (n = P(e)) || t && e && "number" == typeof e.length) {
|
|
1705
|
+
n && (e = n);
|
|
1706
|
+
var r = 0, o = function() {};
|
|
1707
|
+
return {
|
|
1708
|
+
s: o,
|
|
1709
|
+
n: function() {
|
|
1710
|
+
return r >= e.length ? { done: !0 } : {
|
|
1711
|
+
done: !1,
|
|
1712
|
+
value: e[r++]
|
|
1713
|
+
};
|
|
1714
|
+
},
|
|
1715
|
+
e: function(e) {
|
|
1716
|
+
throw e;
|
|
1717
|
+
},
|
|
1718
|
+
f: o
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
1722
|
+
}
|
|
1723
|
+
var i, a = !0, u = !1;
|
|
1724
|
+
return {
|
|
1725
|
+
s: function() {
|
|
1726
|
+
n = n.call(e);
|
|
1727
|
+
},
|
|
1728
|
+
n: function() {
|
|
1729
|
+
var e = n.next();
|
|
1730
|
+
return a = e.done, e;
|
|
1731
|
+
},
|
|
1732
|
+
e: function(e) {
|
|
1733
|
+
u = !0, i = e;
|
|
1734
|
+
},
|
|
1735
|
+
f: function() {
|
|
1736
|
+
try {
|
|
1737
|
+
a || null == n.return || n.return();
|
|
1738
|
+
} finally {
|
|
1739
|
+
if (u) throw i;
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
function k(e, t) {
|
|
1745
|
+
return (function(e) {
|
|
1746
|
+
if (Array.isArray(e)) return e;
|
|
1747
|
+
})(e) || (function(e, t) {
|
|
1748
|
+
var n = null == e ? null : "undefined" != typeof Symbol && e[Symbol.iterator] || e["@@iterator"];
|
|
1749
|
+
if (null != n) {
|
|
1750
|
+
var r, o, i, a, u = [], p = !0, l = !1;
|
|
1751
|
+
try {
|
|
1752
|
+
if (i = (n = n.call(e)).next, 0 === t) {
|
|
1753
|
+
if (Object(n) !== n) return;
|
|
1754
|
+
p = !1;
|
|
1755
|
+
} else for (; !(p = (r = i.call(n)).done) && (u.push(r.value), u.length !== t); p = !0);
|
|
1756
|
+
} catch (e) {
|
|
1757
|
+
l = !0, o = e;
|
|
1758
|
+
} finally {
|
|
1759
|
+
try {
|
|
1760
|
+
if (!p && null != n.return && (a = n.return(), Object(a) !== a)) return;
|
|
1761
|
+
} finally {
|
|
1762
|
+
if (l) throw o;
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
return u;
|
|
1766
|
+
}
|
|
1767
|
+
})(e, t) || P(e, t) || (function() {
|
|
1768
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
1769
|
+
})();
|
|
1770
|
+
}
|
|
1771
|
+
function P(e, t) {
|
|
1772
|
+
if (e) {
|
|
1773
|
+
if ("string" == typeof e) return C(e, t);
|
|
1774
|
+
var n = {}.toString.call(e).slice(8, -1);
|
|
1775
|
+
return "Object" === n && e.constructor && (n = e.constructor.name), "Map" === n || "Set" === n ? Array.from(e) : "Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n) ? C(e, t) : void 0;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
function C(e, t) {
|
|
1779
|
+
(null == t || t > e.length) && (t = e.length);
|
|
1780
|
+
for (var n = 0, r = Array(t); n < t; n++) r[n] = e[n];
|
|
1781
|
+
return r;
|
|
1782
|
+
}
|
|
1783
|
+
function E() {
|
|
1784
|
+
for (var e = /(?:[0]{1,2}[:-]){5}[0]{1,2}/, t = o.a.networkInterfaces(), n = 0, r = Object.entries(t); n < r.length; n++) {
|
|
1785
|
+
var i = k(r[n], 2), a = (i[0], i[1]);
|
|
1786
|
+
if (a) {
|
|
1787
|
+
var u, p = D(a);
|
|
1788
|
+
try {
|
|
1789
|
+
for (p.s(); !(u = p.n()).done;) {
|
|
1790
|
+
var l = u.value;
|
|
1791
|
+
if (!1 === e.test(l.mac)) return l.mac;
|
|
1792
|
+
}
|
|
1793
|
+
} catch (e) {
|
|
1794
|
+
p.e(e);
|
|
1795
|
+
} finally {
|
|
1796
|
+
p.f();
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
return "00:00:00:00:00:00";
|
|
1801
|
+
}
|
|
1802
|
+
var x, M, q = (x = process.version, {
|
|
1803
|
+
os: o.a.type(),
|
|
1804
|
+
os_version: o.a.release(),
|
|
1805
|
+
app_name: "node",
|
|
1806
|
+
app_version: x,
|
|
1807
|
+
device_id: N.a.createHash("md5").update(E()).digest("hex"),
|
|
1808
|
+
platform: "node"
|
|
1809
|
+
}), I = Object(T.promisify)(S.a.resolve);
|
|
1810
|
+
function H(e) {
|
|
1811
|
+
this._offlineQueue = [], e.endpoint = e.endpoint || "gm.mmstat.com", _.call(this, V(V({}, q), e)), this._config.endpoint_url = "https://".concat(this._config.endpoint).concat("/aes.1.1");
|
|
1812
|
+
}
|
|
1813
|
+
H.prototype = ((M = function() {}).prototype = _.prototype, new M()), H.prototype.constructor = H, H.prototype.send = function(e) {
|
|
1814
|
+
var t, n = this;
|
|
1815
|
+
return (t = this._config.endpoint, I(t)).then(function(t) {
|
|
1816
|
+
return n._offlineQueue.forEach(function(e) {
|
|
1817
|
+
n.send(e);
|
|
1818
|
+
}), n._offlineQueue = [], n._print("send", e), a()(n._config.endpoint_url, {
|
|
1819
|
+
method: "POST",
|
|
1820
|
+
keepalive: true,
|
|
1821
|
+
body: JSON.stringify({
|
|
1822
|
+
gokey: encodeURIComponent(e),
|
|
1823
|
+
gmkey: "EXP"
|
|
1824
|
+
})
|
|
1825
|
+
}).catch(function(e) {
|
|
1826
|
+
console.warn("send fail", e);
|
|
1827
|
+
});
|
|
1828
|
+
}).catch(function(t) {
|
|
1829
|
+
n._offlineQueue.length > 500 && n._offlineQueue.shift(), n._offlineQueue.push(e);
|
|
1830
|
+
});
|
|
1831
|
+
};
|
|
1832
|
+
t.default = H;
|
|
1833
|
+
}
|
|
1834
|
+
]).default;
|
|
1835
|
+
}));
|
|
1836
|
+
//#endregion
|
|
1837
|
+
//#region lib/remote-telemetry/event-plugin.js
|
|
1838
|
+
var require_event_plugin = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
1839
|
+
module.exports = (function(e) {
|
|
1840
|
+
var t = {};
|
|
1841
|
+
function n(r) {
|
|
1842
|
+
if (t[r]) return t[r].exports;
|
|
1843
|
+
var o = t[r] = {
|
|
1844
|
+
i: r,
|
|
1845
|
+
l: !1,
|
|
1846
|
+
exports: {}
|
|
1847
|
+
};
|
|
1848
|
+
return e[r].call(o.exports, o, o.exports, n), o.l = !0, o.exports;
|
|
1849
|
+
}
|
|
1850
|
+
return n.m = e, n.c = t, n.d = function(e, t, r) {
|
|
1851
|
+
n.o(e, t) || Object.defineProperty(e, t, {
|
|
1852
|
+
enumerable: !0,
|
|
1853
|
+
get: r
|
|
1854
|
+
});
|
|
1855
|
+
}, n.r = function(e) {
|
|
1856
|
+
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 });
|
|
1857
|
+
}, n.t = function(e, t) {
|
|
1858
|
+
if (1 & t && (e = n(e)), 8 & t) return e;
|
|
1859
|
+
if (4 & t && "object" == typeof e && e && e.__esModule) return e;
|
|
1860
|
+
var r = Object.create(null);
|
|
1861
|
+
if (n.r(r), Object.defineProperty(r, "default", {
|
|
1862
|
+
enumerable: !0,
|
|
1863
|
+
value: e
|
|
1864
|
+
}), 2 & t && "string" != typeof e) for (var o in e) n.d(r, o, function(t) {
|
|
1865
|
+
return e[t];
|
|
1866
|
+
}.bind(null, o));
|
|
1867
|
+
return r;
|
|
1868
|
+
}, n.n = function(e) {
|
|
1869
|
+
var t = e && e.__esModule ? function() {
|
|
1870
|
+
return e.default;
|
|
1871
|
+
} : function() {
|
|
1872
|
+
return e;
|
|
1873
|
+
};
|
|
1874
|
+
return n.d(t, "a", t), t;
|
|
1875
|
+
}, n.o = function(e, t) {
|
|
1876
|
+
return Object.prototype.hasOwnProperty.call(e, t);
|
|
1877
|
+
}, n.p = "", n(n.s = 0);
|
|
1878
|
+
})([function(e, t, n) {
|
|
1879
|
+
"use strict";
|
|
1880
|
+
n.r(t);
|
|
1881
|
+
var r = [
|
|
1882
|
+
"ec",
|
|
1883
|
+
"ea",
|
|
1884
|
+
"el",
|
|
1885
|
+
"et"
|
|
1886
|
+
];
|
|
1887
|
+
var o = function(e, t) {
|
|
1888
|
+
var n = function(e) {
|
|
1889
|
+
var n = e.ec, r = e.ea, o = e.el, l = e.et, u = void 0 === l ? "CLK" : l, a = e.xpath;
|
|
1890
|
+
delete e.ec, delete e.ea, delete e.el, delete e.et, delete e.xpath, e.p1 = n, e.p2 = r, e.p3 = o, e.p4 = u, e.p5 = a;
|
|
1891
|
+
try {
|
|
1892
|
+
t.log("event", e);
|
|
1893
|
+
} catch (e) {}
|
|
1894
|
+
};
|
|
1895
|
+
return function() {
|
|
1896
|
+
var t = arguments, o = {};
|
|
1897
|
+
if (0 !== t.length) {
|
|
1898
|
+
for (var l = 0; l < t.length; l++) {
|
|
1899
|
+
var u, a, i = t[l];
|
|
1900
|
+
if (0 !== l && "object" == typeof i && l !== t.length - 1) return void (null == e || null === (u = e.console) || void 0 === u || null === (a = u.warn) || void 0 === a || a.call(u, "Only the last argument can be object type"));
|
|
1901
|
+
if ("string" == typeof i || "number" == typeof i) o[r[l]] = i;
|
|
1902
|
+
else if ("object" == typeof i && l === t.length - 1) for (var c in i) i.hasOwnProperty(c) && (o[c] = i[c]);
|
|
1903
|
+
}
|
|
1904
|
+
n(o);
|
|
1905
|
+
} else {
|
|
1906
|
+
var f, p;
|
|
1907
|
+
null === (f = e.console) || void 0 === f || null === (p = f.warn) || void 0 === p || p.call(f, "At lease one augument");
|
|
1908
|
+
}
|
|
1909
|
+
};
|
|
1910
|
+
};
|
|
1911
|
+
t.default = function(e, t) {
|
|
1912
|
+
return o(global, e);
|
|
1913
|
+
};
|
|
1914
|
+
}]).default;
|
|
1915
|
+
}));
|
|
1916
|
+
//#endregion
|
|
1917
|
+
//#region src/telemetry/sink.ts
|
|
1918
|
+
var import_tracker = /* @__PURE__ */ __toESM(require_tracker(), 1);
|
|
1919
|
+
var import_event_plugin = /* @__PURE__ */ __toESM(require_event_plugin(), 1);
|
|
1920
|
+
const TELEMETRY_FILE = () => join(getConfigDir(), "telemetry.jsonl");
|
|
1921
|
+
const MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
1922
|
+
let remoteSendEvent;
|
|
1923
|
+
const inflightSends = /* @__PURE__ */ new Set();
|
|
1924
|
+
let remoteClient = void 0;
|
|
1925
|
+
try {
|
|
1926
|
+
const client = new import_tracker.default({
|
|
1927
|
+
pid: "bailian-cli-node",
|
|
1928
|
+
env: detectEnv()
|
|
1929
|
+
});
|
|
1930
|
+
const originalSend = client.send.bind(client);
|
|
1931
|
+
client.send = function(payload) {
|
|
1932
|
+
const result = originalSend(payload);
|
|
1933
|
+
if (result && typeof result.then === "function") {
|
|
1934
|
+
const p = result;
|
|
1935
|
+
inflightSends.add(p);
|
|
1936
|
+
p.finally(() => inflightSends.delete(p));
|
|
1937
|
+
}
|
|
1938
|
+
return result;
|
|
1939
|
+
};
|
|
1940
|
+
remoteClient = client;
|
|
1941
|
+
remoteSendEvent = client.use(import_event_plugin.default);
|
|
1942
|
+
} catch {}
|
|
1943
|
+
/**
|
|
1944
|
+
* 尽力等待所有在途的埋点发送完成(best-effort)。
|
|
1945
|
+
*
|
|
1946
|
+
* 1. 先调用 `_sendAll` 排空 tracker 内部的去抖队列,把还卡在 500ms 合并窗口里
|
|
1947
|
+
* 的事件立刻推上网络。
|
|
1948
|
+
* 2. 然后用硬超时 race 所有已追踪的 fetch promise。
|
|
1949
|
+
*
|
|
1950
|
+
* 埋点永远不应阻塞 CLI:调用方应传入较短的超时(例如 1000ms),并始终与超时
|
|
1951
|
+
* race。错误与超时一律静默吞掉。
|
|
1952
|
+
*/
|
|
1953
|
+
async function flushTelemetry(timeoutMs = 1e3) {
|
|
1954
|
+
try {
|
|
1955
|
+
if (remoteClient) try {
|
|
1956
|
+
if (typeof remoteClient._sendAll === "function") remoteClient._sendAll();
|
|
1957
|
+
} catch {}
|
|
1958
|
+
if (inflightSends.size === 0) return;
|
|
1959
|
+
const pending = [...inflightSends].map((p) => p.catch(() => void 0));
|
|
1960
|
+
await Promise.race([Promise.allSettled(pending), new Promise((resolve) => setTimeout(resolve, timeoutMs).unref?.())]);
|
|
1961
|
+
} catch {}
|
|
1962
|
+
}
|
|
1963
|
+
async function localSink(event) {
|
|
1964
|
+
try {
|
|
1965
|
+
await ensureConfigDir();
|
|
1966
|
+
const path = TELEMETRY_FILE();
|
|
1967
|
+
try {
|
|
1968
|
+
if (statSync(path).size > MAX_FILE_SIZE) unlinkSync(path);
|
|
1969
|
+
} catch {}
|
|
1970
|
+
appendFileSync(path, JSON.stringify(event) + "\n", { mode: 384 });
|
|
1971
|
+
} catch {}
|
|
1972
|
+
}
|
|
1973
|
+
async function remoteSink(event) {
|
|
1974
|
+
try {
|
|
1975
|
+
if (!remoteSendEvent) return;
|
|
1976
|
+
remoteSendEvent(event.command, buildRemoteAemOptions(event));
|
|
1977
|
+
} catch {}
|
|
1978
|
+
}
|
|
1979
|
+
//#endregion
|
|
1980
|
+
//#region src/telemetry/tracker.ts
|
|
1981
|
+
const GLOBAL_FLAG_KEYS = new Set([
|
|
1982
|
+
"apiKey",
|
|
1983
|
+
"baseUrl",
|
|
1984
|
+
"output",
|
|
1985
|
+
"quiet",
|
|
1986
|
+
"verbose",
|
|
1987
|
+
"timeout",
|
|
1988
|
+
"noColor",
|
|
1989
|
+
"yes",
|
|
1990
|
+
"dryRun",
|
|
1991
|
+
"help",
|
|
1992
|
+
"nonInteractive",
|
|
1993
|
+
"async",
|
|
1994
|
+
"region",
|
|
1995
|
+
"console"
|
|
1996
|
+
]);
|
|
1997
|
+
/**
|
|
1998
|
+
* Allowlist of flag names safe to send to telemetry.
|
|
1999
|
+
*
|
|
2000
|
+
* Default is to NOT report. Only flags whose value space is enumerable / numeric / boolean
|
|
2001
|
+
* (and therefore cannot leak user content, credentials, file paths, URLs, or customer IDs)
|
|
2002
|
+
* belong here. When adding a new flag, ask: could this field carry PII, secrets, prompts,
|
|
2003
|
+
* file paths, URLs, or tenant identifiers? If yes, do NOT add it.
|
|
2004
|
+
*/
|
|
2005
|
+
const PARAM_ALLOWLIST = new Set([
|
|
2006
|
+
"page",
|
|
2007
|
+
"pageSize",
|
|
2008
|
+
"n",
|
|
2009
|
+
"count",
|
|
2010
|
+
"model",
|
|
2011
|
+
"voice",
|
|
2012
|
+
"language",
|
|
2013
|
+
"provider",
|
|
2014
|
+
"capability",
|
|
2015
|
+
"temperature",
|
|
2016
|
+
"topP",
|
|
2017
|
+
"topK",
|
|
2018
|
+
"maxTokens",
|
|
2019
|
+
"seed",
|
|
2020
|
+
"stream",
|
|
2021
|
+
"size",
|
|
2022
|
+
"resolution",
|
|
2023
|
+
"ratio",
|
|
2024
|
+
"duration",
|
|
2025
|
+
"format",
|
|
2026
|
+
"audioFormat",
|
|
2027
|
+
"sampleRate",
|
|
2028
|
+
"pitch",
|
|
2029
|
+
"rate",
|
|
2030
|
+
"volume",
|
|
2031
|
+
"api",
|
|
2032
|
+
"mode",
|
|
2033
|
+
"download",
|
|
2034
|
+
"noWait",
|
|
2035
|
+
"textOnly",
|
|
2036
|
+
"promptExtend",
|
|
2037
|
+
"noPromptExtend",
|
|
2038
|
+
"enableSsml",
|
|
2039
|
+
"watermark",
|
|
2040
|
+
"hasThoughts",
|
|
2041
|
+
"listTools",
|
|
2042
|
+
"rerank",
|
|
2043
|
+
"rerankTopN",
|
|
2044
|
+
"diarization"
|
|
2045
|
+
]);
|
|
2046
|
+
function extractParams(flags) {
|
|
2047
|
+
const params = {};
|
|
2048
|
+
for (const [key, value] of Object.entries(flags)) {
|
|
2049
|
+
if (key.startsWith("_")) continue;
|
|
2050
|
+
if (GLOBAL_FLAG_KEYS.has(key)) continue;
|
|
2051
|
+
if (!PARAM_ALLOWLIST.has(key)) continue;
|
|
2052
|
+
if (value === void 0 || value === false) continue;
|
|
2053
|
+
params[key] = value;
|
|
2054
|
+
}
|
|
2055
|
+
return params;
|
|
2056
|
+
}
|
|
2057
|
+
async function trackCommandExecution(config, commandPath, flags, fn) {
|
|
2058
|
+
if (!config.telemetry) {
|
|
2059
|
+
await fn();
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
const start = performance.now();
|
|
2063
|
+
let success = true;
|
|
2064
|
+
let errorMessage;
|
|
2065
|
+
let httpStatus;
|
|
2066
|
+
let requestId;
|
|
2067
|
+
try {
|
|
2068
|
+
await fn();
|
|
2069
|
+
} catch (err) {
|
|
2070
|
+
success = false;
|
|
2071
|
+
if (err instanceof BailianError) {
|
|
2072
|
+
errorMessage = err.message;
|
|
2073
|
+
httpStatus = err.api?.httpStatus;
|
|
2074
|
+
requestId = err.api?.requestId;
|
|
2075
|
+
} else if (err instanceof Error) errorMessage = err.message;
|
|
2076
|
+
throw err;
|
|
2077
|
+
} finally {
|
|
2078
|
+
const durationMs = Math.round(performance.now() - start);
|
|
2079
|
+
let authMethod;
|
|
2080
|
+
if (config.apiKey) authMethod = "api-key";
|
|
2081
|
+
else if (config.fileApiKey) authMethod = "api-key";
|
|
2082
|
+
else if (config.accessTokenEnv || config.fileAccessToken) authMethod = "access-token";
|
|
2083
|
+
const event = createTrackingEvent({
|
|
2084
|
+
command: commandPath.join(" "),
|
|
2085
|
+
durationMs,
|
|
2086
|
+
success,
|
|
2087
|
+
error: success ? void 0 : {
|
|
2088
|
+
message: errorMessage,
|
|
2089
|
+
httpStatus,
|
|
2090
|
+
requestId
|
|
2091
|
+
},
|
|
2092
|
+
cliVersion: config.clientVersion ?? "unknown",
|
|
2093
|
+
region: config.region,
|
|
2094
|
+
authMethod,
|
|
2095
|
+
params: extractParams(flags)
|
|
2096
|
+
});
|
|
2097
|
+
localSink(event).catch(() => {});
|
|
2098
|
+
remoteSink(event).catch(() => {});
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
//#endregion
|
|
2102
|
+
export { BAILIAN_HOST, BailianError, CHANNEL, CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, DOCS_HOSTS, ExitCode, GLOBAL_OPTIONS, McpClient, REGIONS, SOURCE_CONFIG, TAGS, appCompletionEndpoint, bailianMcpUrl, callConsoleGateway, chatEndpoint, clearApiKey, createTrackingEvent, defineCommand, detectOutputFormat, ensureConfigDir, flushTelemetry, formatErrorJson, formatJson, formatOutput, formatText, generateFilename, generateToolSchema, getConfigDir, getConfigPath, getCredentialsPath, imageEndpoint, imageSyncEndpoint, isCI, isInteractive, isLocalFile, loadApiKeyFromConfig, loadConfig, localSink, mapApiError, maskToken, mcpWebSearchEndpoint, memoryAddEndpoint, memoryListEndpoint, memoryNodeEndpoint, memorySearchEndpoint, parseConfigFile, parseSSE, profileSchemaEndpoint, readConfigFile, remoteSink, request, requestJson, resolveConsoleGatewayCredential, resolveCredential, resolveFileUrl, resolveOutputDir, saveApiKeyToConfig, signRequest, speechRecognizeEndpoint, speechSynthesizeEndpoint, stripUndefined, taskEndpoint, trackCommandExecution, trackingHeaders, uploadFile, userProfileEndpoint, videoGenerateEndpoint, writeConfigFile };
|