@kenz1117/dsh-ui-usage-billing 0.6.0 → 0.8.0
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/README.md +13 -5
- package/lib/client.js +775 -284
- package/lib/index.js +462 -19
- package/lib/types/balance.d.ts +17 -1
- package/lib/types/client/UsageBilling.d.ts +3 -0
- package/lib/types/client/budget-store.d.ts +3 -0
- package/lib/types/client/live-cost.d.ts +27 -1
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/client/plan-knowledge.d.ts +41 -0
- package/lib/types/client/pricing.d.ts +53 -0
- package/lib/types/index.d.ts +3 -1
- package/lib/types/plans.d.ts +39 -0
- package/lib/types/pricing-fetch.d.ts +9 -1
- package/lib/types/pricing-shared.d.ts +58 -0
- package/package.json +1 -1
|
@@ -9,9 +9,15 @@
|
|
|
9
9
|
* the current session id off the framework snapshot (`useSession` parent of
|
|
10
10
|
* `sessionId`) and matches `bySession` (session total) and `byTurn` (latest
|
|
11
11
|
* turn cost). Rendering is a pure function of the snapshot, never a side effect.
|
|
12
|
+
*
|
|
13
|
+
* The bar also carries two ambient signals: the current peak/off-peak pricing
|
|
14
|
+
* tier with a switch countdown (DeepSeek time-of-day pricing), and quota chips
|
|
15
|
+
* for subscription plans running low (≤20% remaining), so cost pressure is
|
|
16
|
+
* visible without opening the dashboard.
|
|
12
17
|
*/
|
|
13
18
|
import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
|
|
14
19
|
import type { ConversationSnapshot } from '@deepseek-ai/dsh-client-runtime/client';
|
|
20
|
+
import type { UsageBillingKey } from './locales.ts';
|
|
15
21
|
/** The usage-stats shape the composer bar needs (a thin slice, not the whole doc). */
|
|
16
22
|
export interface LiveStats {
|
|
17
23
|
bySession?: readonly {
|
|
@@ -24,6 +30,15 @@ export interface LiveStats {
|
|
|
24
30
|
cost: number;
|
|
25
31
|
}[];
|
|
26
32
|
}
|
|
33
|
+
/** 订阅额度的薄切片(/api/billing/subscriptions 响应的行)。 */
|
|
34
|
+
export interface QuotaSlice {
|
|
35
|
+
displayName: string;
|
|
36
|
+
status: string;
|
|
37
|
+
windows: readonly {
|
|
38
|
+
kind: string;
|
|
39
|
+
remainingPercent: number;
|
|
40
|
+
}[];
|
|
41
|
+
}
|
|
27
42
|
/**
|
|
28
43
|
* 当前会话累计费用:bySession 里会话 id 匹配的那行;缺省为 0。
|
|
29
44
|
* 导出供测试:纯函数。
|
|
@@ -41,11 +56,22 @@ export declare function sessionCostOf(stats: LiveStats | null, sessionId: string
|
|
|
41
56
|
* @returns 最新一轮费用(人民币元)。
|
|
42
57
|
*/
|
|
43
58
|
export declare function turnCostOf(stats: LiveStats | null, sessionId: string | undefined): number;
|
|
59
|
+
/**
|
|
60
|
+
* 低额度预警 chips:查询成功(ok)且任一窗口剩余 ≤ threshold 的套餐,
|
|
61
|
+
* 按剩余升序、最多 3 枚。导出供测试:纯函数。
|
|
62
|
+
* @param quotas - 订阅额度行切片。
|
|
63
|
+
* @param threshold - 剩余百分比阈值(默认 20%)。
|
|
64
|
+
*/
|
|
65
|
+
export declare function lowQuotaChips(quotas: readonly QuotaSlice[], threshold?: number): readonly {
|
|
66
|
+
name: string;
|
|
67
|
+
kind: string;
|
|
68
|
+
pct: number;
|
|
69
|
+
}[];
|
|
44
70
|
/** Props: the session-scope snapshot selector the framework injects. */
|
|
45
71
|
export interface LiveCostBarProps {
|
|
46
72
|
useSession: SnapshotSelectorHook<ConversationSnapshot>;
|
|
47
73
|
/** The owning dock's locale seat (bound to the billing NS). */
|
|
48
|
-
t: (key:
|
|
74
|
+
t: (key: UsageBillingKey) => string;
|
|
49
75
|
}
|
|
50
76
|
/**
|
|
51
77
|
* Render the live cost ticker for the current session.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Locale dictionaries for the usage billing surface. */
|
|
2
|
-
export type UsageBillingKey = 'billing.title' | 'billing.subtitle' | 'billing.cost' | 'billing.todayCost' | 'billing.monthCost' | 'billing.yearCost' | 'billing.monthProjected' | 'billing.liveTurn' | 'billing.liveSession' | 'billing.totalCost' | 'billing.calls' | 'billing.cacheHitRate' | 'billing.tokens' | 'billing.inputTokens' | 'billing.outputTokens' | 'billing.avgCost' | 'billing.trend' | 'billing.trend7d' | 'billing.trend30d' | 'billing.trendEmpty' | 'billing.budget' | 'billing.sessions' | 'billing.project' | 'billing.lastActive' | 'billing.sessionOverflow' | 'billing.budgetTierBody' | 'billing.models' | 'billing.providerBilling' | 'billing.estimated' | 'billing.actual' | 'billing.pricing' | 'billing.showPricing' | 'billing.hidePricing' | 'billing.pricePerM' | 'billing.input' | 'billing.output' | 'billing.cacheHit' | 'billing.peak' | 'billing.offPeak' | 'billing.flat' | 'billing.peakHours' | 'billing.band' | 'billing.openDashboard' | 'billing.close' | 'billing.lastUpdated' | 'billing.noData' | 'billing.todayRate' | 'billing.rateLive' | 'billing.rateBuiltin' | 'billing.balance' | 'billing.balanceUnconfigured' | 'billing.balanceUnauthorized' | 'billing.balanceUnreachable' | 'billing.uncatalogued' | 'billing.estimatedPricing' | 'billing.balanceDays' | 'billing.balanceLowBody' | 'billing.subscriptions' | 'billing.subscriptionNotConfigured' | 'billing.subscriptionUnauthorized' | 'billing.subscriptionUnavailable' | 'billing.subscriptionInvalid' | 'billing.subscriptionRateLimited' | 'billing.subscriptionSession' | 'billing.subscriptionWeekly' | 'billing.subscriptionMonthly' | 'billing.subscriptionBilling' | 'billing.subscriptionRemaining' | 'billing.subscriptionReset' | 'billing.subscriptionNoApi' | 'billing.heatmapLess' | 'billing.heatmapMore' | 'billing.currency' | 'billing.currencyCny' | 'billing.currencyUsd' | 'billing.heatmap' | 'billing.rounds' | 'billing.anomaly' | 'billing.workspaces' | 'billing.plan' | 'billing.remaining' | 'billing.unknownModel' | 'billing.model' | 'billing.currentRound' | 'billing.costAbbr' | 'billing.tabOverview' | 'billing.tabTrends' | 'billing.tabProviders' | 'billing.tabDetails' | 'billing.tabPricing' | 'billing.export' | 'billing.exportCsvDay' | 'billing.exportCsvSession' | 'billing.exportJson' | 'billing.peakShare' | 'billing.peakShareHint' | 'billing.weekCost' | 'billing.roleCost' | 'billing.roleUser' | 'billing.roleAssistant' | 'billing.roleTool' | 'billing.roleHint';
|
|
2
|
+
export type UsageBillingKey = 'billing.title' | 'billing.subtitle' | 'billing.cost' | 'billing.todayCost' | 'billing.monthCost' | 'billing.yearCost' | 'billing.monthProjected' | 'billing.liveTurn' | 'billing.liveSession' | 'billing.totalCost' | 'billing.calls' | 'billing.cacheHitRate' | 'billing.tokens' | 'billing.inputTokens' | 'billing.outputTokens' | 'billing.avgCost' | 'billing.trend' | 'billing.trend7d' | 'billing.trend30d' | 'billing.trendEmpty' | 'billing.budget' | 'billing.sessions' | 'billing.project' | 'billing.lastActive' | 'billing.sessionOverflow' | 'billing.budgetTierBody' | 'billing.models' | 'billing.providerBilling' | 'billing.estimated' | 'billing.actual' | 'billing.pricing' | 'billing.showPricing' | 'billing.hidePricing' | 'billing.pricePerM' | 'billing.input' | 'billing.output' | 'billing.cacheHit' | 'billing.peak' | 'billing.offPeak' | 'billing.flat' | 'billing.peakHours' | 'billing.band' | 'billing.openDashboard' | 'billing.close' | 'billing.lastUpdated' | 'billing.noData' | 'billing.todayRate' | 'billing.rateLive' | 'billing.rateBuiltin' | 'billing.balance' | 'billing.balanceUnconfigured' | 'billing.balanceUnauthorized' | 'billing.balanceUnreachable' | 'billing.uncatalogued' | 'billing.estimatedPricing' | 'billing.balanceDays' | 'billing.balanceLowBody' | 'billing.subscriptions' | 'billing.subscriptionNotConfigured' | 'billing.subscriptionUnauthorized' | 'billing.subscriptionUnavailable' | 'billing.subscriptionInvalid' | 'billing.subscriptionRateLimited' | 'billing.subscriptionSession' | 'billing.subscriptionWeekly' | 'billing.subscriptionMonthly' | 'billing.subscriptionBilling' | 'billing.subscriptionRemaining' | 'billing.subscriptionExhausted' | 'billing.subscriptionReset' | 'billing.subscriptionNoApi' | 'billing.heatmapLess' | 'billing.heatmapMore' | 'billing.currency' | 'billing.currencyCny' | 'billing.currencyUsd' | 'billing.heatmap' | 'billing.rounds' | 'billing.anomaly' | 'billing.workspaces' | 'billing.plan' | 'billing.remaining' | 'billing.unknownModel' | 'billing.model' | 'billing.currentRound' | 'billing.costAbbr' | 'billing.tabOverview' | 'billing.tabTrends' | 'billing.tabProviders' | 'billing.tabDetails' | 'billing.tabPricing' | 'billing.export' | 'billing.exportCsvDay' | 'billing.exportCsvSession' | 'billing.exportJson' | 'billing.peakShare' | 'billing.peakShareHint' | 'billing.weekCost' | 'billing.roleCost' | 'billing.roleUser' | 'billing.roleAssistant' | 'billing.roleTool' | 'billing.roleHint' | 'billing.tierPeak' | 'billing.tierOff' | 'billing.tierToPeak' | 'billing.tierToOff' | 'billing.tierAlertEnterPeak' | 'billing.tierAlertEnterOff' | 'billing.planTypeCode' | 'billing.planTypeToken' | 'billing.subscriptionFeePerMonth';
|
|
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>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan-knowledge reference (adapted from dsh-spend's `knowledge.js`, MIT):
|
|
3
|
+
* billing-plan shape (code = subscription, token = usage) for known providers,
|
|
4
|
+
* plus official token rates as a pricing fallback for providers whose models
|
|
5
|
+
* are not covered by the built-in catalog or models.dev.
|
|
6
|
+
*
|
|
7
|
+
* The cost model follows dsh-spend's dual-basis:
|
|
8
|
+
* - `code` plan (OpenCode Go, Coding/Token plans, etc.): the monthly cost is
|
|
9
|
+
* the subscription fee, counted into the projected month total.
|
|
10
|
+
* - `token` plan (pay-as-you-go API providers): cost = tokens × unit price.
|
|
11
|
+
*
|
|
12
|
+
* We keep our own live-pricing path (models.dev + OpenRouter) for token plans;
|
|
13
|
+
* this table only fills the subscription amount, the plan type, and a fallback
|
|
14
|
+
* rate for the few models those live sources may miss.
|
|
15
|
+
*/
|
|
16
|
+
/** Plan type: code = subscription + quota, token = per-token usage. */
|
|
17
|
+
export type PlanType = 'code' | 'token';
|
|
18
|
+
/** One plan row: provider id (after alias) → plan shape + optional subscription fee. */
|
|
19
|
+
export interface PlanKnowledgeEntry {
|
|
20
|
+
type: PlanType;
|
|
21
|
+
/** 订阅月费(人民币元);code 计划用,计入「本月预计」。 */
|
|
22
|
+
subscriptionCny?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 订阅/计划 provider id → plan 知识(引用 dsh-spend 的 code/token 双口径)。
|
|
26
|
+
* 覆盖我们实际会识别到的订阅通道;其余按量 API 不计入此表(默认 token)。
|
|
27
|
+
*/
|
|
28
|
+
export declare const PLAN_KNOWLEDGE: Readonly<Record<string, PlanKnowledgeEntry>>;
|
|
29
|
+
/** provider id(llm-pi-ai 设置键)→ plan 知识;未命中默认 token。 */
|
|
30
|
+
export declare function planTypeOf(providerId: string): PlanType;
|
|
31
|
+
/** 订阅月费(人民币元);非 code 或未配置时为 0。 */
|
|
32
|
+
export declare function subscriptionCnyOf(providerId: string): number;
|
|
33
|
+
export interface FallbackRate {
|
|
34
|
+
/** 归一化模型 id(计费键,与 catalogEntries 的 key 同口径)。 */
|
|
35
|
+
key: string;
|
|
36
|
+
input: number;
|
|
37
|
+
cacheHit: number;
|
|
38
|
+
output: number;
|
|
39
|
+
}
|
|
40
|
+
export declare const FALLBACK_RATES: readonly FallbackRate[];
|
|
41
|
+
//# sourceMappingURL=plan-knowledge.d.ts.map
|
|
@@ -27,6 +27,22 @@ export declare const USD_TO_CNY = 6.79;
|
|
|
27
27
|
* @param pricing - the `/api/billing/pricing` response.
|
|
28
28
|
*/
|
|
29
29
|
export declare function applyLivePricing(pricing: LivePricing): void;
|
|
30
|
+
/**
|
|
31
|
+
* 注入探活得到的「系统里实际配置/预制的模型」清单(host 的 llm.models 返回
|
|
32
|
+
* groups[].models[],含模型 id/name,无价格)。费率表据此对标现实可用模型——
|
|
33
|
+
* 有价的补价(内置目录 / models.dev 补充),无价的标「未收录」。纯内存状态,
|
|
34
|
+
* 供 `catalogEntries()` 渲染。
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyLiveCatalogModels(models: readonly CatalogModel[]): void;
|
|
37
|
+
/** 探活模型清单条目(host 的 ModelCatalogModel 投影出需要的字段)。 */
|
|
38
|
+
export interface CatalogModel {
|
|
39
|
+
/** 模型 id(如 `deepseek-v4-flash`)。 */
|
|
40
|
+
id: string;
|
|
41
|
+
/** 显示名;缺省用 id。 */
|
|
42
|
+
name?: string;
|
|
43
|
+
/** 厂商显示名(探活 group 名)。 */
|
|
44
|
+
provider: string;
|
|
45
|
+
}
|
|
30
46
|
/**
|
|
31
47
|
* 当前生效的 USD → CNY 汇率及其来源:live = 启动时实时拉取成功,
|
|
32
48
|
* builtin = 实时拉取失败、正在用内置默认值。
|
|
@@ -52,6 +68,30 @@ export declare function isPeakHour(beijingHour: number): boolean;
|
|
|
52
68
|
* @param timeMs - Unix epoch 毫秒;null/undefined/NaN 视为未知。
|
|
53
69
|
*/
|
|
54
70
|
export declare function tierAt(timeMs: number | null | undefined): PriceTierId;
|
|
71
|
+
/**
|
|
72
|
+
* 当前峰谷档位与距下次切换的时长。导出供测试:纯函数。
|
|
73
|
+
* @param nowMs - 当前时刻(epoch 毫秒)。
|
|
74
|
+
* @returns 当前档位与到下一个切换边界的毫秒数。
|
|
75
|
+
*/
|
|
76
|
+
export declare function tierCountdown(nowMs: number): {
|
|
77
|
+
tier: PriceTierId;
|
|
78
|
+
nextSwitchInMs: number;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* 峰/谷切换预告:距下次切换不足 leadMs 时返回即将进入的档位与切换时刻,
|
|
82
|
+
* 否则 null。导出供测试:纯函数。
|
|
83
|
+
* @param nowMs - 当前时刻(epoch 毫秒)。
|
|
84
|
+
* @param leadMs - 提前量(毫秒)。
|
|
85
|
+
*/
|
|
86
|
+
export declare function upcomingTierSwitch(nowMs: number, leadMs: number): {
|
|
87
|
+
entering: PriceTierId;
|
|
88
|
+
atMs: number;
|
|
89
|
+
} | null;
|
|
90
|
+
/**
|
|
91
|
+
* 切换倒计时短格式:`1h23m` / `45m` / `3m`。导出供测试:纯函数。
|
|
92
|
+
* @param ms - 剩余毫秒数。
|
|
93
|
+
*/
|
|
94
|
+
export declare function formatSwitchCountdown(ms: number): string;
|
|
55
95
|
/** Usage buckets consumed by one model (counts in raw tokens). */
|
|
56
96
|
export interface TokenUsageBuckets {
|
|
57
97
|
/** Uncached input tokens. */
|
|
@@ -100,6 +140,8 @@ export interface ModelEntry {
|
|
|
100
140
|
* 展示时标注以免误当正式定价;正式定价公布后移除。
|
|
101
141
|
*/
|
|
102
142
|
estimated?: boolean;
|
|
143
|
+
/** 探活命中但无内置/models.dev 价:费率表标「未收录」,不参与计价。 */
|
|
144
|
+
uncatalogued?: boolean;
|
|
103
145
|
}
|
|
104
146
|
/**
|
|
105
147
|
* Built-in catalog of current mainstream models as of 2026-08-16, priced from
|
|
@@ -126,6 +168,17 @@ export declare const MODEL_CATALOG: readonly ModelEntry[];
|
|
|
126
168
|
export declare const MODEL_KEY_ALIASES: Readonly<Record<string, string>>;
|
|
127
169
|
/** Lookup a model by its stats key; falls back to the generic `other` entry. */
|
|
128
170
|
export declare function modelOf(key: string): ModelEntry;
|
|
171
|
+
/**
|
|
172
|
+
* 模型是否可计价:内置目录、models.dev 补充、或 dsh-spend 官方价兜底命中。
|
|
173
|
+
* 聚合层的计价闸门(目录外模型不产生费用,避免兜底档误估)。
|
|
174
|
+
*/
|
|
175
|
+
export declare function isPriced(key: string): boolean;
|
|
176
|
+
/**
|
|
177
|
+
* 费率表渲染的完整目录:内置 + models.dev 补充条目 + 探活模型(无价标记)。
|
|
178
|
+
* 探活模型去重(按归一化 id):内置/补充已有的不再重复;无价的保留并标记
|
|
179
|
+
* `uncatalogued`,费率表据此显示「未收录」。
|
|
180
|
+
*/
|
|
181
|
+
export declare function catalogEntries(): readonly ModelEntry[];
|
|
129
182
|
/** Resolve a price-table row by its CSS variable name (theme token or fallback color). */
|
|
130
183
|
export declare function resolveToken(name: string): string;
|
|
131
184
|
/**
|
package/lib/types/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import type { Context } from '@deepseek-ai/cordis';
|
|
13
13
|
import type { CredentialProvider } from '@deepseek-ai/dsh-credentials';
|
|
14
14
|
import type { SettingsProvider } from '@deepseek-ai/dsh-settings';
|
|
15
|
-
import type { SubscriptionPlanConfig } from './pricing-shared.ts';
|
|
15
|
+
import type { CustomBalanceConfig, SubscriptionPlanConfig } from './pricing-shared.ts';
|
|
16
16
|
import { type IdentifiedSubscriptionPlan, type SubscriptionKeys } from './subscriptions.ts';
|
|
17
17
|
/** Plugin configuration. */
|
|
18
18
|
export interface UsageBillingConfig {
|
|
@@ -29,6 +29,8 @@ export interface UsageBillingConfig {
|
|
|
29
29
|
/** 余额不足告警阈值(人民币元):余额低于此值时仪表盘每天提醒一次;
|
|
30
30
|
不设置则客户端按默认阈值(50 元)兜底。 */
|
|
31
31
|
lowBalanceThreshold?: number;
|
|
32
|
+
/** 自定义 Provider 余额查询(任意 HTTP 端点 + extract 规则,适配 NewApi/LiteLLM 等)。 */
|
|
33
|
+
customBalances?: readonly CustomBalanceConfig[];
|
|
32
34
|
}
|
|
33
35
|
/** Required services: the web server, the persisted session log store, and user settings. */
|
|
34
36
|
export declare const inject: string[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 供应商计费计划知识库(对标 dsh-spend 的 PROVIDER_KNOWLEDGE / PROVIDER_ALIASES)。
|
|
3
|
+
*
|
|
4
|
+
* 每个 provider 归入两种计费口径之一:
|
|
5
|
+
* - `code` —— 订阅制(coding / token / agent plan):费用 = 订阅月费,额度按周期
|
|
6
|
+
* 计量,token 用量不计费(不按 token 扣钱)。
|
|
7
|
+
* - `token` —— 按量制:费用 = token × 单价(由 models.dev / OpenRouter / 内置目录
|
|
8
|
+
* 定价)。无知识库命中的 provider 默认按 token 口径。
|
|
9
|
+
*
|
|
10
|
+
* `aliasOf` 把部署里杂乱的 provider id(glm / kimi / dashscope…)归一化到知识库键,
|
|
11
|
+
* `planOf` 据此返回计费计划;日志出现的 provider 经此自动识别,无需人工配置。
|
|
12
|
+
*/
|
|
13
|
+
/** 计费口径:code = 订阅制(计月费),token = 按量制(计 token 单价)。 */
|
|
14
|
+
export type BillingPlanKind = 'code' | 'token';
|
|
15
|
+
/** 订阅月费的币种(只支持单一币种计费,与仪表盘币种一致)。 */
|
|
16
|
+
export type BillingCurrency = 'CNY' | 'USD';
|
|
17
|
+
/** 一个 provider 的计费计划。 */
|
|
18
|
+
export interface BillingPlan {
|
|
19
|
+
/** 计费口径。 */
|
|
20
|
+
kind: BillingPlanKind;
|
|
21
|
+
/** 厂商显示名(未命中知识库时用 provider id 原样)。 */
|
|
22
|
+
label: string;
|
|
23
|
+
/** code 计划的订阅月费(单位 {@link currency});token 计划无此项。 */
|
|
24
|
+
subscriptionMonthly?: number;
|
|
25
|
+
/** 订阅月费币种。 */
|
|
26
|
+
currency?: BillingCurrency;
|
|
27
|
+
/** 订阅额度周期(天);额度按此周期计量。 */
|
|
28
|
+
periodDays?: number;
|
|
29
|
+
}
|
|
30
|
+
/** 归一化 provider id 到知识库键;未命中的原样返回(避免误吞)。 */
|
|
31
|
+
export declare function aliasOf(provider: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* 某 provider 的计费计划:命中的 code 计划返回订阅口径,`PROVIDER_LABELS` 命中的
|
|
34
|
+
* 按量厂商返回 token 口径(无月费);完全未知返回 undefined(调用方按 token 兜底)。
|
|
35
|
+
*/
|
|
36
|
+
export declare function planOf(provider: string): BillingPlan | undefined;
|
|
37
|
+
/** 是否已知为订阅制(code)provider。 */
|
|
38
|
+
export declare function isCodePlan(provider: string): boolean;
|
|
39
|
+
//# sourceMappingURL=plans.d.ts.map
|
|
@@ -7,7 +7,15 @@
|
|
|
7
7
|
* half caches whatever succeeded and the browser dashboard falls back to the
|
|
8
8
|
* catalog for the rest — a total outage answers `{ source: 'builtin' }`.
|
|
9
9
|
*/
|
|
10
|
-
import type { LivePricing } from './pricing-shared.ts';
|
|
10
|
+
import type { ExtraModelPrice, LivePricing } from './pricing-shared.ts';
|
|
11
|
+
/**
|
|
12
|
+
* models.dev 响应 → 目录外补充条目。不再按厂商白名单过滤:凡是有有效
|
|
13
|
+
* cost 的模型都纳入(探活模型可能来自任何预制厂商,白名单会漏掉)。厂商
|
|
14
|
+
* 显示名优先取映射,未命中用 provider id。导出供测试:纯函数。
|
|
15
|
+
* @param data - `https://models.dev/api.json` 的响应体。
|
|
16
|
+
* @returns 补充条目(按 provider 顺序稳定;仅含可计价的模型)。
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildExtraModels(data: unknown): ExtraModelPrice[];
|
|
11
19
|
/**
|
|
12
20
|
* Fetch the live pricing once at boot. Both upstreams run in parallel; a
|
|
13
21
|
* failure in either degrades independently to the built-in value.
|
|
@@ -21,6 +21,22 @@ export interface LivePricing {
|
|
|
21
21
|
rate?: number;
|
|
22
22
|
/** Overrides keyed by built-in catalog key (present when router matches succeeded). */
|
|
23
23
|
prices?: Record<string, LivePrice>;
|
|
24
|
+
/**
|
|
25
|
+
* models.dev 补充的目录外模型价(USD / 1M tokens):与宿主预制提供方对齐——
|
|
26
|
+
* pi-ai 预制目录的上游就是 models.dev,补进来的条目让「提供方支持但我们的
|
|
27
|
+
* 内置目录未收录」的模型也能计价并出现在费率表。
|
|
28
|
+
*/
|
|
29
|
+
extraModels?: readonly ExtraModelPrice[];
|
|
30
|
+
}
|
|
31
|
+
/** models.dev 补充的目录外模型价(USD / 1M tokens)。 */
|
|
32
|
+
export interface ExtraModelPrice {
|
|
33
|
+
/** 归一化模型 id(计费键,如 `deepseek-v4.5-flash`)。 */
|
|
34
|
+
key: string;
|
|
35
|
+
/** 显示名。 */
|
|
36
|
+
name: string;
|
|
37
|
+
/** 厂商显示名(与仪表盘厂商组同口径)。 */
|
|
38
|
+
provider: string;
|
|
39
|
+
price: LivePrice;
|
|
24
40
|
}
|
|
25
41
|
/** 余额查询失败的原因,前端据此显示文案。 */
|
|
26
42
|
export type BalanceError = 'unconfigured' | 'unauthorized' | 'unreachable';
|
|
@@ -72,6 +88,14 @@ export interface SubscriptionQuota {
|
|
|
72
88
|
status: SubscriptionStatus;
|
|
73
89
|
/** Quota windows, newest-window first; empty when the query failed. */
|
|
74
90
|
windows: readonly SubscriptionWindow[];
|
|
91
|
+
/**
|
|
92
|
+
* 计费计划类型(引用 dsh-spend 的双口径):
|
|
93
|
+
* - `code` 订阅制:月度费用按订阅月费计入(dsh-spend 的 subscription);
|
|
94
|
+
* - `token` 按量计费:按 token × 单价估算(dsh-spend 的 token plan)。
|
|
95
|
+
*/
|
|
96
|
+
planType?: 'code' | 'token';
|
|
97
|
+
/** 订阅月费(人民币元;code 计划用,计入「本月预计」)。 */
|
|
98
|
+
subscriptionAmount?: number;
|
|
75
99
|
}
|
|
76
100
|
/** Response of `/api/billing/subscriptions`. */
|
|
77
101
|
export interface SubscriptionResponse {
|
|
@@ -86,4 +110,38 @@ export interface SubscriptionPlanConfig {
|
|
|
86
110
|
/** Z.ai region override; defaults to the settings-namespace `zaiRegion`. */
|
|
87
111
|
region?: 'global' | 'bigmodel-cn';
|
|
88
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* 余额提取规则:从响应 JSON 取数。
|
|
115
|
+
* - `const`:数字常量;
|
|
116
|
+
* - `path`:点路径取值(如 `data.total_available`);
|
|
117
|
+
* - `op: 'add' | 'subtract'` + `paths`:多路径加 / 减;
|
|
118
|
+
* - `op: 'divide'` + `path` + `by`:按除数缩放(适配 NewApi 等 quota 端点,
|
|
119
|
+
* 如 1 USD = 500000 quota)。
|
|
120
|
+
*/
|
|
121
|
+
export interface CustomBalanceExtract {
|
|
122
|
+
const?: number;
|
|
123
|
+
path?: string;
|
|
124
|
+
op?: 'add' | 'subtract' | 'divide';
|
|
125
|
+
paths?: readonly string[];
|
|
126
|
+
by?: number;
|
|
127
|
+
}
|
|
128
|
+
/** 一个自定义 Provider 余额查询配置(插件 config 的 `customBalances` 条目)。 */
|
|
129
|
+
export interface CustomBalanceConfig {
|
|
130
|
+
/** 显示名(中文)。 */
|
|
131
|
+
label: string;
|
|
132
|
+
/** 显示名(英文);缺省用 label。 */
|
|
133
|
+
labelEn?: string;
|
|
134
|
+
/** 余额币种(如 CNY / USD);缺省 CNY。 */
|
|
135
|
+
unit?: string;
|
|
136
|
+
/** 查询端点(完整 URL)。 */
|
|
137
|
+
url: string;
|
|
138
|
+
/** HTTP 方法;缺省 GET。 */
|
|
139
|
+
method?: string;
|
|
140
|
+
/** 请求头;值支持 `{{ENV_NAME}}` 占位符,经凭据 seam 解析(仅请求头支持)。 */
|
|
141
|
+
headers?: Record<string, string>;
|
|
142
|
+
/** 余额提取规则。 */
|
|
143
|
+
extract: {
|
|
144
|
+
remaining: CustomBalanceExtract;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
89
147
|
//# sourceMappingURL=pricing-shared.d.ts.map
|
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": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|