@eddyskywalker/dsh-chatgpt-subscription 0.18.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +103 -1
  3. package/lib/client.js +1546 -269
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +9092 -2555
  6. package/lib/types/client/glm-coding-plan/GlmCodingPlanComposerQuota.d.ts +27 -0
  7. package/lib/types/client/glm-coding-plan/GlmCodingPlanComposerQuota.d.ts.map +1 -0
  8. package/lib/types/client/glm-coding-plan/GlmCodingPlanSection.d.ts +22 -0
  9. package/lib/types/client/glm-coding-plan/GlmCodingPlanSection.d.ts.map +1 -0
  10. package/lib/types/client/glm-coding-plan/api.d.ts +4 -0
  11. package/lib/types/client/glm-coding-plan/api.d.ts.map +1 -0
  12. package/lib/types/client/glm-coding-plan/locales.d.ts +412 -0
  13. package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -0
  14. package/lib/types/client/glm-coding-plan/styles.d.ts +15 -0
  15. package/lib/types/client/glm-coding-plan/styles.d.ts.map +1 -0
  16. package/lib/types/client/glm-coding-plan/useGlmCodingPlanSection.d.ts +65 -0
  17. package/lib/types/client/glm-coding-plan/useGlmCodingPlanSection.d.ts.map +1 -0
  18. package/lib/types/client/hub/brand-icons.d.ts +7 -5
  19. package/lib/types/client/hub/brand-icons.d.ts.map +1 -1
  20. package/lib/types/client/hub/providers.d.ts.map +1 -1
  21. package/lib/types/client/index.d.ts +2 -0
  22. package/lib/types/client/index.d.ts.map +1 -1
  23. package/lib/types/client/kimi-code/locales.d.ts +2 -2
  24. package/lib/types/client/minimax-code/locales.d.ts +2 -2
  25. package/lib/types/host/antigravity/oauth.d.ts +11 -1
  26. package/lib/types/host/antigravity/oauth.d.ts.map +1 -1
  27. package/lib/types/host/common/model-request-control.d.ts +1 -1
  28. package/lib/types/host/common/model-request-control.d.ts.map +1 -1
  29. package/lib/types/host/common/request-diagnostics.d.ts +1 -1
  30. package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
  31. package/lib/types/host/glm-coding-plan/account-pool.d.ts +152 -0
  32. package/lib/types/host/glm-coding-plan/account-pool.d.ts.map +1 -0
  33. package/lib/types/host/glm-coding-plan/adapter.d.ts +169 -0
  34. package/lib/types/host/glm-coding-plan/adapter.d.ts.map +1 -0
  35. package/lib/types/host/glm-coding-plan/adopt.d.ts +354 -0
  36. package/lib/types/host/glm-coding-plan/adopt.d.ts.map +1 -0
  37. package/lib/types/host/glm-coding-plan/biz-token-cache.d.ts +99 -0
  38. package/lib/types/host/glm-coding-plan/biz-token-cache.d.ts.map +1 -0
  39. package/lib/types/host/glm-coding-plan/client.d.ts +218 -0
  40. package/lib/types/host/glm-coding-plan/client.d.ts.map +1 -0
  41. package/lib/types/host/glm-coding-plan/exchange.d.ts +223 -0
  42. package/lib/types/host/glm-coding-plan/exchange.d.ts.map +1 -0
  43. package/lib/types/host/glm-coding-plan/mapper-anthropic.d.ts +308 -0
  44. package/lib/types/host/glm-coding-plan/mapper-anthropic.d.ts.map +1 -0
  45. package/lib/types/host/glm-coding-plan/mapper-openai.d.ts +213 -0
  46. package/lib/types/host/glm-coding-plan/mapper-openai.d.ts.map +1 -0
  47. package/lib/types/host/glm-coding-plan/model-catalog.d.ts +232 -0
  48. package/lib/types/host/glm-coding-plan/model-catalog.d.ts.map +1 -0
  49. package/lib/types/host/glm-coding-plan/oauth.d.ts +211 -0
  50. package/lib/types/host/glm-coding-plan/oauth.d.ts.map +1 -0
  51. package/lib/types/host/glm-coding-plan/routes.d.ts +93 -0
  52. package/lib/types/host/glm-coding-plan/routes.d.ts.map +1 -0
  53. package/lib/types/host/glm-coding-plan/signing.d.ts +323 -0
  54. package/lib/types/host/glm-coding-plan/signing.d.ts.map +1 -0
  55. package/lib/types/host/glm-coding-plan/token-store.d.ts +202 -0
  56. package/lib/types/host/glm-coding-plan/token-store.d.ts.map +1 -0
  57. package/lib/types/host/glm-coding-plan/types.d.ts +413 -0
  58. package/lib/types/host/glm-coding-plan/types.d.ts.map +1 -0
  59. package/lib/types/host/kimi-code/routes.d.ts +10 -0
  60. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  61. package/lib/types/index.d.ts +9 -0
  62. package/lib/types/index.d.ts.map +1 -1
  63. package/lib/types/shared/glm-coding-plan-contracts.d.ts +315 -0
  64. package/lib/types/shared/glm-coding-plan-contracts.d.ts.map +1 -0
  65. package/package.json +1 -1
@@ -0,0 +1,218 @@
1
+ /**
2
+ * GLM(ZCode 账号)线路的上游 I/O:模型目录、配额、订阅列表,外加凭据验活的转出。
3
+ *
4
+ * 本文件有两条互相矛盾、且**不可互相抄**的认证规则,写错任何一处都会得到一个看似合理的
5
+ * 401/鉴权失败,所以它们各自写在自己的函数上方:
6
+ *
7
+ * 1. **模型面**(目录拉取、Anthropic 面、OpenAI 面)用 `Authorization: Bearer {id.secret}`,
8
+ * Anthropic 面还要**成对**发 `x-api-key`。这两个请求头函数直接委托给
9
+ * `./mapper-anthropic.ts` 与 `./mapper-openai.ts` 的实现——它们才是发请求的路径,
10
+ * 在这里另写一份就等于给「认证头」留下第二处可以漂移的真相。
11
+ * 2. **配额 / 订阅面**用**裸 Key**,`authorization: <id>.<secret>`,**不加 `Bearer` 前缀**
12
+ * (逐字证据:`docs/bigmodel-coding-plan-usage-quota.md`,计划 §3.4;官方文档写明
13
+ * 加了 Bearer 会鉴权失败)。`test/glm-coding-plan-client.test.ts` 对此有回归断言。
14
+ *
15
+ * 配额解析的语义照 dsh-web 仓库 `packages/dsh-usage/src/core/adapters.ts` 的 `glmPlan()`
16
+ * 对齐(只读参考,没有复制代码),三条要点都是逐条照抄它的行为:
17
+ *
18
+ * - 上层信封要求 `success === true`,否则不解析;
19
+ * - `TIME_LIMIT` 是 MCP 请求上限,**不是套餐窗口**,跳过;
20
+ * - `unit` 用 `./types.ts` 的 `QUOTA_UNIT_WINDOW` 映射,**未知 unit 一律丢弃**,不发明窗口;
21
+ * - `TOKENS_LIMIT` 的比例取 `percentage`,`CREDIT_LIMIT` 取 `currentValue / usage` 的比例
22
+ * (两者都不成比例时才退回 `percentage`)。
23
+ */
24
+ import type { GlmQuotaSnapshotDto, GlmRegion } from '../../shared/glm-coding-plan-contracts.ts';
25
+ import { QUOTA_PATH, SUBSCRIPTION_PATH } from './types.ts';
26
+ import { modelsUrl } from './mapper-openai.ts';
27
+ import { verifyCodingPlanKey } from './exchange.ts';
28
+ import { catalogSize, isGlmModelId, listModelIds, modelsForRegion, type GlmModelEntry } from './model-catalog.ts';
29
+ export { listModelIds, catalogSize, modelsForRegion, isGlmModelId, verifyCodingPlanKey };
30
+ export type { GlmPlanProbe } from './exchange.ts';
31
+ /** 一次上游读的可调项。`fetchFn` / `signal` 供测试注入,`env` 让 `DSH_GLM_*` 覆盖在调用时生效。 */
32
+ export interface GlmRequestOptions {
33
+ fetchFn?: typeof fetch;
34
+ signal?: AbortSignal;
35
+ env?: NodeJS.ProcessEnv;
36
+ /** 单次请求超时;缺省走 `DISCOVERY_TIMEOUT_MS`。 */
37
+ timeoutMs?: number;
38
+ }
39
+ /**
40
+ * Anthropic 面的请求头(双头:`x-api-key` + `Authorization: Bearer`,同值)。
41
+ *
42
+ * **委托**给 `./mapper-anthropic.ts` 的 `glmAnthropicHeaders`,本文件不复制第二份。
43
+ * 目录拉取与探活都会用它,认证规则只有一处真相。
44
+ */
45
+ export declare function glmAnthropicProbeHeaders(codingPlanKey: string): Record<string, string>;
46
+ /**
47
+ * OpenAI 兼容面的请求头(只有 `Authorization: Bearer`,**没有** `x-api-key`)。
48
+ *
49
+ * **委托**给 `./mapper-openai.ts` 的 `glmOpenAiHeaders`:双头是 Anthropic 面的性质,
50
+ * 这里多发一个头不会更好,只会让复审误以为两面共用一套认证。
51
+ */
52
+ export declare function glmOpenAiProbeHeaders(codingPlanKey: string): Record<string, string>;
53
+ /**
54
+ * 配额 / 订阅面的请求头:**裸 Key,不加 `Bearer`**。
55
+ *
56
+ * 逐字证据:`docs/bigmodel-coding-plan-usage-quota.md`(计划 §3.4)——加了 Bearer 前缀会鉴权失败。
57
+ * 这与模型面正好相反,所以这里没有任何「兼容两种写法」的分支:
58
+ * 那种写法在上游表现为一次必然失败的请求,而失败原因(401)不会告诉你前缀多写了。
59
+ *
60
+ * @param codingPlanKey - 兑换链拼出的 `{apiKeyId}.{secretKey}`。空白即抛错,不发一个注定被拒的请求。
61
+ */
62
+ export declare function quotaRequestHeaders(codingPlanKey: string): Record<string, string>;
63
+ /**
64
+ * 配额 URL:`{business}{QUOTA_PATH}`。
65
+ *
66
+ * 走**业务面** host(国区 `bigmodel.cn` / 国际区 `api.z.ai`)而不是模型面:
67
+ * `./types.ts` 的 `businessHost()` 就是这条路的唯一出处。
68
+ *
69
+ * **未验证**:官方文档写「区域 host `https://api.z.ai` 或 `https://bigmodel.cn`,
70
+ * 国区亦可用 `open.bigmodel.cn`」,国区到底哪个是规范入口没有实测样本(计划 D9:无实机账号)。
71
+ * 本文件取 `businessHost()`,需要指向另一个部署时用 `DSH_GLM_*_BUSINESS_HOST` 覆盖。
72
+ */
73
+ export declare function quotaUrl(region: GlmRegion, env?: NodeJS.ProcessEnv): string;
74
+ /** 订阅列表 URL:`{business}{SUBSCRIPTION_PATH}`(套餐名 / 续费时刻)。 */
75
+ export declare function subscriptionUrl(region: GlmRegion, env?: NodeJS.ProcessEnv): string;
76
+ export { modelsUrl, QUOTA_PATH, SUBSCRIPTION_PATH };
77
+ /**
78
+ * 解析 `/api/coding/paas/v4/models` 的响应。
79
+ *
80
+ * 与随包目录合并的规则(照历史实现 `7e40fce:src/host/zhipu/client.ts` 的 `parseCatalogModels`):
81
+ * **目录里的能力声明永远是权威,实时列表只补它明确给出的那一个字段**——上下文窗口。
82
+ * 梯子、收不收图、可不可关思考、协议面这四项实时列表都不公布(**未验证**:没有样本证明它会公布),
83
+ * 让它们被列表的沉默改写成「猜」就是本文件存在的反面。
84
+ *
85
+ * **未验证**:列表的字段名。历史实现读 `context_window` / `contextWindow` /
86
+ * `max_input_tokens`,本文件连 `context_length` 一起认;真实响应样本缺一份,
87
+ * 上游若换了字段名,表现是「退回随包目录的窗口值」而不是崩溃。
88
+ */
89
+ export declare function parseCatalogListing(payload: unknown, region: GlmRegion): GlmModelEntry[];
90
+ /**
91
+ * 拉一次模型目录。
92
+ *
93
+ * 失败**抛错**而不是静默返回空列表:调用方(连接测试)需要知道「没读到」,
94
+ * 而 {@link loadCatalog} 才是那个负责回落随包目录的函数。
95
+ */
96
+ export declare function fetchCatalog(region: GlmRegion, codingPlanKey: string, options?: GlmRequestOptions): Promise<GlmModelEntry[]>;
97
+ /** 最近一次成功读到的目录;只读缓存,不发请求。 */
98
+ export declare function getCachedCatalog(region?: GlmRegion): GlmModelEntry[];
99
+ /** 忘记目录缓存(登录、登出、测试)。 */
100
+ export declare function clearCachedCatalog(): void;
101
+ /**
102
+ * 带 TTL 的目录读,失败时保留上一份快照、再失败则回落到随包目录。
103
+ *
104
+ * 回落链是有顺序的:**同区域的旧快照** → **随包目录(按区域过滤)**。
105
+ * 绝不让另一区域的快照顶替——它的行只声明了来处那个区域,落到调用方的区域过滤上会一行不剩,
106
+ * 结果是「模型选择器空了」而不是「退回随包目录」。
107
+ */
108
+ export declare function loadCatalog(region: GlmRegion, codingPlanKey: string, options?: GlmRequestOptions & {
109
+ force?: boolean;
110
+ }): Promise<GlmModelEntry[]>;
111
+ /** 上游 `limits` 数组里的一行(只保留本线路要用的字段)。 */
112
+ export interface GlmQuotaLimitRow {
113
+ type: string;
114
+ unit: number | undefined;
115
+ percentage: number | undefined;
116
+ currentValue: number | undefined;
117
+ usage: number | undefined;
118
+ /** 重置时刻(Unix 毫秒);上游没给或给了非正值时为 null。 */
119
+ resetsAt: number | null;
120
+ }
121
+ /**
122
+ * 把 `data.limits` 读成结构化行。
123
+ *
124
+ * 这里**只做搬运不做筛选**:`TIME_LIMIT` 与未知 `unit` 的丢弃发生在
125
+ * {@link parseQuotaSnapshot} 里,留在同一处才能一眼看清「哪些行被丢掉、为什么」。
126
+ *
127
+ * **未验证**:字段名。字段取自历史实现与 dsh-usage 的 `glmPlan()`(`unit` / `type` /
128
+ * `percentage` / `currentValue` / `usage` / `nextResetTime`),没有一份真实响应样本。
129
+ */
130
+ export declare function parseQuotaLimits(payload: unknown): GlmQuotaLimitRow[];
131
+ /** 解析配额快照时由调用方补上的东西(订阅列表读到的部分)。 */
132
+ export interface GlmQuotaParseOptions {
133
+ /** 订阅列表给出的展示套餐名。 */
134
+ planName?: string | null;
135
+ /** 订阅列表给出的续费时刻(Unix 毫秒)。 */
136
+ renewsAt?: number | null;
137
+ /** 本次读取时刻(Unix 毫秒)。 */
138
+ now?: number;
139
+ /** 实际应答的端点路径,供设置卡片诊断。 */
140
+ sources?: readonly string[];
141
+ }
142
+ /**
143
+ * 解析一次配额响应成 `GlmQuotaSnapshotDto`;不可解析时返回 null。
144
+ *
145
+ * 与参考实现 `glmPlan()` 一致的四条:
146
+ *
147
+ * 1. 上层信封必须 `success === true`,否则不解析(这个端点会用 HTTP 200 回一个业务失败);
148
+ * 2. `TIME_LIMIT` 是 MCP 请求上限,**不是套餐窗口**,跳过;
149
+ * 3. `unit` 走封闭映射,**未知编号丢弃**;
150
+ * 4. 剩下的行里 `TOKENS_LIMIT` 取 `percentage`、`CREDIT_LIMIT` 取 `currentValue/usage`。
151
+ *
152
+ * 另外两个本仓库自己的决定:
153
+ *
154
+ * - **同一个窗口键只保留第一行**。上游若给了两行 unit 3,画出来就是两条一模一样的额度条,
155
+ * 而第二条可能是别的计量口径;宁可少画一条,也不把两种口径混成一条。
156
+ * - **一个窗口都没有时返回 null**(参考实现同样把「无窗口」当成没有快照)。
157
+ * 一份没有窗口的快照会在卡片上渲染成「什么都没消耗」,那比不显示更糟。
158
+ */
159
+ export declare function parseQuotaSnapshot(payload: unknown, options?: GlmQuotaParseOptions): GlmQuotaSnapshotDto | null;
160
+ /** `data.level` 是不是本线路认识的机器档位(lite / pro / max)。 */
161
+ export declare function isGlmPlanLevel(value: unknown): value is string;
162
+ /** 订阅列表读到的套餐事实。 */
163
+ export interface GlmSubscriptionPlan {
164
+ planName: string | null;
165
+ renewsAt: number | null;
166
+ }
167
+ /**
168
+ * 解析订阅列表 → 套餐名 / 续费时刻。
169
+ *
170
+ * **尽力而为**:读不到套餐名不影响配额窗口(它们来自另一个端点),
171
+ * 所以本函数的任何不确定都只表现为 null,不会让整张配额卡片失败。
172
+ *
173
+ * **未验证**:字段名。读法取自历史实现(`planName` / `name` / `productName`、
174
+ * `expireTime` / `expiredTime` / `renewTime`,`data` 可以是对象也可以是数组),
175
+ * 没有一份真实响应样本;上游换字段名时表现为「卡片上没有套餐名」,而不是崩溃。
176
+ */
177
+ export declare function parseSubscriptionPlan(payload: unknown): GlmSubscriptionPlan;
178
+ /** 一次配额读的结果。失败以 `error` 呈现,不以异常呈现。 */
179
+ export interface GlmQuotaRead {
180
+ snapshot: GlmQuotaSnapshotDto | null;
181
+ /** 面向用户的失败原因;成功时为 null。与 `GlmStatusDto.quotaError` 是同一个位置。 */
182
+ error: string | null;
183
+ /** 这次是否直接命中缓存。 */
184
+ fromCache: boolean;
185
+ }
186
+ /** 最近一次读到的快照,不发请求。 */
187
+ export declare function getCachedQuota(): GlmQuotaSnapshotDto | null;
188
+ /**
189
+ * 只返回**属于这个账号**的快照,不发请求。
190
+ *
191
+ * 配额跟着账号走:轮转决定了下一个请求花哪个账号的额度,所以一份快照只描述它被读取时
192
+ * 那个账号的消耗。缺省 / 空 id 退回「最新一次读」,那是页面级卡片要的语义。
193
+ */
194
+ export declare function getCachedQuotaFor(accountId?: string | null): GlmQuotaSnapshotDto | null;
195
+ /** 忘记配额缓存(登出、换账号、测试)。不给 id 就全清。 */
196
+ export declare function clearCachedQuota(accountId?: string | null): void;
197
+ /** 读订阅列表;失败一律降级成「没有套餐名」,配额窗口不受影响。 */
198
+ export declare function fetchSubscriptionPlan(region: GlmRegion, codingPlanKey: string, options?: GlmRequestOptions): Promise<GlmSubscriptionPlan | null>;
199
+ /**
200
+ * 读一次配额,返回快照或一句失败原因。
201
+ *
202
+ * 走缓存:命中 `QUOTA_CACHE_TTL_MS` 内的同账号结果直接返回(设置卡片在轮询这个接口)。
203
+ * 订阅列表是**尽力而为**的第二段:它只补套餐名与续费时刻,失败不影响已经拿到的窗口。
204
+ *
205
+ * 为什么不抛异常而用 `error`:卡片的降级契约是「没有数字 + 一句原因」
206
+ * (`GlmStatusDto.quota` 可空、`quotaError` 与它并列),抛异常会把同一个决定
207
+ * 推给七个调用点各写一遍。需要「没读到就算失败」的调用方(连接测试)用
208
+ * {@link verifyCodingPlanKey},它本来就会抛。
209
+ *
210
+ * @param accountId - 这次读是为哪个池内账号做的;缓存按它分桶。
211
+ * @throws 只有一种:凭据是空白。那是调用方的 bug(不该把空凭据发到网络上),
212
+ * 所以它同步抛出,与「上游读失败返回 `error`」那条路径分开。
213
+ */
214
+ export declare function fetchGlmQuota(region: GlmRegion, codingPlanKey: string, options?: GlmRequestOptions & {
215
+ accountId?: string;
216
+ force?: boolean;
217
+ }): Promise<GlmQuotaRead>;
218
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/host/glm-coding-plan/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * 兑换链:OAuth access_token → 可用的 Coding Plan Key(计划 §3.2,证据等级 B)。
3
+ *
4
+ * 链路逐字照三个独立实现(TriDefender/zcode-api、Sakuralaaa/z-code-2api、CLIProxyAPI 插件生态)
5
+ * 同构实现的那一条,四个端点与两种字段形状都记在 `EXCHANGE_PATHS` 的注释里:
6
+ *
7
+ * access_token
8
+ * -> [仅国际区] POST {business}/api/auth/z/login {token} => 业务 JWT + expires_in
9
+ * -> GET {business}/api/biz/customer/getCustomerInfo => 默认机构 orgId / 默认项目 projectId
10
+ * -> GET/POST {business}/api/biz/v1/organization/{org}/projects/{proj}/api_keys => 找或建一把 Key
11
+ * -> GET .../api_keys/copy/{apiKeyId} => secretKey
12
+ * -> {apiKeyId}.{secretKey} => Coding Plan Key
13
+ *
14
+ * **两区的鉴权形状本来就不一样**,这不是实现上的瑕疵(逐字:TriDefender/zcode-api
15
+ * `src/auth/resolver.ts` 的两个分支):
16
+ *
17
+ * - 国际区(`zai`):先 `POST /api/auth/z/login` 换业务 JWT,之后所有 `/api/biz/*`
18
+ * 带 `Authorization: Bearer <bizToken>`。
19
+ * - 国区(`bigmodel`):**跳过 z/login**,直接拿 OAuth access_token 当 `Authorization`
20
+ * 头(裸值,不加 `Bearer`)打 `/api/biz/*`;host 是 `https://bigmodel.cn`
21
+ * (`open.bigmodel.cn` 是**模型面**的 host,别混用)。
22
+ *
23
+ * 推论:国区这一层**没有**业务 JWT,所以 `biz-token-cache.ts` 只服务于国际区。
24
+ *
25
+ * 三条必须写下来的纪律:
26
+ *
27
+ * 1. **本线路用自己的 Key 名**(`GLM_KEY_NAME` = `dsh-glm-coding-plan`):
28
+ * 社区实现用 `zcode-api-key`,撞名会导致本线路登录时轮转或删除官方 ZCode 客户端
29
+ * 正在使用的那把 Key(计划 §3.2)。
30
+ * 2. **落盘前必须验一次**:拿配额接口探一次 Coding Plan 面(裸 Key、无 Bearer,
31
+ * 逐字证据 `docs/bigmodel-coding-plan-usage-quota.md`)。账号没有套餐就在**登录阶段**
32
+ * 报错,而不是等到某次对话里以一个莫名其妙的 429 暴露出来。
33
+ * 3. **国区这一段未验证**(计划 R5 / §9):三个同构实现都以国际区为主,
34
+ * 国区的业务面形状是否同构没有实测。失败时必须给出可操作报错,不得静默。
35
+ *
36
+ * 参考实现的许可证是 null / AGPL-3.0,所以这里**只读协议、照协议重写**,没有复制任何代码。
37
+ */
38
+ import type { GlmAllowanceKind, GlmRegion } from '../../shared/glm-coding-plan-contracts.ts';
39
+ /**
40
+ * 国区兑换链的未验证声明。
41
+ *
42
+ * 任何国区失败都要把它带上:一句「兑换失败」对用户毫无指导意义,
43
+ * 而「国区兑换链未经验证」能直接告诉他下一步是换国际区,还是用 `DSH_GLM_*` 覆盖指向实测过的部署。
44
+ */
45
+ export declare const CN_EXCHANGE_UNVERIFIED_NOTICE: string;
46
+ /** 兑换链的任何一步失败。 */
47
+ export declare class GlmExchangeError extends Error {
48
+ constructor(message: string, options?: {
49
+ cause?: unknown;
50
+ });
51
+ }
52
+ /**
53
+ * 兑换链跑通了,但这把 Key 不能服务 Coding Plan 面。
54
+ *
55
+ * 单独一类是因为处置不同:这不是「再试一次」能解决的,也不是链路的 bug,
56
+ * 而是这个账号没有套餐 / 套餐已失效 / 没有建 Key 的权限,必须让用户在登录阶段就看到。
57
+ */
58
+ export declare class GlmCodingPlanUnavailableError extends Error {
59
+ constructor(message: string);
60
+ }
61
+ /** 兑换链跑通并验过之后的结果。host 侧专用,不进共享契约。 */
62
+ export interface GlmCodingPlanKey {
63
+ region: GlmRegion;
64
+ /** `{apiKeyId}.{secretKey}`:配额接口要的就是这个裸值(不可加 Bearer)。 */
65
+ codingPlanKey: string;
66
+ apiKeyId: string;
67
+ secretKey: string;
68
+ /** Key 名,便于诊断「是不是本线路建的」。 */
69
+ keyName: string;
70
+ /** 本次是新建的还是复用了已存在的同名 Key。 */
71
+ keyCreated: boolean;
72
+ organizationId: string;
73
+ projectId: string;
74
+ /** 控制台侧的机构名,仅用于诊断与卡片展示。 */
75
+ accountName: string | null;
76
+ /**
77
+ * 业务 JWT(控制台口径:zcodejwttoken),落盘给 `biz-token-cache.ts` 用。
78
+ *
79
+ * 国区没有这一层(它拿裸 access_token 直接打 `/api/biz/*`),所以那里是 null。
80
+ */
81
+ bizToken: string | null;
82
+ /** 业务 JWT 的失效时刻(Unix 毫秒);国区为 null。 */
83
+ bizTokenExpiresAt: number | null;
84
+ /** 验活时读到的套餐机器档位(lite / pro / max),上游没给则为 null。 */
85
+ planLevel: string | null;
86
+ /**
87
+ * 验活认定的额度类型。落盘后由设置卡片如实显示,**不假装**免费额度是付费套餐。
88
+ *
89
+ * 缺省取 'unknown' 而不是必填:旧凭据文件里没有这个键,解析时补成 unknown
90
+ * (见 `token-store.ts`),因此它必须允许「读不到」。
91
+ */
92
+ allowance?: GlmAllowanceKind;
93
+ }
94
+ export interface GlmExchangeOptions {
95
+ fetchFn?: typeof fetch;
96
+ signal?: AbortSignal;
97
+ env?: NodeJS.ProcessEnv;
98
+ /** 单次请求超时;缺省走 `DISCOVERY_TIMEOUT_MS`(20s)。 */
99
+ timeoutMs?: number;
100
+ }
101
+ /** 业务 JWT(控制台口径:zcodejwttoken)及其失效时刻。 */
102
+ export interface GlmBizToken {
103
+ token: string;
104
+ /** 上游给的 `expires_in`(秒);上游没给时按 JWT 自身的 `exp` 折算。 */
105
+ expiresInSec: number;
106
+ expiresAt: number;
107
+ }
108
+ /**
109
+ * `POST {business}/api/auth/z/login`,体 `{"token": <oauth access_token>}`。
110
+ *
111
+ * 请求**不带** Authorization 头:access_token 在体里,这是三个同构实现一致的做法。
112
+ * 响应取 `access_token`(同构实现还兼容 `accessToken` 与 `data.access_token`,本线路同样容忍)。
113
+ *
114
+ * `expires_in` 是业务 JWT 缓存的唯一时间来源(计划 §3.6:官方按「提前 120 秒 + 0~60 秒抖动」重取)。
115
+ * 上游漏给时退回 JWT 自身的 `exp`;两者都没有就报错——一个不知道什么时候过期的缓存
116
+ * 等于没有缓存,只会在长会话中途把用户踢出去。
117
+ *
118
+ * **只有国际区会调这个端点**:国区按逆向实现的 bigmodel 分支直接用裸 access_token
119
+ * 打 `/api/biz/*`,根本不经过 z/login(见文件头注释)。留成导出函数是为了让 W6 与测试
120
+ * 都能单独调它,而不是为了两区共用。
121
+ */
122
+ export declare function loginBizToken(accessToken: string, region: GlmRegion, options?: GlmExchangeOptions): Promise<GlmBizToken>;
123
+ /** 默认机构与默认项目。 */
124
+ export interface GlmCustomerScope {
125
+ organizationId: string;
126
+ projectId: string;
127
+ organizationName: string | null;
128
+ projectName: string | null;
129
+ }
130
+ /**
131
+ * `GET {business}/api/biz/customer/getCustomerInfo`:定位默认机构与默认项目。
132
+ *
133
+ * 找不到标记文案时退回列表第一项(同构实现的做法):宁可猜一个,也不要让用户去回答
134
+ * 「你的机构叫什么」——那条交互在本插件里不存在,而列表非空本身就说明账号有机构。
135
+ * 列表为空才是真失败。
136
+ */
137
+ export declare function resolveCustomerScope(region: GlmRegion, authorization: string, options?: GlmExchangeOptions): Promise<GlmCustomerScope>;
138
+ /** 一把 api key 的最小形状。 */
139
+ export interface GlmApiKeyRef {
140
+ apiKeyId: string;
141
+ created: boolean;
142
+ }
143
+ /**
144
+ * 在该机构该项目下找一把本线路的 Key,没有就建一把。
145
+ *
146
+ * 找的条件是**名字等于** `keyName()`(默认 `GLM_KEY_NAME`):撞名的代价是
147
+ * 官方客户端正在用的那把 Key 被轮转或删除(计划 §3.2)。
148
+ * 列表调用失败不直接判死而是继续走新建——同构实现也是这么做的,
149
+ * 因为「列不出来」与「没有建 Key 的权限」是两回事,后者才值得报错。
150
+ */
151
+ export declare function findOrCreateApiKey(region: GlmRegion, authorization: string, scope: {
152
+ organizationId: string;
153
+ projectId: string;
154
+ }, options?: GlmExchangeOptions & {
155
+ name?: string;
156
+ }): Promise<GlmApiKeyRef>;
157
+ /**
158
+ * `GET .../api_keys/copy/{apiKeyId}`:取 secretKey。
159
+ *
160
+ * secret 只在这个端点出现一次,所以每次兑换都要再取一次,没有可依赖的缓存。
161
+ * 缺 secret 是硬失败:Coding Plan Key 的形状就是 `id.secret`(计划 §3.2、D4),
162
+ * 拿半把 Key 去配额接口只会得到一个没有出处的 401。
163
+ */
164
+ export declare function copyApiKeySecret(region: GlmRegion, authorization: string, scope: {
165
+ organizationId: string;
166
+ projectId: string;
167
+ apiKeyId: string;
168
+ }, options?: GlmExchangeOptions): Promise<string>;
169
+ /** 探一次 Coding Plan 面的结果。 */
170
+ export interface GlmPlanProbe {
171
+ planLevel: string | null;
172
+ /**
173
+ * 这次探活认定的额度类型。
174
+ *
175
+ * `plan` = 配额面给出了付费套餐的机器档位;`free-trial` = 配额面明确按套餐/额度维度
176
+ * 拒了它(凭据有效);`unknown` = 分不出是「key 坏了」还是「没有付费套餐」,
177
+ * 而本线路在分不出时**选择放行**。
178
+ */
179
+ allowance: GlmAllowanceKind;
180
+ }
181
+ /**
182
+ * 落盘前的验活:`GET {business}/api/monitor/usage/quota/limit`。
183
+ *
184
+ * 头是 `authorization: <id>.<secret>` **裸值**——加了 Bearer 会鉴权失败,
185
+ * 这与模型面正好相反(逐字:`docs/bigmodel-coding-plan-usage-quota.md`,证据等级 A)。
186
+ *
187
+ * 这一步的价值分两半,而两半的**处置相反**:
188
+ *
189
+ * - 凭据本身坏了(业务码落在 `BAD_CREDENTIAL_REASONS`)→ 登录阶段就失败。一把废 Key
190
+ * 进对话只会让用户在某次请求里以一个莫名其妙的 401 暴露出来。
191
+ * - 凭据有效但**没有付费套餐**(业务码落在 `NO_PLAN_REASONS`,或裸 401/403 分不出)→
192
+ * **放行**,并把额度类型如实记成 `free-trial` / `unknown`。官方文档(逐字:
193
+ * zcode.z.ai/cn/docs/configuration)写明新用户注册即自动获得 5 天、每天 800 万 token 的
194
+ * 「体验套餐:无需付费」,所以「没有付费 Coding Plan」不等于「没有额度」——硬拒在登录阶段
195
+ * 等于把免费额度的新用户全部挡在门外。额度耗尽时上游回 429,那是可恢复的。
196
+ */
197
+ export declare function verifyCodingPlanKey(region: GlmRegion, codingPlanKey: string, options?: GlmExchangeOptions): Promise<GlmPlanProbe>;
198
+ /**
199
+ * 这一层之后 `/api/biz/*` 该带的头。
200
+ *
201
+ * 两区不同,逐字照 TriDefender/zcode-api 的两个分支:国际区换出业务 JWT 再带
202
+ * `Bearer`,国区**跳过换**、直接用裸 access_token。
203
+ */
204
+ export declare function resolveBizAuthorization(accessToken: string, region: GlmRegion, options?: GlmExchangeOptions): Promise<{
205
+ authorization: string;
206
+ bizToken: string | null;
207
+ bizTokenExpiresAt: number | null;
208
+ }>;
209
+ /**
210
+ * 走完整条兑换链并验活。
211
+ *
212
+ * 调用方(W6)拿到的是一把**已经证明凭据有效**的 Coding Plan Key:
213
+ * 任何一步没过都不返回 Key,失败一律以异常形式给出可读原因。
214
+ *
215
+ * 注意「证明可用」这句话现在的口径:它证明的是**这把 Key 会被上游认出来**,
216
+ * 不是「账号有付费套餐」。没有付费套餐(含体验额度)的账号同样在这里成功返回,
217
+ * 额度类型记在 `allowance` 上。
218
+ *
219
+ * @throws {@link GlmCodingPlanUnavailableError} 链路通但这把 Key 不能服务 Coding Plan
220
+ * @throws {@link GlmExchangeError} 链路本身没走通
221
+ */
222
+ export declare function exchangeForCodingPlanKey(accessToken: string, region: GlmRegion, options?: GlmExchangeOptions): Promise<GlmCodingPlanKey>;
223
+ //# sourceMappingURL=exchange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exchange.d.ts","sourceRoot":"","sources":["../../../../src/host/glm-coding-plan/exchange.ts"],"names":[],"mappings":"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"}