webaiapi 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +184 -2
- package/bin/webapi.mjs +45 -0
- package/dist/browser/auth-capture.d.ts +110 -0
- package/dist/browser/auth-capture.d.ts.map +1 -0
- package/dist/browser/auth-capture.js +487 -0
- package/dist/browser/auth-capture.js.map +1 -0
- package/dist/browser/credentials.d.ts +102 -0
- package/dist/browser/credentials.d.ts.map +1 -0
- package/dist/browser/credentials.js +209 -0
- package/dist/browser/credentials.js.map +1 -0
- package/dist/browser/js-eval.d.ts +44 -0
- package/dist/browser/js-eval.d.ts.map +1 -0
- package/dist/browser/js-eval.js +20 -0
- package/dist/browser/js-eval.js.map +1 -0
- package/dist/browser/login-flow.d.ts +171 -0
- package/dist/browser/login-flow.d.ts.map +1 -0
- package/dist/browser/login-flow.js +606 -0
- package/dist/browser/login-flow.js.map +1 -0
- package/dist/browser/manager.d.ts +144 -0
- package/dist/browser/manager.d.ts.map +1 -0
- package/dist/browser/manager.js +586 -0
- package/dist/browser/manager.js.map +1 -0
- package/dist/browser/platforms.d.ts +96 -0
- package/dist/browser/platforms.d.ts.map +1 -0
- package/dist/browser/platforms.js +288 -0
- package/dist/browser/platforms.js.map +1 -0
- package/dist/browser/sse-capture.d.ts +23 -0
- package/dist/browser/sse-capture.d.ts.map +1 -0
- package/dist/browser/sse-capture.js +199 -0
- package/dist/browser/sse-capture.js.map +1 -0
- package/dist/browser/stealth.d.ts +12 -0
- package/dist/browser/stealth.d.ts.map +1 -0
- package/dist/browser/stealth.js +12 -0
- package/dist/browser/stealth.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +441 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +90 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +246 -0
- package/dist/config.js.map +1 -0
- package/dist/controllers/history-db.d.ts +56 -0
- package/dist/controllers/history-db.d.ts.map +1 -0
- package/dist/controllers/history-db.js +260 -0
- package/dist/controllers/history-db.js.map +1 -0
- package/dist/controllers/request-pool.d.ts +78 -0
- package/dist/controllers/request-pool.d.ts.map +1 -0
- package/dist/controllers/request-pool.js +222 -0
- package/dist/controllers/request-pool.js.map +1 -0
- package/dist/controllers/router.d.ts +172 -0
- package/dist/controllers/router.d.ts.map +1 -0
- package/dist/controllers/router.js +569 -0
- package/dist/controllers/router.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/log/api-logger.d.ts +55 -0
- package/dist/log/api-logger.d.ts.map +1 -0
- package/dist/log/api-logger.js +264 -0
- package/dist/log/api-logger.js.map +1 -0
- package/dist/log/debug-logger.d.ts +49 -0
- package/dist/log/debug-logger.d.ts.map +1 -0
- package/dist/log/debug-logger.js +285 -0
- package/dist/log/debug-logger.js.map +1 -0
- package/dist/log/logger.d.ts +16 -0
- package/dist/log/logger.d.ts.map +1 -0
- package/dist/log/logger.js +35 -0
- package/dist/log/logger.js.map +1 -0
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +90 -0
- package/dist/postinstall.js.map +1 -0
- package/dist/providers/base.d.ts +83 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +51 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/chatglm-dom-extract.d.ts +24 -0
- package/dist/providers/chatglm-dom-extract.d.ts.map +1 -0
- package/dist/providers/chatglm-dom-extract.js +175 -0
- package/dist/providers/chatglm-dom-extract.js.map +1 -0
- package/dist/providers/chatglm-dom.d.ts +110 -0
- package/dist/providers/chatglm-dom.d.ts.map +1 -0
- package/dist/providers/chatglm-dom.js +384 -0
- package/dist/providers/chatglm-dom.js.map +1 -0
- package/dist/providers/chatglm-sse.d.ts +119 -0
- package/dist/providers/chatglm-sse.d.ts.map +1 -0
- package/dist/providers/chatglm-sse.js +241 -0
- package/dist/providers/chatglm-sse.js.map +1 -0
- package/dist/providers/chatglm.d.ts +288 -0
- package/dist/providers/chatglm.d.ts.map +1 -0
- package/dist/providers/chatglm.js +1631 -0
- package/dist/providers/chatglm.js.map +1 -0
- package/dist/routes/chat.d.ts +117 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +1346 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/compress.d.ts +142 -0
- package/dist/routes/compress.d.ts.map +1 -0
- package/dist/routes/compress.js +551 -0
- package/dist/routes/compress.js.map +1 -0
- package/dist/routes/failover.d.ts +34 -0
- package/dist/routes/failover.d.ts.map +1 -0
- package/dist/routes/failover.js +221 -0
- package/dist/routes/failover.js.map +1 -0
- package/dist/routes/helpers.d.ts +174 -0
- package/dist/routes/helpers.d.ts.map +1 -0
- package/dist/routes/helpers.js +525 -0
- package/dist/routes/helpers.js.map +1 -0
- package/dist/routes/meta.d.ts +31 -0
- package/dist/routes/meta.d.ts.map +1 -0
- package/dist/routes/meta.js +184 -0
- package/dist/routes/meta.js.map +1 -0
- package/dist/routes/sse.d.ts +82 -0
- package/dist/routes/sse.d.ts.map +1 -0
- package/dist/routes/sse.js +77 -0
- package/dist/routes/sse.js.map +1 -0
- package/dist/server/app.d.ts +24 -0
- package/dist/server/app.d.ts.map +1 -0
- package/dist/server/app.js +292 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/middleware/api-key.d.ts +61 -0
- package/dist/server/middleware/api-key.d.ts.map +1 -0
- package/dist/server/middleware/api-key.js +95 -0
- package/dist/server/middleware/api-key.js.map +1 -0
- package/dist/server/middleware/rate-limit.d.ts +67 -0
- package/dist/server/middleware/rate-limit.d.ts.map +1 -0
- package/dist/server/middleware/rate-limit.js +134 -0
- package/dist/server/middleware/rate-limit.js.map +1 -0
- package/dist/server/middleware/timeout.d.ts +34 -0
- package/dist/server/middleware/timeout.d.ts.map +1 -0
- package/dist/server/middleware/timeout.js +64 -0
- package/dist/server/middleware/timeout.js.map +1 -0
- package/dist/server/types.d.ts +20 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/tools/build.d.ts +14 -0
- package/dist/tools/build.d.ts.map +1 -0
- package/dist/tools/build.js +105 -0
- package/dist/tools/build.js.map +1 -0
- package/dist/tools/clean.d.ts +32 -0
- package/dist/tools/clean.d.ts.map +1 -0
- package/dist/tools/clean.js +65 -0
- package/dist/tools/clean.js.map +1 -0
- package/dist/tools/convert.d.ts +50 -0
- package/dist/tools/convert.d.ts.map +1 -0
- package/dist/tools/convert.js +289 -0
- package/dist/tools/convert.js.map +1 -0
- package/dist/tools/names.d.ts +138 -0
- package/dist/tools/names.d.ts.map +1 -0
- package/dist/tools/names.js +578 -0
- package/dist/tools/names.js.map +1 -0
- package/dist/tools/parse.d.ts +31 -0
- package/dist/tools/parse.d.ts.map +1 -0
- package/dist/tools/parse.js +273 -0
- package/dist/tools/parse.js.map +1 -0
- package/dist/tools/placeholder.d.ts +21 -0
- package/dist/tools/placeholder.d.ts.map +1 -0
- package/dist/tools/placeholder.js +135 -0
- package/dist/tools/placeholder.js.map +1 -0
- package/dist/tools/prompts.d.ts +42 -0
- package/dist/tools/prompts.d.ts.map +1 -0
- package/dist/tools/prompts.js +69 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/protocol.d.ts +58 -0
- package/dist/tools/protocol.d.ts.map +1 -0
- package/dist/tools/protocol.js +287 -0
- package/dist/tools/protocol.js.map +1 -0
- package/dist/tools/repair.d.ts +83 -0
- package/dist/tools/repair.d.ts.map +1 -0
- package/dist/tools/repair.js +510 -0
- package/dist/tools/repair.js.map +1 -0
- package/dist/tools/workspace.d.ts +40 -0
- package/dist/tools/workspace.d.ts.map +1 -0
- package/dist/tools/workspace.js +224 -0
- package/dist/tools/workspace.js.map +1 -0
- package/dist/types/message.d.ts +87 -0
- package/dist/types/message.d.ts.map +1 -0
- package/dist/types/message.js +85 -0
- package/dist/types/message.js.map +1 -0
- package/dist/types/openai.d.ts +100 -0
- package/dist/types/openai.d.ts.map +1 -0
- package/dist/types/openai.js +66 -0
- package/dist/types/openai.js.map +1 -0
- package/dist/utils/errors.d.ts +82 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +115 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/mutex.d.ts +31 -0
- package/dist/utils/mutex.d.ts.map +1 -0
- package/dist/utils/mutex.js +61 -0
- package/dist/utils/mutex.js.map +1 -0
- package/dist/utils/prompt.d.ts +150 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +514 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/text.d.ts +30 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +70 -0
- package/dist/utils/text.js.map +1 -0
- package/package.json +67 -4
- package/postinstall.mjs +34 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自定义异常 —— `legacy-python/src/utils/exceptions.py` 的移植。
|
|
3
|
+
*
|
|
4
|
+
* TypeScript 没有「继承 Exception 并按类型捕获」的惯用法,这里保留类层次
|
|
5
|
+
* (`instanceof` 判断依然好用),但**新增 `code` 字段**:路由层需要把不同异常
|
|
6
|
+
* 映射成不同的 HTTP 状态码与 OpenAI 错误码,靠字符串比较太脆。
|
|
7
|
+
*
|
|
8
|
+
* 与原实现的差异:
|
|
9
|
+
* - Python 侧 `LoginRequiredException` / `LoginExpiredException` / `RateLimitException` /
|
|
10
|
+
* `NetworkException` / `ResponseTimeoutException` / `NoAvailableInstanceError` /
|
|
11
|
+
* `AccountBannedError` 定义了但**从未被抛出**(只有 `ModelNotFoundError` 与
|
|
12
|
+
* `PlatformUnavailableException` 在用)。这里保留它们(成本极低,且是公开 API 的
|
|
13
|
+
* 一部分语义),但标注清楚。
|
|
14
|
+
*/
|
|
15
|
+
export declare class AIAPIServiceError extends Error {
|
|
16
|
+
/** OpenAI 风格错误码(`buildOpenAiError` 的 `code`)。 */
|
|
17
|
+
readonly code: string;
|
|
18
|
+
/** 建议的 HTTP 状态码。 */
|
|
19
|
+
readonly statusCode: number;
|
|
20
|
+
constructor(message: string, options?: {
|
|
21
|
+
code?: string;
|
|
22
|
+
statusCode?: number;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/** 需要登录。 */
|
|
26
|
+
export declare class LoginRequiredError extends AIAPIServiceError {
|
|
27
|
+
constructor(message?: string);
|
|
28
|
+
}
|
|
29
|
+
/** 登录已过期。 */
|
|
30
|
+
export declare class LoginExpiredError extends AIAPIServiceError {
|
|
31
|
+
constructor(message?: string);
|
|
32
|
+
}
|
|
33
|
+
/** 触发限流。 */
|
|
34
|
+
export declare class RateLimitError extends AIAPIServiceError {
|
|
35
|
+
constructor(message?: string);
|
|
36
|
+
}
|
|
37
|
+
/** 网络异常。 */
|
|
38
|
+
export declare class NetworkError extends AIAPIServiceError {
|
|
39
|
+
constructor(message?: string);
|
|
40
|
+
}
|
|
41
|
+
/** 响应超时。 */
|
|
42
|
+
export declare class ResponseTimeoutError extends AIAPIServiceError {
|
|
43
|
+
constructor(message?: string);
|
|
44
|
+
}
|
|
45
|
+
/** 模型未找到(**在用**:`ModelRouter` 路由失败时抛出,映射为 404)。 */
|
|
46
|
+
export declare class ModelNotFoundError extends AIAPIServiceError {
|
|
47
|
+
constructor(model: string);
|
|
48
|
+
}
|
|
49
|
+
/** Provider 未找到。 */
|
|
50
|
+
export declare class ProviderNotFoundError extends AIAPIServiceError {
|
|
51
|
+
constructor(provider: string);
|
|
52
|
+
}
|
|
53
|
+
/** 没有可用的浏览器实例。 */
|
|
54
|
+
export declare class NoAvailableInstanceError extends AIAPIServiceError {
|
|
55
|
+
constructor(message?: string);
|
|
56
|
+
}
|
|
57
|
+
/** 账号被封禁。 */
|
|
58
|
+
export declare class AccountBannedError extends AIAPIServiceError {
|
|
59
|
+
constructor(message?: string);
|
|
60
|
+
}
|
|
61
|
+
/** 无效请求(映射为 400)。 */
|
|
62
|
+
export declare class InvalidRequestError extends AIAPIServiceError {
|
|
63
|
+
constructor(message?: string);
|
|
64
|
+
}
|
|
65
|
+
/** 认证失败(映射为 401)。 */
|
|
66
|
+
export declare class AuthenticationError extends AIAPIServiceError {
|
|
67
|
+
constructor(message?: string);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 平台所有账号都不可用(**在用**)。
|
|
71
|
+
*
|
|
72
|
+
* 当某平台的所有账号都失败(凭证失效 / 限流 / 被封)时抛出:
|
|
73
|
+
* - `mix` 模型:router 捕获后切换到下一个优先级平台
|
|
74
|
+
* - 平台名模型(如 `chatglm`):不跨平台,直接返回错误给用户
|
|
75
|
+
*/
|
|
76
|
+
export declare class PlatformUnavailableError extends AIAPIServiceError {
|
|
77
|
+
readonly platform: string;
|
|
78
|
+
constructor(platform: string, message?: string);
|
|
79
|
+
}
|
|
80
|
+
/** 把任意抛出物转成错误消息(`catch (e)` 的 `e` 类型不确定)。 */
|
|
81
|
+
export declare function errorMessage(error: unknown): string;
|
|
82
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,oBAAoB;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO,EAOhF;CACF;AAED,YAAY;AACZ,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD,YAAY,OAAO,SAAc,EAEhC;CACF;AAED,aAAa;AACb,qBAAa,iBAAkB,SAAQ,iBAAiB;IACtD,YAAY,OAAO,SAAgB,EAElC;CACF;AAED,YAAY;AACZ,qBAAa,cAAe,SAAQ,iBAAiB;IACnD,YAAY,OAAO,SAAiB,EAEnC;CACF;AAED,YAAY;AACZ,qBAAa,YAAa,SAAQ,iBAAiB;IACjD,YAAY,OAAO,SAAS,EAE3B;CACF;AAED,YAAY;AACZ,qBAAa,oBAAqB,SAAQ,iBAAiB;IACzD,YAAY,OAAO,SAAyB,EAE3C;CACF;AAED,mDAAmD;AACnD,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD,YAAY,KAAK,EAAE,MAAM,EAExB;CACF;AAED,oBAAoB;AACpB,qBAAa,qBAAsB,SAAQ,iBAAiB;IAC1D,YAAY,QAAQ,EAAE,MAAM,EAE3B;CACF;AAED,kBAAkB;AAClB,qBAAa,wBAAyB,SAAQ,iBAAiB;IAC7D,YAAY,OAAO,SAAe,EAEjC;CACF;AAED,aAAa;AACb,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD,YAAY,OAAO,SAAW,EAE7B;CACF;AAED,qBAAqB;AACrB,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,YAAY,OAAO,SAAS,EAE3B;CACF;AAED,qBAAqB;AACrB,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,YAAY,OAAO,SAAS,EAE3B;CACF;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,SAAQ,iBAAiB;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,YAAY,QAAQ,EAAE,MAAM,EAAE,OAAO,SAAK,EAQzC;CACF;AAED,6CAA6C;AAC7C,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自定义异常 —— `legacy-python/src/utils/exceptions.py` 的移植。
|
|
3
|
+
*
|
|
4
|
+
* TypeScript 没有「继承 Exception 并按类型捕获」的惯用法,这里保留类层次
|
|
5
|
+
* (`instanceof` 判断依然好用),但**新增 `code` 字段**:路由层需要把不同异常
|
|
6
|
+
* 映射成不同的 HTTP 状态码与 OpenAI 错误码,靠字符串比较太脆。
|
|
7
|
+
*
|
|
8
|
+
* 与原实现的差异:
|
|
9
|
+
* - Python 侧 `LoginRequiredException` / `LoginExpiredException` / `RateLimitException` /
|
|
10
|
+
* `NetworkException` / `ResponseTimeoutException` / `NoAvailableInstanceError` /
|
|
11
|
+
* `AccountBannedError` 定义了但**从未被抛出**(只有 `ModelNotFoundError` 与
|
|
12
|
+
* `PlatformUnavailableException` 在用)。这里保留它们(成本极低,且是公开 API 的
|
|
13
|
+
* 一部分语义),但标注清楚。
|
|
14
|
+
*/
|
|
15
|
+
export class AIAPIServiceError extends Error {
|
|
16
|
+
/** OpenAI 风格错误码(`buildOpenAiError` 的 `code`)。 */
|
|
17
|
+
code;
|
|
18
|
+
/** 建议的 HTTP 状态码。 */
|
|
19
|
+
statusCode;
|
|
20
|
+
constructor(message, options = {}) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = new.target.name;
|
|
23
|
+
this.code = options.code ?? 'internal_error';
|
|
24
|
+
this.statusCode = options.statusCode ?? 500;
|
|
25
|
+
// 让 `instanceof` 在编译到 ES5 目标时也可靠(这里目标是 ES2023,仅为稳妥保留)
|
|
26
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** 需要登录。 */
|
|
30
|
+
export class LoginRequiredError extends AIAPIServiceError {
|
|
31
|
+
constructor(message = '需要登录后才能使用') {
|
|
32
|
+
super(message, { code: 'login_required', statusCode: 401 });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** 登录已过期。 */
|
|
36
|
+
export class LoginExpiredError extends AIAPIServiceError {
|
|
37
|
+
constructor(message = '登录已过期,请重新登录') {
|
|
38
|
+
super(message, { code: 'login_expired', statusCode: 401 });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** 触发限流。 */
|
|
42
|
+
export class RateLimitError extends AIAPIServiceError {
|
|
43
|
+
constructor(message = '请求过于频繁,请稍后再试') {
|
|
44
|
+
super(message, { code: 'rate_limit_exceeded', statusCode: 429 });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** 网络异常。 */
|
|
48
|
+
export class NetworkError extends AIAPIServiceError {
|
|
49
|
+
constructor(message = '网络异常') {
|
|
50
|
+
super(message, { code: 'network_error', statusCode: 502 });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** 响应超时。 */
|
|
54
|
+
export class ResponseTimeoutError extends AIAPIServiceError {
|
|
55
|
+
constructor(message = '请求超时:服务器未能在规定时间内完成响应') {
|
|
56
|
+
super(message, { code: 'request_timeout', statusCode: 504 });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** 模型未找到(**在用**:`ModelRouter` 路由失败时抛出,映射为 404)。 */
|
|
60
|
+
export class ModelNotFoundError extends AIAPIServiceError {
|
|
61
|
+
constructor(model) {
|
|
62
|
+
super(`模型 '${model}' 不存在或不可用`, { code: 'model_not_found', statusCode: 404 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Provider 未找到。 */
|
|
66
|
+
export class ProviderNotFoundError extends AIAPIServiceError {
|
|
67
|
+
constructor(provider) {
|
|
68
|
+
super(`Provider '${provider}' 不存在`, { code: 'provider_not_found', statusCode: 404 });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** 没有可用的浏览器实例。 */
|
|
72
|
+
export class NoAvailableInstanceError extends AIAPIServiceError {
|
|
73
|
+
constructor(message = '没有可用的浏览器实例') {
|
|
74
|
+
super(message, { code: 'no_available_instance', statusCode: 503 });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** 账号被封禁。 */
|
|
78
|
+
export class AccountBannedError extends AIAPIServiceError {
|
|
79
|
+
constructor(message = '账号已被封禁') {
|
|
80
|
+
super(message, { code: 'account_banned', statusCode: 403 });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** 无效请求(映射为 400)。 */
|
|
84
|
+
export class InvalidRequestError extends AIAPIServiceError {
|
|
85
|
+
constructor(message = '无效请求') {
|
|
86
|
+
super(message, { code: 'invalid_request_error', statusCode: 400 });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** 认证失败(映射为 401)。 */
|
|
90
|
+
export class AuthenticationError extends AIAPIServiceError {
|
|
91
|
+
constructor(message = '认证失败') {
|
|
92
|
+
super(message, { code: 'invalid_api_key', statusCode: 401 });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 平台所有账号都不可用(**在用**)。
|
|
97
|
+
*
|
|
98
|
+
* 当某平台的所有账号都失败(凭证失效 / 限流 / 被封)时抛出:
|
|
99
|
+
* - `mix` 模型:router 捕获后切换到下一个优先级平台
|
|
100
|
+
* - 平台名模型(如 `chatglm`):不跨平台,直接返回错误给用户
|
|
101
|
+
*/
|
|
102
|
+
export class PlatformUnavailableError extends AIAPIServiceError {
|
|
103
|
+
platform;
|
|
104
|
+
constructor(platform, message = '') {
|
|
105
|
+
super(message
|
|
106
|
+
? `平台 '${platform}' 不可用: ${message}`
|
|
107
|
+
: `平台 '${platform}' 不可用(所有账号均失败)`, { code: 'platform_unavailable', statusCode: 503 });
|
|
108
|
+
this.platform = platform;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** 把任意抛出物转成错误消息(`catch (e)` 的 `e` 类型不确定)。 */
|
|
112
|
+
export function errorMessage(error) {
|
|
113
|
+
return error instanceof Error ? error.message : String(error);
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 简单互斥锁 —— 替代 Python 的 `asyncio.Lock`。
|
|
3
|
+
*
|
|
4
|
+
* Node 没有内置的异步锁,而为这一处需求引入依赖不划算,所以自己实现(约 30 行)。
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* ```ts
|
|
8
|
+
* const lock = new Mutex();
|
|
9
|
+
* await lock.run(async () => { ... }); // 等价于 Python 的 `async with lock:`
|
|
10
|
+
* if (lock.isLocked) { ... } // 等价于 Python 的 `lock.locked()`
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare class Mutex {
|
|
14
|
+
/** 等待者队列:release 时把锁直接交给队首(而不是先释放再竞争)。 */
|
|
15
|
+
private readonly waiters;
|
|
16
|
+
private held;
|
|
17
|
+
/** 当前是否已被持有。 */
|
|
18
|
+
get isLocked(): boolean;
|
|
19
|
+
/** 等待者数量(仅用于诊断/测试)。 */
|
|
20
|
+
get pending(): number;
|
|
21
|
+
/**
|
|
22
|
+
* 获取锁;返回释放函数。
|
|
23
|
+
*
|
|
24
|
+
* 请在 `finally` 里调用释放函数,保证异常路径也能解锁。
|
|
25
|
+
*/
|
|
26
|
+
acquire(): Promise<() => void>;
|
|
27
|
+
/** 在锁保护下执行 `fn`(等价于 Python 的 `async with lock:`)。 */
|
|
28
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
29
|
+
private release;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=mutex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutex.d.ts","sourceRoot":"","sources":["../../src/utils/mutex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,qBAAa,KAAK;IAChB,0CAA0C;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IAEjD,OAAO,CAAC,IAAI,CAAS;IAErB,gBAAgB;IAChB,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,uBAAuB;IACvB,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,CAWnC;IAED,qDAAqD;IAC/C,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAO7C;IAED,OAAO,CAAC,OAAO;CAShB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 简单互斥锁 —— 替代 Python 的 `asyncio.Lock`。
|
|
3
|
+
*
|
|
4
|
+
* Node 没有内置的异步锁,而为这一处需求引入依赖不划算,所以自己实现(约 30 行)。
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* ```ts
|
|
8
|
+
* const lock = new Mutex();
|
|
9
|
+
* await lock.run(async () => { ... }); // 等价于 Python 的 `async with lock:`
|
|
10
|
+
* if (lock.isLocked) { ... } // 等价于 Python 的 `lock.locked()`
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export class Mutex {
|
|
14
|
+
/** 等待者队列:release 时把锁直接交给队首(而不是先释放再竞争)。 */
|
|
15
|
+
waiters = [];
|
|
16
|
+
held = false;
|
|
17
|
+
/** 当前是否已被持有。 */
|
|
18
|
+
get isLocked() {
|
|
19
|
+
return this.held;
|
|
20
|
+
}
|
|
21
|
+
/** 等待者数量(仅用于诊断/测试)。 */
|
|
22
|
+
get pending() {
|
|
23
|
+
return this.waiters.length;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 获取锁;返回释放函数。
|
|
27
|
+
*
|
|
28
|
+
* 请在 `finally` 里调用释放函数,保证异常路径也能解锁。
|
|
29
|
+
*/
|
|
30
|
+
async acquire() {
|
|
31
|
+
if (!this.held) {
|
|
32
|
+
this.held = true;
|
|
33
|
+
return () => this.release();
|
|
34
|
+
}
|
|
35
|
+
await new Promise((resolve) => {
|
|
36
|
+
this.waiters.push(resolve);
|
|
37
|
+
});
|
|
38
|
+
// 被唤醒时锁已经「转交」给它,仍处于 held 状态
|
|
39
|
+
return () => this.release();
|
|
40
|
+
}
|
|
41
|
+
/** 在锁保护下执行 `fn`(等价于 Python 的 `async with lock:`)。 */
|
|
42
|
+
async run(fn) {
|
|
43
|
+
const release = await this.acquire();
|
|
44
|
+
try {
|
|
45
|
+
return await fn();
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
release();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
release() {
|
|
52
|
+
const next = this.waiters.shift();
|
|
53
|
+
if (next) {
|
|
54
|
+
// 直接转交,避免「释放 → 被别的调用抢占」导致排队失效
|
|
55
|
+
next();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.held = false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=mutex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/utils/mutex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,KAAK;IAChB,0CAA0C;IACzB,OAAO,GAAsB,EAAE,CAAC;IAEzC,IAAI,GAAG,KAAK,CAAC;IAErB,gBAAgB;IAChB,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC9B,CAAC;QAED,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,4BAA4B;QAC5B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;IAC9B,CAAC;IAED,qDAAqD;IACrD,KAAK,CAAC,GAAG,CAAI,EAAoB;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,OAAO;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,EAAE,CAAC;YACT,8BAA8B;YAC9B,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 是否输出 ANSI 颜色。
|
|
3
|
+
*
|
|
4
|
+
* 遵循 `NO_COLOR` 约定(https://no-color.org),且只在输出为 TTY 时上色 ——
|
|
5
|
+
* 否则 `webapi login > log.txt` 会把转义序列写进文件。
|
|
6
|
+
*/
|
|
7
|
+
export declare function supportsColor(): boolean;
|
|
8
|
+
export declare const cyan: (text: string) => string;
|
|
9
|
+
export declare const bold: (text: string) => string;
|
|
10
|
+
export declare const dim: (text: string) => string;
|
|
11
|
+
/**
|
|
12
|
+
* 字符串在终端里占的**列数**。
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ 存在的理由:`String.prototype.length` / `padEnd` 数的是**码元**,
|
|
15
|
+
* 而中文、全角标点在终端占**两列**。用 `padEnd` 对齐「ChatGLM (智谱)」这种
|
|
16
|
+
* 中英混排的表,第二列会参差不齐 —— 菜单看着就是乱的。
|
|
17
|
+
*/
|
|
18
|
+
export declare function displayWidth(text: string): number;
|
|
19
|
+
/** 按**显示宽度**右填空格(`padEnd` 的中英混排安全版)。 */
|
|
20
|
+
export declare function padDisplay(text: string, width: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* 当前是否处于**可交互**环境(两端都是 TTY)。
|
|
23
|
+
*
|
|
24
|
+
* 只要有一端不是 TTY 就不能走 raw mode:`stdout` 被重定向时用户看不到菜单,
|
|
25
|
+
* `stdin` 被重定向时按键根本到不了我们手上。
|
|
26
|
+
*/
|
|
27
|
+
export declare function isInteractive(): boolean;
|
|
28
|
+
export interface Choice<T> {
|
|
29
|
+
/** 返回给调用方的值。 */
|
|
30
|
+
value: T;
|
|
31
|
+
/** 显示文本。 */
|
|
32
|
+
label: string;
|
|
33
|
+
/** 补充说明(灰色,跟在 label 后面)。 */
|
|
34
|
+
hint?: string;
|
|
35
|
+
/** 非空表示**当前不可选**,内容是不可选的原因(会显示给用户)。 */
|
|
36
|
+
disabled?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 把选项列表渲染成多行文本。
|
|
40
|
+
*
|
|
41
|
+
* 返回 `string[]` 而不是拼好的字符串:调用方需要知道**行数**才能在原地重绘
|
|
42
|
+
* (光标上移 N 行 → 清除 → 重画),而且逐行更好断言。
|
|
43
|
+
*/
|
|
44
|
+
export declare function renderChoiceList<T>(choices: ReadonlyArray<Choice<T>>, selectedIndex: number, options?: {
|
|
45
|
+
numbered?: boolean;
|
|
46
|
+
indent?: string;
|
|
47
|
+
}): string[];
|
|
48
|
+
/** {@link resolveChoiceInput} 的判定结果。 */
|
|
49
|
+
export type ChoiceResolution = {
|
|
50
|
+
kind: 'ok';
|
|
51
|
+
index: number;
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'cancel';
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'retry';
|
|
56
|
+
reason: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* 把用户输入的一行文本解析成「选中了第几项」。
|
|
60
|
+
*
|
|
61
|
+
* 与 {@link selectOne} 的**非 TTY 降级路径**共用同一套规则,保证两条路径
|
|
62
|
+
* 对「空输入 / 数字 / q / 越界」的处理完全一致 —— 否则会出现
|
|
63
|
+
* 「管道里能用、终端里不能用」这种最难复现的差异。
|
|
64
|
+
*
|
|
65
|
+
* 规则:
|
|
66
|
+
* - 空输入(直接回车)→ 默认项({@link defaultIndex},未指定则第 1 项)
|
|
67
|
+
* - `数字` → 第 N 项(1 起算)
|
|
68
|
+
* - `q` / `Q` → 取消(返回 `cancel`)
|
|
69
|
+
* - 其余、越界、以及选中 **disabled** 项 → `retry`(带原因,让调用方提示后重问)
|
|
70
|
+
*
|
|
71
|
+
* ⚠️ disabled 项**返回 retry 而不是静默忽略**:用户在非 TTY 下看不到「不可选」
|
|
72
|
+
* 的视觉提示,必须明确告诉他原因,否则他会以为自己选错了数字。
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveChoiceInput<T>(raw: string, choices: ReadonlyArray<Choice<T>>, defaultIndex?: number): ChoiceResolution;
|
|
75
|
+
/** 从 `defaultIndex` 开始往后找第一个可选中的项(找不到返回 0)。 */
|
|
76
|
+
export declare function firstSelectableIndex<T>(choices: ReadonlyArray<Choice<T>>): number;
|
|
77
|
+
/** 一个按键事件。 */
|
|
78
|
+
export type KeyToken = {
|
|
79
|
+
kind: 'up';
|
|
80
|
+
} | {
|
|
81
|
+
kind: 'down';
|
|
82
|
+
} | {
|
|
83
|
+
kind: 'enter';
|
|
84
|
+
} | {
|
|
85
|
+
kind: 'cancel';
|
|
86
|
+
} | {
|
|
87
|
+
kind: 'sigint';
|
|
88
|
+
} | {
|
|
89
|
+
kind: 'char';
|
|
90
|
+
value: string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* 把一段输入切成**逐个按键**。
|
|
94
|
+
*
|
|
95
|
+
* ## ⚠️ 为什么必须做这件事(真实缺陷,不是洁癖)
|
|
96
|
+
* `stdin` 的 `data` 事件**不保证一次只有一个按键**:
|
|
97
|
+
* - 按住方向键时终端会把多个 `\u001b[B` 合并成一个 chunk;
|
|
98
|
+
* - 粘贴、管道、`script` 这类 pty 转发会一次送进来一整串(如 `\u001b[B\r`);
|
|
99
|
+
* - 高延迟/慢终端下两次按键可能落在同一个 chunk 里。
|
|
100
|
+
*
|
|
101
|
+
* 若像最初那样用一个 `switch (chunk)` 精确匹配整块,**只有恰好等于
|
|
102
|
+
* `'\u001b[B'` 的 chunk 才生效**,其余情况全部落进 `default` 分支被丢掉 ——
|
|
103
|
+
* 表现为「方向键时灵时不灵」「按了回车没反应」,且完全不打日志。
|
|
104
|
+
*
|
|
105
|
+
* ## 返回值里的 `rest`
|
|
106
|
+
* 流式解析时末尾可能是**半个转义序列**(chunk 在 `\u001b` 或 `\u001b[` 处被切开),
|
|
107
|
+
* 这部分要留给下一个 chunk 拼接,所以放在 `rest` 里返回而不是当成按键。
|
|
108
|
+
*
|
|
109
|
+
* 但「单独按下 Esc」产生的**恰好也是**一个孤立 `\u001b` —— 两者无法只靠字节区分。
|
|
110
|
+
* 因此调用方在 `rest` 非空时起一个 ~40ms 的定时器:等不到后续字节,
|
|
111
|
+
* 就带 `flushTrailingEscape: true` 再解析一次,把它判定为 Esc。
|
|
112
|
+
*
|
|
113
|
+
* @param options.flushTrailingEscape 等待超时后的收尾解析:把末尾残缺的转义
|
|
114
|
+
* 序列当作「用户按了 Esc」(不这么做的话按 Esc 会永久挂住)。
|
|
115
|
+
*/
|
|
116
|
+
export declare function tokenizeKeys(input: string, options?: {
|
|
117
|
+
flushTrailingEscape?: boolean;
|
|
118
|
+
}): {
|
|
119
|
+
tokens: KeyToken[];
|
|
120
|
+
rest: string;
|
|
121
|
+
};
|
|
122
|
+
/** 读取一段文本输入(可带默认值 / 校验)。取消(EOF)返回 `null`。 */
|
|
123
|
+
export declare function inputText(options: {
|
|
124
|
+
message: string;
|
|
125
|
+
defaultValue?: string;
|
|
126
|
+
/** 返回非空字符串表示校验失败,内容会作为提示显示给用户。 */
|
|
127
|
+
validate?: (value: string) => string | null;
|
|
128
|
+
}): Promise<string | null>;
|
|
129
|
+
/** 是 / 否确认。取消(EOF)返回 `null`。 */
|
|
130
|
+
export declare function confirmYesNo(options: {
|
|
131
|
+
message: string;
|
|
132
|
+
defaultYes?: boolean;
|
|
133
|
+
}): Promise<boolean | null>;
|
|
134
|
+
/**
|
|
135
|
+
* 让用户从列表里选一项。
|
|
136
|
+
*
|
|
137
|
+
* - TTY:↑/↓ 高亮 + Enter 确认(数字键可直接跳)
|
|
138
|
+
* - 非 TTY(管道 / CI):打印编号列表,读一行
|
|
139
|
+
* - 两者都用同一套 {@link resolveChoiceInput} 判定,行为一致
|
|
140
|
+
*
|
|
141
|
+
* @returns 选中的值;用户取消(Esc / Ctrl+C / EOF)返回 `null`。
|
|
142
|
+
*/
|
|
143
|
+
export declare function selectOne<T>(options: {
|
|
144
|
+
message: string;
|
|
145
|
+
choices: ReadonlyArray<Choice<T>>;
|
|
146
|
+
defaultIndex?: number;
|
|
147
|
+
/** 强制走非 TTY 路径(`--no-input` 与单测用)。 */
|
|
148
|
+
forcePlain?: boolean;
|
|
149
|
+
}): Promise<T | null>;
|
|
150
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"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"}
|