@linxin666/dsh-usage 0.4.10 → 0.4.12
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 +2 -2
- package/README.zh.md +2 -2
- package/lib/client.js +1773 -366
- package/lib/client.js.map +1 -1
- package/lib/types/client/PluginSettingsCard.d.ts +255 -0
- package/lib/types/client/RangeBubble.d.ts +46 -0
- package/lib/types/client/SegmentGroup.d.ts +28 -0
- package/lib/types/client/UsagePage.d.ts +19 -0
- package/lib/types/client/UsageSectionCard.d.ts +11 -18
- package/lib/types/client/locales.d.ts +13 -2
- package/lib/types/client/section-integration.d.ts +47 -0
- package/lib/types/client/settings-form.d.ts +235 -0
- package/lib/types/client/usage-settings-card.d.ts +48 -0
- package/lib/types/client/web-extension-page.d.ts +50 -0
- package/package.json +1 -1
- package/src/client/PluginSettingsCard.tsx +838 -0
- package/src/client/RangeBubble.tsx +164 -0
- package/src/client/SegmentGroup.tsx +93 -0
- package/src/client/UsagePage.tsx +108 -0
- package/src/client/UsageSectionCard.tsx +173 -270
- package/src/client/index.ts +19 -30
- package/src/client/locales.ts +46 -24
- package/src/client/section-integration.ts +88 -0
- package/src/client/settings-card.module.css +821 -0
- package/src/client/settings-form.ts +510 -0
- package/src/client/usage-settings-card.ts +72 -0
- package/src/client/usage.module.css +74 -82
- package/src/client/web-extension-page.ts +151 -0
package/src/client/locales.ts
CHANGED
|
@@ -16,9 +16,9 @@ export const zh = {
|
|
|
16
16
|
'usage.refresh': '刷新',
|
|
17
17
|
'usage.refreshing': '刷新中…',
|
|
18
18
|
'usage.updated': '更新于 {time}',
|
|
19
|
-
'usage.loading': '
|
|
19
|
+
'usage.loading': '正在读取用量…',
|
|
20
20
|
'usage.error': '加载失败:{error}',
|
|
21
|
-
'usage.disabled': '
|
|
21
|
+
'usage.disabled': '已停用,打开开关继续统计。',
|
|
22
22
|
'usage.current': '当前',
|
|
23
23
|
'usage.today': '今日用量',
|
|
24
24
|
'usage.today.cost': '今日消费(估算)',
|
|
@@ -42,28 +42,26 @@ export const zh = {
|
|
|
42
42
|
'usage.tokens.cacheRead': '缓存读',
|
|
43
43
|
'usage.tokens.cacheWrite': '缓存写',
|
|
44
44
|
'usage.trend': '近 30 天',
|
|
45
|
-
'usage.noData': '
|
|
45
|
+
'usage.noData': '还没有用量,插件启用后开始统计。',
|
|
46
46
|
'usage.balance': '余额',
|
|
47
|
-
'usage.balance.unsupported': '
|
|
47
|
+
'usage.balance.unsupported': '不支持查询余额',
|
|
48
48
|
'usage.balance.noCredential': '未配置凭据',
|
|
49
|
-
'usage.balance.noneConfigured': '
|
|
50
|
-
'usage.oauth': 'OAuth
|
|
49
|
+
'usage.balance.noneConfigured': '还没有配置提供方',
|
|
50
|
+
'usage.oauth': 'OAuth 凭据,不查余额',
|
|
51
51
|
'usage.plan.reset': '{date} 重置',
|
|
52
|
-
'usage.plan.noPlan': '
|
|
53
|
-
'usage.plan.noneConfigured': '
|
|
52
|
+
'usage.plan.noPlan': '没有读到套餐数据',
|
|
53
|
+
'usage.plan.noneConfigured': '没有配置套餐类提供方,例如 Kimi、GLM、OpenCode Go、MiniMax、Codex 订阅。',
|
|
54
54
|
'usage.plan.windows.5h': '5 小时',
|
|
55
55
|
'usage.plan.windows.week': '每周',
|
|
56
56
|
'usage.plan.windows.month': '每月',
|
|
57
57
|
'usage.provider.error': '查询失败:{error}',
|
|
58
58
|
'usage.errorListSeparator': ';',
|
|
59
59
|
'usage.config.title': '设置',
|
|
60
|
-
'usage.config.enabled': '启用插件',
|
|
61
60
|
'usage.config.pollIntervalSec': '轮询间隔(秒)',
|
|
62
|
-
'usage.config.spendCurrency': '
|
|
63
|
-
'usage.config.cnyPerUsd': '
|
|
64
|
-
'usage.config.saveFailed': '保存失败:设置未被接受。',
|
|
61
|
+
'usage.config.spendCurrency': '货币',
|
|
62
|
+
'usage.config.cnyPerUsd': '汇率',
|
|
65
63
|
'usage.bank.title': '鲸元券',
|
|
66
|
-
'usage.bank.hint': '
|
|
64
|
+
'usage.bank.hint': '每用掉 100 万 tokens 铸造 1 鲸元,可以保存或分享这张票券。',
|
|
67
65
|
'usage.bank.noUsage': '暂无用量数据',
|
|
68
66
|
'usage.bank.minted': '累计铸造 {minted} 鲸元({tokens} tokens)',
|
|
69
67
|
'usage.bank.spend.observed': '官方余额实测花费 {cost}(自 {since} 起)',
|
|
@@ -78,6 +76,19 @@ export const zh = {
|
|
|
78
76
|
'usage.foot.open': '打开使用统计设置',
|
|
79
77
|
'usage.foot.collapse': '收起用量卡片',
|
|
80
78
|
'usage.foot.expand': '展开用量卡片',
|
|
79
|
+
'usage.description': '各提供方的用量、余额与套餐额度。',
|
|
80
|
+
'usage.config.pollIntervalHint': '多久查一次余额与套餐。',
|
|
81
|
+
'usage.config.spendCurrencyHint': '消费金额用这种货币显示。',
|
|
82
|
+
'usage.config.cnyPerUsdHint': '1 美元折合多少人民币。',
|
|
83
|
+
'settings.collapse': '收起',
|
|
84
|
+
'settings.expand': '展开',
|
|
85
|
+
'settings.notExposed': '这个版本的 DSH 没有开放使用统计的设置。',
|
|
86
|
+
'settings.readOnly': '设置只读。',
|
|
87
|
+
'settings.saveFailed': '没有保存成功。',
|
|
88
|
+
'settings.inherit': '默认',
|
|
89
|
+
'settings.overridden': '已修改',
|
|
90
|
+
'settings.reset': '恢复默认',
|
|
91
|
+
'settings.invalidNumber': '填一个数字,留空用默认值。',
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
/** English mirror; every zh key present. */
|
|
@@ -89,9 +100,9 @@ export const en: Record<UsageKey, string> = {
|
|
|
89
100
|
'usage.refresh': 'Refresh',
|
|
90
101
|
'usage.refreshing': 'Refreshing…',
|
|
91
102
|
'usage.updated': 'Updated {time}',
|
|
92
|
-
'usage.loading': '
|
|
103
|
+
'usage.loading': 'Reading usage…',
|
|
93
104
|
'usage.error': 'Failed to load: {error}',
|
|
94
|
-
'usage.disabled': '
|
|
105
|
+
'usage.disabled': 'Turned off; flip the switch to resume.',
|
|
95
106
|
'usage.current': 'Current',
|
|
96
107
|
'usage.today': 'Today',
|
|
97
108
|
'usage.today.cost': 'Today spend (estimated)',
|
|
@@ -115,28 +126,26 @@ export const en: Record<UsageKey, string> = {
|
|
|
115
126
|
'usage.tokens.cacheRead': 'Cache read',
|
|
116
127
|
'usage.tokens.cacheWrite': 'Cache write',
|
|
117
128
|
'usage.trend': 'Last 30 days',
|
|
118
|
-
'usage.noData': 'No usage
|
|
129
|
+
'usage.noData': 'No usage yet; counting starts once the plugin is on.',
|
|
119
130
|
'usage.balance': 'Balance',
|
|
120
|
-
'usage.balance.unsupported': '
|
|
131
|
+
'usage.balance.unsupported': 'No balance query',
|
|
121
132
|
'usage.balance.noCredential': 'No credential configured',
|
|
122
133
|
'usage.balance.noneConfigured': 'No providers configured',
|
|
123
134
|
'usage.oauth': 'OAuth credential, no balance query',
|
|
124
135
|
'usage.plan.reset': 'resets {date}',
|
|
125
|
-
'usage.plan.noPlan': 'No plan data
|
|
126
|
-
'usage.plan.noneConfigured': 'No plan
|
|
136
|
+
'usage.plan.noPlan': 'No plan data',
|
|
137
|
+
'usage.plan.noneConfigured': 'No plan provider configured, such as Kimi, GLM, OpenCode Go, MiniMax or a Codex subscription.',
|
|
127
138
|
'usage.plan.windows.5h': '5 hours',
|
|
128
139
|
'usage.plan.windows.week': 'Weekly',
|
|
129
140
|
'usage.plan.windows.month': 'Monthly',
|
|
130
141
|
'usage.provider.error': 'Query failed: {error}',
|
|
131
142
|
'usage.errorListSeparator': '; ',
|
|
132
143
|
'usage.config.title': 'Settings',
|
|
133
|
-
'usage.config.enabled': 'Enable plugin',
|
|
134
144
|
'usage.config.pollIntervalSec': 'Poll interval (seconds)',
|
|
135
|
-
'usage.config.spendCurrency': '
|
|
136
|
-
'usage.config.cnyPerUsd': 'Exchange rate
|
|
137
|
-
'usage.config.saveFailed': 'Save failed: the deployment did not accept the setting.',
|
|
145
|
+
'usage.config.spendCurrency': 'Currency',
|
|
146
|
+
'usage.config.cnyPerUsd': 'Exchange rate',
|
|
138
147
|
'usage.bank.title': 'Whale-yuan voucher',
|
|
139
|
-
'usage.bank.hint': 'Every
|
|
148
|
+
'usage.bank.hint': 'Every million tokens mints one whale yuan; save or share the note.',
|
|
140
149
|
'usage.bank.noUsage': 'No usage data yet',
|
|
141
150
|
'usage.bank.minted': 'Minted {minted} whale yuan ({tokens} tokens)',
|
|
142
151
|
'usage.bank.spend.observed': 'Spent {cost} observed on the official balance (watching since {since})',
|
|
@@ -151,6 +160,19 @@ export const en: Record<UsageKey, string> = {
|
|
|
151
160
|
'usage.foot.open': 'Open usage statistics settings',
|
|
152
161
|
'usage.foot.collapse': 'Collapse the usage card',
|
|
153
162
|
'usage.foot.expand': 'Expand the usage card',
|
|
163
|
+
'usage.description': 'Usage, balances and plan quotas for each provider.',
|
|
164
|
+
'usage.config.pollIntervalHint': 'How often balances and plans are read.',
|
|
165
|
+
'usage.config.spendCurrencyHint': 'Spend figures show in this currency.',
|
|
166
|
+
'usage.config.cnyPerUsdHint': 'Yuan per US dollar.',
|
|
167
|
+
'settings.collapse': 'Collapse',
|
|
168
|
+
'settings.expand': 'Expand',
|
|
169
|
+
'settings.notExposed': 'This DSH version does not open the usage settings.',
|
|
170
|
+
'settings.readOnly': 'Settings are read-only.',
|
|
171
|
+
'settings.saveFailed': 'Not saved.',
|
|
172
|
+
'settings.inherit': 'Default',
|
|
173
|
+
'settings.overridden': 'Changed',
|
|
174
|
+
'settings.reset': 'Reset',
|
|
175
|
+
'settings.invalidNumber': 'Enter a number, or leave it empty for the default.',
|
|
154
176
|
}
|
|
155
177
|
|
|
156
178
|
export type UsageKey = keyof typeof zh
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional integration with the family Web Extensions parent.
|
|
3
|
+
*
|
|
4
|
+
* The parent service owns page mounting; this module contributes one page
|
|
5
|
+
* contract and keeps the original first-level section as the standalone
|
|
6
|
+
* fallback. Deep links still resolve the parent service first.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { openUsageSettings, settingsShellStore, type SlotSeatReader } from './foot-card-mount.tsx'
|
|
10
|
+
import { t } from './locales.ts'
|
|
11
|
+
import { installWebExtensionPage, type WebExtensionPageContext } from './web-extension-page.ts'
|
|
12
|
+
|
|
13
|
+
/** The original first-level settings seat and its usage entry id. */
|
|
14
|
+
export const USAGE_SETTINGS_SEAT = 'settings.section'
|
|
15
|
+
export const USAGE_SECTION_ID = 'dsh-usage'
|
|
16
|
+
|
|
17
|
+
/** The family section's keyed extension seat. */
|
|
18
|
+
export const WEB_UI_EXTENSION_SEAT = 'web-ui.extension'
|
|
19
|
+
|
|
20
|
+
/** Optional navigation contract published by the family extensions plugin. */
|
|
21
|
+
export interface WebUiExtensionsService {
|
|
22
|
+
sectionId: 'web-ui-plugins'
|
|
23
|
+
label(): string
|
|
24
|
+
open(id: string): boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The context slice needed by the migrating section registration. */
|
|
28
|
+
export type UsageSectionContext = WebExtensionPageContext
|
|
29
|
+
|
|
30
|
+
/** The context slice needed by the foot card's settings navigation. */
|
|
31
|
+
export interface UsageNavigationContext {
|
|
32
|
+
get?(name: string): unknown
|
|
33
|
+
slots: SlotSeatReader
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The usage card contribution, independent of the seat that owns it. */
|
|
37
|
+
export interface UsageSectionRegistration {
|
|
38
|
+
order: number
|
|
39
|
+
locale: string
|
|
40
|
+
label(): string
|
|
41
|
+
inject(): object
|
|
42
|
+
component: unknown
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Read the optional service without assuming a particular cordis test double. */
|
|
46
|
+
export function getWebUiExtensions(ctx: { get?(name: string): unknown }): WebUiExtensionsService | undefined {
|
|
47
|
+
if (typeof ctx.get !== 'function') return undefined
|
|
48
|
+
try {
|
|
49
|
+
const service = ctx.get('webUiExtensions') as Partial<WebUiExtensionsService> | undefined
|
|
50
|
+
return service?.sectionId === 'web-ui-plugins'
|
|
51
|
+
&& typeof service.label === 'function'
|
|
52
|
+
&& typeof service.open === 'function'
|
|
53
|
+
? service as WebUiExtensionsService
|
|
54
|
+
: undefined
|
|
55
|
+
} catch {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Register the one usage page; disposal is owned by the calling plugin fiber. */
|
|
61
|
+
export function installUsageSection(
|
|
62
|
+
ctx: UsageSectionContext,
|
|
63
|
+
registration: UsageSectionRegistration,
|
|
64
|
+
): () => void {
|
|
65
|
+
return installWebExtensionPage(ctx, {
|
|
66
|
+
key: USAGE_SECTION_ID,
|
|
67
|
+
order: registration.order,
|
|
68
|
+
locale: registration.locale,
|
|
69
|
+
label: registration.label,
|
|
70
|
+
inject: registration.inject,
|
|
71
|
+
component: registration.component,
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Open usage through the family service first. If it declines, fall back to the
|
|
77
|
+
* native settings shell on the family section (or on the original usage row
|
|
78
|
+
* when the service is absent), preserving the matching localized nav label.
|
|
79
|
+
*/
|
|
80
|
+
export function openIntegratedUsageSettings(ctx: UsageNavigationContext): void {
|
|
81
|
+
const service = getWebUiExtensions(ctx)
|
|
82
|
+
if (service?.open(USAGE_SECTION_ID) === true) return
|
|
83
|
+
openUsageSettings({
|
|
84
|
+
id: service?.sectionId ?? USAGE_SECTION_ID,
|
|
85
|
+
label: service === undefined ? () => t('usage.title') : () => service.label(),
|
|
86
|
+
store: settingsShellStore(ctx.slots),
|
|
87
|
+
})
|
|
88
|
+
}
|