@kenz1117/dsh-ui-usage-billing 1.1.12 → 1.1.14

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/index.js CHANGED
@@ -231,19 +231,24 @@ const WEEKEND_OFFPEAK_START_MS = Date.parse("2026-08-22T16:00:00Z");
231
231
  const FLASH_REPRICE_MS = Date.parse("2026-09-10T04:00:00Z");
232
232
  /**
233
233
  * flash 系调价前的官方谷档价(CNY / 1M tokens):{@link FLASH_REPRICE_MS}
234
- * 之前的 flash / flash-vision-exp 事件按此回算(峰档 = 谷档 × 2)。
234
+ * 之前的 flash / flash-vision-exp 事件按此回算(峰档 = 谷档 × 2)。pro 的
235
+ * 同表条目是 V4 Pro 峰谷时代刊例(谷 4.5/0.15/13.5):官方公告自
236
+ * {@link FLASH_REPRICE_MS} 起 V4 Pro 请求全部路由至 V4.1 Flash 并按其单价
237
+ * 计费(V4.1 Pro 上线前),故分界前回算 V4 Pro 刊例、分界后走目录的 Flash 价。
235
238
  * 用户价 = 实付价,与 legacy 口径相同地跳过本表。
236
239
  */
240
+ const FLASH_PRE_REPRICE_BAND = {
241
+ input: 1.5,
242
+ cacheHit: .05,
243
+ output: 4.5
244
+ };
237
245
  const FLASH_REPRICED_OFFPEAK = {
238
- flash: {
239
- input: 1.5,
240
- cacheHit: .05,
241
- output: 4.5
242
- },
243
- "flash-vision-exp": {
244
- input: 1.5,
245
- cacheHit: .05,
246
- output: 4.5
246
+ flash: FLASH_PRE_REPRICE_BAND,
247
+ "flash-vision-exp": FLASH_PRE_REPRICE_BAND,
248
+ pro: {
249
+ input: 4.5,
250
+ cacheHit: .15,
251
+ output: 13.5
247
252
  }
248
253
  };
249
254
  /**
@@ -309,6 +314,9 @@ function isBeijingWeekend(timeMs) {
309
314
  * splits peak (09:00-12:00 / 14:00-18:00 Beijing) at 2x the off-peak rate
310
315
  * from 2026-08-17, and Gemini's Flex tier discounts spare-capacity traffic.
311
316
  */
317
+ /** DeepSeek 官方高峰时段说明(峰谷分时计费目录条目共用)。 */
318
+ const DEEPSEEK_PEAK_HOURS = "09:00-12:00 / 14:00-18:00";
319
+ const GEMINI_PEAK_HOURS = "Standard / Flex";
312
320
  const MODEL_CATALOG = [
313
321
  {
314
322
  key: "flash",
@@ -326,7 +334,7 @@ const MODEL_CATALOG = [
326
334
  output: 4
327
335
  }
328
336
  },
329
- peakHours: "09:00-12:00 / 14:00-18:00"
337
+ peakHours: DEEPSEEK_PEAK_HOURS
330
338
  },
331
339
  {
332
340
  key: "flash-vision-exp",
@@ -344,7 +352,7 @@ const MODEL_CATALOG = [
344
352
  output: 4
345
353
  }
346
354
  },
347
- peakHours: "09:00-12:00 / 14:00-18:00"
355
+ peakHours: DEEPSEEK_PEAK_HOURS
348
356
  },
349
357
  {
350
358
  key: "pro",
@@ -353,16 +361,16 @@ const MODEL_CATALOG = [
353
361
  colorVar: "dsw-static-deepseek-500",
354
362
  price: {
355
363
  currency: "CNY",
356
- input: 9,
357
- cacheHit: .3,
358
- output: 27,
364
+ input: 2,
365
+ cacheHit: .04,
366
+ output: 8,
359
367
  offPeak: {
360
- input: 4.5,
361
- cacheHit: .15,
362
- output: 13.5
368
+ input: 1,
369
+ cacheHit: .02,
370
+ output: 4
363
371
  }
364
372
  },
365
- peakHours: "09:00-12:00 / 14:00-18:00"
373
+ peakHours: DEEPSEEK_PEAK_HOURS
366
374
  },
367
375
  {
368
376
  key: "glm",
@@ -967,7 +975,7 @@ const MODEL_CATALOG = [
967
975
  output: 6
968
976
  }
969
977
  },
970
- peakHours: "Standard / Flex",
978
+ peakHours: GEMINI_PEAK_HOURS,
971
979
  tierSemantics: "latency"
972
980
  },
973
981
  {
@@ -986,7 +994,7 @@ const MODEL_CATALOG = [
986
994
  output: 3.75
987
995
  }
988
996
  },
989
- peakHours: "Standard / Flex",
997
+ peakHours: GEMINI_PEAK_HOURS,
990
998
  tierSemantics: "latency"
991
999
  },
992
1000
  {
@@ -1397,6 +1405,8 @@ const MODEL_CATALOG = [
1397
1405
  const MODEL_KEY_ALIASES = {
1398
1406
  "deepseek-v4-flash": "flash",
1399
1407
  "deepseek-v4-flash-vision-exp": "flash-vision-exp",
1408
+ "deepseek-v4.1-flash": "flash",
1409
+ "deepseek-v4.1-flash-expires-on-0910": "flash",
1400
1410
  "deepseek-v4-pro": "pro",
1401
1411
  "glm-5.2": "glm",
1402
1412
  "glm-4.5-air": "glm-4.5-air",
@@ -2360,7 +2370,7 @@ function createUsageAggregator(persistence, options = {}) {
2360
2370
  id,
2361
2371
  ...cwd === void 0 ? {} : { cwd },
2362
2372
  ...stamp === null ? {} : { stamp },
2363
- foldVersion: 7,
2373
+ foldVersion: 9,
2364
2374
  fold: serializeFold(fold)
2365
2375
  };
2366
2376
  const row = ledger.get(id);
@@ -2450,7 +2460,7 @@ function createUsageAggregator(persistence, options = {}) {
2450
2460
  try {
2451
2461
  const cwd = meta.cwd;
2452
2462
  const ledgerRow = ledger.get(id);
2453
- if (ledgerRow !== void 0 && ledgerRow.stamp !== void 0 && stamp !== null && ledgerRow.stamp === stamp && (ledgerRow.foldVersion ?? 1) === 7) {
2463
+ if (ledgerRow !== void 0 && ledgerRow.stamp !== void 0 && stamp !== null && ledgerRow.stamp === stamp && (ledgerRow.foldVersion ?? 1) === 9) {
2454
2464
  const fold = deserializeFold(ledgerRow.fold);
2455
2465
  folds.push({
2456
2466
  id,
@@ -2533,7 +2543,7 @@ function createUsageAggregator(persistence, options = {}) {
2533
2543
  for (const entry of ledger.values()) {
2534
2544
  if (included.has(entry.id)) continue;
2535
2545
  try {
2536
- const stale = (entry.foldVersion ?? 1) < 7;
2546
+ const stale = (entry.foldVersion ?? 1) < 9;
2537
2547
  folds.push({
2538
2548
  id: entry.id,
2539
2549
  ...entry.cwd === void 0 ? {} : { cwd: entry.cwd },
@@ -5250,13 +5260,7 @@ function apply(ctx, config = {}) {
5250
5260
  const now = Date.now();
5251
5261
  if (now - lastSnapshotAt < SNAPSHOT_INTERVAL_MS) return;
5252
5262
  lastSnapshotAt = now;
5253
- const payload = JSON.stringify({
5254
- ...doc,
5255
- _writer: {
5256
- pid: process.pid,
5257
- at: now
5258
- }
5259
- });
5263
+ const payload = JSON.stringify(doc);
5260
5264
  (async () => {
5261
5265
  try {
5262
5266
  const existing = await readFile(snapshotPath, "utf8");
@@ -5280,13 +5284,67 @@ function apply(ctx, config = {}) {
5280
5284
  } catch {}
5281
5285
  return null;
5282
5286
  };
5283
- (async () => {
5284
- try {
5285
- const text = await readFile(snapshotPath, "utf8");
5286
- const writer = JSON.parse(text)._writer;
5287
- if (writer?.pid !== void 0 && writer.pid !== process.pid && writer.at !== void 0 && Date.now() - writer.at < 6e4) console.warn(`[usage-billing] 检测到另一实例(pid ${writer.pid})正在提供用量统计,双实例可能导致提醒重复。`);
5288
- } catch {}
5289
- })();
5287
+ const notifyClaimsPath = `${snapshotPath}.notify-claims.json`;
5288
+ const notifyClaims = {
5289
+ loaded: false,
5290
+ keys: []
5291
+ };
5292
+ ctx.effect(() => ctx.webServer.register({
5293
+ kind: "exact",
5294
+ path: "/api/billing/notify-claim",
5295
+ handler: async (req, res) => {
5296
+ if (!guardLoopback(req, res)) return;
5297
+ if (req.method !== "POST") {
5298
+ res.writeHead(405, { "content-type": "application/json; charset=utf-8" });
5299
+ res.end(JSON.stringify({ error: "method not allowed" }));
5300
+ return;
5301
+ }
5302
+ if (!isLoopbackOrigin(req.headers.origin) || !(req.headers["content-type"] ?? "").toLowerCase().includes("application/json")) {
5303
+ res.writeHead(403, { "content-type": "application/json; charset=utf-8" });
5304
+ res.end(JSON.stringify({ error: "forbidden: loopback only" }));
5305
+ return;
5306
+ }
5307
+ try {
5308
+ let body = "";
5309
+ for await (const chunk of req) {
5310
+ body += String(chunk);
5311
+ if (body.length > 2048) {
5312
+ res.end(JSON.stringify({ error: "body too large" }));
5313
+ return;
5314
+ }
5315
+ }
5316
+ const parsed = JSON.parse(body === "" ? "{}" : body);
5317
+ if (typeof parsed.key !== "string" || parsed.key === "" || parsed.key.length > 200) {
5318
+ res.writeHead(400, { "content-type": "application/json; charset=utf-8" });
5319
+ res.end(JSON.stringify({ error: "invalid key" }));
5320
+ return;
5321
+ }
5322
+ if (!notifyClaims.loaded) {
5323
+ notifyClaims.loaded = true;
5324
+ try {
5325
+ const stored = JSON.parse(await readFile(notifyClaimsPath, "utf8"));
5326
+ if (Array.isArray(stored.keys)) notifyClaims.keys = stored.keys.filter((k) => typeof k === "string");
5327
+ } catch {}
5328
+ }
5329
+ if (notifyClaims.keys.includes(parsed.key)) {
5330
+ res.writeHead(200, { "content-type": "application/json; charset=utf-8" });
5331
+ res.end(JSON.stringify({ claimed: false }));
5332
+ return;
5333
+ }
5334
+ notifyClaims.keys.push(parsed.key);
5335
+ if (notifyClaims.keys.length > 400) notifyClaims.keys = notifyClaims.keys.slice(-200);
5336
+ writeFileAtomic(notifyClaimsPath, JSON.stringify({ keys: notifyClaims.keys }), {
5337
+ mode: 384,
5338
+ dirMode: 448
5339
+ }).catch(() => {});
5340
+ res.writeHead(200, { "content-type": "application/json; charset=utf-8" });
5341
+ res.end(JSON.stringify({ claimed: true }));
5342
+ } catch {
5343
+ res.writeHead(400, { "content-type": "application/json; charset=utf-8" });
5344
+ res.end(JSON.stringify({ error: "invalid" }));
5345
+ }
5346
+ }
5347
+ }), "usage-billing: notify-claim route");
5290
5348
  ctx.inject(["settings"], (sctx) => {
5291
5349
  const scope = sctx.settings.register(usageBillingSettingsNs, UsageBillingSettingsSchema, { base: { enableUsageStatsTool: config.enableUsageStatsTool ?? false } });
5292
5350
  usageSettingsScope = scope;
@@ -427,8 +427,15 @@ export interface UsageLedgerDocument {
427
427
  * `session/end-seed`,resume 续写后继续对话时把本会话历史段误判为种子丢弃,
428
428
  * 会话费用只剩最近一段,issue #29)。
429
429
  * 持久账本行据此区分新旧算法:日志已删/不可读而只能沿用旧行时,UI 标注置信度提示。
430
+ * 8:官方公告自 2026-09-10 12:00(北京)起 V4 Pro 请求路由至 V4.1 Flash 按 Flash
431
+ * 单价计费(V4.1 Pro 上线前)——pro 目录价改写为 Flash 价、V4 Pro 刊例(峰
432
+ * 9/0.3/27、谷 4.5/0.15/13.5)进 FLASH_REPRICED_OFFPEAK 供分界前回算;v7 及更早
433
+ * 的行把分界后的 pro 全部按 V4 Pro 刊例折算(高估数倍),bump 全量重折对齐时间线。
434
+ * 9:V4.1 Flash 内测端点 id(expires-on-0910)收录进别名表——此前该 id 落目录兜底
435
+ * 条目(Custom),费用按 0 计且把「主力消耗模型余额」挤成「未配置」(issue #40
436
+ * 反馈);bump 让存量账单的内测用量按 flash 时间线重折归并。
430
437
  */
431
- export declare const FOLD_VERSION = 7;
438
+ export declare const FOLD_VERSION = 9;
432
439
  /**
433
440
  * 一次性账本迁移:id 唯一,apply 在加载边界对原始文档执行,已应用过的跳过。
434
441
  * 未来账本/schema 字段变更(重命名、拆桶、语义调整)时,在此追加一条迁移并
@@ -7,6 +7,7 @@
7
7
  * 4. 工具调用排行(byTool 计次;token 无法按工具归因)。
8
8
  */
9
9
  import type { UsageBillingKey } from './locales.ts';
10
+ import type { TrendSeriesModel } from './TrendChart.tsx';
10
11
  import type { UsageStats } from './UsageBilling.tsx';
11
12
  /**
12
13
  * Token 洞察面板。
@@ -18,6 +19,9 @@ export declare function TokenPanel(props: {
18
19
  stats: UsageStats;
19
20
  trendDays: 7 | 30;
20
21
  onTrendDays: (d: 7 | 30) => void;
22
+ models?: readonly TrendSeriesModel[];
23
+ /** 金额格式化(跟随仪表盘币种切换):费用构成区块展示用。 */
24
+ money: (cny: number) => string;
21
25
  t: (key: UsageBillingKey) => string;
22
26
  }): React.ReactNode;
23
27
  //# sourceMappingURL=TokenPanel.d.ts.map
@@ -84,6 +84,15 @@ export declare function projectMonthCost(byDay: Record<string, {
84
84
  * @returns 重估后的文档;无用户价或缺 byDayModels 时原样返回。
85
85
  */
86
86
  export declare function recostWithUserPrices(stats: UsageStats): UsageStats;
87
+ /**
88
+ * 跨实例提醒认领后发系统通知(issue #44):多实例(CLI + 桌面等)合法共存,
89
+ * 各自轮询会重复弹通知。两级去重——进程内 Set 挡同进程的并发/重渲染(trigger
90
+ * 与仪表盘是两个组件实例,effect 同周期并发时本地 store 标记读到的还是旧值);
91
+ * 跨进程走宿主认领端点(先到先得),另一实例刚发过则跳过。端点不可达(旧版本/
92
+ * 网络故障)时放行,退化为原有 per-客户端去重。通知构造失败(平台限制)静默。
93
+ * Set 导出供测试重置(模块级状态会跨用例泄漏)。
94
+ */
95
+ export declare const notifiedKeys: Set<string>;
87
96
  /** 近 7 天费用序列(含今天,缺日补 0):触发卡 hover 速览的迷你柱数据源。
88
97
  * 导出供测试:纯函数(日期取本地时区)。 */
89
98
  export declare function activeDaysOf(byDay: Record<string, {
@@ -1,5 +1,5 @@
1
1
  /** Locale dictionaries for the usage billing surface. */
2
- export type UsageBillingKey = 'title' | 'subtitle' | 'cost' | 'todayCost' | 'monthCost' | 'yearCost' | 'monthProjected' | 'liveTurn' | 'liveSession' | 'totalCost' | 'calls' | 'cacheHitRate' | 'tokens' | 'inputTokens' | 'outputTokens' | 'avgCost' | 'trend' | 'trend7d' | 'trend30d' | 'trendMetric' | 'trendMetricCost' | 'trendMetricTokens' | 'trendEmpty' | 'budget' | 'budgetAmount' | 'budgetSummary' | 'sessions' | 'sessionTitle' | 'project' | 'lastActive' | 'sessionOverflow' | 'budgetTierBody' | 'models' | 'providerBilling' | 'estimated' | 'actual' | 'pricing' | 'showPricing' | 'hidePricing' | 'pricePerM' | 'input' | 'output' | 'cacheHit' | 'peak' | 'offPeak' | 'flat' | 'peakHours' | 'band' | 'openDashboard' | 'close' | 'footer' | 'footerCredit' | 'lastUpdated' | 'noData' | 'todayRate' | 'rateLive' | 'rateBuiltin' | 'promoBadge' | 'promoUntil' | 'promoOpenEnded' | 'pricingTip' | 'pricingUnit' | 'pricingNotes' | 'ubPeak' | 'ubOff' | 'ubStd' | 'peakBand' | 'pricingSource' | 'noteCache' | 'noteBand' | 'noteSource' | 'balance' | 'balanceUnconfigured' | 'balanceUnauthorized' | 'balanceUnreachable' | 'uncatalogued' | 'estimatedPricing' | 'balanceDays' | 'balanceLowBody' | 'reconcileDrift' | 'reconcileDismiss' | 'subscriptions' | 'subscriptionNotConfigured' | 'subscriptionUnauthorized' | 'subscriptionUnavailable' | 'subscriptionInvalid' | 'subscriptionRateLimited' | 'subscriptionSession' | 'subscriptionWeekly' | 'subscriptionMonthly' | 'subscriptionBilling' | 'subscriptionRemaining' | 'subscriptionExhausted' | 'subscriptionReset' | 'subscriptionNoApi' | 'floatWindow' | 'floatModeCombined' | 'floatModeSubscription' | 'floatMode' | 'floatTargets' | 'floatWindowHint' | 'floatNoTargets' | 'floatNoTargetsHint' | 'cardDisplay' | 'cardDisplayHint' | 'cardMetric' | 'cardMetricMoney' | 'cardMetricTokens' | 'triggerMonthTokens' | 'floatPrev' | 'floatNext' | 'subscriptionsStale' | 'staleLedgerNotice' | 'tokenCacheWrite' | 'toolRank' | 'toolName' | 'userPrices' | 'userPricesHint' | 'userPriceSave' | 'userPriceModel' | 'userPriceSource' | 'userPriceSourceHint' | 'userPriceCurrency' | 'userPriceAdd' | 'userPriceRemove' | 'sessionStaleBadge' | 'sessionUntitled' | 'heatmapLess' | 'heatmapMore' | 'currency' | 'currencyCny' | 'currencyUsd' | 'heatmap' | 'rounds' | 'roundsHint' | 'anomaly' | 'workspaces' | 'workspacesHint' | 'plan' | 'remaining' | 'unknownModel' | 'model' | 'thModel' | 'thInputMiss' | 'thInputHit' | 'currentRound' | 'costAbbr' | 'tabOverview' | 'tabTrends' | 'tabProviders' | 'tabDetails' | 'tabPricing' | 'tabSettings' | 'settingsHead' | 'settingsHint' | 'budgetHint' | 'peakAlertHint' | 'peakAlertDescPeak' | 'peakAlertDescOff' | 'export' | 'exportCsvDay' | 'exportCsvSession' | 'exportJson' | 'peakShare' | 'peakSharePerCall' | 'offPeakSavings' | 'perfMax' | 'weekCost' | 'roleCost' | 'roleUser' | 'roleAssistant' | 'roleTool' | 'roleHint' | 'tierPeak' | 'tierOff' | 'tierToPeak' | 'tierToOff' | 'tierAlertEnterPeak' | 'tierAlertEnterOff' | 'peakAlertTitlePeak' | 'peakAlertTitleOff' | 'peakAlert' | 'peakAlertLeadMin' | 'peakAlertPos' | 'peakAlertMode' | 'peakAlertPosCorner' | 'peakAlertPosCenter' | 'peakAlertModePeak' | 'peakAlertModeOff' | 'peakAlertModeBoth' | 'peakAlertWebNotify' | 'peakAlertPreview' | 'planTypeCode' | 'planTypeToken' | 'subscriptionFeePerMonth' | 'triggerToday' | 'triggerMonth' | 'subscriptionIncluded' | 'free' | 'official' | 'thirdParty' | 'officialCost' | 'thirdPartyCost' | 'perfSamples' | 'perfTtft' | 'perfP50' | 'perfP90' | 'perfTps' | 'perfLatency' | 'perfEstimated' | 'perfEmpty' | 'perfTpsUnit' | 'perfTitle' | 'perfHint' | 'heatmapYear' | 'heatmapMonth' | 'activeDays' | 'streakDays' | 'subscriptionAutoDetect' | 'pluginInfo' | 'pluginName' | 'pluginDescription' | 'pluginVersion' | 'pluginAuthor' | 'pluginRepository' | 'pluginNpm' | 'pluginLicense' | 'tabToken' | 'tokenExport' | 'tokenExportCsv' | 'tokenCacheHitRate' | 'tokenReasoningShare' | 'tokenReasoningShort' | 'tokenIo' | 'tokenPeak' | 'tokenDaily' | 'tokenByModel' | 'tokenMiss' | 'tokenHit' | 'tokenOutput' | 'tokenTotal' | 'tokenShare' | 'usageStatsTool' | 'usageStatsToolHint' | 'balanceGranted' | 'balanceTopped' | 'balanceDaily' | 'balanceDaysLong' | 'balanceDaysUnit' | 'popTodayModel' | 'popNoConsumption' | 'popQuotaAlert' | 'popRiskNone' | 'popTitle' | 'popDirectLead' | 'popSubLead' | 'popBalanceNormal' | 'popBalanceLow' | 'popQuotaNormal' | 'popQuotaLow' | 'alertBalanceLow' | 'alertQuotaLow' | 'unpricedHint' | 'searchEstimateHint' | 'siteListDisplay' | 'siteListDisplayHint' | 'exportCsvSite' | 'panelRelay' | 'relaySite' | 'relayDirect' | 'relayUnknown' | 'panelRelayQuota' | 'relayBalance' | 'relayNoQuota' | 'relayWindowUsed' | 'relayKindNewApi' | 'relayKindSub2Api' | 'relayKindUnknown' | 'relayCalls';
2
+ export type UsageBillingKey = 'title' | 'subtitle' | 'cost' | 'todayCost' | 'monthCost' | 'yearCost' | 'monthProjected' | 'liveTurn' | 'liveSession' | 'totalCost' | 'calls' | 'cacheHitRate' | 'tokens' | 'inputTokens' | 'outputTokens' | 'avgCost' | 'trend' | 'trend7d' | 'trend30d' | 'trendMetric' | 'trendMetricCost' | 'trendMetricTokens' | 'trendEmpty' | 'budget' | 'budgetAmount' | 'budgetSummary' | 'sessions' | 'sessionTitle' | 'project' | 'lastActive' | 'sessionOverflow' | 'budgetTierBody' | 'models' | 'providerBilling' | 'estimated' | 'actual' | 'pricing' | 'showPricing' | 'hidePricing' | 'pricePerM' | 'input' | 'output' | 'cacheHit' | 'peak' | 'offPeak' | 'flat' | 'peakHours' | 'band' | 'openDashboard' | 'close' | 'footer' | 'footerCredit' | 'lastUpdated' | 'noData' | 'todayRate' | 'rateLive' | 'rateBuiltin' | 'promoBadge' | 'promoUntil' | 'promoOpenEnded' | 'pricingTip' | 'pricingUnit' | 'pricingNotes' | 'ubPeak' | 'ubOff' | 'ubStd' | 'peakBand' | 'pricingSource' | 'noteCache' | 'noteBand' | 'noteSource' | 'balance' | 'balanceUnconfigured' | 'balanceUnauthorized' | 'balanceUnreachable' | 'uncatalogued' | 'estimatedPricing' | 'balanceDays' | 'balanceLowBody' | 'reconcileDrift' | 'reconcileDismiss' | 'subscriptions' | 'subscriptionNotConfigured' | 'subscriptionUnauthorized' | 'subscriptionUnavailable' | 'subscriptionInvalid' | 'subscriptionRateLimited' | 'subscriptionSession' | 'subscriptionWeekly' | 'subscriptionMonthly' | 'subscriptionBilling' | 'subscriptionRemaining' | 'subscriptionExhausted' | 'subscriptionReset' | 'subscriptionNoApi' | 'floatWindow' | 'floatModeCombined' | 'floatModeSubscription' | 'floatMode' | 'floatTargets' | 'floatWindowHint' | 'floatNoTargets' | 'floatNoTargetsHint' | 'cardDisplay' | 'cardDisplayHint' | 'cardMetric' | 'cardMetricMoney' | 'cardMetricTokens' | 'triggerMonthTokens' | 'floatPrev' | 'floatNext' | 'subscriptionsStale' | 'staleLedgerNotice' | 'tokenCacheWrite' | 'toolRank' | 'toolName' | 'userPrices' | 'userPricesHint' | 'userPriceSave' | 'userPriceModel' | 'userPriceSource' | 'userPriceSourceHint' | 'userPriceCurrency' | 'userPriceAdd' | 'userPriceRemove' | 'sessionStaleBadge' | 'sessionUntitled' | 'heatmapLess' | 'heatmapMore' | 'currency' | 'currencyCny' | 'currencyUsd' | 'heatmap' | 'rounds' | 'roundsHint' | 'anomaly' | 'workspaces' | 'workspacesHint' | 'plan' | 'remaining' | 'unknownModel' | 'model' | 'thModel' | 'thInputMiss' | 'thInputHit' | 'currentRound' | 'costAbbr' | 'tabOverview' | 'tabTrends' | 'tabProviders' | 'tabDetails' | 'tabPricing' | 'tabSettings' | 'settingsHead' | 'settingsHint' | 'budgetHint' | 'peakAlertHint' | 'peakAlertDescPeak' | 'peakAlertDescOff' | 'export' | 'exportCsvDay' | 'exportCsvSession' | 'exportJson' | 'peakShare' | 'peakSharePerCall' | 'offPeakSavings' | 'perfMax' | 'weekCost' | 'roleCost' | 'roleUser' | 'roleAssistant' | 'roleTool' | 'roleHint' | 'tierPeak' | 'tierOff' | 'tierToPeak' | 'tierToOff' | 'tierAlertEnterPeak' | 'tierAlertEnterOff' | 'peakAlertTitlePeak' | 'peakAlertTitleOff' | 'peakAlert' | 'peakAlertLeadMin' | 'peakAlertPos' | 'peakAlertMode' | 'peakAlertPosCorner' | 'peakAlertPosCenter' | 'peakAlertModePeak' | 'peakAlertModeOff' | 'peakAlertModeBoth' | 'peakAlertWebNotify' | 'peakAlertPreview' | 'planTypeCode' | 'planTypeToken' | 'subscriptionFeePerMonth' | 'triggerToday' | 'triggerMonth' | 'subscriptionIncluded' | 'free' | 'perfSamples' | 'perfTtft' | 'perfP50' | 'perfP90' | 'perfTps' | 'perfLatency' | 'perfEstimated' | 'perfEmpty' | 'perfTpsUnit' | 'perfTitle' | 'perfHint' | 'heatmapYear' | 'heatmapMonth' | 'activeDays' | 'streakDays' | 'subscriptionAutoDetect' | 'pluginInfo' | 'pluginName' | 'pluginDescription' | 'pluginVersion' | 'pluginAuthor' | 'pluginRepository' | 'pluginNpm' | 'pluginLicense' | 'tabToken' | 'tokenExport' | 'tokenExportCsv' | 'tokenCacheHitRate' | 'tokenReasoningShare' | 'tokenReasoningShort' | 'tokenIo' | 'tokenPeak' | 'tokenDaily' | 'tokenByModel' | 'tokenMiss' | 'tokenHit' | 'tokenOutput' | 'tokenTotal' | 'tokenShare' | 'usageStatsTool' | 'usageStatsToolHint' | 'balanceGranted' | 'balanceTopped' | 'balanceDaily' | 'balanceDaysLong' | 'balanceDaysUnit' | 'popTodayModel' | 'popNoConsumption' | 'popQuotaAlert' | 'popRiskNone' | 'popTitle' | 'popDirectLead' | 'popSubLead' | 'popBalanceNormal' | 'popBalanceLow' | 'popQuotaNormal' | 'popQuotaLow' | 'alertBalanceLow' | 'alertQuotaLow' | 'unpricedHint' | 'searchEstimateHint' | 'siteListDisplay' | 'siteListDisplayHint' | 'exportCsvSite' | 'panelRelay' | 'relaySite' | 'relayDirect' | 'relayUnknown' | 'panelRelayQuota' | 'relayBalance' | 'relayNoQuota' | 'relayWindowUsed' | 'relayKindNewApi' | 'relayKindSub2Api' | 'relayKindUnknown' | 'relayCalls';
3
3
  export declare const NS = "usageBilling";
4
4
  export declare const zh: Record<UsageBillingKey, string>;
5
5
  export declare const en: Record<UsageBillingKey, string>;
@@ -265,21 +265,6 @@ export interface ModelEntry {
265
265
  /** 该条目当前按用户自定义单价计价(设置面板可维护);费率表标注「自定义」。 */
266
266
  userPriced?: boolean;
267
267
  }
268
- /**
269
- * Built-in catalog of current mainstream models as of 2026-08-16, priced from
270
- * each provider's official price page. Domestic providers are OpenAI-API
271
- * compatible and publish RMB prices directly; overseas providers publish USD
272
- * and convert through the exchange rate at estimate time. Retired models
273
- * (GPT-4o family, Gemini 2.x, GLM-4.x-lite, older Qwen) are deliberately
274
- * absent, as are Anthropic Claude models (their native API is not
275
- * OpenAI-compatible, so the harness cannot drive them directly). DeepSeek
276
- * keys match the harness stats file so real usage prices from the catalog;
277
- * unknown keys fall back to `other`.
278
- *
279
- * Time-of-day billing (peak/off-peak) is now real: DeepSeek V4 officially
280
- * splits peak (09:00-12:00 / 14:00-18:00 Beijing) at 2x the off-peak rate
281
- * from 2026-08-17, and Gemini's Flex tier discounts spare-capacity traffic.
282
- */
283
268
  export declare const MODEL_CATALOG: readonly ModelEntry[];
284
269
  /**
285
270
  * 真实 provider model id → 计费目录键(`MODEL_CATALOG[].key`)的映射。未知 id
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kenz1117/dsh-ui-usage-billing",
3
3
  "description": "Usage billing dashboard for DeepSeek Harness: sidebar cost metrics plus a full dashboard modal, priced from a current multi-provider catalog with real usage aggregated from session logs.",
4
- "version": "1.1.12",
4
+ "version": "1.1.14",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },