@linxin666/dsh-usage 0.4.4 → 0.4.6

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/lib/client.js CHANGED
@@ -72,6 +72,13 @@ window.__ModuleLoader__.load({
72
72
  "usage.current": "当前",
73
73
  "usage.today": "今日用量",
74
74
  "usage.today.cost": "今日消费(估算)",
75
+ "usage.day.label": "查看日期",
76
+ "usage.day.today": "今日",
77
+ "usage.day.title": "{date} 用量",
78
+ "usage.day.cost": "当日消费(估算)",
79
+ "usage.day.empty": "该日没有用量记录",
80
+ "usage.day.loading": "正在加载该日用量…",
81
+ "usage.day.error": "该日用量加载失败:{error}",
75
82
  "usage.peak.on": "DeepSeek 高峰时段:计价 ×2,{time} 结束",
76
83
  "usage.peak.off": "DeepSeek 空闲时段:计价为高峰一半,{time} 进入高峰",
77
84
  "usage.calls": "{n} 次调用",
@@ -100,12 +107,13 @@ window.__ModuleLoader__.load({
100
107
  "usage.config.pollIntervalSec": "轮询间隔(秒)",
101
108
  "usage.config.saveFailed": "保存失败:设置未被接受。",
102
109
  "usage.bank.title": "鲸元券",
103
- "usage.bank.hint": "官方 API 每消耗 100 万 tokens 铸造 1 鲸元;保存或分享这张票券。",
104
- "usage.bank.noUsage": "暂无 DeepSeek 官方用量数据(统计自插件启用起)",
110
+ "usage.bank.hint": "DeepSeek 官方 API 与 MiMo 每消耗 100 万 tokens 铸造 1 鲸元;保存或分享这张票券。",
111
+ "usage.bank.noUsage": "暂无 DeepSeek 官方 / MiMo 用量数据(统计自插件启用起)",
105
112
  "usage.bank.minted": "累计铸造 {minted} 鲸元({tokens} tokens)",
106
113
  "usage.bank.spend.observed": "官方余额实测花费 ¥{cost}(自 {since} 起)",
107
114
  "usage.bank.spend.estimated": "消费估算:约 ¥{cost}",
108
115
  "usage.bank.window": "统计窗口 {from} ~ {to}",
116
+ "usage.bank.windowAll": "全部保留期",
109
117
  "usage.bank.save": "保存图片",
110
118
  "usage.bank.share": "分享",
111
119
  "usage.bank.drawError": "票券生成失败:{error}",
@@ -130,6 +138,13 @@ window.__ModuleLoader__.load({
130
138
  "usage.current": "Current",
131
139
  "usage.today": "Today",
132
140
  "usage.today.cost": "Today spend (estimated)",
141
+ "usage.day.label": "Day",
142
+ "usage.day.today": "Today",
143
+ "usage.day.title": "Usage · {date}",
144
+ "usage.day.cost": "Day spend (estimated)",
145
+ "usage.day.empty": "No usage recorded on this day",
146
+ "usage.day.loading": "Loading that day…",
147
+ "usage.day.error": "Failed to load that day: {error}",
133
148
  "usage.peak.on": "DeepSeek peak hours: 2x pricing, ends {time}",
134
149
  "usage.peak.off": "DeepSeek off-peak: half of peak pricing, peak returns {time}",
135
150
  "usage.calls": "{n} calls",
@@ -158,12 +173,13 @@ window.__ModuleLoader__.load({
158
173
  "usage.config.pollIntervalSec": "Poll interval (seconds)",
159
174
  "usage.config.saveFailed": "Save failed: the deployment did not accept the setting.",
160
175
  "usage.bank.title": "Whale-yuan voucher",
161
- "usage.bank.hint": "Every 1,000,000 tokens spent on the official API mint one whale yuan; save or share the note.",
162
- "usage.bank.noUsage": "No official DeepSeek usage yet (counting starts when the plugin is enabled)",
176
+ "usage.bank.hint": "Every 1,000,000 tokens spent on the DeepSeek official API or on MiMo mint one whale yuan; save or share the note.",
177
+ "usage.bank.noUsage": "No DeepSeek official or MiMo usage yet (counting starts when the plugin is enabled)",
163
178
  "usage.bank.minted": "Minted {minted} whale yuan ({tokens} tokens)",
164
179
  "usage.bank.spend.observed": "Spent ¥{cost} observed on the official balance (watching since {since})",
165
180
  "usage.bank.spend.estimated": "Estimated spend: about ¥{cost}",
166
181
  "usage.bank.window": "Window {from} - {to}",
182
+ "usage.bank.windowAll": "All retained days",
167
183
  "usage.bank.save": "Save image",
168
184
  "usage.bank.share": "Share",
169
185
  "usage.bank.drawError": "Failed to render the voucher: {error}",
@@ -189,7 +205,7 @@ window.__ModuleLoader__.load({
189
205
  }
190
206
  //#endregion
191
207
  //#region \0dsh-css:packages/dsh-usage/src/client/usage.module.css.mjs
192
- const css = ".cvtkAW_section{color:inherit;flex-direction:column;gap:16px;display:flex}.cvtkAW_header{justify-content:space-between;align-items:center;gap:12px;display:flex}.cvtkAW_currentProvider{opacity:.75;font-size:13px}.cvtkAW_refreshBtn{appearance:none;color:inherit;font:inherit;cursor:pointer;opacity:.85;background:0 0;border:1px solid;border-radius:8px;padding:4px 12px;font-size:12px;transition:opacity .12s,background-color .12s}.cvtkAW_refreshBtn:hover:not(:disabled){opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.cvtkAW_refreshBtn:disabled{cursor:default;opacity:.5}.cvtkAW_refreshBtn:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_tabs{border-bottom:1px solid color-mix(in srgb, currentColor 14%, transparent);gap:4px;display:flex}.cvtkAW_tab{appearance:none;color:inherit;font:inherit;cursor:pointer;opacity:.65;background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-1px;padding:6px 14px;font-size:13px}.cvtkAW_tab:hover{opacity:.9}.cvtkAW_tab:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_tabActive{opacity:1;border-bottom-color:currentColor;font-weight:600}.cvtkAW_card{border:1px solid color-mix(in srgb, currentColor 14%, transparent);border-radius:12px;flex-direction:column;gap:10px;padding:14px 16px;display:flex}.cvtkAW_cardTitle{letter-spacing:.04em;text-transform:uppercase;opacity:.6;font-size:12px;font-weight:600}.cvtkAW_statRow{flex-wrap:wrap;gap:18px;display:flex}.cvtkAW_stat{flex-direction:column;gap:2px;display:flex}.cvtkAW_statValue{font-variant-numeric:tabular-nums;font-size:18px;font-weight:600}.cvtkAW_statLabel{opacity:.6;font-size:11px}.cvtkAW_providerRow{border-top:1px solid color-mix(in srgb, currentColor 8%, transparent);justify-content:space-between;align-items:center;gap:12px;padding:6px 0;font-size:13px;display:flex}.cvtkAW_providerRow:first-of-type{border-top:none}.cvtkAW_providerName{align-items:center;gap:8px;min-width:0;display:flex}.cvtkAW_providerTokens{font-variant-numeric:tabular-nums;opacity:.75;white-space:nowrap}.cvtkAW_providerBalance{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.cvtkAW_currentBadge{border:1px solid color-mix(in srgb, currentColor 35%, transparent);opacity:.8;border-radius:999px;flex:none;padding:1px 7px;font-size:10px;font-weight:600}.cvtkAW_chart{flex-direction:column;gap:12px;display:flex}.cvtkAW_chartProvider{flex-direction:column;gap:4px;display:flex}.cvtkAW_chartHead{justify-content:space-between;align-items:baseline;gap:10px;font-size:13px;display:flex}.cvtkAW_chartTokens{font-variant-numeric:tabular-nums;opacity:.65;white-space:nowrap;font-size:11px}.cvtkAW_chartBar{background:color-mix(in srgb, currentColor 8%, transparent);border-radius:999px;height:8px;display:block;overflow:hidden}.cvtkAW_chartFill{background:color-mix(in srgb, currentColor 55%, transparent);border-radius:999px;height:100%;transition:width .3s;display:block}.cvtkAW_chartModel{opacity:.8;grid-template-columns:minmax(80px,180px) 1fr auto;align-items:center;gap:8px;padding-left:14px;font-size:11px;display:grid}.cvtkAW_chartModelName{text-overflow:ellipsis;white-space:nowrap;opacity:.8;overflow:hidden}.cvtkAW_chartModelBar{background:color-mix(in srgb, currentColor 6%, transparent);border-radius:999px;height:4px;display:block;overflow:hidden}.cvtkAW_chartModelFill{background:color-mix(in srgb, currentColor 35%, transparent);border-radius:999px;height:100%;transition:width .3s;display:block}.cvtkAW_trendAxis{opacity:.5;font-variant-numeric:tabular-nums;justify-content:space-between;font-size:10px;display:flex}.cvtkAW_muted{opacity:.6;font-size:12px}.cvtkAW_voucherPreview canvas{border-radius:8px;width:100%;height:auto;display:block}.cvtkAW_buttonRow{gap:8px;display:flex}.cvtkAW_errorLine{opacity:.75;font-size:12px}.cvtkAW_planCard{flex-direction:column;gap:8px;display:flex}.cvtkAW_planHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.cvtkAW_planName{font-size:14px;font-weight:600}.cvtkAW_windowRow{flex-direction:column;gap:4px;display:flex}.cvtkAW_windowLabel{opacity:.8;font-variant-numeric:tabular-nums;justify-content:space-between;font-size:12px;display:flex}.cvtkAW_bar{background:color-mix(in srgb, currentColor 10%, transparent);border-radius:999px;height:6px;overflow:hidden}.cvtkAW_barFill{background:color-mix(in srgb, currentColor 55%, transparent);border-radius:999px;height:100%;transition:width .3s}.cvtkAW_barWarn{background:#d97706}.cvtkAW_barLow{background:#dc2626}.cvtkAW_resetLine{opacity:.55;font-variant-numeric:tabular-nums;font-size:11px}.cvtkAW_settingsGrid{flex-wrap:wrap;align-items:center;gap:16px;display:flex}.cvtkAW_settingItem{align-items:center;gap:8px;font-size:13px;display:flex}.cvtkAW_settingItem input[type=checkbox]{accent-color:currentColor}.cvtkAW_settingItem input[type=number]{border:1px solid color-mix(in srgb, currentColor 25%, transparent);width:90px;color:inherit;font:inherit;background:0 0;border-radius:6px;padding:3px 8px;font-size:13px}.cvtkAW_settingItem select{border:1px solid color-mix(in srgb, currentColor 25%, transparent);color:inherit;font:inherit;background:0 0;border-radius:6px;padding:3px 8px;font-size:13px}.cvtkAW_settingItem input:focus-visible,.cvtkAW_settingItem select:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_footCard{box-sizing:border-box;background:color-mix(in srgb, currentColor 4%, transparent);width:100%;color:inherit;border:none;border-radius:12px;margin:2px 0 4px;transition:background-color .12s;position:relative}.cvtkAW_footCard:hover{background:var(--dsw-alias-interactive-bg-hover)}.cvtkAW_footCardCollapsed{background:0 0}.cvtkAW_footMain{appearance:none;box-sizing:border-box;width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:12px;flex-direction:column;gap:4px;padding:8px;display:flex}.cvtkAW_footMain:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_footToggle{appearance:none;width:20px;height:20px;color:inherit;cursor:pointer;opacity:.55;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;transition:opacity .12s,background-color .12s;display:inline-flex;position:absolute;top:6px;right:6px}.cvtkAW_footCard:hover .cvtkAW_footToggle{opacity:.8}.cvtkAW_footToggle:hover{opacity:1;background:color-mix(in srgb, currentColor 10%, transparent)}.cvtkAW_footToggle:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_footToggle svg{display:block}.cvtkAW_footHead{justify-content:space-between;align-items:baseline;gap:8px;display:flex}.cvtkAW_footTitle{opacity:.65;white-space:nowrap;align-items:center;gap:6px;min-width:0;font-size:12px;display:inline-flex}.cvtkAW_footTitle svg{flex:none;display:block}.cvtkAW_footValue{font-variant-numeric:tabular-nums;white-space:nowrap;margin-right:18px;font-size:15px;font-weight:600}.cvtkAW_footLine{opacity:.7;font-variant-numeric:tabular-nums;text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.cvtkAW_footMeta{opacity:.5;font-variant-numeric:tabular-nums;font-size:10px}.cvtkAW_footCardCollapsed .cvtkAW_footMain{min-height:36px;padding:7px 8px}.cvtkAW_footStrip{white-space:nowrap;align-items:center;gap:6px;padding-right:20px;font-size:12px;display:flex;overflow:hidden}.cvtkAW_footStrip svg{opacity:.65;flex:none;display:block}.cvtkAW_footStripProvider{text-overflow:ellipsis;flex:none;max-width:45%;font-weight:500;overflow:hidden}.cvtkAW_footStripLabel{opacity:.65;text-overflow:ellipsis;overflow:hidden}.cvtkAW_footStripValue{font-variant-numeric:tabular-nums;margin-left:auto;font-weight:600}[data-dsh-frame][data-sidebar-collapsed] .cvtkAW_footCard,[data-sidebar-collapsed] .cvtkAW_footCard{display:none}";
208
+ const css = ".cvtkAW_section{color:inherit;flex-direction:column;gap:16px;display:flex}.cvtkAW_header{justify-content:space-between;align-items:center;gap:12px;display:flex}.cvtkAW_currentProvider{opacity:.75;font-size:13px}.cvtkAW_refreshBtn{appearance:none;color:inherit;font:inherit;cursor:pointer;opacity:.85;background:0 0;border:1px solid;border-radius:8px;padding:4px 12px;font-size:12px;transition:opacity .12s,background-color .12s}.cvtkAW_refreshBtn:hover:not(:disabled){opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.cvtkAW_refreshBtn:disabled{cursor:default;opacity:.5}.cvtkAW_refreshBtn:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_tabs{border-bottom:1px solid color-mix(in srgb, currentColor 14%, transparent);gap:4px;display:flex}.cvtkAW_tab{appearance:none;color:inherit;font:inherit;cursor:pointer;opacity:.65;background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-1px;padding:6px 14px;font-size:13px}.cvtkAW_tab:hover{opacity:.9}.cvtkAW_tab:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_tabActive{opacity:1;border-bottom-color:currentColor;font-weight:600}.cvtkAW_card{border:1px solid color-mix(in srgb, currentColor 14%, transparent);border-radius:12px;flex-direction:column;gap:10px;padding:14px 16px;display:flex}.cvtkAW_cardTitle{letter-spacing:.04em;text-transform:uppercase;opacity:.6;font-size:12px;font-weight:600}.cvtkAW_dayPicker{align-items:center;gap:8px;display:flex}.cvtkAW_dayPickerLabel{opacity:.6;font-size:11px}.cvtkAW_daySelect{border:1px solid color-mix(in srgb, currentColor 25%, transparent);color:inherit;font:inherit;font-variant-numeric:tabular-nums;background:0 0;border-radius:6px;padding:3px 8px;font-size:12px}.cvtkAW_daySelect:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_daySelect option,.cvtkAW_settingItem select option{background-color:var(--dsw-alias-bg-multi-select,Canvas);color:var(--dsw-alias-label-primary,CanvasText)}.cvtkAW_statRow{flex-wrap:wrap;gap:18px;display:flex}.cvtkAW_stat{flex-direction:column;gap:2px;display:flex}.cvtkAW_statValue{font-variant-numeric:tabular-nums;font-size:18px;font-weight:600}.cvtkAW_statLabel{opacity:.6;font-size:11px}.cvtkAW_providerRow{border-top:1px solid color-mix(in srgb, currentColor 8%, transparent);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;padding:6px 0;font-size:13px;display:flex}.cvtkAW_providerRow:first-of-type{border-top:none}.cvtkAW_providerName{align-items:center;gap:8px;min-width:0;display:flex}.cvtkAW_providerTokens{font-variant-numeric:tabular-nums;opacity:.75;white-space:nowrap}.cvtkAW_providerBalance{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.cvtkAW_currentBadge{border:1px solid color-mix(in srgb, currentColor 35%, transparent);opacity:.8;border-radius:999px;flex:none;padding:1px 7px;font-size:10px;font-weight:600}.cvtkAW_chart{flex-direction:column;gap:12px;display:flex}.cvtkAW_chartProvider{flex-direction:column;gap:4px;display:flex}.cvtkAW_chartHead{justify-content:space-between;align-items:baseline;gap:10px;font-size:13px;display:flex}.cvtkAW_chartTokens{font-variant-numeric:tabular-nums;opacity:.65;white-space:nowrap;font-size:11px}.cvtkAW_chartBar{background:color-mix(in srgb, currentColor 8%, transparent);border-radius:999px;height:8px;display:block;overflow:hidden}.cvtkAW_chartFill{background:color-mix(in srgb, currentColor 55%, transparent);border-radius:999px;height:100%;transition:width .3s;display:block}.cvtkAW_chartModel{opacity:.8;grid-template-columns:minmax(80px,180px) 1fr auto;align-items:center;gap:8px;padding-left:14px;font-size:11px;display:grid}.cvtkAW_chartModelName{text-overflow:ellipsis;white-space:nowrap;opacity:.8;overflow:hidden}.cvtkAW_chartModelBar{background:color-mix(in srgb, currentColor 6%, transparent);border-radius:999px;height:4px;display:block;overflow:hidden}.cvtkAW_chartModelFill{background:color-mix(in srgb, currentColor 35%, transparent);border-radius:999px;height:100%;transition:width .3s;display:block}.cvtkAW_trendAxis{opacity:.5;font-variant-numeric:tabular-nums;justify-content:space-between;font-size:10px;display:flex}.cvtkAW_muted{opacity:.6;font-size:12px}.cvtkAW_voucherPreview canvas{border-radius:8px;width:100%;height:auto;display:block}.cvtkAW_buttonRow{gap:8px;display:flex}.cvtkAW_errorLine{opacity:.75;font-size:12px}.cvtkAW_planCard{flex-direction:column;gap:8px;display:flex}.cvtkAW_planHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.cvtkAW_planName{font-size:14px;font-weight:600}.cvtkAW_windowRow{flex-direction:column;gap:4px;display:flex}.cvtkAW_windowLabel{opacity:.8;font-variant-numeric:tabular-nums;justify-content:space-between;font-size:12px;display:flex}.cvtkAW_bar{background:color-mix(in srgb, currentColor 10%, transparent);border-radius:999px;height:6px;overflow:hidden}.cvtkAW_barFill{background:color-mix(in srgb, currentColor 55%, transparent);border-radius:999px;height:100%;transition:width .3s}.cvtkAW_barWarn{background:#d97706}.cvtkAW_barLow{background:#dc2626}.cvtkAW_resetLine{opacity:.55;font-variant-numeric:tabular-nums;font-size:11px}.cvtkAW_settingsGrid{flex-wrap:wrap;align-items:center;gap:16px;display:flex}.cvtkAW_settingItem{align-items:center;gap:8px;font-size:13px;display:flex}.cvtkAW_settingItem input[type=checkbox]{accent-color:currentColor}.cvtkAW_settingItem input[type=number]{border:1px solid color-mix(in srgb, currentColor 25%, transparent);width:90px;color:inherit;font:inherit;background:0 0;border-radius:6px;padding:3px 8px;font-size:13px}.cvtkAW_settingItem select{border:1px solid color-mix(in srgb, currentColor 25%, transparent);color:inherit;font:inherit;background:0 0;border-radius:6px;padding:3px 8px;font-size:13px}.cvtkAW_settingItem input:focus-visible,.cvtkAW_settingItem select:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_footCard{box-sizing:border-box;background:color-mix(in srgb, currentColor 4%, transparent);width:100%;color:inherit;border:none;border-radius:12px;margin:2px 0 4px;transition:background-color .12s;position:relative}.cvtkAW_footCard:hover{background:var(--dsw-alias-interactive-bg-hover)}.cvtkAW_footCardCollapsed{background:0 0}.cvtkAW_footMain{appearance:none;box-sizing:border-box;width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:12px;flex-direction:column;gap:4px;padding:8px;display:flex}.cvtkAW_footMain:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_footToggle{appearance:none;width:20px;height:20px;color:inherit;cursor:pointer;opacity:.55;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;transition:opacity .12s,background-color .12s;display:inline-flex;position:absolute;top:6px;right:6px}.cvtkAW_footCard:hover .cvtkAW_footToggle{opacity:.8}.cvtkAW_footToggle:hover{opacity:1;background:color-mix(in srgb, currentColor 10%, transparent)}.cvtkAW_footToggle:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);outline:none}.cvtkAW_footToggle svg{display:block}.cvtkAW_footHead{justify-content:space-between;align-items:baseline;gap:8px;display:flex}.cvtkAW_footTitle{opacity:.65;white-space:nowrap;align-items:center;gap:6px;min-width:0;font-size:12px;display:inline-flex}.cvtkAW_footTitle svg{flex:none;display:block}.cvtkAW_footValue{font-variant-numeric:tabular-nums;white-space:nowrap;margin-right:18px;font-size:15px;font-weight:600}.cvtkAW_footLine{opacity:.7;font-variant-numeric:tabular-nums;text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.cvtkAW_footMeta{opacity:.5;font-variant-numeric:tabular-nums;font-size:10px}.cvtkAW_footCardCollapsed .cvtkAW_footMain{min-height:36px;padding:7px 8px}.cvtkAW_footStrip{white-space:nowrap;align-items:center;gap:6px;padding-right:20px;font-size:12px;display:flex;overflow:hidden}.cvtkAW_footStrip svg{opacity:.65;flex:none;display:block}.cvtkAW_footStripProvider{text-overflow:ellipsis;flex:none;max-width:45%;font-weight:500;overflow:hidden}.cvtkAW_footStripLabel{opacity:.65;text-overflow:ellipsis;overflow:hidden}.cvtkAW_footStripValue{font-variant-numeric:tabular-nums;margin-left:auto;font-weight:600}[data-dsh-frame][data-sidebar-collapsed] .cvtkAW_footCard,[data-sidebar-collapsed] .cvtkAW_footCard{display:none}";
193
209
  const tagId = "@linxin666/dsh-usage/packages/dsh-usage/src/client/usage.module.css";
194
210
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
195
211
  const tag = document.createElement("style");
@@ -218,6 +234,9 @@ window.__ModuleLoader__.load({
218
234
  "chartTokens": "cvtkAW_chartTokens",
219
235
  "currentBadge": "cvtkAW_currentBadge",
220
236
  "currentProvider": "cvtkAW_currentProvider",
237
+ "dayPicker": "cvtkAW_dayPicker",
238
+ "dayPickerLabel": "cvtkAW_dayPickerLabel",
239
+ "daySelect": "cvtkAW_daySelect",
221
240
  "errorLine": "cvtkAW_errorLine",
222
241
  "footCard": "cvtkAW_footCard",
223
242
  "footCardCollapsed": "cvtkAW_footCardCollapsed",
@@ -305,6 +324,7 @@ window.__ModuleLoader__.load({
305
324
  }
306
325
  const DEEPSEEK = {
307
326
  ids: ["deepseek", "deepseek-official"],
327
+ familyOnlyIds: ["deepseek-account"],
308
328
  displayName: "DeepSeek",
309
329
  balance: {
310
330
  origin: "https://api.deepseek.com",
@@ -690,13 +710,268 @@ window.__ModuleLoader__.load({
690
710
  /**
691
711
  * Whether a provider route belongs to the official DeepSeek family: the only
692
712
  * family with a spend price book and a settings-section-owned env credential
693
- * (llm-deepseek) rather than a pi-ai profile. Drives the env fallback in
694
- * credential resolution and the fold-time cost stamping.
713
+ * (llm-deepseek) rather than a pi-ai profile. Drives the fold-time cost
714
+ * stamping, the client fold-time spend estimate, and the whale-yuan bank.
715
+ *
716
+ * Family membership is wider than the probe directory. The account route
717
+ * (deepseek-account) bills the same account but authenticates with the account
718
+ * token, so it prices and mints while `adapterFor()` still returns undefined
719
+ * for it and no probe or env-credential fallback can reach it. Every caller of
720
+ * this predicate is an accounting decision; the credential and probing
721
+ * decisions read `adapterFor()` instead, so the two never widen together
722
+ * (issue #1772).
695
723
  */
696
724
  function isDeepSeekProviderRoute(provider) {
697
- return adapterFor(provider) === DEEPSEEK;
725
+ if (adapterFor(provider) === DEEPSEEK) return true;
726
+ return DEEPSEEK.familyOnlyIds?.includes(provider) === true;
698
727
  }
699
728
  //#endregion
729
+ //#region src/core/holidays.ts
730
+ /**
731
+ * Chinese public-holiday dates, Beijing calendar days, as `YYYY-MM-DD`.
732
+ *
733
+ * The DeepSeek peak rule bills a public holiday off-peak in full, and the
734
+ * State Council publishes these dates per year, so they cannot be derived
735
+ * from a rule. This module is that data; `pricing.ts` keeps the arithmetic.
736
+ *
737
+ * Adjusted workdays are deliberately absent: the provider counts the
738
+ * calendar day, so an adjusted Saturday or Sunday is off-peak exactly like
739
+ * any other weekend and listing it would price it as peak.
740
+ *
741
+ * Source: the yearly schedules in bastengao/chinese-holidays-node
742
+ * (`data/<year>.json`, MIT). Only the `holiday` entries are taken; that
743
+ * package's runtime code (which fetches over the network) and its
744
+ * dependencies are not vendored.
745
+ *
746
+ * Coverage ends at the newest year below. A year with no entry is priced as
747
+ * if it had no holidays, which is the documented default of
748
+ * {@link PublicHolidayCalendar} in `pricing.ts`.
749
+ * @module @linxin666/dsh-usage/core/holidays
750
+ */
751
+ /** Public-holiday dates keyed by Beijing calendar year. */
752
+ const CHINESE_PUBLIC_HOLIDAYS = {
753
+ "2020": [
754
+ "2020-01-24",
755
+ "2020-01-25",
756
+ "2020-01-26",
757
+ "2020-01-27",
758
+ "2020-01-28",
759
+ "2020-01-29",
760
+ "2020-01-30",
761
+ "2020-04-04",
762
+ "2020-04-05",
763
+ "2020-04-06",
764
+ "2020-05-01",
765
+ "2020-05-02",
766
+ "2020-05-03",
767
+ "2020-05-04",
768
+ "2020-05-05",
769
+ "2020-06-25",
770
+ "2020-06-26",
771
+ "2020-06-27",
772
+ "2020-10-01",
773
+ "2020-10-02",
774
+ "2020-10-03",
775
+ "2020-10-04",
776
+ "2020-10-05",
777
+ "2020-10-06",
778
+ "2020-10-07",
779
+ "2020-10-08"
780
+ ],
781
+ "2021": [
782
+ "2021-01-01",
783
+ "2021-01-02",
784
+ "2021-01-03",
785
+ "2021-02-11",
786
+ "2021-02-12",
787
+ "2021-02-13",
788
+ "2021-02-14",
789
+ "2021-02-15",
790
+ "2021-02-16",
791
+ "2021-02-17",
792
+ "2021-04-03",
793
+ "2021-04-04",
794
+ "2021-04-05",
795
+ "2021-05-01",
796
+ "2021-05-02",
797
+ "2021-05-03",
798
+ "2021-05-04",
799
+ "2021-05-05",
800
+ "2021-06-12",
801
+ "2021-06-13",
802
+ "2021-06-14",
803
+ "2021-09-19",
804
+ "2021-09-20",
805
+ "2021-09-21",
806
+ "2021-10-01",
807
+ "2021-10-02",
808
+ "2021-10-03",
809
+ "2021-10-04",
810
+ "2021-10-05",
811
+ "2021-10-06",
812
+ "2021-10-07"
813
+ ],
814
+ "2022": [
815
+ "2022-01-01",
816
+ "2022-01-02",
817
+ "2022-01-03",
818
+ "2022-01-31",
819
+ "2022-02-01",
820
+ "2022-02-02",
821
+ "2022-02-03",
822
+ "2022-02-04",
823
+ "2022-02-05",
824
+ "2022-02-06",
825
+ "2022-04-03",
826
+ "2022-04-04",
827
+ "2022-04-05",
828
+ "2022-04-30",
829
+ "2022-05-01",
830
+ "2022-05-02",
831
+ "2022-05-03",
832
+ "2022-05-04",
833
+ "2022-06-03",
834
+ "2022-06-04",
835
+ "2022-06-05",
836
+ "2022-09-10",
837
+ "2022-09-11",
838
+ "2022-09-12",
839
+ "2022-10-01",
840
+ "2022-10-02",
841
+ "2022-10-03",
842
+ "2022-10-04",
843
+ "2022-10-05",
844
+ "2022-10-06",
845
+ "2022-10-07"
846
+ ],
847
+ "2023": [
848
+ "2022-12-31",
849
+ "2023-01-01",
850
+ "2023-01-02",
851
+ "2023-01-21",
852
+ "2023-01-22",
853
+ "2023-01-23",
854
+ "2023-01-24",
855
+ "2023-01-25",
856
+ "2023-01-26",
857
+ "2023-01-27",
858
+ "2023-04-29",
859
+ "2023-04-30",
860
+ "2023-05-01",
861
+ "2023-05-02",
862
+ "2023-05-03",
863
+ "2023-06-22",
864
+ "2023-06-23",
865
+ "2023-06-24",
866
+ "2023-09-29",
867
+ "2023-09-30",
868
+ "2023-10-01",
869
+ "2023-10-02",
870
+ "2023-10-03",
871
+ "2023-10-04",
872
+ "2023-10-05",
873
+ "2023-10-06"
874
+ ],
875
+ "2024": [
876
+ "2023-12-30",
877
+ "2023-12-31",
878
+ "2024-01-01",
879
+ "2024-02-10",
880
+ "2024-02-11",
881
+ "2024-02-12",
882
+ "2024-02-13",
883
+ "2024-02-14",
884
+ "2024-02-15",
885
+ "2024-02-16",
886
+ "2024-02-17",
887
+ "2024-04-04",
888
+ "2024-04-05",
889
+ "2024-04-06",
890
+ "2024-05-01",
891
+ "2024-05-02",
892
+ "2024-05-03",
893
+ "2024-05-04",
894
+ "2024-05-05",
895
+ "2024-06-08",
896
+ "2024-06-09",
897
+ "2024-06-10",
898
+ "2024-09-15",
899
+ "2024-09-16",
900
+ "2024-09-17",
901
+ "2024-10-01",
902
+ "2024-10-02",
903
+ "2024-10-03",
904
+ "2024-10-04",
905
+ "2024-10-05",
906
+ "2024-10-06",
907
+ "2024-10-07"
908
+ ],
909
+ "2025": [
910
+ "2025-01-28",
911
+ "2025-01-29",
912
+ "2025-01-30",
913
+ "2025-01-31",
914
+ "2025-02-01",
915
+ "2025-02-02",
916
+ "2025-02-03",
917
+ "2025-02-04",
918
+ "2025-04-04",
919
+ "2025-04-05",
920
+ "2025-04-06",
921
+ "2025-05-01",
922
+ "2025-05-02",
923
+ "2025-05-03",
924
+ "2025-05-04",
925
+ "2025-05-05",
926
+ "2025-05-31",
927
+ "2025-06-01",
928
+ "2025-06-02",
929
+ "2025-10-01",
930
+ "2025-10-02",
931
+ "2025-10-03",
932
+ "2025-10-04",
933
+ "2025-10-05",
934
+ "2025-10-06",
935
+ "2025-10-07",
936
+ "2025-10-08"
937
+ ],
938
+ "2026": [
939
+ "2026-01-01",
940
+ "2026-01-02",
941
+ "2026-01-03",
942
+ "2026-02-15",
943
+ "2026-02-16",
944
+ "2026-02-17",
945
+ "2026-02-18",
946
+ "2026-02-19",
947
+ "2026-02-20",
948
+ "2026-02-21",
949
+ "2026-02-22",
950
+ "2026-02-23",
951
+ "2026-04-04",
952
+ "2026-04-05",
953
+ "2026-04-06",
954
+ "2026-05-01",
955
+ "2026-05-02",
956
+ "2026-05-03",
957
+ "2026-05-04",
958
+ "2026-05-05",
959
+ "2026-06-19",
960
+ "2026-06-20",
961
+ "2026-06-21",
962
+ "2026-09-25",
963
+ "2026-09-26",
964
+ "2026-09-27",
965
+ "2026-10-01",
966
+ "2026-10-02",
967
+ "2026-10-03",
968
+ "2026-10-04",
969
+ "2026-10-05",
970
+ "2026-10-06",
971
+ "2026-10-07"
972
+ ]
973
+ };
974
+ //#endregion
700
975
  //#region src/core/pricing.ts
701
976
  /** The published peak windows: weekday 09:00-12:00 and 14:00-18:00. */
702
977
  const PEAK_WINDOWS = [{
@@ -712,23 +987,52 @@ window.__ModuleLoader__.load({
712
987
  return PEAK_WINDOWS.find((window) => minuteOfDay >= window.from && minuteOfDay < window.to);
713
988
  }
714
989
  /**
990
+ * The default calendar: the published Chinese public-holiday table, so a holiday
991
+ * weekday prices off-peak instead of over-reporting at the peak rate. A year the
992
+ * table does not cover holds no dates and falls back to peak on weekdays, which
993
+ * is the safe direction to be wrong in: the estimate reads high rather than low.
994
+ */
995
+ const CN_PUBLIC_HOLIDAYS = { isPublicHoliday: (date) => {
996
+ const year = date.slice(0, 4);
997
+ if (Number(year) > 2026) return false;
998
+ return CHINESE_PUBLIC_HOLIDAYS[year]?.includes(date) ?? false;
999
+ } };
1000
+ /** The Beijing-time `YYYY-MM-DD` calendar day of `ms` (UTC+8 has no DST, so the shift is exact). */
1001
+ function beijingDate(ms) {
1002
+ const shifted = new Date(ms + BEIJING_UTC_OFFSET_MS);
1003
+ const month = `${shifted.getUTCMonth() + 1}`.padStart(2, "0");
1004
+ const day = `${shifted.getUTCDate()}`.padStart(2, "0");
1005
+ return `${shifted.getUTCFullYear()}-${month}-${day}`;
1006
+ }
1007
+ /**
1008
+ * Whether `ms` falls on a peak-eligible Beijing day: Monday-Friday that is
1009
+ * not a public holiday. A Saturday or Sunday is never eligible, including on
1010
+ * an adjusted workday — the provider counts the calendar day, not the
1011
+ * working schedule.
1012
+ */
1013
+ function isPeakDay(ms, calendar) {
1014
+ const weekday = new Date(ms + BEIJING_UTC_OFFSET_MS).getUTCDay();
1015
+ if (weekday < 1 || weekday > 5) return false;
1016
+ return !calendar.isPublicHoliday(beijingDate(ms));
1017
+ }
1018
+ /**
715
1019
  * The DeepSeek billing period at `ms`, plus when it next flips. The clock is
716
1020
  * Beijing time regardless of the host timezone (UTC+8 has no DST, so a fixed
717
1021
  * shift is exact). `boundaryMs` is the instant the current period ends — the
718
1022
  * window's close while peaking, the next window's open otherwise.
719
1023
  */
720
- function deepseekPeriodAt(ms) {
1024
+ function deepseekPeriodAt(ms, calendar = CN_PUBLIC_HOLIDAYS) {
721
1025
  const shifted = new Date(ms + BEIJING_UTC_OFFSET_MS);
722
- const weekday = shifted.getUTCDay();
723
1026
  const minuteOfDay = shifted.getUTCHours() * 60 + shifted.getUTCMinutes();
724
- const current = weekday >= 1 && weekday <= 5 ? withinWindow(minuteOfDay) : void 0;
1027
+ const current = isPeakDay(ms, calendar) ? withinWindow(minuteOfDay) : void 0;
725
1028
  if (current !== void 0) return {
726
1029
  peak: true,
727
1030
  boundaryMs: ms + (current.to - minuteOfDay) * 6e4 - shifted.getUTCSeconds() * 1e3 - shifted.getUTCMilliseconds()
728
1031
  };
729
1032
  for (let dayOffset = 0; dayOffset < 8; dayOffset += 1) {
730
- const day = new Date(ms + BEIJING_UTC_OFFSET_MS + dayOffset * 864e5);
731
- if (day.getUTCDay() < 1 || day.getUTCDay() > 5) continue;
1033
+ const dayStartMs = ms + dayOffset * 864e5;
1034
+ if (!isPeakDay(dayStartMs, calendar)) continue;
1035
+ const day = new Date(dayStartMs + BEIJING_UTC_OFFSET_MS);
732
1036
  const realDayStart = Date.UTC(day.getUTCFullYear(), day.getUTCMonth(), day.getUTCDate()) - BEIJING_UTC_OFFSET_MS;
733
1037
  for (const window of PEAK_WINDOWS) {
734
1038
  if (dayOffset === 0 && window.from <= minuteOfDay) continue;
@@ -763,8 +1067,8 @@ window.__ModuleLoader__.load({
763
1067
  //#endregion
764
1068
  //#region src/client/voucher.ts
765
1069
  /**
766
- * The Whale-yuan voucher (鲸元券): the DeepSeek official family's retained
767
- * ledger totals stamped onto the banknote artwork as a denomination, ready
1070
+ * The Whale-yuan voucher (鲸元券): the mint family's retained ledger totals
1071
+ * stamped onto the banknote artwork as a denomination, ready
768
1072
  * to save or share. The canvas copy is deliberately locale-neutral (digits,
769
1073
  * latin captions, ISO dates) so the exported image needs no dictionary;
770
1074
  * everything user-facing around it lives in the section's locales. The pure
@@ -786,21 +1090,41 @@ window.__ModuleLoader__.load({
786
1090
  return `${date.getFullYear()}-${month}-${day}`;
787
1091
  }
788
1092
  /**
789
- * Sum the DeepSeek official family rows out of a usage window (both the
790
- * `deepseek` catalog alias and the live `deepseek-official` route fold into
791
- * one voucher). Undefined when the window is absent (older host) or the
792
- * family has no usage — a zero-token note mints nothing.
1093
+ * Provider route ids minted beside the DeepSeek official family: the MiMo
1094
+ * gateway, which a profile may run as its default route and which the ledger
1095
+ * records under its own route id. The bank counts the tokens a profile spends,
1096
+ * not only the ones DeepSeek bills. Route ids rather than adapter families
1097
+ * because minting is an accounting decision that must never widen the
1098
+ * credential or probing paths — the same split `isDeepSeekProviderRoute()`
1099
+ * keeps against `adapterFor()` (issue #1772). An empty list mints exactly the
1100
+ * official family, which is how a profile that never runs MiMo behaves.
1101
+ */
1102
+ const EXTRA_MINT_ROUTE_IDS = ["mimo"];
1103
+ /** Whether one provider route's ledger rows mint whale yuan. */
1104
+ function mintsWhaleYuan(provider) {
1105
+ return isDeepSeekProviderRoute(provider) || EXTRA_MINT_ROUTE_IDS.includes(provider);
1106
+ }
1107
+ /**
1108
+ * Sum the mint family's rows out of a usage window: the whole DeepSeek
1109
+ * official family (the `deepseek` catalog alias, the live `deepseek-official`
1110
+ * route and the signed-in `deepseek-account` route all fold into one voucher)
1111
+ * plus {@link EXTRA_MINT_ROUTE_IDS}. Undefined when the window is absent
1112
+ * (older host) or the family has no usage — a zero-token note mints nothing.
1113
+ *
1114
+ * Only the priced family contributes `cost`: MiMo ships no price book, so it
1115
+ * mints tokens and calls while the spend line keeps reporting the official
1116
+ * family's fold-time estimate (and the observed-balance watch above it).
793
1117
  */
794
- function deepseekVoucherData(window) {
1118
+ function voucherData(window) {
795
1119
  if (window === void 0) return void 0;
796
1120
  let tokens = 0;
797
1121
  let calls = 0;
798
1122
  let cost = 0;
799
1123
  for (const row of window.providers) {
800
- if (!isDeepSeekProviderRoute(row.provider)) continue;
1124
+ if (!mintsWhaleYuan(row.provider)) continue;
801
1125
  tokens += totalTokens(row.totals);
802
1126
  calls += row.totals.calls;
803
- cost += row.totals.cost;
1127
+ if (isDeepSeekProviderRoute(row.provider)) cost += row.totals.cost;
804
1128
  }
805
1129
  if (tokens <= 0) return void 0;
806
1130
  return {
@@ -888,6 +1212,11 @@ window.__ModuleLoader__.load({
888
1212
  */
889
1213
  /** Poll cadence while the section is open. */
890
1214
  const SECTION_POLL_MS = 1e4;
1215
+ /**
1216
+ * The Token bank's default window: the whole retained ledger. It is a select
1217
+ * value rather than a date, so it can never collide with a day key.
1218
+ */
1219
+ const BANK_ALL_DAYS = "all";
891
1220
  /** Compact token count: 12345 -> 12.3k, 1234567 -> 1.23M. */
892
1221
  function formatTokens(value) {
893
1222
  if (!Number.isFinite(value) || value <= 0) return "0";
@@ -1041,13 +1370,83 @@ window.__ModuleLoader__.load({
1041
1370
  })]
1042
1371
  });
1043
1372
  }
1373
+ /**
1374
+ * Fetch the day a picker selected, or stay idle for the default window. Today
1375
+ * never fetches: the overview already carries it live, so switching back to
1376
+ * today is instant and keeps counting with the poll. A superseded selection
1377
+ * never lands (the effect cancels), and a failed load reports its own message
1378
+ * instead of leaving the card on a stale day.
1379
+ */
1380
+ function useDayView(loadDay, date, today) {
1381
+ const [load, setLoad] = (0, react.useState)(void 0);
1382
+ (0, react.useEffect)(() => {
1383
+ if (date === void 0 || date === today) {
1384
+ setLoad((previous) => previous === void 0 ? previous : void 0);
1385
+ return;
1386
+ }
1387
+ let cancelled = false;
1388
+ setLoad({ status: "loading" });
1389
+ loadDay(date).then((view) => {
1390
+ if (!cancelled) setLoad({
1391
+ status: "ready",
1392
+ view
1393
+ });
1394
+ }, (error) => {
1395
+ if (!cancelled) setLoad({
1396
+ status: "error",
1397
+ error: error instanceof Error ? error.message : String(error)
1398
+ });
1399
+ });
1400
+ return () => {
1401
+ cancelled = true;
1402
+ };
1403
+ }, [
1404
+ date,
1405
+ today,
1406
+ loadDay
1407
+ ]);
1408
+ return load;
1409
+ }
1410
+ /**
1411
+ * The day picker: today plus every retained day that recorded usage, newest
1412
+ * first (the host serves the list ascending). Without that list (an older host
1413
+ * document) no picker renders and the card stays on its default window.
1414
+ */
1415
+ function DayPicker(props) {
1416
+ const { value, options, today, leading, onSelect, part } = props;
1417
+ if (options.length === 0) return null;
1418
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1419
+ className: usage_module_css_default.dayPicker,
1420
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1421
+ className: usage_module_css_default.dayPickerLabel,
1422
+ htmlFor: "dsh-usage-day-" + part,
1423
+ children: t("usage.day.label")
1424
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1425
+ id: "dsh-usage-day-" + part,
1426
+ className: usage_module_css_default.daySelect,
1427
+ value,
1428
+ onChange: (event) => {
1429
+ onSelect(event.target.value);
1430
+ },
1431
+ children: [leading !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1432
+ value: leading.value,
1433
+ children: leading.label
1434
+ }), options.map((date) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1435
+ value: date,
1436
+ children: date === today ? t("usage.day.today") : date
1437
+ }, date))]
1438
+ })]
1439
+ });
1440
+ }
1044
1441
  /** The section component; the slot merges the face into these props. */
1045
1442
  function UsageSectionCard(props) {
1046
- const { store, poll, refresh, settings } = props;
1443
+ const { store, poll, refresh, loadDay, settings } = props;
1047
1444
  const ui = (0, react.useSyncExternalStore)(store.subscribe, store.getSnapshot);
1048
1445
  const settingsSnapshot = settings.getSnapshot();
1049
1446
  const settingsValue = settingsSnapshot.value ?? {};
1050
1447
  const [tab, setTab] = (0, react.useState)("usage");
1448
+ const [usageDay, setUsageDay] = (0, react.useState)(void 0);
1449
+ const [bankDay, setBankDay] = (0, react.useState)(void 0);
1051
1450
  const [refreshing, setRefreshing] = (0, react.useState)(false);
1052
1451
  const [, bumpSettings] = (0, react.useState)(0);
1053
1452
  (0, react.useEffect)(() => settings.subscribe(() => bumpSettings((count) => count + 1)), [settings]);
@@ -1076,6 +1475,22 @@ window.__ModuleLoader__.load({
1076
1475
  };
1077
1476
  }, [poll, enabled]);
1078
1477
  const snapshot = ui.snapshot;
1478
+ const todayDate = snapshot?.usage.today.date;
1479
+ const dayOptions = snapshot === null ? [] : [...new Set([todayDate, ...snapshot.usage.availableDays ?? []].filter((date) => date !== void 0))].sort().reverse();
1480
+ const usageSelection = usageDay !== void 0 && dayOptions.includes(usageDay) ? usageDay : void 0;
1481
+ const bankSelection = bankDay !== void 0 && dayOptions.includes(bankDay) ? bankDay : void 0;
1482
+ const selectedDay = usageSelection ?? todayDate;
1483
+ const isToday = selectedDay === todayDate;
1484
+ const usageDayLoad = useDayView(loadDay, usageSelection, todayDate);
1485
+ const bankDayLoad = useDayView(loadDay, bankSelection, todayDate);
1486
+ const day = isToday ? snapshot?.usage.today : usageDayLoad?.view;
1487
+ const bankDayView = bankSelection === void 0 ? void 0 : bankSelection === todayDate ? snapshot?.usage.today : bankDayLoad?.view;
1488
+ const bankWindow = bankSelection === void 0 ? snapshot?.usage.all ?? snapshot?.usage.range : bankDayView === void 0 ? void 0 : {
1489
+ from: bankDayView.date,
1490
+ to: bankDayView.date,
1491
+ totals: bankDayView.totals,
1492
+ providers: bankDayView.providers
1493
+ };
1079
1494
  const onRefresh = () => {
1080
1495
  setRefreshing(true);
1081
1496
  try {
@@ -1100,7 +1515,7 @@ window.__ModuleLoader__.load({
1100
1515
  const current = snapshot.current;
1101
1516
  const currentProvider = snapshot.providers.find((provider) => provider.provider === current.provider);
1102
1517
  const deepseekPeriod = deepseekPeriodAt(Date.now());
1103
- const deepseekVisible = current.provider !== void 0 && isDeepSeekProviderRoute(current.provider) || snapshot.usage.today.providers.some((row) => isDeepSeekProviderRoute(row.provider));
1518
+ const deepseekVisible = isToday && (current.provider !== void 0 && isDeepSeekProviderRoute(current.provider) || snapshot.usage.today.providers.some((row) => isDeepSeekProviderRoute(row.provider)));
1104
1519
  const planProviders = snapshot.providers.filter((provider) => isConfigured(provider) && (provider.planSupported === true || provider.planSupported === void 0 && provider.plan !== void 0));
1105
1520
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1106
1521
  className: usage_module_css_default.section,
@@ -1168,31 +1583,46 @@ window.__ModuleLoader__.load({
1168
1583
  children: [
1169
1584
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1170
1585
  className: usage_module_css_default.cardTitle,
1171
- children: t("usage.today")
1586
+ children: isToday ? t("usage.today") : t("usage.day.title", { date: selectedDay ?? "" })
1587
+ }),
1588
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DayPicker, {
1589
+ part: "usage",
1590
+ value: selectedDay ?? "",
1591
+ options: dayOptions,
1592
+ today: todayDate ?? "",
1593
+ onSelect: (date) => {
1594
+ setUsageDay(date === todayDate ? void 0 : date);
1595
+ }
1172
1596
  }),
1173
1597
  deepseekVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1174
1598
  className: usage_module_css_default.muted,
1175
1599
  "data-dsh-part": "peak-status",
1176
1600
  children: t(deepseekPeriod.peak ? "usage.peak.on" : "usage.peak.off", { time: formatClock$1(deepseekPeriod.boundaryMs) })
1177
1601
  }),
1178
- snapshot.usage.today.totals.calls === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1602
+ usageDayLoad?.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1603
+ className: usage_module_css_default.errorLine,
1604
+ children: t("usage.day.error", { error: usageDayLoad.error ?? "" })
1605
+ }) : day === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1606
+ className: usage_module_css_default.muted,
1607
+ children: t("usage.day.loading")
1608
+ }) : day.totals.calls === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1179
1609
  className: usage_module_css_default.muted,
1180
- children: t("usage.noData")
1181
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TotalsRow, { totals: snapshot.usage.today.totals }),
1182
- snapshot.usage.today.totals.cost > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1610
+ children: isToday ? t("usage.noData") : t("usage.day.empty")
1611
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TotalsRow, { totals: day.totals }),
1612
+ (day?.totals.cost ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1183
1613
  className: usage_module_css_default.providerRow,
1184
1614
  "data-dsh-part": "today-cost",
1185
1615
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1186
1616
  className: usage_module_css_default.providerName,
1187
- children: t("usage.today.cost")
1617
+ children: isToday ? t("usage.today.cost") : t("usage.day.cost")
1188
1618
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1189
1619
  className: usage_module_css_default.providerTokens,
1190
- children: formatCost(snapshot.usage.today.totals.cost)
1620
+ children: formatCost(day?.totals.cost ?? 0)
1191
1621
  })]
1192
1622
  }),
1193
- snapshot.usage.today.providers.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1623
+ (day?.providers.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1194
1624
  "data-dsh-part": "provider-list",
1195
- children: snapshot.usage.today.providers.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1625
+ children: (day?.providers ?? []).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1196
1626
  className: usage_module_css_default.providerRow,
1197
1627
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1198
1628
  className: usage_module_css_default.providerName,
@@ -1260,10 +1690,24 @@ window.__ModuleLoader__.load({
1260
1690
  provider,
1261
1691
  current: current.provider
1262
1692
  }, provider.provider))),
1263
- tab === "bank" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VoucherCard, {
1264
- window: snapshot.usage.all ?? snapshot.usage.range,
1265
- observedSpend: snapshot.usage.observedSpend
1266
- })
1693
+ tab === "bank" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DayPicker, {
1694
+ part: "bank",
1695
+ value: bankSelection ?? BANK_ALL_DAYS,
1696
+ options: dayOptions,
1697
+ today: todayDate ?? "",
1698
+ leading: {
1699
+ value: BANK_ALL_DAYS,
1700
+ label: t("usage.bank.windowAll")
1701
+ },
1702
+ onSelect: (date) => {
1703
+ setBankDay(date === BANK_ALL_DAYS ? void 0 : date);
1704
+ }
1705
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VoucherCard, {
1706
+ window: bankWindow,
1707
+ observedSpend: bankSelection === void 0 ? snapshot.usage.observedSpend : void 0,
1708
+ loading: bankSelection !== void 0 && bankDayLoad?.status === "loading",
1709
+ ...bankDayLoad?.status === "error" ? { error: bankDayLoad.error ?? "" } : {}
1710
+ })] })
1267
1711
  ]
1268
1712
  });
1269
1713
  }
@@ -1367,17 +1811,18 @@ window.__ModuleLoader__.load({
1367
1811
  return totals.inputTokens + totals.cacheReadTokens + totals.cacheWriteTokens + totals.outputTokens;
1368
1812
  }
1369
1813
  /**
1370
- * The Token 银行 card: the DeepSeek official family's retained-ledger usage
1371
- * minted onto the whale-yuan note at 1,000,000 tokens per whale yuan. The window
1372
- * prefers the host's whole-ledger aggregate and falls back to the 30-day
1373
- * trend when an older host serves no `all`; the spend line prefers the
1374
- * official balance watch and falls back to the fold-time estimate; the
1375
- * artwork draw failure degrades to an error line and never takes the
1376
- * section down.
1814
+ * The Token 银行 card: the mint family's (DeepSeek official + MiMo)
1815
+ * retained-ledger usage minted onto the whale-yuan note at 1,000,000 tokens
1816
+ * per whale yuan. The window is the whole retained ledger by default (the
1817
+ * host's aggregate, falling back to the 30-day trend when an older host serves
1818
+ * no `all`) or the single day the user picked; the spend line prefers the
1819
+ * official balance watch (whole window only) and falls back to the fold-time
1820
+ * estimate, which only the priced family feeds; the artwork draw failure
1821
+ * degrades to an error line and never takes the section down.
1377
1822
  */
1378
1823
  function VoucherCard(props) {
1379
- const { window: ledger, observedSpend } = props;
1380
- const data = deepseekVoucherData(ledger);
1824
+ const { window: ledger, observedSpend, loading, error } = props;
1825
+ const data = voucherData(ledger);
1381
1826
  const canvasRef = (0, react.useRef)(null);
1382
1827
  const [drawError, setDrawError] = (0, react.useState)(void 0);
1383
1828
  (0, react.useEffect)(() => {
@@ -1434,7 +1879,13 @@ window.__ModuleLoader__.load({
1434
1879
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1435
1880
  className: usage_module_css_default.cardTitle,
1436
1881
  children: t("usage.bank.title")
1437
- }), data === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1882
+ }), error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1883
+ className: usage_module_css_default.errorLine,
1884
+ children: t("usage.day.error", { error })
1885
+ }) : loading === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1886
+ className: usage_module_css_default.muted,
1887
+ children: t("usage.day.loading")
1888
+ }) : data === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1438
1889
  className: usage_module_css_default.muted,
1439
1890
  children: t("usage.bank.noUsage")
1440
1891
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
@@ -2221,6 +2672,7 @@ window.__ModuleLoader__.load({
2221
2672
  }
2222
2673
  const usageApi = {
2223
2674
  overview: () => usageFetch("api/dsh-usage/overview", "GET"),
2675
+ day: async (date) => (await usageFetch("api/dsh-usage/day?date=" + encodeURIComponent(date), "GET")).day,
2224
2676
  refresh: () => usageFetch("api/dsh-usage/refresh", "POST")
2225
2677
  };
2226
2678
  /**
@@ -2290,10 +2742,12 @@ window.__ModuleLoader__.load({
2290
2742
  store.actions.setState("error", error instanceof Error ? error.message : String(error));
2291
2743
  });
2292
2744
  };
2745
+ const loadDay = (date) => usageApi.day(date);
2293
2746
  const face = () => ({
2294
2747
  store,
2295
2748
  poll,
2296
2749
  refresh,
2750
+ loadDay,
2297
2751
  settings: settingsForm
2298
2752
  });
2299
2753
  const disposeFootCard = mountUsageFootCard({