dsh-subscriptions 0.1.2 → 0.1.4
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 +92 -10
- package/lib/auth/rpc.d.ts +3 -1
- package/lib/auth/rpc.js +10 -1
- package/lib/client/ExternalUsageCards.d.ts +11 -1
- package/lib/client/ExternalUsageCards.js +18 -3
- package/lib/client/ProviderAccountManager.js +34 -41
- package/lib/client/ProviderModelEditor.js +5 -9
- package/lib/client/SpeedSelect.js +8 -7
- package/lib/client/SubscriptionUsageBadge.d.ts +19 -2
- package/lib/client/SubscriptionUsageBadge.js +65 -9
- package/lib/client/SubscriptionsSection.d.ts +22 -0
- package/lib/client/SubscriptionsSection.js +128 -38
- package/lib/client/UsageBadgeDisplaySetting.js +6 -10
- package/lib/client/UsageMeter.js +11 -6
- package/lib/client/host-contract.d.ts +1 -1
- package/lib/client/host-contract.js +22 -0
- package/lib/client/locales.d.ts +60 -0
- package/lib/client/locales.js +62 -2
- package/lib/client/provider-settings-styles.d.ts +3 -0
- package/lib/client/provider-settings-styles.js +206 -0
- package/lib/client/reset-action.d.ts +14 -0
- package/lib/client/reset-action.js +15 -0
- package/lib/client/reset-credits-view.d.ts +53 -0
- package/lib/client/reset-credits-view.js +103 -0
- package/lib/client/usage-badge-preferences.d.ts +7 -2
- package/lib/client/usage-badge-preferences.js +3 -2
- package/lib/client/usage-pace.d.ts +14 -1
- package/lib/client/usage-pace.js +14 -1
- package/lib/client.js +1036 -334
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +9 -0
- package/lib/index.js +1120 -602
- package/lib/providers/account-preferences.js +3 -2
- package/lib/providers/catalog-store.d.ts +3 -2
- package/lib/providers/catalog-store.js +57 -26
- package/lib/providers/claude.d.ts +22 -3
- package/lib/providers/claude.js +113 -15
- package/lib/providers/codex.d.ts +15 -2
- package/lib/providers/codex.js +72 -4
- package/lib/providers/common.d.ts +25 -0
- package/lib/providers/common.js +22 -18
- package/lib/providers/copilot.d.ts +2 -1
- package/lib/providers/copilot.js +10 -3
- package/lib/providers/grok.d.ts +2 -2
- package/lib/providers/grok.js +2 -2
- package/lib/providers/minimax-usage.d.ts +22 -1
- package/lib/providers/minimax-usage.js +37 -7
- package/lib/providers/pool-health.d.ts +2 -0
- package/lib/providers/pool-health.js +9 -0
- package/lib/providers/pool-usage.d.ts +13 -1
- package/lib/providers/pool-usage.js +39 -7
- package/lib/providers/pool.d.ts +7 -5
- package/lib/providers/pool.js +89 -12
- package/lib/providers/rate-limit.d.ts +0 -14
- package/lib/providers/rate-limit.js +0 -26
- package/lib/providers/replay.d.ts +4 -0
- package/lib/providers/replay.js +50 -0
- package/lib/providers/reset-redemption.d.ts +51 -0
- package/lib/providers/reset-redemption.js +102 -0
- package/lib/translate/anthropic.d.ts +21 -2
- package/lib/translate/anthropic.js +35 -11
- package/lib/translate/antigravity.js +13 -6
- package/lib/translate/chat-completions.js +1 -1
- package/lib/translate/resolved.d.ts +21 -0
- package/lib/translate/resolved.js +63 -3
- package/lib/translate/responses.js +8 -6
- package/lib/translate/sse.js +8 -0
- package/package.json +1 -1
package/lib/client/locales.d.ts
CHANGED
|
@@ -104,6 +104,35 @@ export declare const en: {
|
|
|
104
104
|
usageColorPaceHint: string;
|
|
105
105
|
usageColorRemainingHint: string;
|
|
106
106
|
usagePlan: string;
|
|
107
|
+
resetCreditsTitle: string;
|
|
108
|
+
resetCreditsAvailable: string;
|
|
109
|
+
resetCreditsError: string;
|
|
110
|
+
resetCreditsErrorFixed: string;
|
|
111
|
+
resetCreditReadOnly: string;
|
|
112
|
+
resetCreditReadOnlyLabel: string;
|
|
113
|
+
resetCreditAvailable: string;
|
|
114
|
+
resetCreditNotUsable: string;
|
|
115
|
+
resetCreditPaused: string;
|
|
116
|
+
resetCreditExhausted: string;
|
|
117
|
+
resetCreditExpired: string;
|
|
118
|
+
resetCreditRemaining: string;
|
|
119
|
+
resetCreditLeft: string;
|
|
120
|
+
resetCreditRemainingUnknown: string;
|
|
121
|
+
resetCreditCooldownUntil: string;
|
|
122
|
+
resetUseButton: string;
|
|
123
|
+
resetUseChecking: string;
|
|
124
|
+
resetUseGuard: string;
|
|
125
|
+
resetUseRestart: string;
|
|
126
|
+
resetUseRefresh: string;
|
|
127
|
+
resetUseReady: string;
|
|
128
|
+
resetUseConfirmTitle: string;
|
|
129
|
+
resetUseWarning: string;
|
|
130
|
+
resetUseAcknowledge: string;
|
|
131
|
+
resetUseConfirm: string;
|
|
132
|
+
resetUseSuccess: string;
|
|
133
|
+
resetCreditFull: string;
|
|
134
|
+
resetCreditExpires: string;
|
|
135
|
+
resetCreditExpiryUnknown: string;
|
|
107
136
|
externalUsageTitle: string;
|
|
108
137
|
externalUsageConnected: string;
|
|
109
138
|
externalUsageNotConfigured: string;
|
|
@@ -155,6 +184,7 @@ export declare const en: {
|
|
|
155
184
|
usageBadgeTitle: string;
|
|
156
185
|
usageBadgeDisplay: string;
|
|
157
186
|
usageBadgeDisplayRecent: string;
|
|
187
|
+
usageBadgeDisplayAlways: string;
|
|
158
188
|
usageBadgeDisplayHidden: string;
|
|
159
189
|
usageBadgeDisplayHint: string;
|
|
160
190
|
usageBadgeDisplaySaveFailed: string;
|
|
@@ -275,6 +305,35 @@ export declare const zh: {
|
|
|
275
305
|
usageColorPaceHint: string;
|
|
276
306
|
usageColorRemainingHint: string;
|
|
277
307
|
usagePlan: string;
|
|
308
|
+
resetCreditsTitle: string;
|
|
309
|
+
resetCreditsAvailable: string;
|
|
310
|
+
resetCreditsError: string;
|
|
311
|
+
resetCreditsErrorFixed: string;
|
|
312
|
+
resetCreditReadOnly: string;
|
|
313
|
+
resetCreditReadOnlyLabel: string;
|
|
314
|
+
resetCreditAvailable: string;
|
|
315
|
+
resetCreditNotUsable: string;
|
|
316
|
+
resetCreditPaused: string;
|
|
317
|
+
resetCreditExhausted: string;
|
|
318
|
+
resetCreditExpired: string;
|
|
319
|
+
resetCreditRemaining: string;
|
|
320
|
+
resetCreditLeft: string;
|
|
321
|
+
resetCreditRemainingUnknown: string;
|
|
322
|
+
resetCreditCooldownUntil: string;
|
|
323
|
+
resetUseButton: string;
|
|
324
|
+
resetUseChecking: string;
|
|
325
|
+
resetUseGuard: string;
|
|
326
|
+
resetUseRestart: string;
|
|
327
|
+
resetUseRefresh: string;
|
|
328
|
+
resetUseReady: string;
|
|
329
|
+
resetUseConfirmTitle: string;
|
|
330
|
+
resetUseWarning: string;
|
|
331
|
+
resetUseAcknowledge: string;
|
|
332
|
+
resetUseConfirm: string;
|
|
333
|
+
resetUseSuccess: string;
|
|
334
|
+
resetCreditFull: string;
|
|
335
|
+
resetCreditExpires: string;
|
|
336
|
+
resetCreditExpiryUnknown: string;
|
|
278
337
|
externalUsageTitle: string;
|
|
279
338
|
externalUsageConnected: string;
|
|
280
339
|
externalUsageNotConfigured: string;
|
|
@@ -326,6 +385,7 @@ export declare const zh: {
|
|
|
326
385
|
usageBadgeTitle: string;
|
|
327
386
|
usageBadgeDisplay: string;
|
|
328
387
|
usageBadgeDisplayRecent: string;
|
|
388
|
+
usageBadgeDisplayAlways: string;
|
|
329
389
|
usageBadgeDisplayHidden: string;
|
|
330
390
|
usageBadgeDisplayHint: string;
|
|
331
391
|
usageBadgeDisplaySaveFailed: string;
|
package/lib/client/locales.js
CHANGED
|
@@ -104,6 +104,35 @@ export const en = {
|
|
|
104
104
|
usageColorPaceHint: 'Yellow when usage leads elapsed time by {allowance} points; red at 90% used takes priority. Saved in this browser; only colors change.',
|
|
105
105
|
usageColorRemainingHint: 'Red at 90% used; no yellow pace warnings. Reliable time markers remain visible. Saved in this browser.',
|
|
106
106
|
usagePlan: 'Plan: {plan}',
|
|
107
|
+
resetCreditsTitle: 'Usage limit resets',
|
|
108
|
+
resetCreditsAvailable: '{count} available',
|
|
109
|
+
resetCreditsError: 'Usage limit resets unavailable: {message}',
|
|
110
|
+
resetCreditsErrorFixed: 'Usage limit resets are unavailable. Refresh usage to try again.',
|
|
111
|
+
resetCreditReadOnly: 'Read only. This page cannot spend a Claude reset.',
|
|
112
|
+
resetCreditReadOnlyLabel: 'Read only',
|
|
113
|
+
resetCreditAvailable: 'Available',
|
|
114
|
+
resetCreditNotUsable: 'Not yet usable',
|
|
115
|
+
resetCreditPaused: 'Paused',
|
|
116
|
+
resetCreditExhausted: 'Exhausted',
|
|
117
|
+
resetCreditExpired: 'Expired',
|
|
118
|
+
resetCreditRemaining: '{left} of {total} left',
|
|
119
|
+
resetCreditLeft: '{left} left',
|
|
120
|
+
resetCreditRemainingUnknown: 'Remaining count unavailable',
|
|
121
|
+
resetCreditCooldownUntil: 'Usable after {date}',
|
|
122
|
+
resetUseButton: 'Use…',
|
|
123
|
+
resetUseChecking: 'Checking…',
|
|
124
|
+
resetUseGuard: 'You can use this reset when weekly usage reaches at least 80%.',
|
|
125
|
+
resetUseRestart: 'Reset details are missing. Restart DSH, reload this page, then refresh usage.',
|
|
126
|
+
resetUseRefresh: 'Refresh usage to verify current limits and reset availability.',
|
|
127
|
+
resetUseReady: 'Use this reset — the earliest-expiring credit. Confirmation required.',
|
|
128
|
+
resetUseConfirmTitle: 'Confirm full reset',
|
|
129
|
+
resetUseWarning: 'This consumes one credit and resets weekly + 5-hour limits. This interface cannot undo it. Confirmation expires in 60 seconds.',
|
|
130
|
+
resetUseAcknowledge: 'I understand that one credit will be consumed.',
|
|
131
|
+
resetUseConfirm: 'Consume 1 reset',
|
|
132
|
+
resetUseSuccess: 'Reset confirmed. Usage refreshed.',
|
|
133
|
+
resetCreditFull: 'Full reset',
|
|
134
|
+
resetCreditExpires: 'Expires {date}',
|
|
135
|
+
resetCreditExpiryUnknown: 'Expiry date unavailable',
|
|
107
136
|
externalUsageTitle: 'Built-in provider usage',
|
|
108
137
|
externalUsageConnected: 'API key configured',
|
|
109
138
|
externalUsageNotConfigured: 'Not configured',
|
|
@@ -155,8 +184,9 @@ export const en = {
|
|
|
155
184
|
usageBadgeTitle: 'Provider usage',
|
|
156
185
|
usageBadgeDisplay: 'Status-bar quota display',
|
|
157
186
|
usageBadgeDisplayRecent: 'Current / most recent provider with usage',
|
|
187
|
+
usageBadgeDisplayAlways: 'Always show one provider, rotating through the rest',
|
|
158
188
|
usageBadgeDisplayHidden: 'Hidden',
|
|
159
|
-
usageBadgeDisplayHint: 'Saved automatically in this browser. One provider is shown at a time. Models without a quota source keep the most recent provider selected in this view, or show nothing. Hiding does not affect usage details here.',
|
|
189
|
+
usageBadgeDisplayHint: 'Saved automatically in this browser. One provider is shown at a time. Models without a quota source keep the most recent provider selected in this view, or show nothing. Always show instead rotates through the providers with usage every 10 seconds while the current model has no quota source. Hiding does not affect usage details here.',
|
|
160
190
|
usageBadgeDisplaySaveFailed: 'Could not save the display preference. Check browser storage permissions.',
|
|
161
191
|
usageBadgeCurrent: 'current',
|
|
162
192
|
usageBadgeModelCount: '{count} model quotas',
|
|
@@ -275,6 +305,35 @@ export const zh = {
|
|
|
275
305
|
usageColorPaceHint: '用量领先时间进度 {allowance} 个百分点时变黄;已用达到 90% 时优先变红。自动保存到当前浏览器,仅改变配色。',
|
|
276
306
|
usageColorRemainingHint: '已用达到 90% 时变红,不显示黄色节奏警告。可靠的时间标记仍保留,自动保存到当前浏览器。',
|
|
277
307
|
usagePlan: '计划:{plan}',
|
|
308
|
+
resetCreditsTitle: '用量限制重置',
|
|
309
|
+
resetCreditsAvailable: '可用 {count} 次',
|
|
310
|
+
resetCreditsError: '用量限制重置查询失败:{message}',
|
|
311
|
+
resetCreditsErrorFixed: '用量限制重置暂不可用,请刷新用量后重试。',
|
|
312
|
+
resetCreditReadOnly: '只读。此页面不能消耗 Claude 的重置额度。',
|
|
313
|
+
resetCreditReadOnlyLabel: '只读',
|
|
314
|
+
resetCreditAvailable: '可用',
|
|
315
|
+
resetCreditNotUsable: '暂不可用',
|
|
316
|
+
resetCreditPaused: '已暂停',
|
|
317
|
+
resetCreditExhausted: '已用尽',
|
|
318
|
+
resetCreditExpired: '已过期',
|
|
319
|
+
resetCreditRemaining: '剩余 {left} / {total}',
|
|
320
|
+
resetCreditLeft: '剩余 {left}',
|
|
321
|
+
resetCreditRemainingUnknown: '剩余次数不可用',
|
|
322
|
+
resetCreditCooldownUntil: '{date} 后可用',
|
|
323
|
+
resetUseButton: '使用…',
|
|
324
|
+
resetUseChecking: '正在检查…',
|
|
325
|
+
resetUseGuard: '每周用量达到 80% 后才可使用此重置。',
|
|
326
|
+
resetUseRestart: '缺少重置详情。请重启 DSH、重新加载页面并刷新用量。',
|
|
327
|
+
resetUseRefresh: '请刷新用量以验证当前限制和重置可用性。',
|
|
328
|
+
resetUseReady: '使用此最早到期的重置额度,操作前需要确认。',
|
|
329
|
+
resetUseConfirmTitle: '确认完整重置',
|
|
330
|
+
resetUseWarning: '将消耗一次额度并重置每周和 5 小时限制,无法撤销。确认将在 60 秒后过期。',
|
|
331
|
+
resetUseAcknowledge: '我理解将消耗一次额度。',
|
|
332
|
+
resetUseConfirm: '消耗一次重置',
|
|
333
|
+
resetUseSuccess: '重置已确认,用量已刷新。',
|
|
334
|
+
resetCreditFull: '完整重置',
|
|
335
|
+
resetCreditExpires: '{date} 到期',
|
|
336
|
+
resetCreditExpiryUnknown: '到期时间不可用',
|
|
278
337
|
externalUsageTitle: '内置供应商用量',
|
|
279
338
|
externalUsageConnected: '已配置 API 密钥',
|
|
280
339
|
externalUsageNotConfigured: '未配置',
|
|
@@ -326,8 +385,9 @@ export const zh = {
|
|
|
326
385
|
usageBadgeTitle: '服务商用量',
|
|
327
386
|
usageBadgeDisplay: '状态栏额度显示',
|
|
328
387
|
usageBadgeDisplayRecent: '仅显示当前/最近使用的用量服务商',
|
|
388
|
+
usageBadgeDisplayAlways: '始终显示一家,其余服务商轮播',
|
|
329
389
|
usageBadgeDisplayHidden: '不显示',
|
|
330
|
-
usageBadgeDisplayHint: '
|
|
390
|
+
usageBadgeDisplayHint: '自动保存到当前浏览器。状态栏一次显示一家服务商;没有额度来源的模型沿用本视图最近选择的服务商,没有记录则隐藏。选择“始终显示”时,当前模型没有额度来源,就每 10 秒轮播一家有额度的服务商。关闭不影响本页的额度详情。',
|
|
331
391
|
usageBadgeDisplaySaveFailed: '显示设置保存失败,请检查浏览器存储权限。',
|
|
332
392
|
usageBadgeCurrent: '当前',
|
|
333
393
|
usageBadgeModelCount: '{count} 个模型配额',
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const providerSettingsCss = "\n.dsh-subscription-manager {\n box-sizing: border-box;\n padding: 0;\n border: 0;\n border-radius: var(--dsw-radius-panel, 16px);\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n box-shadow: var(--dsw-elevation-prominent, 0 20px 70px #0004);\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n}\n.dsh-subscriptions-settings {\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n}\n.dsh-subscription-manager::backdrop {\n background: var(--dsw-alias-bg-mask-1, #0006);\n backdrop-filter: var(--dsw-mask-blur, none);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) h2 {\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) h3 {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) strong,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) .dsh-subscription-label {\n font-size: 13px;\n line-height: 1.5;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) legend {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) small,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) .dsh-subscription-hint,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) [role=\"status\"] {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) [role=\"alert\"] {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary, #b42318);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input:not([type=\"checkbox\"]),\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) select {\n box-sizing: border-box;\n min-width: 0;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4, var(--dsw-alias-border-l2));\n border-radius: var(--dsw-radius-md, 8px);\n background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 13px;\n font-weight: 400;\n line-height: 1.5;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input::placeholder {\n color: var(--dsw-alias-label-tertiary);\n opacity: 1;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input:not([type=\"checkbox\"]):focus-visible,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) select:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-state-business-primary, var(--dsw-alias-brand-primary));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input:not([type=\"checkbox\"]):disabled,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) select:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input[aria-invalid=\"true\"] {\n border-color: var(--dsw-alias-state-error-primary, #b42318);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) option {\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) label:has(> input[type=\"checkbox\"]) {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 14px;\n line-height: 20px;\n cursor: pointer;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input[type=\"checkbox\"] {\n flex: 0 0 auto;\n width: 16px;\n height: 16px;\n margin: 2px 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: inherit;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) label:has(> input[type=\"checkbox\"]:disabled) {\n cursor: default;\n opacity: 0.5;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-height: 28px;\n padding: 0 10px;\n border: 0.5px solid var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n border-radius: var(--dsw-radius-sm, 6px);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n cursor: pointer;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-3));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-3));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button.dsh-subscription-quiet {\n border-color: transparent;\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) :is(footer, .dsh-subscription-dialog-actions) button {\n min-height: 34px;\n padding: 0 14px;\n border-radius: var(--dsw-radius-md, 8px);\n font-size: 13px;\n line-height: 1.5;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button.dsh-subscription-primary {\n border-color: transparent;\n background: var(--dsw-alias-button-primary-fill, var(--dsw-alias-label-primary));\n color: var(--dsw-alias-label-primary-foreground, var(--dsw-alias-bg-layer-1));\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button.dsh-subscription-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover, var(--dsw-alias-label-secondary));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:focus-visible,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input[type=\"checkbox\"]:focus-visible,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) summary:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) summary {\n border-radius: var(--dsw-radius-sm, 6px);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) summary:hover {\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n";
|
|
2
|
+
/** Composer controls retain their own geometry, separate from settings forms. */
|
|
3
|
+
export declare const subscriptionChromeCss = "\n.dsh-subscription-usage-pill { corner-shape: round; }\n.dsh-subscription-usage-panel {\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n backdrop-filter: var(--dsw-menu-backdrop-filter, none);\n}\n.dsh-subscription-speed button:hover:not(:disabled) {\n --dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-hover);\n}\n.dsh-subscription-speed button:active:not(:disabled) {\n --dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-active);\n}\n.dsh-subscription-speed button:disabled { opacity: 0.4; cursor: default; }\n.dsh-subscription-speed button:focus-visible,\n.dsh-subscription-usage-pill:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n";
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host loads one JS client bundle, so keep this small, scoped stylesheet
|
|
3
|
+
* with the dialog instead of relying on a separate CSS asset. Geometry and
|
|
4
|
+
* theme tokens follow the host's settings-form and ui-primitives controls.
|
|
5
|
+
*
|
|
6
|
+
* `color-scheme` is left to the host deliberately. Its boot script sets the
|
|
7
|
+
* property on `:root`, and it inherits, so native controls inside these panels
|
|
8
|
+
* follow the theme. Upstream also pins `color-scheme: light` here and flips it
|
|
9
|
+
* back under `body[data-ds-dark-theme]`; without that flip our scoped rules are
|
|
10
|
+
* more specific than `:root` and would force every native control light inside
|
|
11
|
+
* a dark theme.
|
|
12
|
+
*/
|
|
13
|
+
const formScope = ':is(.dsh-subscription-manager, .dsh-subscriptions-settings)';
|
|
14
|
+
export const providerSettingsCss = `
|
|
15
|
+
.dsh-subscription-manager {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
padding: 0;
|
|
18
|
+
border: 0;
|
|
19
|
+
border-radius: var(--dsw-radius-panel, 16px);
|
|
20
|
+
background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));
|
|
21
|
+
color: var(--dsw-alias-label-primary);
|
|
22
|
+
box-shadow: var(--dsw-elevation-prominent, 0 20px 70px #0004);
|
|
23
|
+
font-family: inherit;
|
|
24
|
+
font-size: 13px;
|
|
25
|
+
line-height: 1.5;
|
|
26
|
+
}
|
|
27
|
+
.dsh-subscriptions-settings {
|
|
28
|
+
font-family: inherit;
|
|
29
|
+
font-size: 13px;
|
|
30
|
+
line-height: 1.5;
|
|
31
|
+
}
|
|
32
|
+
.dsh-subscription-manager::backdrop {
|
|
33
|
+
background: var(--dsw-alias-bg-mask-1, #0006);
|
|
34
|
+
backdrop-filter: var(--dsw-mask-blur, none);
|
|
35
|
+
}
|
|
36
|
+
${formScope} h2 {
|
|
37
|
+
font-size: 16px;
|
|
38
|
+
line-height: 24px;
|
|
39
|
+
font-weight: 500;
|
|
40
|
+
}
|
|
41
|
+
${formScope} h3 {
|
|
42
|
+
font-size: 14px;
|
|
43
|
+
line-height: 22px;
|
|
44
|
+
font-weight: 500;
|
|
45
|
+
}
|
|
46
|
+
${formScope} strong,
|
|
47
|
+
${formScope} .dsh-subscription-label {
|
|
48
|
+
font-size: 13px;
|
|
49
|
+
line-height: 1.5;
|
|
50
|
+
font-weight: 500;
|
|
51
|
+
}
|
|
52
|
+
${formScope} legend {
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
line-height: 22px;
|
|
55
|
+
font-weight: 500;
|
|
56
|
+
}
|
|
57
|
+
${formScope} small,
|
|
58
|
+
${formScope} .dsh-subscription-hint,
|
|
59
|
+
${formScope} [role="status"] {
|
|
60
|
+
margin: 0;
|
|
61
|
+
font-size: 12px;
|
|
62
|
+
line-height: 1.5;
|
|
63
|
+
color: var(--dsw-alias-label-tertiary);
|
|
64
|
+
}
|
|
65
|
+
${formScope} [role="alert"] {
|
|
66
|
+
margin: 0;
|
|
67
|
+
font-size: 12px;
|
|
68
|
+
line-height: 1.5;
|
|
69
|
+
color: var(--dsw-alias-state-error-primary, #b42318);
|
|
70
|
+
}
|
|
71
|
+
${formScope} input:not([type="checkbox"]),
|
|
72
|
+
${formScope} select {
|
|
73
|
+
box-sizing: border-box;
|
|
74
|
+
min-width: 0;
|
|
75
|
+
height: 34px;
|
|
76
|
+
padding: 0 12px;
|
|
77
|
+
border: 0.5px solid var(--dsw-alias-border-l4, var(--dsw-alias-border-l2));
|
|
78
|
+
border-radius: var(--dsw-radius-md, 8px);
|
|
79
|
+
background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-1));
|
|
80
|
+
color: var(--dsw-alias-label-primary);
|
|
81
|
+
font: inherit;
|
|
82
|
+
font-size: 13px;
|
|
83
|
+
font-weight: 400;
|
|
84
|
+
line-height: 1.5;
|
|
85
|
+
}
|
|
86
|
+
${formScope} input::placeholder {
|
|
87
|
+
color: var(--dsw-alias-label-tertiary);
|
|
88
|
+
opacity: 1;
|
|
89
|
+
}
|
|
90
|
+
${formScope} input:not([type="checkbox"]):focus-visible,
|
|
91
|
+
${formScope} select:focus-visible {
|
|
92
|
+
outline: none;
|
|
93
|
+
border-color: var(--dsw-alias-state-business-primary, var(--dsw-alias-brand-primary));
|
|
94
|
+
}
|
|
95
|
+
${formScope} input:not([type="checkbox"]):disabled,
|
|
96
|
+
${formScope} select:disabled {
|
|
97
|
+
color: var(--dsw-alias-label-tertiary);
|
|
98
|
+
cursor: default;
|
|
99
|
+
}
|
|
100
|
+
${formScope} input[aria-invalid="true"] {
|
|
101
|
+
border-color: var(--dsw-alias-state-error-primary, #b42318);
|
|
102
|
+
}
|
|
103
|
+
${formScope} option {
|
|
104
|
+
background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));
|
|
105
|
+
color: var(--dsw-alias-label-primary);
|
|
106
|
+
}
|
|
107
|
+
${formScope} label:has(> input[type="checkbox"]) {
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: flex-start;
|
|
110
|
+
gap: 6px;
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
line-height: 20px;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
}
|
|
115
|
+
${formScope} input[type="checkbox"] {
|
|
116
|
+
flex: 0 0 auto;
|
|
117
|
+
width: 16px;
|
|
118
|
+
height: 16px;
|
|
119
|
+
margin: 2px 0;
|
|
120
|
+
accent-color: var(--dsw-alias-brand-primary);
|
|
121
|
+
cursor: inherit;
|
|
122
|
+
}
|
|
123
|
+
${formScope} label:has(> input[type="checkbox"]:disabled) {
|
|
124
|
+
cursor: default;
|
|
125
|
+
opacity: 0.5;
|
|
126
|
+
}
|
|
127
|
+
${formScope} button {
|
|
128
|
+
box-sizing: border-box;
|
|
129
|
+
display: inline-flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
justify-content: center;
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
min-height: 28px;
|
|
134
|
+
padding: 0 10px;
|
|
135
|
+
border: 0.5px solid var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));
|
|
136
|
+
border-radius: var(--dsw-radius-sm, 6px);
|
|
137
|
+
background: transparent;
|
|
138
|
+
color: var(--dsw-alias-label-primary);
|
|
139
|
+
font: inherit;
|
|
140
|
+
font-size: 12px;
|
|
141
|
+
line-height: 18px;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
}
|
|
144
|
+
${formScope} button:hover:not(:disabled) {
|
|
145
|
+
background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-3));
|
|
146
|
+
}
|
|
147
|
+
${formScope} button:active:not(:disabled) {
|
|
148
|
+
background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-3));
|
|
149
|
+
}
|
|
150
|
+
${formScope} button:disabled {
|
|
151
|
+
opacity: 0.4;
|
|
152
|
+
cursor: default;
|
|
153
|
+
}
|
|
154
|
+
${formScope} button.dsh-subscription-quiet {
|
|
155
|
+
border-color: transparent;
|
|
156
|
+
color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));
|
|
157
|
+
}
|
|
158
|
+
${formScope} :is(footer, .dsh-subscription-dialog-actions) button {
|
|
159
|
+
min-height: 34px;
|
|
160
|
+
padding: 0 14px;
|
|
161
|
+
border-radius: var(--dsw-radius-md, 8px);
|
|
162
|
+
font-size: 13px;
|
|
163
|
+
line-height: 1.5;
|
|
164
|
+
}
|
|
165
|
+
${formScope} button.dsh-subscription-primary {
|
|
166
|
+
border-color: transparent;
|
|
167
|
+
background: var(--dsw-alias-button-primary-fill, var(--dsw-alias-label-primary));
|
|
168
|
+
color: var(--dsw-alias-label-primary-foreground, var(--dsw-alias-bg-layer-1));
|
|
169
|
+
font-weight: 500;
|
|
170
|
+
}
|
|
171
|
+
${formScope} button.dsh-subscription-primary:hover:not(:disabled) {
|
|
172
|
+
background: var(--dsw-alias-button-primary-hover, var(--dsw-alias-label-secondary));
|
|
173
|
+
}
|
|
174
|
+
${formScope} button:focus-visible,
|
|
175
|
+
${formScope} input[type="checkbox"]:focus-visible,
|
|
176
|
+
${formScope} summary:focus-visible {
|
|
177
|
+
outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
178
|
+
outline-offset: 2px;
|
|
179
|
+
}
|
|
180
|
+
${formScope} summary {
|
|
181
|
+
border-radius: var(--dsw-radius-sm, 6px);
|
|
182
|
+
}
|
|
183
|
+
${formScope} summary:hover {
|
|
184
|
+
color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));
|
|
185
|
+
}
|
|
186
|
+
`;
|
|
187
|
+
/** Composer controls retain their own geometry, separate from settings forms. */
|
|
188
|
+
export const subscriptionChromeCss = `
|
|
189
|
+
.dsh-subscription-usage-pill { corner-shape: round; }
|
|
190
|
+
.dsh-subscription-usage-panel {
|
|
191
|
+
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
|
|
192
|
+
backdrop-filter: var(--dsw-menu-backdrop-filter, none);
|
|
193
|
+
}
|
|
194
|
+
.dsh-subscription-speed button:hover:not(:disabled) {
|
|
195
|
+
--dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-hover);
|
|
196
|
+
}
|
|
197
|
+
.dsh-subscription-speed button:active:not(:disabled) {
|
|
198
|
+
--dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-active);
|
|
199
|
+
}
|
|
200
|
+
.dsh-subscription-speed button:disabled { opacity: 0.4; cursor: default; }
|
|
201
|
+
.dsh-subscription-speed button:focus-visible,
|
|
202
|
+
.dsh-subscription-usage-pill:focus-visible {
|
|
203
|
+
outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
204
|
+
outline-offset: 2px;
|
|
205
|
+
}
|
|
206
|
+
`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Explain client-side gating; the server independently revalidates before spending. */
|
|
2
|
+
export declare function resetActionBlock(usage: {
|
|
3
|
+
windows?: {
|
|
4
|
+
kind: string;
|
|
5
|
+
scope?: string;
|
|
6
|
+
usedPercent: number;
|
|
7
|
+
resetsAt?: number;
|
|
8
|
+
}[];
|
|
9
|
+
resetCredits?: {
|
|
10
|
+
id?: string;
|
|
11
|
+
expiresAt?: number;
|
|
12
|
+
}[];
|
|
13
|
+
resetCreditsError?: string;
|
|
14
|
+
}, now?: number): 'resetUseGuard' | 'resetUseRefresh' | 'resetUseRestart' | undefined;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Explain client-side gating; the server independently revalidates before spending. */
|
|
2
|
+
export function resetActionBlock(usage, now = Date.now()) {
|
|
3
|
+
const weekly = usage.windows?.find(w => w.kind === 'weekly' && w.scope === undefined);
|
|
4
|
+
if (!weekly || !Number.isFinite(weekly.usedPercent))
|
|
5
|
+
return 'resetUseRefresh';
|
|
6
|
+
if (weekly.usedPercent < 80)
|
|
7
|
+
return 'resetUseGuard';
|
|
8
|
+
if (weekly.resetsAt === undefined || weekly.resetsAt <= now || usage.resetCreditsError)
|
|
9
|
+
return 'resetUseRefresh';
|
|
10
|
+
if (!usage.resetCredits?.some(c => c.id))
|
|
11
|
+
return 'resetUseRestart';
|
|
12
|
+
if (!usage.resetCredits.some(c => c.id && (c.expiresAt === undefined || c.expiresAt > now)))
|
|
13
|
+
return 'resetUseRefresh';
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ResetCreditView, SubscriptionsSectionInjected } from './SubscriptionsSection.js';
|
|
2
|
+
type Translate = SubscriptionsSectionInjected['t'];
|
|
3
|
+
/** How one grant reads. Color is not the only carrier; the state word is in the row name. */
|
|
4
|
+
export type ResetCreditState = 'available' | 'notUsable' | 'paused' | 'exhausted' | 'expired';
|
|
5
|
+
/**
|
|
6
|
+
* Classify one grant. Expired outranks every other flag. A future
|
|
7
|
+
* `cooldownUntil` or `usableNow: false` is not usable even when `claimable`
|
|
8
|
+
* is true. `claimable` does not change the word: it is not an action.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resetCreditState(credit: ResetCreditView, now: number): ResetCreditState;
|
|
11
|
+
/**
|
|
12
|
+
* Headline count. Codex passes one entry per credit, so the count is the
|
|
13
|
+
* list length. Claude passes one entry per grant, so the count is the sum of
|
|
14
|
+
* `resetsLeft` on grants that are neither expired nor paused. A missing
|
|
15
|
+
* `resetsLeft` adds nothing; the row says the count is unavailable.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resetCreditsAvailableCount(credits: readonly ResetCreditView[], now: number, mode: 'credits' | 'grants'): number;
|
|
18
|
+
/** Codex Use control. Absent for Claude, which must not render a button. */
|
|
19
|
+
export interface ResetCreditUseAction {
|
|
20
|
+
accountKey: string;
|
|
21
|
+
busy: boolean;
|
|
22
|
+
disabled: boolean;
|
|
23
|
+
title: string;
|
|
24
|
+
label: string;
|
|
25
|
+
onUse: () => void;
|
|
26
|
+
}
|
|
27
|
+
/** Accessible name of one Claude grant row: state, remaining, and expiry, not a control name. */
|
|
28
|
+
export declare function resetCreditRowName(t: Translate, credit: ResetCreditView, now: number): string;
|
|
29
|
+
/** Claude omits an empty grant list; Codex still shows a defined, possibly empty, list. */
|
|
30
|
+
export declare function showsResetCredits(provider: 'codex' | 'claude', credits: readonly ResetCreditView[] | undefined): boolean;
|
|
31
|
+
/** The error line the settings card mounts. Claude never interpolates provider text. */
|
|
32
|
+
export declare function ResetCreditsErrorLine({ provider, message, t }: {
|
|
33
|
+
provider: 'codex' | 'claude';
|
|
34
|
+
message: string;
|
|
35
|
+
t: Translate;
|
|
36
|
+
}): import("react").JSX.Element;
|
|
37
|
+
/** Fixed sentence for Claude. Codex may include the lookup message; Claude must not. */
|
|
38
|
+
export declare function resetCreditsErrorText(provider: 'codex' | 'claude', message: string, t: Translate): string;
|
|
39
|
+
/**
|
|
40
|
+
* The closed disclosure both providers share. Claude rows are plain text:
|
|
41
|
+
* no button, no `role="button"`, and `cursor: default`, including when
|
|
42
|
+
* `claimable` is true.
|
|
43
|
+
*/
|
|
44
|
+
export declare function ResetCreditsDisclosure({ mode, credits, t, now, nextCredit, useAction, statusMessage, }: {
|
|
45
|
+
mode: 'credits' | 'grants';
|
|
46
|
+
credits: readonly ResetCreditView[];
|
|
47
|
+
t: Translate;
|
|
48
|
+
now?: number;
|
|
49
|
+
nextCredit?: ResetCreditView;
|
|
50
|
+
useAction?: ResetCreditUseAction;
|
|
51
|
+
statusMessage?: string;
|
|
52
|
+
}): import("react").JSX.Element;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { subscriptionCardStyles as cardStyles } from './subscription-card-styles.js';
|
|
3
|
+
const STATE_KEYS = {
|
|
4
|
+
available: 'resetCreditAvailable',
|
|
5
|
+
notUsable: 'resetCreditNotUsable',
|
|
6
|
+
paused: 'resetCreditPaused',
|
|
7
|
+
exhausted: 'resetCreditExhausted',
|
|
8
|
+
expired: 'resetCreditExpired',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Classify one grant. Expired outranks every other flag. A future
|
|
12
|
+
* `cooldownUntil` or `usableNow: false` is not usable even when `claimable`
|
|
13
|
+
* is true. `claimable` does not change the word: it is not an action.
|
|
14
|
+
*/
|
|
15
|
+
export function resetCreditState(credit, now) {
|
|
16
|
+
if (credit.expiresAt !== undefined && credit.expiresAt <= now)
|
|
17
|
+
return 'expired';
|
|
18
|
+
if (credit.paused === true)
|
|
19
|
+
return 'paused';
|
|
20
|
+
if (credit.resetsLeft === 0)
|
|
21
|
+
return 'exhausted';
|
|
22
|
+
if ((credit.cooldownUntil !== undefined && credit.cooldownUntil > now) || credit.usableNow === false)
|
|
23
|
+
return 'notUsable';
|
|
24
|
+
return 'available';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Headline count. Codex passes one entry per credit, so the count is the
|
|
28
|
+
* list length. Claude passes one entry per grant, so the count is the sum of
|
|
29
|
+
* `resetsLeft` on grants that are neither expired nor paused. A missing
|
|
30
|
+
* `resetsLeft` adds nothing; the row says the count is unavailable.
|
|
31
|
+
*/
|
|
32
|
+
export function resetCreditsAvailableCount(credits, now, mode) {
|
|
33
|
+
if (mode === 'credits')
|
|
34
|
+
return credits.length;
|
|
35
|
+
let sum = 0;
|
|
36
|
+
for (const credit of credits) {
|
|
37
|
+
const state = resetCreditState(credit, now);
|
|
38
|
+
if (state === 'expired' || state === 'paused')
|
|
39
|
+
continue;
|
|
40
|
+
if (typeof credit.resetsLeft === 'number' && Number.isFinite(credit.resetsLeft) && credit.resetsLeft > 0) {
|
|
41
|
+
sum += credit.resetsLeft;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return sum;
|
|
45
|
+
}
|
|
46
|
+
function expiryText(t, credit) {
|
|
47
|
+
return credit.expiresAt === undefined
|
|
48
|
+
? t('resetCreditExpiryUnknown')
|
|
49
|
+
: t('resetCreditExpires', { date: new Date(credit.expiresAt).toLocaleString() });
|
|
50
|
+
}
|
|
51
|
+
function remainingText(t, credit) {
|
|
52
|
+
const left = credit.resetsLeft;
|
|
53
|
+
const total = credit.resetsTotal;
|
|
54
|
+
const hasLeft = typeof left === 'number' && Number.isFinite(left);
|
|
55
|
+
const hasTotal = typeof total === 'number' && Number.isFinite(total);
|
|
56
|
+
if (hasLeft && hasTotal)
|
|
57
|
+
return t('resetCreditRemaining', { left, total });
|
|
58
|
+
if (hasLeft)
|
|
59
|
+
return t('resetCreditLeft', { left });
|
|
60
|
+
return t('resetCreditRemainingUnknown');
|
|
61
|
+
}
|
|
62
|
+
/** Accessible name of one Claude grant row: state, remaining, and expiry, not a control name. */
|
|
63
|
+
export function resetCreditRowName(t, credit, now) {
|
|
64
|
+
const state = resetCreditState(credit, now);
|
|
65
|
+
const parts = [t('resetCreditFull'), t(STATE_KEYS[state]), remainingText(t, credit), expiryText(t, credit)];
|
|
66
|
+
if (state === 'notUsable' && credit.cooldownUntil !== undefined && credit.cooldownUntil > now) {
|
|
67
|
+
parts.push(t('resetCreditCooldownUntil', { date: new Date(credit.cooldownUntil).toLocaleString() }));
|
|
68
|
+
}
|
|
69
|
+
return parts.join(', ');
|
|
70
|
+
}
|
|
71
|
+
/** Claude omits an empty grant list; Codex still shows a defined, possibly empty, list. */
|
|
72
|
+
export function showsResetCredits(provider, credits) {
|
|
73
|
+
if (provider === 'codex')
|
|
74
|
+
return credits !== undefined;
|
|
75
|
+
return (credits?.length ?? 0) > 0;
|
|
76
|
+
}
|
|
77
|
+
/** The error line the settings card mounts. Claude never interpolates provider text. */
|
|
78
|
+
export function ResetCreditsErrorLine({ provider, message, t }) {
|
|
79
|
+
return _jsx("p", { style: cardStyles.error, children: resetCreditsErrorText(provider, message, t) });
|
|
80
|
+
}
|
|
81
|
+
/** Fixed sentence for Claude. Codex may include the lookup message; Claude must not. */
|
|
82
|
+
export function resetCreditsErrorText(provider, message, t) {
|
|
83
|
+
return provider === 'claude' ? t('resetCreditsErrorFixed') : t('resetCreditsError', { message });
|
|
84
|
+
}
|
|
85
|
+
const summaryStyle = {
|
|
86
|
+
...cardStyles.usageMeta, cursor: 'pointer', listStyle: 'none', justifyContent: 'flex-start', gap: 6,
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The closed disclosure both providers share. Claude rows are plain text:
|
|
90
|
+
* no button, no `role="button"`, and `cursor: default`, including when
|
|
91
|
+
* `claimable` is true.
|
|
92
|
+
*/
|
|
93
|
+
export function ResetCreditsDisclosure({ mode, credits, t, now = Date.now(), nextCredit, useAction, statusMessage, }) {
|
|
94
|
+
const count = resetCreditsAvailableCount(credits, now, mode);
|
|
95
|
+
return (_jsxs("details", { className: "subscriptions-reset-credits", style: cardStyles.usageRow, children: [_jsxs("summary", { style: summaryStyle, children: [_jsx("svg", { "aria-hidden": "true", width: "12", height: "12", viewBox: "0 0 16 16", style: { flexShrink: 0 }, children: _jsx("path", { d: "m6 3 5 5-5 5", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }), _jsx("span", { children: t('resetCreditsTitle') }), mode === 'grants' && _jsx("span", { children: t('resetCreditReadOnlyLabel') }), _jsx("span", { style: { marginLeft: 'auto' }, children: t('resetCreditsAvailable', { count }) })] }), _jsx("style", { children: '.subscriptions-reset-credits > summary::-webkit-details-marker { display: none; }'
|
|
96
|
+
+ '.subscriptions-reset-credits[open] > summary > svg { transform: rotate(90deg); }' }), _jsxs("div", { style: { paddingLeft: 18, marginTop: 6 }, children: [mode === 'grants' && _jsx("p", { style: cardStyles.status, children: t('resetCreditReadOnly') }), credits.map((credit, index) => {
|
|
97
|
+
const state = resetCreditState(credit, now);
|
|
98
|
+
const showUse = mode === 'credits' && useAction !== undefined && credit === nextCredit;
|
|
99
|
+
return (_jsxs("div", { "data-reset-state": mode === 'grants' ? state : undefined, "data-reset-claimable": mode === 'grants' && credit.claimable === true ? 'true' : undefined, role: mode === 'grants' ? 'group' : undefined, "aria-label": mode === 'grants' ? resetCreditRowName(t, credit, now) : undefined, style: { ...cardStyles.usageMeta, minHeight: 28, gap: 12, cursor: mode === 'grants' ? 'default' : undefined }, children: [_jsxs("span", { style: { display: 'inline-flex', alignItems: 'center', gap: 8, flexShrink: 0 }, children: [t('resetCreditFull'), mode === 'grants' && (_jsx("span", { "aria-hidden": "true", "data-reset-state-word": state, children: t(STATE_KEYS[state]) })), showUse && (_jsx("button", { type: "button", "aria-disabled": useAction.disabled, title: useAction.title, style: { minHeight: 22, height: 22, padding: '0 7px', borderRadius: 6,
|
|
100
|
+
opacity: useAction.disabled ? 0.35 : 1, cursor: useAction.disabled ? 'not-allowed' : 'pointer' }, onClick: () => { if (!useAction.disabled)
|
|
101
|
+
useAction.onUse(); }, children: useAction.busy ? t('resetUseChecking') : useAction.label }))] }), _jsxs("span", { style: { textAlign: 'right' }, children: [mode === 'grants' && _jsxs("span", { "aria-hidden": "true", children: [remainingText(t, credit), " \u00B7 "] }), mode === 'grants' && state === 'notUsable' && credit.cooldownUntil !== undefined && credit.cooldownUntil > now && (_jsxs("span", { "aria-hidden": "true", children: [t('resetCreditCooldownUntil', { date: new Date(credit.cooldownUntil).toLocaleString() }), " \u00B7 "] })), _jsx("span", { "aria-hidden": mode === 'grants' ? true : undefined, children: expiryText(t, credit) })] })] }, credit.id ?? index));
|
|
102
|
+
}), statusMessage !== undefined && statusMessage !== '' && _jsx("p", { role: "status", style: cardStyles.status, children: statusMessage })] })] }));
|
|
103
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Display-only preference: no credentials or account history are stored.
|
|
3
|
+
* `recent` pins the current/most-recent provider; `always` keeps a provider
|
|
4
|
+
* visible at all times, rotating through the others when the current model
|
|
5
|
+
* has no quota source; `hidden` shows nothing.
|
|
6
|
+
*/
|
|
7
|
+
export type UsageBadgeMode = 'recent' | 'always' | 'hidden';
|
|
3
8
|
export declare const USAGE_BADGE_REFRESH_EVENT = "dsh:subscriptions:usage-refresh";
|
|
4
9
|
/** Read the browser preference; blocked storage retains the default display. */
|
|
5
10
|
export declare function readUsageBadgeMode(): UsageBadgeMode;
|
|
@@ -7,7 +7,8 @@ export function readUsageBadgeMode() {
|
|
|
7
7
|
if (typeof window === 'undefined')
|
|
8
8
|
return 'recent';
|
|
9
9
|
try {
|
|
10
|
-
|
|
10
|
+
const value = window.localStorage.getItem(MODE_KEY);
|
|
11
|
+
return value === 'hidden' || value === 'always' ? value : 'recent';
|
|
11
12
|
}
|
|
12
13
|
catch (error) {
|
|
13
14
|
if (!(error instanceof DOMException) || error.name !== 'SecurityError')
|
|
@@ -17,7 +18,7 @@ export function readUsageBadgeMode() {
|
|
|
17
18
|
}
|
|
18
19
|
/** Save first, then notify; the settings control reports a rejected write. */
|
|
19
20
|
export function setUsageBadgeMode(mode) {
|
|
20
|
-
if (mode !== 'recent' && mode !== 'hidden')
|
|
21
|
+
if (mode !== 'recent' && mode !== 'always' && mode !== 'hidden')
|
|
21
22
|
throw new TypeError('Invalid subscription usage display mode');
|
|
22
23
|
window.localStorage.setItem(MODE_KEY, mode);
|
|
23
24
|
window.dispatchEvent(new Event(MODE_EVENT));
|
|
@@ -22,8 +22,21 @@ export interface CountdownPart {
|
|
|
22
22
|
* window never announces zero remaining time. Always at least one minute.
|
|
23
23
|
*/
|
|
24
24
|
export declare function resetCountdownParts(ms: number): CountdownPart[];
|
|
25
|
+
/**
|
|
26
|
+
* Whether the reported percentage still describes the window now. Only a fresh
|
|
27
|
+
* reading may be compared with the current time (pace warnings); an old one
|
|
28
|
+
* keeps its absolute color. This does not decide whether the time cursor is
|
|
29
|
+
* drawn: where the window stands in time never depends on the reading.
|
|
30
|
+
*/
|
|
25
31
|
export declare function isUsageFresh(window: UsageWindow, observation: UsageObservation, now?: number): boolean;
|
|
26
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* How far through its window the clock is, from the window's own timing alone.
|
|
34
|
+
* It ignores the percentage and how recently it was read, so an unused,
|
|
35
|
+
* stale, aged or unobserved reading keeps its cursor whenever the timing
|
|
36
|
+
* places it. Returns undefined when the timing cannot: only an explicit
|
|
37
|
+
* interval or a provider-verified fixed duration supports linear pace, and no
|
|
38
|
+
* start is invented from a window's kind or label.
|
|
39
|
+
*/
|
|
27
40
|
export declare function elapsedPercent(window: UsageWindow, now?: number): number | undefined;
|
|
28
41
|
export declare function usageColorState(used: number, elapsed: number | undefined, preset: UsageColorPreset, fresh: boolean): UsageColorState;
|
|
29
42
|
export declare function usageBarColor(used: number, elapsed?: number, preset?: UsageColorPreset, fresh?: boolean): string;
|