@rayadesu/dsh-client-ui-billing 0.1.0-rc.8 → 0.2.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.i18n.yaml +2 -2
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/lib/client.js +160 -51
- package/lib/types/client/BalanceBadge.d.ts +6 -2
- package/lib/types/client/locales.d.ts +1 -1
- package/package.json +9 -9
- package/LICENSE +0 -21
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# last confirmed-consistent state. Both languages carry equal authority; after
|
|
3
3
|
# editing either side, bring the other along and re-record both hashes with:
|
|
4
4
|
# git hash-object README.md README.zh.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 8672854e338576b027810cbfe8bf1a976ffa0824
|
|
6
|
+
README.zh.md: 6c7e0cbd95094d437535def3f2d5d01d5bc98f6c
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ English | [中文](README.zh.md)
|
|
|
4
4
|
|
|
5
5
|
Web billing feature owner: contributes one entry to `conversation.session.header.utilities` that mounts its own `billing` Remote, reads the DeepSeek account balance, this session's billed spend, and today's spend across every session through `billing/getBalance`, `billing/getSessionSpend`, and `billing/getTodaySpend`, and renders them as a top-right label box. The host half of the capability lives in [`dsh-llm-billing`](../llm-billing/README.md), which owns the `/user/balance` transport, the peak/off-peak pricing table, and the `billing` Remote namespace; this package mounts that Remote and renders what it returns.
|
|
6
6
|
|
|
7
|
-
The trigger shows two lines — the remaining balance and this conversation's billed spend ("本轮对话花费 ¥X") — and renders nothing while the first fetch is in flight. Clicking it opens a label box with the remaining amount, this session's billed spend (本会话花费, priced per message at the official peak/off-peak rate) with today's all-session spend beside it (今日共花费), one priced row per model with the cache-hit / cache-miss-input / output cost breakdown ("缓存命中 ¥X · 未命中输入 ¥Y · 输出 ¥Z"), a manual refresh action, and a spend disclaimer. Refreshing keeps the last values visible rather than blanking them, and a refresh failure retains the last good value. A session or day without priced usage shows a "no usage recorded" word rather than a fabricated figure. A failure — no API key configured, a rejected credential, a transport error — renders a muted "Balance unavailable" word whose tooltip carries the Remote's own error message.
|
|
7
|
+
The trigger shows two lines — the remaining balance and this conversation's billed spend ("本轮对话花费 ¥X") — and renders nothing while the first fetch is in flight. Clicking it opens a label box with the remaining amount, this session's billed spend (本会话花费, priced per message at the official peak/off-peak rate — peak windows apply weekdays Mon–Fri only, weekends are off-peak) with today's all-session spend beside it (今日共花费), one priced row per model with the cache-hit / cache-miss-input / output cost breakdown ("缓存命中 ¥X · 未命中输入 ¥Y · 输出 ¥Z"), a manual refresh action, and a spend disclaimer. Refreshing keeps the last values visible rather than blanking them, and a refresh failure retains the last good value. A session or day without priced usage shows a "no usage recorded" word rather than a fabricated figure. A failure — no API key configured, a rejected credential, a transport error — renders a muted "Balance unavailable" word whose tooltip carries the Remote's own error message.
|
|
8
8
|
|
|
9
9
|
The badge is account-level even though the slot is session-scoped: the header utilities row is simply the one always-visible title-bar seat the shell offers, and the balance it shows does not vary by session — but the spend lines do, because they price the current session's own token usage through `billing/getSessionSpend` and every session's usage through `billing/getTodaySpend`. Copy goes through the package's own `billing` locale namespace; styling uses tokens only.
|
|
10
10
|
|
|
@@ -12,9 +12,9 @@ The badge is account-level even though the slot is session-scoped: the header ut
|
|
|
12
12
|
|
|
13
13
|
The spends follow the conversation and the balance stays a manual snapshot:
|
|
14
14
|
|
|
15
|
-
- **Spends follow new messages** — the component subscribes to the current session's message count through the framework `useSession` seat. When a new message lands, it recomputes this session's spend (`billing/getSessionSpend`) and today's spend (`billing/getTodaySpend`), local pricing passes with no network request, so the spend lines stay live during an ongoing conversation.
|
|
15
|
+
- **Spends follow new messages, debounced** — the component subscribes to the current session's message count through the framework `useSession` seat. When a new message lands, it recomputes this session's spend (`billing/getSessionSpend`) and today's spend (`billing/getTodaySpend`), local pricing passes with no network request, so the spend lines stay live during an ongoing conversation. The recompute is debounced for two seconds, so a burst of messages (a streaming agent turn) prices once instead of once per message; the host-side cache (see `dsh-llm-billing`) then serves the first miss for the rest of the minute.
|
|
16
16
|
- **Balance is manual** — the account balance is fetched on mount, on session switch, and on the explicit refresh action (`billing/getBalance`). There is no polling and no automatic refetch: the balance line only changes when one of those events happens.
|
|
17
|
-
- **Refresh keeps the last values** — an in-flight refresh leaves the previous values on screen, and a failed refresh retains the last good value instead of blanking it.
|
|
17
|
+
- **Refresh keeps the last values** — an in-flight refresh leaves the previous values on screen, and a failed refresh retains the last good value instead of blanking it. The refresh action calls `billing/getTodaySpend(true)`, which bypasses the host-side cache; the message-triggered recompute and the mount/session-switch read use the cached path.
|
|
18
18
|
|
|
19
19
|
## Model Experience
|
|
20
20
|
|
package/README.zh.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Web 额度特性的归属方:向 `conversation.session.header.utilities` 贡献一个条目,自己挂载 `billing` Remote,通过 `billing/getBalance`、`billing/getSessionSpend` 与 `billing/getTodaySpend` 读取 DeepSeek 账户余额、本会话的计费花费与今日所有会话的计费花费,并在右上角渲染成一个标签框。该能力的宿主侧在 [`dsh-llm-billing`](../llm-billing/README.md),它拥有 `/user/balance` 传输、峰谷计价表与 `billing` Remote 命名空间;本包挂载那个 Remote 并渲染它返回的内容。
|
|
6
6
|
|
|
7
|
-
触发器显示两行——剩余额度与本轮对话的计费花费(「本轮对话花费 ¥X
|
|
7
|
+
触发器显示两行——剩余额度与本轮对话的计费花费(「本轮对话花费 ¥X」)——首个请求在途时不渲染任何东西。点击后展开一个标签框:剩余金额、本会话的计费花费(本会话花费,按官方峰/谷单价逐条消息计价——高峰窗口仅周一至周五适用,周末按低谷价——右侧并列今日所有会话的合计「今日共花费」)、每个模型一行的花费及其缓存命中/未命中输入/输出分项(「缓存命中 ¥X · 未命中输入 ¥Y · 输出 ¥Z」)、手动刷新按钮与花费说明。刷新时旧值不消失,刷新失败保留上一次有效值。没有可计价消耗的会话或日子显示「暂无消耗记录」而不是编造数字。失败——未配置 API key、凭据被拒绝、传输错误——渲染弱化的「额度不可用」,其提示携带 Remote 自己的错误信息。
|
|
8
8
|
|
|
9
9
|
角标是账户级的,尽管插槽是会话作用域:顶栏工具行不过是外壳提供的那个始终可见的标题栏席位,余额并不随会话变化——但花费行会,因为它通过 `billing/getSessionSpend` 按当前会话自己的 token 用量计价、通过 `billing/getTodaySpend` 按所有会话的用量计价。文案走本包自己的 `billing` locale 命名空间;样式只用 token。
|
|
10
10
|
|
|
@@ -12,9 +12,9 @@ Web 额度特性的归属方:向 `conversation.session.header.utilities` 贡
|
|
|
12
12
|
|
|
13
13
|
花费跟随会话、额度保持手动快照:
|
|
14
14
|
|
|
15
|
-
-
|
|
15
|
+
- **花费随新消息自动更新(去抖)** —— 组件通过框架 `useSession` 座位订阅当前会话的消息数。每到达一条新消息,就只重算**本会话的花费**(`billing/getSessionSpend`)与**今日共花费**(`billing/getTodaySpend`,纯本地计价、不发网络请求),连续对话时花费行实时跟随。重算有 2 秒去抖,消息突发(流式 agent 回合)只计价一次;宿主侧缓存(见 `dsh-llm-billing`)随后在一分钟内服务首次未命中。
|
|
16
16
|
- **额度保持手动** —— 账户余额在挂载、切换会话、点刷新按钮时拉取(`billing/getBalance`)。**没有轮询、不会自动重拉**:余额行只在这几个时机变化。
|
|
17
|
-
- **刷新保留旧值** ——
|
|
17
|
+
- **刷新保留旧值** —— 刷新在途时旧值留在屏幕上,刷新失败保留上一次有效值,不清空。刷新按钮调用 `billing/getTodaySpend(true)`,绕过宿主侧缓存;消息触发的重算与挂载/切换会话的读取走缓存路径。
|
|
18
18
|
|
|
19
19
|
## 模型体验
|
|
20
20
|
|
package/lib/client.js
CHANGED
|
@@ -613,6 +613,7 @@ window.__ModuleLoader__.load({
|
|
|
613
613
|
const integer = /^-?\d+$/;
|
|
614
614
|
const number$1 = /^-?\d+(?:\.\d+)?$/;
|
|
615
615
|
const boolean$1 = /^(?:true|false)$/i;
|
|
616
|
+
const _undefined$2 = /^undefined$/i;
|
|
616
617
|
const lowercase = /^[^A-Z]*$/;
|
|
617
618
|
const uppercase = /^[^a-z]*$/;
|
|
618
619
|
//#endregion
|
|
@@ -1425,6 +1426,22 @@ window.__ModuleLoader__.load({
|
|
|
1425
1426
|
return payload;
|
|
1426
1427
|
};
|
|
1427
1428
|
});
|
|
1429
|
+
const $ZodUndefined = /*@__PURE__*/ $constructor("$ZodUndefined", (inst, def) => {
|
|
1430
|
+
$ZodType.init(inst, def);
|
|
1431
|
+
inst._zod.pattern = _undefined$2;
|
|
1432
|
+
inst._zod.values = new Set([void 0]);
|
|
1433
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
1434
|
+
const input = payload.value;
|
|
1435
|
+
if (typeof input === "undefined") return payload;
|
|
1436
|
+
payload.issues.push({
|
|
1437
|
+
expected: "undefined",
|
|
1438
|
+
code: "invalid_type",
|
|
1439
|
+
input,
|
|
1440
|
+
inst
|
|
1441
|
+
});
|
|
1442
|
+
return payload;
|
|
1443
|
+
};
|
|
1444
|
+
});
|
|
1428
1445
|
const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => {
|
|
1429
1446
|
$ZodType.init(inst, def);
|
|
1430
1447
|
inst._zod.parse = (payload) => payload;
|
|
@@ -1886,6 +1903,24 @@ window.__ModuleLoader__.load({
|
|
|
1886
1903
|
return payload;
|
|
1887
1904
|
};
|
|
1888
1905
|
});
|
|
1906
|
+
const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => {
|
|
1907
|
+
$ZodType.init(inst, def);
|
|
1908
|
+
if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values");
|
|
1909
|
+
const values = new Set(def.values);
|
|
1910
|
+
inst._zod.values = values;
|
|
1911
|
+
inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
|
|
1912
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
1913
|
+
const input = payload.value;
|
|
1914
|
+
if (values.has(input)) return payload;
|
|
1915
|
+
payload.issues.push({
|
|
1916
|
+
code: "invalid_value",
|
|
1917
|
+
values: def.values,
|
|
1918
|
+
input,
|
|
1919
|
+
inst
|
|
1920
|
+
});
|
|
1921
|
+
return payload;
|
|
1922
|
+
};
|
|
1923
|
+
});
|
|
1889
1924
|
const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => {
|
|
1890
1925
|
$ZodType.init(inst, def);
|
|
1891
1926
|
inst._zod.optin = "optional";
|
|
@@ -2464,6 +2499,13 @@ window.__ModuleLoader__.load({
|
|
|
2464
2499
|
});
|
|
2465
2500
|
}
|
|
2466
2501
|
// @__NO_SIDE_EFFECTS__
|
|
2502
|
+
function _undefined$1(Class, params) {
|
|
2503
|
+
return new Class({
|
|
2504
|
+
type: "undefined",
|
|
2505
|
+
...normalizeParams(params)
|
|
2506
|
+
});
|
|
2507
|
+
}
|
|
2508
|
+
// @__NO_SIDE_EFFECTS__
|
|
2467
2509
|
function _unknown(Class) {
|
|
2468
2510
|
return new Class({ type: "unknown" });
|
|
2469
2511
|
}
|
|
@@ -3012,6 +3054,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3012
3054
|
const booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
3013
3055
|
json.type = "boolean";
|
|
3014
3056
|
};
|
|
3057
|
+
const undefinedProcessor = (_schema, ctx, _json, _params) => {
|
|
3058
|
+
if (ctx.unrepresentable === "throw") throw new Error("Undefined cannot be represented in JSON Schema");
|
|
3059
|
+
};
|
|
3015
3060
|
const neverProcessor = (_schema, _ctx, json, _params) => {
|
|
3016
3061
|
json.not = {};
|
|
3017
3062
|
};
|
|
@@ -3022,6 +3067,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3022
3067
|
if (values.every((v) => typeof v === "string")) json.type = "string";
|
|
3023
3068
|
json.enum = values;
|
|
3024
3069
|
};
|
|
3070
|
+
const literalProcessor = (schema, ctx, json, _params) => {
|
|
3071
|
+
const def = schema._zod.def;
|
|
3072
|
+
const vals = [];
|
|
3073
|
+
for (const val of def.values) if (val === void 0) {
|
|
3074
|
+
if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
3075
|
+
} else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
3076
|
+
else vals.push(Number(val));
|
|
3077
|
+
else vals.push(val);
|
|
3078
|
+
if (vals.length === 0) {} else if (vals.length === 1) {
|
|
3079
|
+
const val = vals[0];
|
|
3080
|
+
json.type = val === null ? "null" : typeof val;
|
|
3081
|
+
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val];
|
|
3082
|
+
else json.const = val;
|
|
3083
|
+
} else {
|
|
3084
|
+
if (vals.every((v) => typeof v === "number")) json.type = "number";
|
|
3085
|
+
if (vals.every((v) => typeof v === "string")) json.type = "string";
|
|
3086
|
+
if (vals.every((v) => typeof v === "boolean")) json.type = "boolean";
|
|
3087
|
+
if (vals.every((v) => v === null)) json.type = "null";
|
|
3088
|
+
json.enum = vals;
|
|
3089
|
+
}
|
|
3090
|
+
};
|
|
3025
3091
|
const customProcessor = (_schema, ctx, _json, _params) => {
|
|
3026
3092
|
if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema");
|
|
3027
3093
|
};
|
|
@@ -3648,6 +3714,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3648
3714
|
function boolean(params) {
|
|
3649
3715
|
return /* @__PURE__ */ _boolean(ZodBoolean, params);
|
|
3650
3716
|
}
|
|
3717
|
+
const ZodUndefined = /*@__PURE__*/ $constructor("ZodUndefined", (inst, def) => {
|
|
3718
|
+
$ZodUndefined.init(inst, def);
|
|
3719
|
+
ZodType.init(inst, def);
|
|
3720
|
+
inst._zod.processJSONSchema = (ctx, json, params) => undefinedProcessor(inst, ctx, json, params);
|
|
3721
|
+
});
|
|
3722
|
+
function _undefined(params) {
|
|
3723
|
+
return /* @__PURE__ */ _undefined$1(ZodUndefined, params);
|
|
3724
|
+
}
|
|
3651
3725
|
const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => {
|
|
3652
3726
|
$ZodUnknown.init(inst, def);
|
|
3653
3727
|
ZodType.init(inst, def);
|
|
@@ -3823,6 +3897,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3823
3897
|
...normalizeParams(params)
|
|
3824
3898
|
});
|
|
3825
3899
|
}
|
|
3900
|
+
const ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => {
|
|
3901
|
+
$ZodLiteral.init(inst, def);
|
|
3902
|
+
ZodType.init(inst, def);
|
|
3903
|
+
inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params);
|
|
3904
|
+
inst.values = new Set(def.values);
|
|
3905
|
+
Object.defineProperty(inst, "value", { get() {
|
|
3906
|
+
if (def.values.length > 1) throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");
|
|
3907
|
+
return def.values[0];
|
|
3908
|
+
} });
|
|
3909
|
+
});
|
|
3910
|
+
function literal(value, params) {
|
|
3911
|
+
return new ZodLiteral({
|
|
3912
|
+
type: "literal",
|
|
3913
|
+
values: Array.isArray(value) ? value : [value],
|
|
3914
|
+
...normalizeParams(params)
|
|
3915
|
+
});
|
|
3916
|
+
}
|
|
3826
3917
|
const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => {
|
|
3827
3918
|
$ZodTransform.init(inst, def);
|
|
3828
3919
|
ZodType.init(inst, def);
|
|
@@ -3990,7 +4081,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3990
4081
|
}
|
|
3991
4082
|
//#endregion
|
|
3992
4083
|
//#region ../../llm/llm-billing/lib/typert.remote-client.js
|
|
3993
|
-
const
|
|
4084
|
+
const _rayadesu_dsh_llm_billing_billing_getBalance_result$schema = object({
|
|
3994
4085
|
"isAvailable": boolean(),
|
|
3995
4086
|
"lines": array(object({
|
|
3996
4087
|
"currency": string(),
|
|
@@ -3999,8 +4090,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3999
4090
|
"toppedUp": string()
|
|
4000
4091
|
}))
|
|
4001
4092
|
});
|
|
4002
|
-
const
|
|
4003
|
-
const
|
|
4093
|
+
const _rayadesu_dsh_llm_billing_billing_getSessionSpend_parameter_0$schema = intersection(string(), unknown());
|
|
4094
|
+
const _rayadesu_dsh_llm_billing_billing_getSessionSpend_result$schema = object({
|
|
4004
4095
|
"total": number(),
|
|
4005
4096
|
"models": array(object({
|
|
4006
4097
|
"model": string(),
|
|
@@ -4016,7 +4107,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4016
4107
|
"outputCost": number()
|
|
4017
4108
|
}))
|
|
4018
4109
|
});
|
|
4019
|
-
const
|
|
4110
|
+
const _rayadesu_dsh_llm_billing_billing_getTodaySpend_parameter_0$schema = union([
|
|
4111
|
+
_undefined(),
|
|
4112
|
+
literal(false),
|
|
4113
|
+
literal(true)
|
|
4114
|
+
]);
|
|
4115
|
+
const _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema = object({
|
|
4020
4116
|
"total": number(),
|
|
4021
4117
|
"models": array(object({
|
|
4022
4118
|
"model": string(),
|
|
@@ -4045,11 +4141,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4045
4141
|
result: {
|
|
4046
4142
|
mode: "strict",
|
|
4047
4143
|
typeSymbol: "@rayadesu/dsh-llm-billing/types#DeepSeekBalance",
|
|
4048
|
-
schema:
|
|
4144
|
+
schema: _rayadesu_dsh_llm_billing_billing_getBalance_result$schema
|
|
4049
4145
|
},
|
|
4050
4146
|
sourceLocation: {
|
|
4051
4147
|
"file": "packages/llm/llm-billing/src/balance.ts",
|
|
4052
|
-
"line":
|
|
4148
|
+
"line": 143,
|
|
4053
4149
|
"column": 3
|
|
4054
4150
|
}
|
|
4055
4151
|
},
|
|
@@ -4066,17 +4162,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4066
4162
|
codec: {
|
|
4067
4163
|
mode: "strict",
|
|
4068
4164
|
typeSymbol: "@deepseek-ai/dsh-session/types#SessionId",
|
|
4069
|
-
schema:
|
|
4165
|
+
schema: _rayadesu_dsh_llm_billing_billing_getSessionSpend_parameter_0$schema
|
|
4070
4166
|
}
|
|
4071
4167
|
}],
|
|
4072
4168
|
result: {
|
|
4073
4169
|
mode: "strict",
|
|
4074
4170
|
typeSymbol: "@rayadesu/dsh-llm-billing/types#DeepSeekSessionSpend",
|
|
4075
|
-
schema:
|
|
4171
|
+
schema: _rayadesu_dsh_llm_billing_billing_getSessionSpend_result$schema
|
|
4076
4172
|
},
|
|
4077
4173
|
sourceLocation: {
|
|
4078
4174
|
"file": "packages/llm/llm-billing/src/balance.ts",
|
|
4079
|
-
"line":
|
|
4175
|
+
"line": 154,
|
|
4080
4176
|
"column": 3
|
|
4081
4177
|
}
|
|
4082
4178
|
},
|
|
@@ -4086,23 +4182,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4086
4182
|
namespace: "billing",
|
|
4087
4183
|
method: "getTodaySpend",
|
|
4088
4184
|
invocation: { kind: "direct" },
|
|
4089
|
-
parameters: [
|
|
4185
|
+
parameters: [{
|
|
4186
|
+
name: "force",
|
|
4187
|
+
wire: "force",
|
|
4188
|
+
source: "json",
|
|
4189
|
+
acceptsUndefined: true,
|
|
4190
|
+
codec: {
|
|
4191
|
+
mode: "strict",
|
|
4192
|
+
typeSymbol: "@rayadesu/dsh-llm-billing#billing/getTodaySpend:force",
|
|
4193
|
+
schema: _rayadesu_dsh_llm_billing_billing_getTodaySpend_parameter_0$schema
|
|
4194
|
+
}
|
|
4195
|
+
}],
|
|
4090
4196
|
result: {
|
|
4091
4197
|
mode: "strict",
|
|
4092
4198
|
typeSymbol: "@rayadesu/dsh-llm-billing/types#DeepSeekTodaySpend",
|
|
4093
|
-
schema:
|
|
4199
|
+
schema: _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema
|
|
4094
4200
|
},
|
|
4095
4201
|
sourceLocation: {
|
|
4096
4202
|
"file": "packages/llm/llm-billing/src/balance.ts",
|
|
4097
|
-
"line":
|
|
4203
|
+
"line": 167,
|
|
4098
4204
|
"column": 3
|
|
4099
4205
|
}
|
|
4100
4206
|
}
|
|
4101
4207
|
]
|
|
4102
4208
|
};
|
|
4103
4209
|
//#endregion
|
|
4104
|
-
//#region \0dsh-css:
|
|
4105
|
-
const css = ".
|
|
4210
|
+
//#region \0dsh-css:C:\Users\admin\Desktop\me\code\deepseek-harness\packages\client\ui-billing\src\client\BalanceBadge.module.css.mjs
|
|
4211
|
+
const css = ".v_-kjq_root{position:relative}.v_-kjq_trigger{background:var(--dsw-alias-fill-l2);min-height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;border:0;border-radius:8px;align-items:center;gap:4px;padding:4px 8px;display:inline-flex}.v_-kjq_trigger:hover,.v_-kjq_trigger:focus-visible{color:var(--dsw-alias-label-primary)}.v_-kjq_trigger svg{transition:transform .12s}.v_-kjq_chevronOpen{transform:rotate(180deg)}.v_-kjq_triggerLines{text-align:left;flex-direction:column;align-items:flex-start;gap:0;display:flex}.v_-kjq_linePrimary{font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.v_-kjq_lineSecondary{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:15px}.v_-kjq_unavailable{color:var(--dsw-alias-label-tertiary)}.v_-kjq_inlineIcon{color:var(--dsw-alias-label-tertiary);flex:none}.v_-kjq_spinning{color:var(--dsw-alias-label-tertiary);flex:none;animation:.8s linear infinite v_-kjq_spin}@keyframes v_-kjq_spin{to{transform:rotate(360deg)}}.v_-kjq_panel{z-index:100;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-menu);width:336px;max-width:min(360px,100vw - 32px);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:2px;padding:6px;display:flex;position:absolute;top:calc(100% + 6px);right:0}.v_-kjq_amountRow{border-radius:8px;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;display:flex}.v_-kjq_amountLabel{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:13px;line-height:18px}.v_-kjq_spendRow{border-top:1px solid var(--dsw-alias-border-l2);border-radius:0;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;display:flex}.v_-kjq_costRow{align-items:center;padding:2px 8px 6px;display:flex}.v_-kjq_costBreakdown{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.v_-kjq_amountActions{align-items:center;gap:2px;display:inline-flex}.v_-kjq_infoButton,.v_-kjq_refreshButton{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.v_-kjq_infoButton:hover,.v_-kjq_infoButton:focus-visible,.v_-kjq_refreshButton:hover,.v_-kjq_refreshButton:focus-visible{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-l2)}.v_-kjq_modelRow{border-radius:8px;justify-content:space-between;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.v_-kjq_modelName{color:var(--dsw-alias-label-secondary);flex:none;font-size:12px;line-height:18px}.v_-kjq_tasks{text-align:right;min-width:0;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;overflow-wrap:anywhere;font-size:12px;line-height:18px}";
|
|
4106
4212
|
const tagId = "@rayadesu/dsh-client-ui-billing/BalanceBadge.module.css";
|
|
4107
4213
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
4108
4214
|
const tag = document.createElement("style");
|
|
@@ -4112,28 +4218,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4112
4218
|
document.head.appendChild(tag);
|
|
4113
4219
|
}
|
|
4114
4220
|
var BalanceBadge_module_css_default = {
|
|
4115
|
-
"amountActions": "
|
|
4116
|
-
"amountLabel": "
|
|
4117
|
-
"amountRow": "
|
|
4118
|
-
"chevronOpen": "
|
|
4119
|
-
"costBreakdown": "
|
|
4120
|
-
"costRow": "
|
|
4121
|
-
"infoButton": "
|
|
4122
|
-
"inlineIcon": "
|
|
4123
|
-
"linePrimary": "
|
|
4124
|
-
"lineSecondary": "
|
|
4125
|
-
"modelName": "
|
|
4126
|
-
"modelRow": "
|
|
4127
|
-
"panel": "
|
|
4128
|
-
"refreshButton": "
|
|
4129
|
-
"root": "
|
|
4130
|
-
"spendRow": "
|
|
4131
|
-
"spin": "
|
|
4132
|
-
"spinning": "
|
|
4133
|
-
"tasks": "
|
|
4134
|
-
"trigger": "
|
|
4135
|
-
"triggerLines": "
|
|
4136
|
-
"unavailable": "
|
|
4221
|
+
"amountActions": "v_-kjq_amountActions",
|
|
4222
|
+
"amountLabel": "v_-kjq_amountLabel",
|
|
4223
|
+
"amountRow": "v_-kjq_amountRow",
|
|
4224
|
+
"chevronOpen": "v_-kjq_chevronOpen",
|
|
4225
|
+
"costBreakdown": "v_-kjq_costBreakdown",
|
|
4226
|
+
"costRow": "v_-kjq_costRow",
|
|
4227
|
+
"infoButton": "v_-kjq_infoButton",
|
|
4228
|
+
"inlineIcon": "v_-kjq_inlineIcon",
|
|
4229
|
+
"linePrimary": "v_-kjq_linePrimary",
|
|
4230
|
+
"lineSecondary": "v_-kjq_lineSecondary",
|
|
4231
|
+
"modelName": "v_-kjq_modelName",
|
|
4232
|
+
"modelRow": "v_-kjq_modelRow",
|
|
4233
|
+
"panel": "v_-kjq_panel",
|
|
4234
|
+
"refreshButton": "v_-kjq_refreshButton",
|
|
4235
|
+
"root": "v_-kjq_root",
|
|
4236
|
+
"spendRow": "v_-kjq_spendRow",
|
|
4237
|
+
"spin": "v_-kjq_spin",
|
|
4238
|
+
"spinning": "v_-kjq_spinning",
|
|
4239
|
+
"tasks": "v_-kjq_tasks",
|
|
4240
|
+
"trigger": "v_-kjq_trigger",
|
|
4241
|
+
"triggerLines": "v_-kjq_triggerLines",
|
|
4242
|
+
"unavailable": "v_-kjq_unavailable"
|
|
4137
4243
|
};
|
|
4138
4244
|
//#endregion
|
|
4139
4245
|
//#region lib/types/client/BalanceBadge.js
|
|
@@ -4199,7 +4305,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4199
4305
|
if (!current) return;
|
|
4200
4306
|
setSpend(value);
|
|
4201
4307
|
}, () => {});
|
|
4202
|
-
const todaySpendRequest = Promise.resolve().then(getTodaySpend).then((value) => {
|
|
4308
|
+
const todaySpendRequest = Promise.resolve().then(() => getTodaySpend(request > 0)).then((value) => {
|
|
4203
4309
|
if (!current) return;
|
|
4204
4310
|
setTodaySpend(value);
|
|
4205
4311
|
}, () => {});
|
|
@@ -4225,17 +4331,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4225
4331
|
if (messageCount === pricedMessageCountRef.current) return;
|
|
4226
4332
|
pricedMessageCountRef.current = messageCount;
|
|
4227
4333
|
let current = true;
|
|
4228
|
-
|
|
4229
|
-
Promise.resolve().then(() =>
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4334
|
+
const timer = setTimeout(() => {
|
|
4335
|
+
Promise.resolve().then(() => {
|
|
4336
|
+
Promise.resolve().then(() => getSessionSpend(sessionId)).then((value) => {
|
|
4337
|
+
if (!current) return;
|
|
4338
|
+
setSpend(value);
|
|
4339
|
+
}, () => {});
|
|
4340
|
+
Promise.resolve().then(() => getTodaySpend()).then((value) => {
|
|
4341
|
+
if (!current) return;
|
|
4342
|
+
setTodaySpend(value);
|
|
4343
|
+
}, () => {});
|
|
4344
|
+
});
|
|
4345
|
+
}, 2e3);
|
|
4238
4346
|
return () => {
|
|
4347
|
+
clearTimeout(timer);
|
|
4239
4348
|
current = false;
|
|
4240
4349
|
};
|
|
4241
4350
|
}, [
|
|
@@ -4387,7 +4496,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4387
4496
|
"state.unavailable": "额度不可用",
|
|
4388
4497
|
"action.refresh": "刷新",
|
|
4389
4498
|
"info.aria": "花费说明",
|
|
4390
|
-
"info.hint": "仅能预估 DeepSeek
|
|
4499
|
+
"info.hint": "仅能预估 DeepSeek 相关模型。本会话花费按每条消息的发生时刻(北京时间)所在峰谷时段单价计费:缓存命中输入、未命中输入(含缓存写入)、输出(含推理)分别计价。费率按 8 月 17 日实行的标准,高峰时段为北京时间周一至周五 9:00–12:00、14:00–18:00,周末全天按低谷价计费。",
|
|
4391
4500
|
"badge.aria": "DeepSeek 额度:{amount}",
|
|
4392
4501
|
"panel.aria": "DeepSeek 额度详情"
|
|
4393
4502
|
};
|
|
@@ -4405,7 +4514,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4405
4514
|
"state.unavailable": "Balance unavailable",
|
|
4406
4515
|
"action.refresh": "Refresh",
|
|
4407
4516
|
"info.aria": "About this spend",
|
|
4408
|
-
"info.hint": "Only DeepSeek models are estimated. This session's spend is priced per message at the rate of its Beijing-time peak/off-peak hour: cache-hit input, cache-miss input (including cache writes), and output (including reasoning) are billed separately.
|
|
4517
|
+
"info.hint": "Only DeepSeek models are estimated. This session's spend is priced per message at the rate of its Beijing-time peak/off-peak hour: cache-hit input, cache-miss input (including cache writes), and output (including reasoning) are billed separately. Rates follow the August 17 pricing; peak hours are Beijing time Monday–Friday 09:00–12:00 and 14:00–18:00, and weekends are billed at off-peak prices all day.",
|
|
4409
4518
|
"badge.aria": "DeepSeek balance {amount}",
|
|
4410
4519
|
"panel.aria": "DeepSeek balance details"
|
|
4411
4520
|
};
|
|
@@ -4442,8 +4551,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4442
4551
|
if (!result.ok) throw new Error(`billing.getSessionSpend failed: ${result.error.code}: ${result.error.message}`);
|
|
4443
4552
|
return result.value;
|
|
4444
4553
|
},
|
|
4445
|
-
getTodaySpend: async () => {
|
|
4446
|
-
const result = await billing.getTodaySpend();
|
|
4554
|
+
getTodaySpend: async (force) => {
|
|
4555
|
+
const result = await billing.getTodaySpend(force);
|
|
4447
4556
|
if (!result.ok) throw new Error(`billing.getTodaySpend failed: ${result.error.code}: ${result.error.message}`);
|
|
4448
4557
|
return result.value;
|
|
4449
4558
|
}
|
|
@@ -9,8 +9,12 @@ export interface BalanceBadgeInjected {
|
|
|
9
9
|
getBalance: () => Promise<DeepSeekBalance>;
|
|
10
10
|
/** Read one session's billed spend; rejects with the Remote error message. */
|
|
11
11
|
getSessionSpend: (sessionId: SessionId) => Promise<DeepSeekSessionSpend>;
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Read today's billed spend across every session; rejects with the Remote
|
|
14
|
+
* error message. `force` bypasses the host-side cache — the manual refresh
|
|
15
|
+
* passes it, the message-triggered recompute does not.
|
|
16
|
+
*/
|
|
17
|
+
getTodaySpend: (force?: boolean) => Promise<DeepSeekTodaySpend>;
|
|
14
18
|
}
|
|
15
19
|
/** Full props assembled by the header utilities slot renderer. */
|
|
16
20
|
export type BalanceBadgeProps = PropsRuntime<'conversation.session.header.utilities'> & InjectFace<BalanceBadgeInjected> & PropsLocale<typeof NS>;
|
|
@@ -15,7 +15,7 @@ export declare const zh: {
|
|
|
15
15
|
readonly 'state.unavailable': "额度不可用";
|
|
16
16
|
readonly 'action.refresh': "刷新";
|
|
17
17
|
readonly 'info.aria': "花费说明";
|
|
18
|
-
readonly 'info.hint': "仅能预估 DeepSeek
|
|
18
|
+
readonly 'info.hint': "仅能预估 DeepSeek 相关模型。本会话花费按每条消息的发生时刻(北京时间)所在峰谷时段单价计费:缓存命中输入、未命中输入(含缓存写入)、输出(含推理)分别计价。费率按 8 月 17 日实行的标准,高峰时段为北京时间周一至周五 9:00–12:00、14:00–18:00,周末全天按低谷价计费。";
|
|
19
19
|
readonly 'badge.aria': "DeepSeek 额度:{amount}";
|
|
20
20
|
readonly 'panel.aria': "DeepSeek 额度详情";
|
|
21
21
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rayadesu/dsh-client-ui-billing",
|
|
3
3
|
"description": "Session-header DeepSeek account-balance and conversation-spend badge over the billing Remote",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
"platform": "web"
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"bundle": "tsdown",
|
|
36
|
+
"watch": "tsdown --watch"
|
|
37
|
+
},
|
|
34
38
|
"license": "MIT",
|
|
35
39
|
"repository": {
|
|
36
40
|
"type": "git",
|
|
@@ -41,7 +45,7 @@
|
|
|
41
45
|
"access": "public"
|
|
42
46
|
},
|
|
43
47
|
"peerDependencies": {
|
|
44
|
-
"@rayadesu/dsh-llm-billing": "^0.
|
|
48
|
+
"@rayadesu/dsh-llm-billing": "^0.2.0",
|
|
45
49
|
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8",
|
|
46
50
|
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8",
|
|
47
51
|
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8",
|
|
@@ -50,7 +54,7 @@
|
|
|
50
54
|
"@deepseek-ai/cordis": "^4.0.1"
|
|
51
55
|
},
|
|
52
56
|
"devDependencies": {
|
|
53
|
-
"@rayadesu/dsh-llm-billing": "^0.
|
|
57
|
+
"@rayadesu/dsh-llm-billing": "^0.2.0",
|
|
54
58
|
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8",
|
|
55
59
|
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8",
|
|
56
60
|
"@deepseek-ai/dsh-client-test-runtime": "^0.1.0-rc.8",
|
|
@@ -68,9 +72,5 @@
|
|
|
68
72
|
"lib/invariant.js",
|
|
69
73
|
"lib/client.js",
|
|
70
74
|
"lib/types/**/*.d.ts"
|
|
71
|
-
]
|
|
72
|
-
|
|
73
|
-
"bundle": "tsdown",
|
|
74
|
-
"watch": "tsdown --watch"
|
|
75
|
-
}
|
|
76
|
-
}
|
|
75
|
+
]
|
|
76
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 WilliamLIiii
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|