@kenz1117/dsh-ui-usage-billing 1.4.22 → 1.4.24

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
@@ -2,12 +2,12 @@ import { createRequire } from "node:module";
2
2
  import { lstat, mkdir, readFile, rm, stat } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { dirname, join } from "node:path";
5
- import { SessionLogOffset } from "@deepseek-ai/dsh-session/types";
6
5
  import { defineTool } from "@deepseek-ai/dsh-tools";
7
6
  import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
8
7
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
9
8
  import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
10
9
  import z from "@deepseek-ai/schemastery";
10
+ import * as sessionTypes from "@deepseek-ai/dsh-session/types";
11
11
  import { createHash, createHmac } from "node:crypto";
12
12
  //#region lib/types/client/plan-knowledge.js
13
13
  /**
@@ -585,15 +585,15 @@ function isPriced(key) {
585
585
  return FALLBACK_RATES.some((rate) => rate.key.toLowerCase() === resolved.toLowerCase());
586
586
  }
587
587
  /**
588
- * 促销在 nowMs 是否生效:factor 必须落在 (0,1) 区间,截止时刻及之后视为过期;
589
- * endsAtMs 缺省表示长期活动,在 factor 合法期间持续生效。
588
+ * 促销在 nowMs 是否生效:factor 必须落在 [0,1) 区间(0 = 活动期免费,issue #86),
589
+ * 截止时刻及之后视为过期;endsAtMs 缺省表示长期活动,在 factor 合法期间持续生效。
590
590
  * 导出供测试:纯函数。
591
591
  * @param promo - 待判定的促销窗口。
592
592
  * @param nowMs - 判定时刻(epoch ms)。
593
593
  */
594
594
  function isPromoActive(promo, nowMs) {
595
595
  const expired = promo.endsAtMs !== void 0 && nowMs >= promo.endsAtMs;
596
- return Number.isFinite(nowMs) && !expired && promo.factor > 0 && promo.factor < 1;
596
+ return Number.isFinite(nowMs) && !expired && promo.factor >= 0 && promo.factor < 1;
597
597
  }
598
598
  /**
599
599
  * 把限时促销折入条目单价:生效期内返回 price 主档与 offPeak 逐档乘折扣系数的
@@ -606,7 +606,10 @@ function isPromoActive(promo, nowMs) {
606
606
  function applyPromo(entry, nowMs) {
607
607
  const { promo } = entry;
608
608
  if (promo === void 0 || !isPromoActive(promo, nowMs)) return entry;
609
- const factorOf = (field) => promo.factors?.[field] ?? promo.factor;
609
+ const factorOf = (field) => {
610
+ const perBand = promo.factors?.[field];
611
+ return perBand !== void 0 && perBand >= 0 && perBand < 1 ? perBand : promo.factor;
612
+ };
610
613
  const scaled = (band) => ({
611
614
  input: band.input * factorOf("input"),
612
615
  cacheHit: band.cacheHit * factorOf("cacheHit"),
@@ -1308,6 +1311,59 @@ const BUILTIN_MODEL_CATALOG = [
1308
1311
  output: 16.8
1309
1312
  }
1310
1313
  },
1314
+ {
1315
+ key: "minimax-m3.1-flash-preview",
1316
+ name: "MiniMax M3.1 Flash Preview",
1317
+ provider: "MiniMax",
1318
+ colorVar: "ds-amber",
1319
+ price: {
1320
+ currency: "CNY",
1321
+ input: 2.1,
1322
+ cacheHit: .42,
1323
+ output: 8.4
1324
+ }
1325
+ },
1326
+ {
1327
+ key: "u2-flash",
1328
+ name: "U2 Flash",
1329
+ provider: "云知声",
1330
+ colorVar: "dsw-static-violet-400",
1331
+ price: {
1332
+ currency: "CNY",
1333
+ input: 1,
1334
+ cacheHit: .2,
1335
+ output: 2
1336
+ },
1337
+ promo: {
1338
+ factor: 0,
1339
+ endsAtMs: Date.UTC(2026, 9, 31, 16, 0, 0),
1340
+ note: "限时免费至 2026-10-31"
1341
+ }
1342
+ },
1343
+ {
1344
+ key: "u2",
1345
+ name: "Unisound U2",
1346
+ provider: "云知声",
1347
+ colorVar: "dsw-static-violet-400",
1348
+ price: {
1349
+ currency: "CNY",
1350
+ input: 1,
1351
+ cacheHit: .2,
1352
+ output: 2
1353
+ }
1354
+ },
1355
+ {
1356
+ key: "u2-med",
1357
+ name: "U2-Med",
1358
+ provider: "云知声",
1359
+ colorVar: "dsw-static-violet-400",
1360
+ price: {
1361
+ currency: "CNY",
1362
+ input: 8,
1363
+ cacheHit: 2,
1364
+ output: 28
1365
+ }
1366
+ },
1311
1367
  {
1312
1368
  key: "ernie",
1313
1369
  name: "ERNIE-5.1",
@@ -2244,6 +2300,11 @@ const BUILTIN_MODEL_KEY_ALIASES = {
2244
2300
  "minimax-m2-7": "minimax-m2.7",
2245
2301
  "minimax-m2-7-highspeed": "minimax-m2.7-highspeed",
2246
2302
  "minimax-m2-7-high-speed": "minimax-m2.7-highspeed",
2303
+ "minimax-m3.1-flash-preview": "minimax-m3.1-flash-preview",
2304
+ "minimax-m3-1-flash-preview": "minimax-m3.1-flash-preview",
2305
+ "u2-flash": "u2-flash",
2306
+ "u2": "u2",
2307
+ "u2-med": "u2-med",
2247
2308
  "gpt-6": "gpt-6-astra",
2248
2309
  "gpt-6-astra": "gpt-6-astra",
2249
2310
  "gpt-6-sol": "gpt-6-sol",
@@ -2269,6 +2330,11 @@ const BUILTIN_MODEL_KEY_ALIASES = {
2269
2330
  * zero while their tokens still count. Pure functions only: the persistence
2270
2331
  * handle is injected, so the fold is unit-testable without a host.
2271
2332
  */
2333
+ /** 会话日志偏移:宿主 0.1.2-alpha.4 前的 dsh-session/types 不导出 SessionLogOffset
2334
+ * 值,具名导入让这些宿主装载即崩(v1.4.19~v1.4.22 实测,alpha.3 真机复现);
2335
+ * namespace 导入不做具名导出校验,缺导出时退化为恒等——偏移类型是
2336
+ * BrandedNumber,值域与 number 同构,老宿主的 readFrom 原样收数字。 */
2337
+ const sessionLogOffsetOf = sessionTypes.SessionLogOffset ?? ((value) => value);
2272
2338
  /**
2273
2339
  * 走订阅套餐(coding / token plan / opencode 订阅)的 provider id:这些通道的
2274
2340
  * 调用按套餐计费,不再按 token 计费,因此即使模型 id 与计费表撞名也一律豁免。
@@ -3352,7 +3418,7 @@ function createUsageAggregator(persistence, options = {}) {
3352
3418
  const previous = cache.get(id);
3353
3419
  if (previous?.machine !== void 0 && previous.lastSeq !== void 0) {
3354
3420
  const from = previous.lastSeq + 1;
3355
- const { events, inheritedEventCount } = await persistence.readFrom(meta.id, SessionLogOffset(from));
3421
+ const { events, inheritedEventCount } = await persistence.readFrom(meta.id, sessionLogOffsetOf(from));
3356
3422
  const after = await stampOf(meta);
3357
3423
  if (stamp !== null && after !== stamp) {
3358
3424
  cache.delete(id);
@@ -3378,7 +3444,7 @@ function createUsageAggregator(persistence, options = {}) {
3378
3444
  recordLedger(id, cwd, stamp, previous.fold);
3379
3445
  continue;
3380
3446
  }
3381
- const { events, inheritedEventCount } = await persistence.readFrom(meta.id, SessionLogOffset(0));
3447
+ const { events, inheritedEventCount } = await persistence.readFrom(meta.id, sessionLogOffsetOf(0));
3382
3448
  const after = await stampOf(meta);
3383
3449
  if (stamp !== null && after !== stamp) continue;
3384
3450
  const fold = freshFold();
@@ -6921,8 +6987,8 @@ function adaptSessionPersistence(raw) {
6921
6987
  const events = Array.isArray(slice) ? slice : slice.events;
6922
6988
  return {
6923
6989
  meta: handle.header,
6924
- fromSeq: SessionLogOffset(fromSeq),
6925
- inheritedEventCount: SessionLogOffset(handle.inheritedEventCount),
6990
+ fromSeq: sessionLogOffsetOf(fromSeq),
6991
+ inheritedEventCount: sessionLogOffsetOf(handle.inheritedEventCount),
6926
6992
  events
6927
6993
  };
6928
6994
  } finally {
@@ -10,11 +10,15 @@
10
10
  * zero while their tokens still count. Pure functions only: the persistence
11
11
  * handle is injected, so the fold is unit-testable without a host.
12
12
  */
13
- import { SessionLogOffset } from '@deepseek-ai/dsh-session/types';
14
- import type { SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session/types';
13
+ import type { SessionEvent, SessionHeader, SessionId, SessionLogOffset as SessionLogOffsetT } from '@deepseek-ai/dsh-session/types';
15
14
  import type { TokenUsage } from '@deepseek-ai/dsh-llm';
16
15
  import { resolveCatalogKey } from './client/pricing.ts';
17
16
  import { BUILTIN_MODEL_KEY_ALIASES } from './builtin-catalog.ts';
17
+ /** 会话日志偏移:宿主 0.1.2-alpha.4 前的 dsh-session/types 不导出 SessionLogOffset
18
+ * 值,具名导入让这些宿主装载即崩(v1.4.19~v1.4.22 实测,alpha.3 真机复现);
19
+ * namespace 导入不做具名导出校验,缺导出时退化为恒等——偏移类型是
20
+ * BrandedNumber,值域与 number 同构,老宿主的 readFrom 原样收数字。 */
21
+ export declare const sessionLogOffsetOf: (value: number) => SessionLogOffsetT;
18
22
  export { BUILTIN_MODEL_KEY_ALIASES, resolveCatalogKey };
19
23
  /**
20
24
  * 走订阅套餐(coding / token plan / opencode 订阅)的 provider id:这些通道的
@@ -212,8 +216,8 @@ export declare function workspaceNameOf(cwd: string | undefined): string;
212
216
  /** readFrom 返回的后缀切片:与宿主 0.1.2 的 SessionEventSuffix 同构,本地结构声明。 */
213
217
  export interface UsageEventSuffix {
214
218
  readonly meta: SessionHeader;
215
- readonly inheritedEventCount: SessionLogOffset;
216
- readonly fromSeq: SessionLogOffset;
219
+ readonly inheritedEventCount: SessionLogOffsetT;
220
+ readonly fromSeq: SessionLogOffsetT;
217
221
  readonly events: readonly SessionEvent[];
218
222
  }
219
223
  /**
@@ -227,7 +231,7 @@ export interface UsageEventSuffix {
227
231
  */
228
232
  export interface UsagePersistence {
229
233
  list(): Promise<readonly SessionHeader[]>;
230
- readFrom(id: SessionId, fromSeq: SessionLogOffset): Promise<UsageEventSuffix>;
234
+ readFrom(id: SessionId, fromSeq: SessionLogOffsetT): Promise<UsageEventSuffix>;
231
235
  locate?(meta: SessionHeader): {
232
236
  path: string;
233
237
  } | undefined;
@@ -278,12 +278,12 @@ export interface ModelPrice extends PriceBand {
278
278
  * (主档与 offPeak)单价按 factor 折扣计价与显示,截止时刻起自动恢复刊例价。
279
279
  */
280
280
  export interface PricePromo {
281
- /** 折扣系数(0.5 = 五折);仅 (0,1) 区间有效,非法值视为无促销。 */
281
+ /** 折扣系数(0.5 = 五折,0 = 活动期免费);仅 [0,1) 区间有效,非法值视为无促销。 */
282
282
  factor: number;
283
283
  /**
284
284
  * 分档折扣覆盖:厂商对不同档位给不同折扣时逐档指定(如 GPT-5.6 Sol 促销为
285
285
  * 缓存 0.8 / 输入 0.8 / 输出 2/3)。缺省档位沿用 {@link factor};单档取值
286
- * 仅 (0,1) 区间有效,非法值回落 factor。
286
+ * 仅 [0,1) 区间有效(0 = 该档活动期免费),非法值回落 factor。
287
287
  */
288
288
  factors?: Partial<Record<'input' | 'cacheHit' | 'cacheMiss' | 'output', number>>;
289
289
  /**
@@ -382,8 +382,8 @@ export declare function modelOf(key: string): ModelEntry;
382
382
  */
383
383
  export declare function isPriced(key: string): boolean;
384
384
  /**
385
- * 促销在 nowMs 是否生效:factor 必须落在 (0,1) 区间,截止时刻及之后视为过期;
386
- * endsAtMs 缺省表示长期活动,在 factor 合法期间持续生效。
385
+ * 促销在 nowMs 是否生效:factor 必须落在 [0,1) 区间(0 = 活动期免费,issue #86),
386
+ * 截止时刻及之后视为过期;endsAtMs 缺省表示长期活动,在 factor 合法期间持续生效。
387
387
  * 导出供测试:纯函数。
388
388
  * @param promo - 待判定的促销窗口。
389
389
  * @param nowMs - 判定时刻(epoch ms)。
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.4.22",
4
+ "version": "1.4.24",
5
5
  "keywords": [
6
6
  "deepseek-harness",
7
7
  "deepseek",