Bundle
dsh-billing-badge
Billing season and account balance chip for the DeepSeek Harness web GUI composer: a native-looking pill after the cache-hit stat, with a panel on click. DeepSeek Harness 计费时段与余额插件
- Source
- devacc8
- License
- MIT
- Updated
- Updated 18 hours ago
Readme
# dsh-billing-badge
[](https://www.npmjs.com/package/dsh-billing-badge)
[](LICENSE)
Billing season and account balance for the DeepSeek Harness web GUI. A pill in the
composer's statistics row, immediately after the native **Cache hit** reading, that
opens a small panel with the full picture.
```
2288M tok · Cache hit 99.8% · ● Off-peak · 2h13m
```
## What it shows
| Where | What |
|---|---|
| The pill | a coloured dot (amber for peak, green for off-peak), the season, and the time until it flips |
| The panel (click) | billing season, next switch with the Beijing wall clock, current Beijing time, account balance with its currency, granted and topped-up split, and a refresh button |
The season rule is the published one: peak is Beijing time, Monday to Friday,
09:00-12:00 and 14:00-18:00. Everything else, including all of Saturday and Sunday,
is off-peak at half price.
## The balance
The numbers come from the official `GET /user/balance` endpoint, and the three of them
mean different things:
```
total_balance = granted_balance + topped_up_balance
```
- `total_balance`, shown as **Account balance**, is everything you can spend.
- `granted_balance`, shown as **Granted**, is credit DeepSeek gave you. The endpoint
reports only the part that has not expired, so a lapsed grant disappears from this
row on its own.
- `topped_up_balance`, shown as **Topped up**, is money you paid in.
When the two upper rows are equal there is no grant on the account. `is_available`
is a top-level field of the response and answers one question: is the balance enough
for API calls. The panel adds a warning row when the answer is no, and stays quiet
otherwise, because the flag is true for every funded account.
The currency is taken from the response, never assumed: an account reporting USD is
not labelled with a CNY sign.
## Why another one
Two community plugins cover parts of this, and both taught something:
- [dsh-price-phase](https://github.com/lijunyu726/dsh-price-phase) shows the season.
Its countdown once pointed at Saturday 09:00 after Friday close, an event that does
not happen, and it centres its badge on a hashed CSS class, which collides with the
model chip when the model name is long. This plugin compares each candidate boundary
with the instant before it and only counts a real state flip, and its chip is an
ordinary flex child in the native statistics row.
- [dsh-usage-monitor](https://github.com/liyiersan/dsh-usage-monitor) shows the
balance, but formats it as CNY whatever the API reports.
This plugin deliberately does **not** do cost or token accounting.
## Install
From npm:
```sh
dsh plugin --profile web add dsh-billing-badge
```
or straight from the repository:
```sh
dsh plugin --profile web add github:devacc8/dsh-billing-badge
```
then restart `dsh web`. The package declares `dsh.bundle.patch`, so the host half is
reconciled into the profile's bundle list automatically.
Working on the plugin itself, install the checkout by path instead:
```sh
dsh plugin --profile web add link:/absolute/path/to/dsh-billing-badge
```
## Security
A balance is a small surface, so it stays small:
- the API key is resolved in the host through the DSH credentials seam
(`ctx.credentials.resolve('DEEPSEEK_API_KEY')`, environment fallback) and never
reaches the browser;
- the single route requires the `x-dsh-billing-badge: 1` header and rejects a
cross-origin `Origin`, so a cross-site page cannot reach it;
- nothing is written to disk, and no endpoint other than `api.deepseek.com` is
contacted;
- a missing key, an HTTP error or a network failure all degrade to a state the panel
renders, never to a throw.
## Development
The season logic lives in `lib/season.js` as a plain ESM module so it can be tested
directly. A browser bundle cannot import a sibling file (the loader resolves only
platform seeds, materialized packages and registered factories, and a self-subpath
`require` throws "missed the module table"), so `scripts/inline-season.mjs` copies the
module into `lib/client.js` between two markers with `export ` stripped, and
`test/client-sync.test.mjs` fails if the copy drifts.
```sh
npm test # 30 tests: season rule, countdown invariant, host route, bundle
npm run sync # re-inline season.js into the bundle
npm run check # sync check plus a syntax check of both halves
```
The countdown has an invariant test rather than fixtures: every 13 minutes across nine
days, the reported target must be in the future, must change the season, and the
season must not change before it.
## Layout
```
lib/season.js season rule, countdown, formatting (source of truth, tested)
lib/index.js host half: the balance route
lib/client.js browser half: the pill and its panel, with season.js inlined
cordis.patch.yml mounts the host half into the profile
scripts/ the inliner
test/ season, sync, host and bundle tests
```
GitHub Actions runs `npm test` and `npm run check` on Node 20 and 22.
## 中文说明
DeepSeek Harness 网页界面的计费时段与账户余额插件。它在输入框下方的统计行里、原生 **Cache hit** 之后加一个小胶囊,点击后展开一个小面板。
```
2288M tok · Cache hit 99.8% · ● Off-peak · 2h13m
```
- **胶囊**:一个圆点(高峰为琥珀色,非高峰为绿色)、当前时段,以及距离切换的倒计时。
- **面板**(点击展开):计费时段、下次切换时间与北京时间、当前北京时间、账户余额及其货币、赠送额度与充值额度的拆分,以及刷新按钮。
计费时段采用官方公布的规则:高峰为北京时间周一至周五 09:00-12:00 与 14:00-18:00,其余时间(含整个周六与周日)均为非高峰,价格为半价。
余额来自官方 `GET /user/balance` 接口,其中三个数字含义不同:
```
total_balance = granted_balance + topped_up_balance
```
- `total_balance`(Account balance):可用总额。
- `granted_balance`(Granted):官方赠送的额度,接口只返回尚未过期的部分,过期的赠送额度会自动从这一行消失。
- `topped_up_balance`(Topped up):你自己充值的金额。
前两行数值相等时,说明账户没有赠送额度。`is_available` 是响应顶层的字段,回答一个问题:余额是否足够调用接口。只有接口报告余额不足时,面板才会加一行警告;该字段对任何有余额的账户都是 true,因此平时不显示。货币一律取自接口返回值,不做假设:返回 USD 的账户不会被标上人民币符号。
### 安装
从 npm 安装:
```sh
dsh plugin --profile web add dsh-billing-badge
```
或直接从仓库安装:
```sh
dsh plugin --profile web add github:devacc8/dsh-billing-badge
```
然后重启 `dsh web`。包内声明了 `dsh.bundle.patch`,宿主部分会自动写入 profile 的 bundle 列表。
### 安全
- API key 只在宿主进程中通过 DSH credentials 接口读取(`ctx.credentials.resolve('DEEPSEEK_API_KEY')`,环境变量兜底),不会进入浏览器;
- 唯一的路由要求请求头 `x-dsh-billing-badge: 1`,并拒绝跨站 `Origin`;
- 不写任何文件,除 `api.deepseek.com` 外不访问其他地址;
- 缺少 key、HTTP 错误或网络故障都会降级为面板可显示的状态,不会抛异常。
MIT.
Install
dsh plugin --profile web add github:devacc8/dsh-billing-badge
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-billing-badge from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.