@lancecheney/dsh-deepseek-balance 0.1.2 → 0.1.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.
Files changed (3) hide show
  1. package/lib/client.js +30 -5
  2. package/lib/index.js +111 -62
  3. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -22,13 +22,35 @@ window.__ModuleLoader__.load({
22
22
  const C = { root: "Dbg1_root", num: "Dbg1_num", sep: "Dbg1_sep", chip: "Dbg1_chip", peak: "Dbg1_peak", offPeak: "Dbg1_offPeak", legacy: "Dbg1_legacy", dimmed: "Dbg1_dimmed", plus: "Dbg1_plus", unit: "Dbg1_unit" };
23
23
  const P = { backdrop: "Dp1_backdrop", panel: "Dp1_panel", head: "Dp1_head", avatar: "Dp1_avatar", name: "Dp1_name", key: "Dp1_key", close: "Dp1_close", body: "Dp1_body", stats: "Dp1_stats", statItem: "Dp1_statItem", statValue: "Dp1_statValue", statLabel: "Dp1_statLabel", sepBar: "Dp1_sepBar", balance: "Dp1_balance", balanceBlock: "Dp1_balanceBlock", balanceBlockLabel: "Dp1_balanceBlockLabel", balanceBlockValue: "Dp1_balanceBlockValue", btn: "Dp1_btn", btnPrimary: "Dp1_btnPrimary", section: "Dp1_section", title: "Dp1_title", row: "Dp1_row", twoCol: "Dp1_twoCol", rowTitle: "Dp1_rowTitle", rowTitleGray: "Dp1_rowTitleGray", rowVal: "Dp1_rowVal", rank: "Dp1_rank", monthNav: "Dp1_monthNav", monthGrids: "Dp1_monthGrids", monthGroup: "Dp1_monthGroup", monthGroupTitle: "Dp1_monthGroupTitle", grid: "Dp1_grid", cell: "Dp1_cell", cellFlat: "Dp1_cellFlat", cellPeak: "Dp1_cellPeak", cellOff: "Dp1_cellOff", cellBlue: "Dp1_cellBlue", legend: "Dp1_legend", dot: "Dp1_dot", nameRow: "Dp1_nameRow", edit: "Dp1_edit", editRow: "Dp1_editRow", editInput: "Dp1_editInput" };
24
24
 
25
- const MODEL_META = { "deepseek-v4-pro": { label: "DeepSeek-V4-Pro" }, "deepseek-v4-flash": { label: "DeepSeek-V4-Flash" } };
25
+ const MODEL_META = { "deepseek-v4-pro": { label: "DeepSeek-V4-Pro" }, "deepseek-flash": { label: "DeepSeek-Flash" }, "deepseek-v4-flash": { label: "DeepSeek-Flash" }, "deepseek-v4-flash-vision-exp": { label: "DeepSeek-Flash (vision)" } };
26
26
  const FALLBACK_PRICING = {
27
27
  effectiveFrom: "2026-08-17T00:00:00+08:00",
28
28
  weekendFrom: "2026-08-23T00:00:00+08:00",
29
29
  currencies: {
30
- CNY: { symbol: "¥", models: { "deepseek-v4-pro": { legacy: { hit: 0.025, miss: 3.0, output: 6.0 }, peak: { hit: 0.30, miss: 9.0, output: 27.0 }, offPeak: { hit: 0.15, miss: 4.5, output: 13.5 } }, "deepseek-v4-flash": { legacy: { hit: 0.02, miss: 1.0, output: 2.0 }, peak: { hit: 0.10, miss: 3.0, output: 9.0 }, offPeak: { hit: 0.05, miss: 1.5, output: 4.5 } }, "deepseek-v4-flash-vision-exp": { legacy: { hit: 0.02, miss: 1.0, output: 2.0 }, peak: { hit: 0.10, miss: 3.0, output: 9.0 }, offPeak: { hit: 0.05, miss: 1.5, output: 4.5 } } } },
31
- USD: { symbol: "$", models: { "deepseek-v4-pro": { legacy: { hit: 0.003625, miss: 0.435, output: 0.87 }, peak: { hit: 0.044, miss: 1.32, output: 3.96 }, offPeak: { hit: 0.022, miss: 0.66, output: 1.98 } }, "deepseek-v4-flash": { legacy: { hit: 0.0028, miss: 0.14, output: 0.28 }, peak: { hit: 0.014, miss: 0.44, output: 1.32 }, offPeak: { hit: 0.007, miss: 0.22, output: 0.66 } }, "deepseek-v4-flash-vision-exp": { legacy: { hit: 0.0028, miss: 0.14, output: 0.28 }, peak: { hit: 0.014, miss: 0.44, output: 1.32 }, offPeak: { hit: 0.007, miss: 0.22, output: 0.66 } } } }
30
+ CNY: { symbol: "¥", models: {
31
+ "deepseek-flash": { eras: [
32
+ { from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
33
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.05, miss: 1.5, output: 4.5 }, peak: { hit: 0.10, miss: 3.0, output: 9.0 } },
34
+ { from: null, legacy: { hit: 0.02, miss: 1.0, output: 2.0 } }
35
+ ] },
36
+ "deepseek-v4-pro": { eras: [
37
+ { from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
38
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.15, miss: 4.5, output: 13.5 }, peak: { hit: 0.30, miss: 9.0, output: 27.0 } },
39
+ { from: null, legacy: { hit: 0.025, miss: 3.0, output: 6.0 } }
40
+ ] }
41
+ } },
42
+ USD: { symbol: "$", models: {
43
+ "deepseek-flash": { eras: [
44
+ { from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
45
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.007, miss: 0.22, output: 0.66 }, peak: { hit: 0.014, miss: 0.44, output: 1.32 } },
46
+ { from: null, legacy: { hit: 0.0028, miss: 0.14, output: 0.28 } }
47
+ ] },
48
+ "deepseek-v4-pro": { eras: [
49
+ { from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
50
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.022, miss: 0.66, output: 1.98 }, peak: { hit: 0.044, miss: 1.32, output: 3.96 } },
51
+ { from: null, legacy: { hit: 0.003625, miss: 0.435, output: 0.87 } }
52
+ ] }
53
+ } }
32
54
  }
33
55
  };
34
56
  const DEFAULT_MODEL = "deepseek-v4-pro";
@@ -108,8 +130,11 @@ window.__ModuleLoader__.load({
108
130
  const isPeak = period === "peak";
109
131
  const isLegacy = period === "legacy";
110
132
  const model = models[modelId] || models[DEFAULT_MODEL] || FALLBACK_PRICING.currencies.CNY.models[DEFAULT_MODEL];
111
- const p = (period === "peak" ? model.peak : period === "offPeak" ? model.offPeak : model.legacy) || model.peak;
112
- const outputPrice = fmtPrice(p.output);
133
+ const eras = Array.isArray(model.eras) ? model.eras : [];
134
+ const nowMs = Date.now();
135
+ const era = eras.find((e) => e.from != null && nowMs >= Date.parse(e.from)) || eras[eras.length - 1] || model;
136
+ const p = (period === "peak" ? era.peak : period === "offPeak" ? era.offPeak : era.legacy) || era.peak || era.offPeak || era.legacy;
137
+ const outputPrice = fmtPrice(p ? p.output : "—");
113
138
  const cost = state.usage && state.usage.spend ? state.usage.spend.total : null;
114
139
  const plus = reasoningEffort === "max" ? "++" : reasoningEffort === "off" ? "" : "+";
115
140
  const periodClass = isLegacy ? C.legacy : isPeak ? C.peak : C.offPeak;
package/lib/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
2
- import { settingsNamespace } from "@deepseek-ai/dsh-settings";
3
2
  import { z } from "zod";
4
3
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
5
4
  import { homedir } from "node:os";
@@ -26,7 +25,10 @@ const PRICING_CN_URL = "https://api-docs.deepseek.com/zh-cn/quick_start/pricing/
26
25
  const PRICING_US_URL = "https://api-docs.deepseek.com/quick_start/pricing/";
27
26
  const PRICING_FETCH_TIMEOUT_MS = 15000;
28
27
 
29
- /** Last-known-good prices: legacy + the 2026-08-17 peak/off-peak table, per currency. */
28
+ /** Prices per currency. Each model carries an `eras` list (newest first): the
29
+ * currently effective peak/off-peak table plus historical tiers, so tokens are
30
+ * billed at the price in force when they were used. `from: null` is the
31
+ * pre-peak/off-peak legacy (flat) tier. */
30
32
  const FALLBACK_PRICING = {
31
33
  effectiveFrom: "2026-08-17T00:00:00+08:00",
32
34
  weekendFrom: "2026-08-23T00:00:00+08:00",
@@ -34,46 +36,74 @@ const FALLBACK_PRICING = {
34
36
  CNY: {
35
37
  symbol: "¥",
36
38
  models: {
37
- "deepseek-v4-flash": {
38
- legacy: { hit: 0.02, miss: 1.0, output: 2.0 },
39
- peak: { hit: 0.10, miss: 3.0, output: 9.0 },
40
- offPeak: { hit: 0.05, miss: 1.5, output: 4.5 }
39
+ "deepseek-flash": {
40
+ eras: [
41
+ { from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
42
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.05, miss: 1.5, output: 4.5 }, peak: { hit: 0.10, miss: 3.0, output: 9.0 } },
43
+ { from: null, legacy: { hit: 0.02, miss: 1.0, output: 2.0 } }
44
+ ]
41
45
  },
42
46
  "deepseek-v4-pro": {
43
- legacy: { hit: 0.025, miss: 3.0, output: 6.0 },
44
- peak: { hit: 0.30, miss: 9.0, output: 27.0 },
45
- offPeak: { hit: 0.15, miss: 4.5, output: 13.5 }
46
- },
47
- "deepseek-v4-flash-vision-exp": {
48
- legacy: { hit: 0.02, miss: 1.0, output: 2.0 },
49
- peak: { hit: 0.10, miss: 3.0, output: 9.0 },
50
- offPeak: { hit: 0.05, miss: 1.5, output: 4.5 }
47
+ eras: [
48
+ { from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.02, miss: 1.0, output: 4.0 }, peak: { hit: 0.04, miss: 2.0, output: 8.0 } },
49
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.15, miss: 4.5, output: 13.5 }, peak: { hit: 0.30, miss: 9.0, output: 27.0 } },
50
+ { from: null, legacy: { hit: 0.025, miss: 3.0, output: 6.0 } }
51
+ ]
51
52
  }
52
53
  }
53
54
  },
54
55
  USD: {
55
56
  symbol: "$",
56
57
  models: {
57
- "deepseek-v4-flash": {
58
- legacy: { hit: 0.0028, miss: 0.14, output: 0.28 },
59
- peak: { hit: 0.014, miss: 0.44, output: 1.32 },
60
- offPeak: { hit: 0.007, miss: 0.22, output: 0.66 }
58
+ "deepseek-flash": {
59
+ eras: [
60
+ { from: "2026-09-10T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
61
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.007, miss: 0.22, output: 0.66 }, peak: { hit: 0.014, miss: 0.44, output: 1.32 } },
62
+ { from: null, legacy: { hit: 0.0028, miss: 0.14, output: 0.28 } }
63
+ ]
61
64
  },
62
65
  "deepseek-v4-pro": {
63
- legacy: { hit: 0.003625, miss: 0.435, output: 0.87 },
64
- peak: { hit: 0.044, miss: 1.32, output: 3.96 },
65
- offPeak: { hit: 0.022, miss: 0.66, output: 1.98 }
66
- },
67
- "deepseek-v4-flash-vision-exp": {
68
- legacy: { hit: 0.0028, miss: 0.14, output: 0.28 },
69
- peak: { hit: 0.014, miss: 0.44, output: 1.32 },
70
- offPeak: { hit: 0.007, miss: 0.22, output: 0.66 }
66
+ eras: [
67
+ { from: "2026-09-14T12:00:00+08:00", offPeak: { hit: 0.003, miss: 0.15, output: 0.6 }, peak: { hit: 0.006, miss: 0.3, output: 1.2 } },
68
+ { from: "2026-08-17T00:00:00+08:00", offPeak: { hit: 0.022, miss: 0.66, output: 1.98 }, peak: { hit: 0.044, miss: 1.32, output: 3.96 } },
69
+ { from: null, legacy: { hit: 0.003625, miss: 0.435, output: 0.87 } }
70
+ ]
71
71
  }
72
72
  }
73
73
  }
74
74
  }
75
75
  };
76
76
 
77
+ /** Legacy model names retired/renamed by DeepSeek; their requests are served by
78
+ * DeepSeek-V4.1-Flash and billed at the Flash price. */
79
+ const MODEL_ALIASES = {
80
+ "deepseek-v4-flash": "deepseek-flash",
81
+ "deepseek-v4-flash-vision-exp": "deepseek-flash"
82
+ };
83
+
84
+ function resolveModelId(rawModel) {
85
+ const id = typeof rawModel === "string" && rawModel.length > 0 ? rawModel : "";
86
+ return MODEL_ALIASES[id] || id;
87
+ }
88
+
89
+ /** Index of the price era in force at `time` (eras are newest-first). */
90
+ function priceEraIndex(modelId, time) {
91
+ const m = FALLBACK_PRICING.currencies.CNY.models[modelId];
92
+ if (!m || !Array.isArray(m.eras)) return 0;
93
+ for (let i = 0; i < m.eras.length; i++) {
94
+ const from = m.eras[i].from;
95
+ if (from === null || from === void 0 || time >= Date.parse(from)) return i;
96
+ }
97
+ return m.eras.length - 1;
98
+ }
99
+
100
+ /** Price era for a model at `time`, falling back to legacy/flat when unknown. */
101
+ function priceEraAt(modelId, time) {
102
+ const m = FALLBACK_PRICING.currencies.CNY.models[modelId];
103
+ if (!m || !Array.isArray(m.eras)) return null;
104
+ return m.eras[priceEraIndex(modelId, time)] || null;
105
+ }
106
+
77
107
  function json(res, status, body) {
78
108
  const payload = JSON.stringify(body);
79
109
  res.writeHead(status, {
@@ -87,7 +117,7 @@ function resolveSettingsSection(ctx) {
87
117
  try {
88
118
  const settings = ctx.get("settings");
89
119
  if (settings && typeof settings.get === "function") {
90
- return settings.get(settingsNamespace("llm-deepseek"));
120
+ return settings.get("llm-deepseek");
91
121
  }
92
122
  } catch {}
93
123
  return void 0;
@@ -147,16 +177,16 @@ const number = (match, index) => {
147
177
  return Number.isFinite(value) ? value : void 0;
148
178
  };
149
179
 
150
- /** Parse the zh-CN docs page: CNY peak/off-peak table (3 columns). */
180
+ /** Parse the zh-CN docs page: CNY peak/off-peak table (2 columns: flash, pro). */
151
181
  function parseCnPricing(html) {
152
182
  const text = stripTags(html);
153
183
  const grab = (label) => {
154
- const re = new RegExp(label + "\\s*空闲时段\\s*([\\d.]+)元\\s*([\\d.]+)元\\s*([\\d.]+)元\\s*高峰时段\\s*([\\d.]+)元\\s*([\\d.]+)元\\s*([\\d.]+)元");
184
+ const re = new RegExp(label + "\\s*空闲时段\\s*([\\d.]+)元\\s*([\\d.]+)元\\s*高峰时段\\s*([\\d.]+)元\\s*([\\d.]+)元");
155
185
  const m = text.match(re);
156
186
  if (!m) return void 0;
157
187
  return {
158
- offPeak: [number(m, 1), number(m, 2), number(m, 3)],
159
- peak: [number(m, 4), number(m, 5), number(m, 6)]
188
+ offPeak: [number(m, 1), number(m, 2)],
189
+ peak: [number(m, 3), number(m, 4)]
160
190
  };
161
191
  };
162
192
  const hit = grab("百万tokens输入\\s*(缓存命中)");
@@ -171,23 +201,22 @@ function parseCnPricing(html) {
171
201
 
172
202
  return {
173
203
  models: {
174
- "deepseek-v4-flash": mk(0),
175
- "deepseek-v4-pro": mk(1),
176
- "deepseek-v4-flash-vision-exp": mk(2)
204
+ "deepseek-flash": mk(0),
205
+ "deepseek-v4-pro": mk(1)
177
206
  }
178
207
  };
179
208
  }
180
209
 
181
- /** Parse the English docs page: USD peak/off-peak table (3 columns). */
210
+ /** Parse the English docs page: USD peak/off-peak table (2 columns: flash, pro). */
182
211
  function parseUsModels(html) {
183
212
  const text = stripTags(html);
184
213
  const grab = (label) => {
185
- const re = new RegExp(label + "\\s+OFF-PEAK\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)\\s+PEAK\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)", "i");
214
+ const re = new RegExp(label + "\\s+OFF-PEAK\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)\\s+PEAK\\s+\\$([\\d.]+)\\s+\\$([\\d.]+)", "i");
186
215
  const m = text.match(re);
187
216
  if (!m) return void 0;
188
217
  return {
189
- offPeak: [number(m, 1), number(m, 2), number(m, 3)],
190
- peak: [number(m, 4), number(m, 5), number(m, 6)]
218
+ offPeak: [number(m, 1), number(m, 2)],
219
+ peak: [number(m, 3), number(m, 4)]
191
220
  };
192
221
  };
193
222
  const hit = grab("1M INPUT TOKENS\\s*\\(CACHE HIT\\)");
@@ -202,9 +231,8 @@ function parseUsModels(html) {
202
231
 
203
232
  return {
204
233
  models: {
205
- "deepseek-v4-flash": mk(0),
206
- "deepseek-v4-pro": mk(1),
207
- "deepseek-v4-flash-vision-exp": mk(2)
234
+ "deepseek-flash": mk(0),
235
+ "deepseek-v4-pro": mk(1)
208
236
  }
209
237
  };
210
238
  }
@@ -212,15 +240,26 @@ function parseUsModels(html) {
212
240
  const pricing = { data: FALLBACK_PRICING, fetchedAt: 0, source: "fallback" };
213
241
  let pricingRefresh = null;
214
242
 
243
+ /** Merge freshly parsed current prices into the era in force right now. */
215
244
  function mergeLegacy(models, fallbackModels) {
216
245
  const result = {};
217
- for (const [id, m] of Object.entries(models)) {
218
- const fb = fallbackModels[id];
219
- result[id] = {
220
- ...(fb && fb.legacy ? { legacy: fb.legacy } : {}),
221
- peak: m.peak,
222
- offPeak: m.offPeak
223
- };
246
+ const now = Date.now();
247
+ for (const [id, fb] of Object.entries(fallbackModels)) {
248
+ const parsed = models[id];
249
+ if (!parsed || !Array.isArray(fb.eras)) {
250
+ result[id] = fb;
251
+ continue;
252
+ }
253
+ let curIdx = fb.eras.length - 1;
254
+ for (let i = 0; i < fb.eras.length; i++) {
255
+ const from = fb.eras[i].from;
256
+ if (from !== null && from !== void 0 && now >= Date.parse(from)) {
257
+ curIdx = i;
258
+ break;
259
+ }
260
+ }
261
+ const eras = fb.eras.map((era, i) => (i === curIdx ? { ...era, peak: parsed.peak, offPeak: parsed.offPeak } : era));
262
+ result[id] = { ...fb, eras };
224
263
  }
225
264
  return result;
226
265
  }
@@ -460,13 +499,16 @@ function aggregateSessions(archivedIds = []) {
460
499
  else if (r.type === "assistant/chunk" && r.data?.chunk?.type === "usage") usage = r.data.chunk.usage;
461
500
  if (usage && time !== null && dedupe.has(r)) {
462
501
  const t = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0) + (usage.cacheReadTokens ?? 0);
463
- const period = periodOfUsage(time, effectiveFromMs, weekendFromMs);
502
+ const modelId = resolveModelId(model);
503
+ const eraIdx = priceEraIndex(modelId, time);
504
+ const era = priceEraAt(modelId, time);
505
+ const period = era && era.legacy ? "flat" : periodOfUsage(time, effectiveFromMs, weekendFromMs);
464
506
  const dayKey = beijingDayKey(time);
465
507
  tokens += t;
466
508
  if (period === "peak") peakTokens += t;
467
509
  else if (period === "offPeak") offPeakTokens += t;
468
510
  else flatTokens += t;
469
- const mkModel = model ?? "";
511
+ const mkModel = `${modelId}@${eraIdx}`;
470
512
  const b = bucketsFrom(usage);
471
513
  dayTokens[dayKey] = dayTokens[dayKey] || {};
472
514
  dayTokens[dayKey][mkModel] = dayTokens[dayKey][mkModel] || { flat: zeroBucket(), peak: zeroBucket(), offPeak: zeroBucket() };
@@ -565,10 +607,9 @@ function computeSpend(summary, currency = "CNY") {
565
607
  pricing.data.currencies?.CNY ||
566
608
  FALLBACK_PRICING.currencies.CNY;
567
609
  const models = pricingSet.models || {};
568
- const defaultModel = models[DEFAULT_MODEL] || { legacy: null, peak: { miss: 0, hit: 0, output: 0 }, offPeak: { miss: 0, hit: 0, output: 0 } };
569
610
  const priceOf = (tokens, price) => (tokens || 0) * (price || 0) / 1e6;
570
- const bucketCost = (b, mm) => {
571
- if (!mm) return 0;
611
+ const eraCost = (b, era) => {
612
+ if (!era) return 0;
572
613
  const cost = (bucket, price) => {
573
614
  if (!price) return 0;
574
615
  return priceOf(bucket.uncachedInputTokens, price.miss)
@@ -576,22 +617,30 @@ function computeSpend(summary, currency = "CNY") {
576
617
  + priceOf(bucket.cacheReadTokens, price.hit)
577
618
  + priceOf(bucket.outputTokens, price.output);
578
619
  };
579
- return (mm.legacy ? cost(b.flat, mm.legacy) : 0) + cost(b.peak, mm.peak) + cost(b.offPeak, mm.offPeak);
620
+ if (era.legacy) return cost(b.flat, era.legacy);
621
+ return cost(b.peak, era.peak) + cost(b.offPeak, era.offPeak);
622
+ };
623
+ // Bucket keys are `${modelId}@${eraIndex}` so each token is billed at the
624
+ // price era in force when it was used.
625
+ const bucketCost = (b, key) => {
626
+ const at = typeof key === "string" ? key.lastIndexOf("@") : -1;
627
+ if (at < 0) return 0;
628
+ const modelId = key.slice(0, at);
629
+ const eraIdx = Number(key.slice(at + 1));
630
+ const mm = models[modelId];
631
+ if (!mm || !Array.isArray(mm.eras)) return 0;
632
+ const era = mm.eras[Number.isFinite(eraIdx) ? eraIdx : 0] || mm.eras[mm.eras.length - 1];
633
+ return eraCost(b, era);
580
634
  };
581
635
  let total = 0;
582
636
  for (const [k, b] of Object.entries(summary.byModel || {})) {
583
- const [m] = k.split("|");
584
- total += bucketCost(b, models[m] || defaultModel);
637
+ total += bucketCost(b, k);
585
638
  }
586
639
  const day = (summary.days || {})[beijingDayKey(Date.now())];
587
640
  let today = null;
588
641
  if (day) {
589
- if (day.byModel) {
590
- today = 0;
591
- for (const [m, b] of Object.entries(day.byModel)) today += bucketCost(b, models[m] || defaultModel);
592
- } else {
593
- today = bucketCost(day, defaultModel);
594
- }
642
+ today = 0;
643
+ for (const [k, b] of Object.entries(day.byModel || {})) today += bucketCost(b, k);
595
644
  }
596
645
  return { total, today, currency };
597
646
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lancecheney/dsh-deepseek-balance",
3
3
  "description": "Session-header DeepSeek API balance, per-conversation spend, and peak/off-peak pricing indicator",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {