dsh-subusage 0.8.2 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## 安装与快速开始
8
8
 
9
- 当前仓库版本 **0.8.2**,可从 GitHub Release 获取。npm 自动发布采用 Trusted Publishing(GitHub OIDC);可用版本见 [npm](https://www.npmjs.com/package/dsh-subusage)。安装时使用目标 DSH 部署提供的插件管理器或 CLI,并启用本 bundle:
9
+ 当前仓库版本 **0.8.3**,可从 GitHub Release 获取。npm 自动发布采用 Trusted Publishing(GitHub OIDC);可用版本见 [npm](https://www.npmjs.com/package/dsh-subusage)。安装时使用目标 DSH 部署提供的插件管理器或 CLI,并启用本 bundle:
10
10
 
11
11
  | 来源 | 安装标识或下载地址 |
12
12
  |---|---|
@@ -51,7 +51,7 @@
51
51
  | Z.ai 国际 | `ZAI_CODING_API_KEY` | `zai-coding`,默认关闭,独立国际 Coding Plan Key |
52
52
  | Synthetic | `SYNTHETIC_API_KEY` | `synthetic`,默认关闭,模型订阅请求额度 |
53
53
  | NanoGPT | `NANOGPT_API_KEY` | `nanogpt`,默认关闭;也可手动填写 Usage only 管理令牌 |
54
- | Kimi | `KIMI_CODING_API_KEY` | 需要 Kimi Coding Key,不是 Moonshot 开平台 Key |
54
+ | Kimi | `KIMI_CODING_API_KEY` | 需要 Kimi Coding Key,不是 Moonshot 开平台 Key;窗口集合按套餐体系下发(老套餐 5 小时 + 7 天,新套餐 Go / Plus 为 5 小时 + 月度) |
55
55
  | MiMo | 不使用 API Key | 通过控制台 Cookie 会话读取 |
56
56
  | OpenCode Go | `OPENCODE_API_KEY` | OpenCode Go Key |
57
57
  | MiniMax 国际 | `MINIMAX_API_KEY` | `minimax` 路由;国际站订阅 Key |
@@ -100,7 +100,7 @@ JSON 中有域名的条目按 `platform.xiaomimimo.com` 的 Cookie 域规则过
100
100
  | Z.ai 国际 | 5 小时、每周(按响应) | Token / Credits 配额,区域凭据独立 |
101
101
  | Synthetic | 滚动订阅池 | 已用/总请求次数、重置时间 |
102
102
  | NanoGPT | 每日、每周、试用周期(按响应) | 输入 Token 数、重置时间;不包含图像额度 |
103
- | Kimi | 5 小时、7 天 | 已用百分比、套餐档 |
103
+ | Kimi | 5 小时、7 天、月度(按账户下发) | 已用百分比、套餐档 |
104
104
  | MiMo | 本周期额度池 | 用量明细、重置时间、套餐与余额 |
105
105
  | OpenCode Go | 滚动、每周、每月 | 已用百分比、重置时间 |
106
106
  | MiniMax 国际 / 中国 | 短周期(通常 5 小时)、每周 | 通用/编程池已用百分比、可信计数明细、重置时间 |
@@ -108,6 +108,8 @@ JSON 中有域名的条目按 `platform.xiaomimimo.com` 的 Cookie 域规则过
108
108
 
109
109
  非公开控制台接口可能变更;缺失或非法百分比不会当作零用量。部分数据、未知额度和暂时失败有明确状态,不能据此保证推理接口一定可用。
110
110
 
111
+ Kimi 的窗口集合随套餐体系变化:老套餐(节奏命名,如 Allegro)返回 5 小时与 7 天,新套餐(Go / Plus 命名)返回 5 小时与月度总额,因此同一插件在不同账号上显示的窗口数可以不同;月度池里的 Code 份额不是独立预算,不单独成窗。插件按接口实际下发的窗口解析,不要求固定集合。
112
+
111
113
 
112
114
  ## 常见问题
113
115
 
@@ -116,6 +118,7 @@ JSON 中有域名的条目按 `platform.xiaomimimo.com` 的 Cookie 域规则过
116
118
  | 设置页没有提供商标签 | 展开提供商管理,确认开关和凭据;无凭据的条目默认隐藏,可临时关闭自动隐藏查看指引 |
117
119
  | 已配置凭据却没有药丸 | 确认当前模型的提供商 ID 与支持表一致、检测已开启;自定义 ID 可在设置页查看,但不会自动映射 |
118
120
  | 显示认证失效 | 检查是否用了对应产品/区域的订阅 Key;MiMo 重新登录或导入 Cookie;旧额度不会当作有效数据保留 |
121
+ | Kimi 缺少 7 天窗口,或提示结构错误 | 窗口集合按套餐体系下发:老套餐(节奏命名,如 Allegro)为 5 小时 + 7 天,新套餐(Go / Plus 命名)为 5 小时 + 月度总额。0.8.3 起按实际下发的窗口解析,不再要求 7 天窗口;升级后仍报「Invalid Kimi usage response」即为未识别的字段结构,插件不会猜测额度,可回报该响应 |
119
122
  | 显示缓存、部分数据或额度未知 | 查看更新时间和错误说明;缓存来自之前的成功读取,部分数据不保证有可用额度,余额也不等于订阅余量 |
120
123
  | 刷新后数字暂未变化 | 成功结果按提供商缓存 60 秒;手动刷新可跳过普通 TTL,但仍遵守限流退避和 Retry-After |
121
124
  | MiMo 自动登录无法启动 | Host 所在机器需安装 Google Chrome 并有桌面环境;远程或无桌面部署使用手动导入 |
package/lib/index.js CHANGED
@@ -147,7 +147,7 @@ function failure(code, message, retryable = false, retryAfterMs) {
147
147
  }
148
148
  async function fetchJson(fetcher, url, headers, lifetimeSignal) {
149
149
  let response;
150
- try { response = await fetcher(url, { headers: { accept: "application/json", "user-agent": "dsh-subusage/0.8.2", ...headers }, signal: lifetimeSignal ? AbortSignal.any([AbortSignal.timeout(10000), lifetimeSignal]) : AbortSignal.timeout(10000), redirect: "manual" }); }
150
+ try { response = await fetcher(url, { headers: { accept: "application/json", "user-agent": "dsh-subusage/0.8.3", ...headers }, signal: lifetimeSignal ? AbortSignal.any([AbortSignal.timeout(10000), lifetimeSignal]) : AbortSignal.timeout(10000), redirect: "manual" }); }
151
151
  catch { throw failure("subusage/network", "网络请求失败或超时", true); }
152
152
  if (response.status >= 300 && response.status < 400 || response.status === 401 || response.status === 403) throw failure("subusage/auth", "登录或凭据已失效");
153
153
  if (!response.ok) {
@@ -185,10 +185,32 @@ function cascadeRateLimited(windows) {
185
185
  return windows;
186
186
  }
187
187
  export function normalizeKimi(body) {
188
- // 已知旧版 usages 和新版 usage/limits 的显式命名窗口;不推断未知字段。
189
- const u = body?.usages ?? body?.usage ?? body?.limits;
190
- if (!u || !u.limit_5h || !u.limit_7d) throw failure("subusage/response", "Invalid Kimi usage response");
191
- return cascadeRateLimited(["5h", "7d"].map(kind => { const row = u[`limit_${kind}`]; if (!numeric(row.used_ratio)) throw failure("subusage/response", "Invalid Kimi used_ratio"); return windowRow(kind, row.used_ratio * 100, row.reset_time); }));
188
+ // 上游 /coding/v1/usages 有两代形态:新版 usages 比例池(limit_5h / limit_7d /
189
+ // limit_month_total),旧版顶层 usage + limits[](绝对 limit / used / remaining)。
190
+ // 只有 300 分钟窗口在所有形态都下发,因此没有哪个窗口名可以当必需字段:现行账户
191
+ // 下发 5h + 月池而省略 limit_7d,旧账户则完全没有 usages。不推断未知字段。
192
+ const pools = [body?.usages, body?.usage, body?.limits].filter(v => v && typeof v === "object" && !Array.isArray(v));
193
+ const windows = [];
194
+ // limit_month_code 是 month_total 的 Code 份额而非独立预算,不作为独立窗口。
195
+ for (const [field, kind] of [["limit_5h", "5h"], ["limit_7d", "7d"], ["limit_month_total", "month"]]) {
196
+ const row = pools.map(pool => pool[field]).find(v => v !== undefined);
197
+ if (row === undefined) continue;
198
+ if (!numeric(row.used_ratio)) throw failure("subusage/response", "Invalid Kimi used_ratio");
199
+ windows.push(windowRow(kind, row.used_ratio * 100, row.reset_time));
200
+ }
201
+ // 无比例池时退回绝对值:limits[] 的 300 分钟项是 5 小时窗口,顶层 usage 是周额度。
202
+ if (!windows.length) {
203
+ const absolute = (row, kind) => {
204
+ const limit = Number(row?.limit), remaining = Number(row?.remaining);
205
+ if (!Number.isFinite(limit) || limit <= 0 || !Number.isFinite(remaining)) return;
206
+ windows.push(windowRow(kind, (limit - remaining) / limit * 100, row.resetTime));
207
+ };
208
+ const burst = (Array.isArray(body?.limits) ? body.limits : []).find(row => row?.window?.duration === 300 && row.window.timeUnit === "TIME_UNIT_MINUTE");
209
+ if (burst) absolute(burst.detail, "5h");
210
+ if (body?.usage && typeof body.usage === "object") absolute(body.usage, "week");
211
+ }
212
+ if (!windows.length) throw failure("subusage/response", "Invalid Kimi usage response");
213
+ return cascadeRateLimited(windows);
192
214
  }
193
215
  export function normalizeZai(body) {
194
216
  const data = body?.data;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-subusage",
3
3
  "displayName": "订阅用量显示",
4
- "version": "0.8.2",
4
+ "version": "0.8.3",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "registry": "https://registry.npmjs.org/"