@kenz1117/dsh-ui-usage-billing 1.5.1 → 1.6.1

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 (43) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +1 -1
  3. package/lib/client.js +5 -5
  4. package/lib/index.js +728 -420
  5. package/lib/types/client/TokenPanel.d.ts +1 -1
  6. package/lib/types/client/UsageBilling.d.ts +7 -347
  7. package/lib/types/client/api/balance.d.ts +24 -0
  8. package/lib/types/client/api/pricing.d.ts +26 -0
  9. package/lib/types/client/api/relay.d.ts +13 -0
  10. package/lib/types/client/api/subscriptions.d.ts +13 -0
  11. package/lib/types/client/api/usage-stats.d.ts +11 -0
  12. package/lib/types/client/api/usage-tool.d.ts +16 -0
  13. package/lib/types/client/budget-store.d.ts +6 -0
  14. package/lib/types/client/constants.d.ts +28 -0
  15. package/lib/types/client/domain/forecast.d.ts +24 -0
  16. package/lib/types/client/domain/host-version.d.ts +18 -0
  17. package/lib/types/client/domain/icons.d.ts +9 -0
  18. package/lib/types/client/domain/kpi.d.ts +34 -0
  19. package/lib/types/client/domain/model-budget.d.ts +13 -0
  20. package/lib/types/client/domain/notify.d.ts +14 -0
  21. package/lib/types/client/domain/provider-aliases.d.ts +28 -0
  22. package/lib/types/client/domain/provider-merge.d.ts +26 -0
  23. package/lib/types/client/domain/recharge.d.ts +15 -0
  24. package/lib/types/client/domain/recost.d.ts +10 -0
  25. package/lib/types/client/domain/session-viewer.d.ts +13 -0
  26. package/lib/types/client/domain/streak.d.ts +25 -0
  27. package/lib/types/client/domain/subscription-vendors.d.ts +11 -0
  28. package/lib/types/client/domain/types.d.ts +312 -0
  29. package/lib/types/client/domain/week.d.ts +35 -0
  30. package/lib/types/client/locales.d.ts +1 -1
  31. package/lib/types/client/settings-search.d.ts +12 -0
  32. package/lib/types/config.d.ts +79 -0
  33. package/lib/types/guard.d.ts +49 -0
  34. package/lib/types/index.d.ts +3 -100
  35. package/lib/types/routes/balance.d.ts +37 -0
  36. package/lib/types/routes/notify-claim.d.ts +24 -0
  37. package/lib/types/routes/pricing.d.ts +26 -0
  38. package/lib/types/routes/relay-quotas.d.ts +27 -0
  39. package/lib/types/routes/subscriptions.d.ts +28 -0
  40. package/lib/types/routes/usage-stats.d.ts +44 -0
  41. package/lib/types/routes/usage-tool.d.ts +27 -0
  42. package/lib/types/silent.d.ts +21 -0
  43. package/package.json +14 -7
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import type { UsageBillingKey } from './locales.ts';
17
17
  import type { TrendSeriesModel } from './TrendChart.tsx';
18
- import type { UsageStats } from './UsageBilling.tsx';
18
+ import type { UsageStats } from './domain/types.ts';
19
19
  /** 短数字刻度:`1.2M` / `3.4K`。导出供概览 KPI 峰值日卡复用。 */
20
20
  export declare function shortNumber(v: number): string;
21
21
  /** 每日 token 堆叠图元(按结构视角)。 */
@@ -8,357 +8,17 @@
8
8
  * table. Data comes from the host's `/api/billing/usage-stats` endpoint;
9
9
  * before real data arrives the dashboard shows an empty (zero) snapshot,
10
10
  * never fabricated samples.
11
+ *
12
+ * v1.5.2 拆分(refactor):纯函数 / 类型 / fetch 抽到 `client/domain/` 与
13
+ * `client/api/`,常量抽到 `client/constants.ts`,本文件只保留组件本身
14
+ * (UsageBilling / BillingDashboard / UsageBillingTrigger / UserPriceCard /
15
+ * PositionMenu / SubscriptionWindowRow / BalanceDetailPopover+Row)。
11
16
  */
12
17
  import type { InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
13
18
  import type { SidebarFooterActionOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client';
14
- import { type ClientPerf } from './PerfPanel.tsx';
15
19
  import type { createBillingBudgetStore } from './budget-store.ts';
16
- import { type CatalogModel } from './pricing.ts';
17
- import type { ReconcileNotice } from '../pricing-shared.ts';
18
- import { NS, type UsageBillingKey } from './locales.ts';
19
- /** Model-connectivity health reported by the host model directory probe. */
20
- export interface ModelHealth {
21
- /** Whether the probe completed (false while still loading). */
22
- checked: boolean;
23
- /** True when at least one connected provider answered its model catalog. */
24
- available: boolean;
25
- /** 可用模型总数:累加每个厂商成功 advertise 的模型数,而非厂商数。 */
26
- models: number;
27
- /** 失效厂商数(目录探测失败的厂商;失败信息不细分到模型级)。 */
28
- failures: number;
29
- /** Display names of providers that answered their model catalog (live). */
30
- okProviders: readonly string[];
31
- /** Display names of providers whose catalog probe failed. */
32
- badProviders: readonly string[];
33
- /** 探活得到的模型清单(系统里实际配置/预制的模型;无价格,费率表据此对标)。 */
34
- catalog?: readonly CatalogModel[];
35
- }
36
- /** 仪表盘分区 Tab id。 */
37
- export type DashboardTab = 'overview' | 'token' | 'trends' | 'providers' | 'pricing' | 'settings';
38
- /**
39
- * Tab 定义(顺序即渲染顺序):概览=主数字/KPI/热力图,账单=厂商计费与订阅,
40
- * 用量=Token 用量,趋势=趋势图/每轮费用,费率=模型单价表,设置=预算与峰谷提醒。
41
- * 导出供测试断言 tab 与文案 key 对齐、decor 锚点落在正确分区。
42
- */
43
- export declare const DASHBOARD_TABS: readonly {
44
- id: DashboardTab;
45
- labelKey: UsageBillingKey;
46
- }[];
47
- /**
48
- * The dashboard's display names (中文厂商名) never equal the provider names a
49
- * user actually configures (deepseek, zhipu, qwen…), so the dot match also
50
- * accepts a bidirectional substring hit and a display-name alias list.
51
- * 导出供一致性守卫测试:catalog 每个厂商都必须在此登记(Custom 除外),
52
- * 防止新增厂商漏配导致健康绿灯不亮。
53
- */
54
- export declare const PROVIDER_ALIASES: Readonly<Record<string, readonly string[]>>;
55
- /**
56
- * 从真实 model id 反推提供方显示名:目录未收录的模型(key 落回「其他」)
57
- * 只靠 entry.provider(Custom)永远点不亮健康灯,这里用厂商别名对 model id
58
- * 做强匹配(别名作为完整 id / 前缀 / 独立段)与弱匹配(长别名子串),
59
- * 命中即显示厂商名并点亮健康点;无命中保持 Custom。
60
- * 导出供守卫测试:短别名(mi/yi)仅允许前缀形式,防止 minimax 等误吞。
61
- */
62
- export declare function providerFromModelKey(modelKey: string): string | undefined;
63
- /** 仅供测试:暴露厂商映射表(subscriptionVendorOf 仍是唯一消费入口)。 */
64
- export declare const SUBSCRIPTION_VENDORS_FOR_TEST: Readonly<Record<string, string>>;
65
- /**
66
- * 余额 provider → 官方充值页 URL。匹配顺序:归一化名精确/前缀命中 →
67
- * 经 PROVIDER_ALIASES 反查(余额 provider 名多为中文显示名,归一化仍是中文,
68
- * 需先命中 display 名再用其英文别名重试)。未收录返回 undefined。
69
- * 导出供测试:纯函数,不依赖组件。
70
- */
71
- export declare function rechargeUrlOf(provider: string): string | undefined;
72
- /**
73
- * 本月预计总花费:按本月已有记录的平均日消耗 × 本月天数外推;无本月记录时
74
- * 回退为最近 7 天日均 × 本月天数;无任何记录时返回 0(调用方不展示)。
75
- * 导出供测试:纯函数,不依赖组件。
76
- * @param byDay - 按日费用表。
77
- * @param monthPrefix - 本月前缀(YYYY-MM)。
78
- * @param today - 今日日期戳(YYYY-MM-DD)。
79
- * @returns 本月预计花费(人民币元);无数据时为 0。
80
- */
81
- export declare function projectMonthCost(byDay: Record<string, {
82
- cost: number;
83
- }>, monthPrefix: string, today: string): number;
84
- /**
85
- * 用户自定义单价显示重估:聚合发生在宿主进程(按内置目录计价),用户价只在
86
- * 客户端显示层生效。对 byDayModels(day×model 完整二维)中命中用户价的模型
87
- * 逐格平价重算 cost,并派生 byDay / byModel / total 的 cost。其余视图
88
- * (bySite / byTier / bySession / byTurn)保持宿主原值——逐格时刻或行级归属
89
- * 在客户端不可得,口径差异在设置面板注明。导出供测试:纯函数。
90
- * @param stats - 服务端聚合文档。
91
- * @returns 重估后的文档;无用户价或缺 byDayModels 时原样返回。
92
- */
93
- export declare function recostWithUserPrices(stats: UsageStats): UsageStats;
94
- /**
95
- * 跨实例提醒认领后发系统通知(issue #44):多实例(CLI + 桌面等)合法共存,
96
- * 各自轮询会重复弹通知。两级去重——进程内 Set 挡同进程的并发/重渲染(trigger
97
- * 与仪表盘是两个组件实例,effect 同周期并发时本地 store 标记读到的还是旧值);
98
- * 跨进程走宿主认领端点(先到先得),另一实例刚发过则跳过。端点不可达(旧版本/
99
- * 网络故障)时放行,退化为原有 per-客户端去重。通知构造失败(平台限制)静默。
100
- * Set 导出供测试重置(模块级状态会跨用例泄漏)。
101
- */
102
- export declare const notifiedKeys: Set<string>;
103
- /** 近 7 天费用序列(含今天,缺日补 0):触发卡 hover 速览的迷你柱数据源。
104
- * 导出供测试:纯函数(日期取本地时区)。 */
105
- export declare function activeDaysOf(byDay: Record<string, {
106
- cost: number;
107
- }>): number;
108
- /** 连续使用天数:从今天往前连续「有调用记录」的天数;今天无记录则为 0。
109
- * 导出供测试:纯函数(日期取本地时区)。 */
110
- export declare function streakDaysOf(byDay: Record<string, {
111
- cost: number;
112
- }>, now?: number): number;
113
- /** 按日 Token 口径:输入 + 输出。stats.input 本身已含缓存命中与未命中
114
- * (aggregate foldUsage:input = cacheHit + cacheMiss),再叠加缓存字段即重复
115
- * 计数——趋势图/热力图/触发卡/峰值日的按日 Token 一律走本函数(issue #85);
116
- * 跨日合计在各行之上累加(KPI 见 kpiAgg,触发卡见 month/weekTokens)。
117
- * 导出供测试:纯函数。 */
118
- export declare function dayTokensOf(day: {
119
- input: number;
120
- output: number;
121
- }): number;
122
- /**
123
- * 近 7 天费用序列(含今天,缺日补 0):触发卡 hover 速览的迷你柱数据源。
124
- * 导出供测试:纯函数(日期取本地时区)。
125
- * @param byDay - 按日费用表。
126
- * @returns 7 个 `{ date, cost }`,最旧在前。
127
- */
128
- export declare function lastSevenDays(byDay: Record<string, {
129
- cost: number;
130
- }>): readonly {
131
- date: string;
132
- cost: number;
133
- }[];
134
- /**
135
- * 本自然周(周一起算)到 `today` 的累计值(issue #39):标签「本周」的语义是
136
- * 自然周,近 7 天滚动窗口会在周一把上周用量卷进来(周一时它与当月几乎相等,
137
- * 用户误解为统计错误)。周一 = `getDay() === 1`;`pick` 决定日行取哪个维度。
138
- * @param byDay - 按日聚合表(key = `YYYY-MM-DD` 本地时区)。
139
- * @param today - 今天的本地日期戳。
140
- * @param pick - 日行取值(缺省取 cost;token 视角传 input+output 合计)。
141
- * @returns 本周一到今天的合计;`today` 本身不在表里(无调用)时为 0。
142
- */
143
- export declare function sinceMondayOf<T>(byDay: Record<string, T>, today: string, pick?: (row: T) => number): number;
144
- /** 平均成本的统计范围(issue #47);`all` = 全量累计,不进逐日求和。 */
145
- export type AvgCostRange = 'today' | '7d' | 'week' | 'month' | 'all';
146
- /** 全局 KPI 按日聚合行的最小字段(byDay 行 = ModelUsage,结构兼容)。 */
147
- interface KpiDayRow {
148
- cost: number;
149
- calls: number;
150
- input: number;
151
- output: number;
152
- cacheHit: number;
153
- cacheMiss: number;
154
- reasoning?: number;
155
- }
156
- /** 全局 KPI 聚合结果:KPI 七卡按所选范围重算所需的全部字段。 */
157
- export interface KpiAgg {
158
- cost: number;
159
- calls: number;
160
- input: number;
161
- output: number;
162
- cacheHit: number;
163
- cacheMiss: number;
164
- reasoning: number;
165
- /** 范围内总处理 Token(缓存读+缓存写+输出)最大的日期戳;窗口无数据时 undefined。 */
166
- peakDay: string | undefined;
167
- /** 峰值日的总处理 Token 量;窗口无数据时 0。 */
168
- peakTokens: number;
169
- }
170
- /**
171
- * 按范围聚合 byDay(issue #47):今日 / 近 7 天(含今天)/ 本周(周一起)/
172
- * 本月。日期戳字典序即时间序(与 dailyBurnRate 同口径);累计口径由调用方
173
- * 直接取 total(含搜索估值兜底),不走此函数。
174
- */
175
- export declare function sumByDayRange(byDay: Record<string, KpiDayRow>, today: string, range: Exclude<AvgCostRange, 'all'>): KpiAgg;
176
- /** 会话明细行(与服务端 SessionUsageRow 同形;旧快照可能缺失整个 bySession)。 */
177
- interface SessionBillingRow {
178
- id: string;
179
- title?: string;
180
- cwd?: string;
181
- /**
182
- * 直接父会话 id(仅子智能体会话携带):宿主把子智能体落成独立会话,
183
- * header 的 origin: subagent + parentSession 指向委派它的对话。
184
- */
185
- parentId?: string;
186
- /** 全部后代子会话费用合计(服务端递归算好);无后代时缺失。 */
187
- subCost?: number;
188
- /** 全部后代子会话调用数;无后代时缺失。 */
189
- subCalls?: number;
190
- /** 数据来自旧算法折叠的持久账本行(原始日志已删,无法重算)。 */
191
- stale?: boolean;
192
- calls: number;
193
- cost: number;
194
- lastActive: number;
195
- /** 展示层合并标记(issue #42):同标题会话归并后的段数(>1 时行尾显示 ×N)。 */
196
- mergedCount?: number;
197
- /** 合并组的段明细(展示层专用):一级行默认收起,展开后逐段显示。合并函数需 push,故非 readonly。 */
198
- children?: SessionBillingRow[];
199
- /** 挂到本组下的子智能体行(展示层专用):与段明细并列展开,带子智能体徽标。 */
200
- subs?: SessionBillingRow[];
201
- }
202
- /** Usage stats structure from `.dsh-usage-stats.json`. */
203
- export interface UsageStats {
204
- /** 服务端聚合时间戳(毫秒);旧快照可能缺失。 */
205
- updatedAt?: number;
206
- /** 宿主进程时区(IANA 名 + UTC 偏移):天按此切分,副标题据此标注;旧快照可能缺失。 */
207
- timezone?: {
208
- name: string;
209
- offset: string;
210
- };
211
- /** 月度预算(人民币元):宿主 Config 注入;未配置时不渲染预算条。 */
212
- budget?: number;
213
- /** 余额不足告警阈值(人民币元):宿主 Config 注入;未配置时客户端用默认值。 */
214
- lowBalanceThreshold?: number;
215
- /** 会话明细(按费用倒序,服务端已封顶);旧快照可能缺失。 */
216
- bySession?: readonly SessionBillingRow[];
217
- total: {
218
- calls: number;
219
- input: number;
220
- output: number;
221
- cacheHit: number;
222
- cacheMiss: number;
223
- /** 显式缓存写入(cacheMiss 子集,部分厂商单独报告);1.0.8 起新增,旧快照缺失。 */
224
- cacheWrite?: number;
225
- cost: number;
226
- /** 输出中的 reasoning(思考)token;已含在 output 内。 */
227
- reasoning: number;
228
- /** 联网搜索请求的估算调用数(已按次估值计入 cost);1.0.9 起新增,旧快照缺失。 */
229
- searchCalls?: number;
230
- };
231
- byModel: Record<string, {
232
- calls: number;
233
- input: number;
234
- output: number;
235
- cacheHit: number;
236
- cacheMiss: number;
237
- cost: number;
238
- reasoning: number;
239
- /** Billed through a subscription plan (no per-token cost). */
240
- plan?: boolean;
241
- /** 走官方 DeepSeek 直连的调用数(其余为第三方);旧快照可能缺失。 */
242
- officialCalls?: number;
243
- /** 走官方渠道的费用(CNY);旧快照可能缺失。 */
244
- officialCost?: number;
245
- }>;
246
- byDay: Record<string, {
247
- calls: number;
248
- input: number;
249
- output: number;
250
- cacheHit: number;
251
- cacheMiss: number;
252
- cost: number;
253
- reasoning: number;
254
- }>;
255
- /** 模型 × 日期 二维统计(趋势图堆叠柱的输入);旧快照可能缺失,渲染时降级为单色柱。 */
256
- byDayModels?: Record<string, Record<string, {
257
- calls: number;
258
- input: number;
259
- output: number;
260
- cacheHit: number;
261
- cacheMiss: number;
262
- cost: number;
263
- }>>;
264
- /** 模型 × 日期 × 站点 三维统计([date][modelKey][siteKey]):按 origin 绑定自定义价的
265
- * 显示层重估数据源;旧快照可能缺失。 */
266
- byDayModelsSite?: Record<string, Record<string, Record<string, {
267
- calls: number;
268
- input: number;
269
- output: number;
270
- cacheHit: number;
271
- cacheMiss: number;
272
- cost: number;
273
- /** 该格全部调用都走订阅通道(聚合侧按三维格置位);旧快照缺失,回退全局口径。 */
274
- plan?: boolean;
275
- }>>>;
276
- /**
277
- * 峰谷分桶(全量逐调用真实判档):1.0.8 起服务端按调用时刻精确归桶,
278
- * 峰谷占比条优先用它(覆盖全部历史调用);旧快照缺失时回退逐轮估算。
279
- */
280
- byTier?: {
281
- peak: {
282
- cost: number;
283
- calls: number;
284
- };
285
- offPeak: {
286
- cost: number;
287
- calls: number;
288
- };
289
- };
290
- /** 工具调用次数排行(键 = 工具名,按次数倒序);旧快照缺失。 */
291
- byTool?: Record<string, number>;
292
- /** 每轮费用明细(服务端聚合路径恒带);旧快照可能缺失。 */
293
- byTurn?: readonly {
294
- sessionId: string;
295
- turn: number;
296
- model: string;
297
- input: number;
298
- output: number;
299
- cacheHit: number;
300
- cacheMiss: number;
301
- cost: number;
302
- startedAt: number;
303
- endedAt?: number;
304
- }[];
305
- /** 工作区聚合(按 cwd 末级目录);旧快照可能缺失。 */
306
- byWorkspace?: readonly {
307
- name: string;
308
- calls: number;
309
- cost: number;
310
- input: number;
311
- output: number;
312
- lastActive: number;
313
- }[];
314
- /** 中转站归组(key = `site:<origin>` / `direct:<provider>` / `unknown`);旧快照可能缺失。 */
315
- bySite?: Record<string, {
316
- calls: number;
317
- input: number;
318
- output: number;
319
- cacheHit: number;
320
- cacheMiss: number;
321
- cost: number;
322
- reasoning: number;
323
- }>;
324
- /** 不可计价模型 id(未收录/无价,费用按 0 计);旧快照可能缺失。 */
325
- unpricedModels?: readonly string[];
326
- /** 联网搜索请求的单次费用估算(人民币元,配置回显);0 或缺省 = 未启用估算。 */
327
- searchCallEstimateCny?: number;
328
- /** 按角色费用归因(估算口径:输出实测,输入按消息长度摊分);旧快照可能缺失。 */
329
- byRole?: {
330
- user: number;
331
- assistant: number;
332
- tool: number;
333
- };
334
- /** 性能指标(TTFT/生成速度/总延迟)按模型与按小时;旧快照可能缺失。 */
335
- perf?: ClientPerf;
336
- /** 旧版算法账本行兜底的会话数(模型归属可能失真);0 或缺省 = 全部数据可信。 */
337
- staleLedgerSessions?: number;
338
- /** 本轮未完整计入的会话数(跨轮次稳定);0 或缺省 = 全部会话已统计。 */
339
- unreadableSessions?: number;
340
- /** 未统计中因会话格式拒读的子集(过新待宿主升级、过旧需迁移);0 或缺省 = 无格式拒读。 */
341
- unreadableFormatSessions?: number;
342
- /** 未统计中无账本存档、完全未计入的子集;0 或缺省 = 拒读会话均有存档兜底。 */
343
- unreadableNoLedgerSessions?: number;
344
- /** 插件版本号(服务端读自包 package.json;旧快照缺失)。 */
345
- pluginVersion?: string;
346
- }
347
- /**
348
- * 拉取官方余额差对账提示(drift 时非空),供余额面板展示;失败返回 undefined。
349
- * 复用 {@link fetchBalanceDoc} 的同一响应,导出供对账提示渲染测试单独解析。
350
- * @returns the reconcile notice, or undefined on any failure / no drift.
351
- */
352
- export declare function fetchReconcile(): Promise<ReconcileNotice | undefined>;
353
- /** 组件注入面:探活 + 计费指标写入(billing 自身写入,主题插件经服务读取)。 */
354
- export interface UsageBillingInjected {
355
- checkModels: () => Promise<ModelHealth>;
356
- publishCosts: (costs: {
357
- todayCost: number;
358
- monthCost: number;
359
- }) => void;
360
- registerOpen: (handler: () => void) => () => void;
361
- }
20
+ import { NS } from './locales.ts';
21
+ import { type UsageBillingInjected } from './domain/types.ts';
362
22
  /** 预算 store 的 props 份额(useStore 读取 + actions 写面)。 */
363
23
  type BillingBudgetStoreProps = PropsStore<ReturnType<typeof createBillingBudgetStore>>;
364
24
  /** Full props type for the UsageBilling component. */
@@ -0,0 +1,24 @@
1
+ /**
2
+ * GET /api/billing/balance:余额 + 对账提示(同一响应体)。30s 轮询单端点
3
+ * 比拆成两个端点更省(余额查询本身已有熔断与重试),失败回退空值。
4
+ */
5
+ import type { ProviderBalance, ReconcileNotice } from '../../pricing-shared.ts';
6
+ /** Path to the account-balance endpoint served by this plugin's node half. */
7
+ export declare const BALANCE_PATH = "/api/billing/balance";
8
+ /**
9
+ * 一次拉取 `/api/billing/balance` 的完整响应(余额行 + 对账提示)。余额与对账
10
+ * 提示来自同一响应体,拆成两个函数会导致每 30 秒对同一端点发两次请求,故合并
11
+ * 为单次 fetch;失败返回空值(余额 []、对账 undefined),由调用方降级。
12
+ * @returns the balances and reconcile notice (both degraded on any failure).
13
+ */
14
+ export declare function fetchBalanceDoc(): Promise<{
15
+ balances: readonly ProviderBalance[];
16
+ reconcile?: ReconcileNotice;
17
+ }>;
18
+ /**
19
+ * 拉取官方余额差对账提示(drift 时非空),供余额面板展示;失败返回 undefined。
20
+ * 复用 {@link fetchBalanceDoc} 的同一响应,导出供对账提示渲染测试单独解析。
21
+ * @returns the reconcile notice, or undefined on any failure / no drift.
22
+ */
23
+ export declare function fetchReconcile(): Promise<ReconcileNotice | undefined>;
24
+ //# sourceMappingURL=balance.d.ts.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * GET /api/billing/pricing + POST /api/billing/pricing/refresh:实时定价。
3
+ * 节点端启动时拉取,pricing source = 'builtin' 时本地内置(首次启动会回退
4
+ * 内置价);重试链在收到完整 live 文档时立即结算。`livePricingRetryPending`
5
+ * 与 `lastPricingSyncedAt` 是模块级 let,**必须**与 `loadLivePricing` 同文件
6
+ * 保留(防止跨文件共享 mutable state;也是测试唯一可读的同步基线)。
7
+ */
8
+ /** Path to the live-pricing endpoint served by this plugin's node half. */
9
+ export declare const PRICING_PATH = "/api/billing/pricing";
10
+ /** Path to the manual pricing-sync endpoint (POST) served by this plugin's node half. */
11
+ export declare const PRICING_REFRESH_PATH = "/api/billing/pricing/refresh";
12
+ /** 上次价格目录同步完成的本机时间戳(毫秒):loadLivePricing 每次拿到完整
13
+ * pricing 文档时更新;组件渲染时读取,手动同步后经 setState 触发重渲染刷新。
14
+ * `export let` 让 ESM live binding 暴露给外部——只读绑定(`import { x }` 在 ESM
15
+ * 中为只读),唯一写入点在本模块内 `lastPricingSyncedAt = ...`。 */
16
+ export declare let lastPricingSyncedAt: number;
17
+ declare function loadLivePricing(attempt?: number): Promise<void>;
18
+ /**
19
+ * 手动同步价格目录:POST /api/billing/pricing/refresh 让服务端立刻重拉
20
+ * models.dev / 汇率,随后重载 pricing 文档并刷新界面。失败静默保持现状。
21
+ * @returns 同步是否成功(供按钮态展示降级)。
22
+ */
23
+ export declare function syncPricingNow(): Promise<boolean>;
24
+ /** 公开 loadLivePricing 供 UsageBilling 触发器/弹窗挂载时调用。 */
25
+ export { loadLivePricing };
26
+ //# sourceMappingURL=pricing.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * GET /api/billing/relay-quotas:中转站额度(New API / Sub2API)。
3
+ * 失败抛出(调用方据此保留旧快照)。
4
+ */
5
+ import type { RelayQuota } from '../../pricing-shared.ts';
6
+ /** Path to the relay-site quota endpoint served by this plugin's node half. */
7
+ export declare const RELAY_PATH = "/api/billing/relay-quotas";
8
+ /**
9
+ * 拉取中转站额度(New API / Sub2API 的余额与滚动窗口);失败抛出(调用方据此保留旧快照)。
10
+ * @returns the relay-site quota rows(成功但无中转配置时为空数组)。
11
+ */
12
+ export declare function fetchRelayQuotas(): Promise<readonly RelayQuota[]>;
13
+ //# sourceMappingURL=relay.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * GET /api/billing/subscriptions:订阅套餐剩余额度(供订阅面板)。
3
+ * 失败抛出(调用方据此保留旧快照)。
4
+ */
5
+ import type { SubscriptionQuota } from '../../pricing-shared.ts';
6
+ /** Path to the subscription-plan quota endpoint served by this plugin's node half. */
7
+ export declare const SUBSCRIPTIONS_PATH = "/api/billing/subscriptions";
8
+ /**
9
+ * 拉取订阅套餐剩余额度(供订阅面板);失败返回空列表。
10
+ * @returns the quota rows, or an empty list on any failure.
11
+ */
12
+ export declare function fetchSubscriptions(): Promise<readonly SubscriptionQuota[]>;
13
+ //# sourceMappingURL=subscriptions.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * GET /api/billing/usage-stats:服务端聚合文档(含 byDay/byModel/bySession/...)。
3
+ * 旧快照可能缺字段(聚合升级前落盘),解析时按字段白名单接受并兜底——避免
4
+ * 渲染路径读 undefined 抛错导致整个插件 surface 被卸载。
5
+ */
6
+ import type { UsageStats } from '../domain/types.ts';
7
+ /** Path to the usage-stats endpoint served by this plugin's node half. */
8
+ export declare const USAGE_STATS_PATH = "/api/billing/usage-stats";
9
+ /** Try to load stats from the server; returns null when no valid JSON stats are served. */
10
+ export declare function loadUsageStats(): Promise<UsageStats | null>;
11
+ //# sourceMappingURL=usage-stats.d.ts.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * GET/POST /api/billing/usage-tool:usage_stats 工具开关读写(插件自带,
3
+ * 不依赖宿主浏览器设置白名单)。工具注入是启动期决策,重启应用后生效。
4
+ */
5
+ /**
6
+ * 读取 usage_stats 工具开关当前值(插件自带接口,不依赖宿主浏览器设置白名单)。
7
+ * @returns 当前是否注入;读取失败(服务未起/非 JSON)返回 undefined。
8
+ */
9
+ export declare function loadUsageTool(): Promise<boolean | undefined>;
10
+ /**
11
+ * 写 usage_stats 工具开关(插件自带接口)。工具注入是启动期决策,重启应用后生效。
12
+ * @param enabled - 是否注入。
13
+ * @returns 是否写成功。
14
+ */
15
+ export declare function saveUsageTool(enabled: boolean): Promise<boolean>;
16
+ //# sourceMappingURL=usage-tool.d.ts.map
@@ -18,6 +18,10 @@ export interface BudgetPrefsState {
18
18
  lastBalanceAlertDay: string;
19
19
  /** 最近一次峰谷切换提醒的切换点时刻(毫秒):同一切换点只提醒一次。 */
20
20
  lastTierSwitchAt: number;
21
+ /** 按模型月度预算(模型目录键 → 人民币元/月;U-3)。缺键 = 该模型不限。 */
22
+ modelBudgets: Record<string, number>;
23
+ /** 按模型预算提醒的最后通知日期戳(`${model}:${tier}` → YYYY-MM-DD):每模型每档每天最多一次。 */
24
+ modelTierAlertDays: Record<string, string>;
21
25
  }
22
26
  /** 预算偏好的完整写面(组件只能经这些 action 写入);type 别名以兼容 ActionsDecl 的索引签名约束。 */
23
27
  export type BudgetPrefsActions = {
@@ -26,6 +30,8 @@ export type BudgetPrefsActions = {
26
30
  markTierAlerted: (d: BudgetPrefsState, tiers: readonly number[], day: string) => void;
27
31
  markBalanceAlerted: (d: BudgetPrefsState, day: string) => void;
28
32
  markTierSwitchAlerted: (d: BudgetPrefsState, at: number) => void;
33
+ setModelBudget: (d: BudgetPrefsState, key: string, value: number) => void;
34
+ markModelTierAlerted: (d: BudgetPrefsState, marks: readonly string[], day: string) => void;
29
35
  };
30
36
  /**
31
37
  * Declare the budget-preferences store handle.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 客户端常量(无 React 依赖、无运行时副作用):把 UsageBilling.tsx 散落的零散
3
+ * 常量集中到这里。UI 文案、key 名仍留在 locales.ts;这里只放「数值 / 路径 /
4
+ * 颜色 / 时间间隔」。
5
+ */
6
+ import type { UsageStats } from './domain/types.ts';
7
+ /** 预算提醒档位(百分比):跨档时桌面通知,每档每天最多一次。 */
8
+ export declare const BUDGET_ALERT_TIERS: readonly number[];
9
+ /** 余额不足告警的默认阈值(人民币元):宿主 Config 未配置时客户端兜底。 */
10
+ export declare const DEFAULT_LOW_BALANCE_THRESHOLD = 50;
11
+ /** 会话明细面板最多展示的行数(完整长尾在服务端另有一层封顶)。 */
12
+ export declare const SESSION_DISPLAY_LIMIT = 20;
13
+ /** 弹窗打开期间统计与定价的自动刷新间隔(毫秒)。 */
14
+ export declare const STATS_REFRESH_INTERVAL_MS = 30000;
15
+ /** 弹窗关闭后的统计刷新间隔(毫秒):侧栏触发器只需大致最新值,降到 5 分钟
16
+ * 省宿主聚合(每轮都是折叠 + 五个端点的串行响应)。 */
17
+ export declare const STATS_REFRESH_CLOSED_MS = 300000;
18
+ /** Empty snapshot: shown before (or without) real host data — zeros, never fabricated samples. */
19
+ export declare const EMPTY_STATS: UsageStats;
20
+ /**
21
+ * 高区分度图表色板:趋势图柱、图例与计费表圆点按模型分配。不用模型品牌色
22
+ * (目录里多为蓝色系,视觉上几乎分不开),保证每个模型一眼可辨。
23
+ * 取设计 spec §3.4 七段色板(与 CSS --ds-c-1..7 同值;SVG presentation
24
+ * attribute 不解析 var(),故用同值字面量而非令牌引用),后三位保持
25
+ * 原有高区分度补位色,10 路循环不变。
26
+ */
27
+ export declare const CHART_PALETTE: readonly string[];
28
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 本月预计 / 日均消耗(issue #47):按日均外推本月总花费;余额可撑天数也复用。
3
+ * 纯函数(日期取本地时区),无 React 依赖。导出供测试。
4
+ */
5
+ /**
6
+ * 日均消耗(元/天):取最近 7 天(含今天)总花费 ÷ 有记录天数;无记录返回 0
7
+ * (此时可用天数无法估算,调用方不显示天数提示)。日期戳字典序即时间序。
8
+ */
9
+ export declare function dailyBurnRate(byDay: Record<string, {
10
+ cost: number;
11
+ }>, today: string): number;
12
+ /**
13
+ * 本月预计总花费:按本月已有记录的平均日消耗 × 本月天数外推;无本月记录时
14
+ * 回退为最近 7 天日均 × 本月天数;无任何记录时返回 0(调用方不展示)。
15
+ * 导出供测试:纯函数,不依赖组件。
16
+ * @param byDay - 按日费用表。
17
+ * @param monthPrefix - 本月前缀(YYYY-MM)。
18
+ * @param today - 今日日期戳(YYYY-MM-DD)。
19
+ * @returns 本月预计花费(人民币元);无数据时为 0。
20
+ */
21
+ export declare function projectMonthCost(byDay: Record<string, {
22
+ cost: number;
23
+ }>, monthPrefix: string, today: string): number;
24
+ //# sourceMappingURL=forecast.d.ts.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 双宿主版本兼容:宿主 0.1.7 起把 IconChevronDownOutline14 拆为 Regular/Medium/Artwork
3
+ * 三个变体,旧名不再导出(issue #72:缺失名经宿主注入表解析为 undefined,渲染时
4
+ * 抛 React #130 并被 sidebar.footer.action 槽位错误边界弹出)。bundle 对 primitives
5
+ * 的 import 编译为运行时查表,缺失名不抛错,因此两个世代的名字都能同时引用:
6
+ * 0.1.6 宿主只有旧名,0.1.7+ 宿主只有新名,按宿主世代取用。Medium 的默认 size 为 14,
7
+ * 与旧组件渲染尺寸一致。导出名横跨两个宿主世代,单一类型版本无法同时声明,两个
8
+ * 名字都按记录类型断言取用(图标无 props 渲染,本地结构类型即可)。
9
+ *
10
+ * 抽到这里避免 BillingDashboard 的 prop 拖一份图标解析;与 primitives import 一同
11
+ * 隔离到独立文件,purify 走 tsdown 内联安全清单时更易管控。
12
+ */
13
+ import type { ReactElement } from 'react';
14
+ type BillingIcon = () => ReactElement | null;
15
+ /** 运行时按宿主世代取用:0.1.7+ 走 Medium,旧名兜底。 */
16
+ export declare const BillingChevronDown: BillingIcon | undefined;
17
+ export {};
18
+ //# sourceMappingURL=host-version.d.ts.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * v1.5 Tab 内联 SVG 图标(14×14,无外部依赖;用 stroke="currentColor" 复用单 CSS 规则)。
3
+ * 抽到独立文件让 UsageBilling.tsx 体积下降;每个图标是 React.ReactNode,可被
4
+ * `<span aria-hidden>{icon}</span>` 包装嵌入。
5
+ */
6
+ import type { ReactNode } from 'react';
7
+ import type { DashboardTab } from './types.ts';
8
+ export declare const TAB_ICONS: Record<DashboardTab, ReactNode>;
9
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 渲染层纯函数:健康点、订阅状态文本、订阅窗口标签、中转站程序类型、厂商组
3
+ * 费用合计、子智能体后代合计、本地时钟。这些函数都返回字符串/数字/CSS
4
+ * className,依赖 CSS module 提供的样式——抽到独立文件后 import 仍走
5
+ * `UsageBilling.module.css`。
6
+ */
7
+ import type { ModelHealth, ModelRow, ProviderBillingGroup, RelayQuota, SessionBillingRow, SubscriptionQuota } from './types.ts';
8
+ import type { UsageBillingKey } from '../locales.ts';
9
+ /** Resolve one provider's dot state: green when live, red when failed, gray when unknown. */
10
+ export declare function providerDot(health: ModelHealth, provider: string): string | undefined;
11
+ /** 订阅额度查询状态的文案(ok 时无需额外标注,返回空串)。 */
12
+ export declare function subscriptionStatusText(status: SubscriptionQuota['status'], t: (key: UsageBillingKey) => string): string;
13
+ /** 订阅额度窗口的类型标签(本次 / 本周 / 本月 / 计费周期)。 */
14
+ export declare function subscriptionWindowLabel(kind: SubscriptionQuota['windows'][number]['kind'], t: (key: UsageBillingKey) => string): string;
15
+ /** 中转站程序类型的徽标文案(New API / Sub2API / 未识别)。 */
16
+ export declare function relayKindText(kind: RelayQuota['kind'], t: (key: UsageBillingKey) => string): string;
17
+ /** 中转站程序类型对应的样式类(复用站点类别配色)。 */
18
+ export declare const RELAY_KIND_CLASS: Record<RelayQuota['kind'], string | undefined>;
19
+ /**
20
+ * 厂商组费用合计(实际优先;订阅豁免行不计入)——付费者视角的一级信息(issue #34)。
21
+ * 订阅豁免行无 actual,其 estimated 是「按量等价」而非支出:计入组头会渲染出
22
+ * 「已豁免还要花钱」的误导(issue #37 的 grok 组头部 ¥383.6),预估语义保留在
23
+ * 模型行的订阅卡(「套餐内预估开销」)。
24
+ */
25
+ export declare const providerCostOf: (group: ProviderBillingGroup) => number;
26
+ /** 组行(单行或同标题合并组)的后代子智能体合计:合并组对成员段的 subCost/subCalls 求和。 */
27
+ export declare function subFamilyOf(row: SessionBillingRow): {
28
+ cost: number;
29
+ calls: number;
30
+ };
31
+ export type { ModelRow };
32
+ /** 本地时钟 `HH:MM:SS`:本仓时区展示用。 */
33
+ export declare function formatClock(time: number): string;
34
+ //# sourceMappingURL=kpi.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * U-3 按模型预算的纯函数:本月每模型消耗聚合与预算档位判定。
3
+ * 导出供测试。
4
+ */
5
+ /** 本月每模型消耗:byDayModels(day×model)按月前缀归并 cost。 */
6
+ export declare function monthCostByModel(byDayModels: Record<string, Record<string, {
7
+ cost: number;
8
+ }>> | undefined, monthPrefix: string): Record<string, number>;
9
+ /** 按模型预算档位(百分比):与全局预算的 BUDGET_ALERT_TIERS 分档口径一致。 */
10
+ export declare const MODEL_BUDGET_TIERS: readonly number[];
11
+ /** 本月消耗跨过的档位列表(升序);无预算或未跨档返回空。 */
12
+ export declare function crossedModelBudgetTiers(cost: number, budget: number): readonly number[];
13
+ //# sourceMappingURL=model-budget.d.ts.map