dsh-plugin-subscription-oauth 0.2.1 → 0.2.2

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 CHANGED
@@ -178,7 +178,7 @@ The CLI forwards its arguments to pnpm, so a pinned version, a git URL and a loc
178
178
  path are all spelled the same way:
179
179
 
180
180
  ```sh
181
- dsh plugin --profile web add dsh-plugin-subscription-oauth@0.2.1
181
+ dsh plugin --profile web add dsh-plugin-subscription-oauth@0.2.2
182
182
  dsh plugin --profile web add github:EricFL1998/dsh-subscription-oauth
183
183
  dsh plugin --profile web add /path/to/dsh-plugin-subscription-oauth
184
184
  ```
@@ -470,15 +470,7 @@ function ProviderCard(props) {
470
470
  : status.loggedIn
471
471
  ? t('statusConnected', { count: accounts.length })
472
472
  : t('statusSignedOut');
473
- return (_jsxs("div", { style: styles.card, children: [_jsxs("div", { style: styles.cardHeader, children: [_jsx("span", { style: { ...styles.dot, background: dotColor(status) }, "aria-hidden": "true" }), _jsx("span", { style: styles.name, children: status.displayName }), _jsx("span", { style: styles.providerId, children: status.provider }), !cardOpen && _jsx("span", { style: styles.cardSummary, children: summaryLine }), _jsx("button", { type: "button", className: "dsh-subscription-quiet", style: styles.pushRight, "aria-expanded": cardOpen, "aria-controls": `dsh-subscription-card-${status.provider}`, onClick: toggleCardOpen, children: cardOpen ? t('collapse') : t('edit') })] }), _jsxs("div", { id: `dsh-subscription-card-${status.provider}`, style: cardOpen ? styles.cardBody : { ...styles.cardBody, display: 'none' }, children: [_jsx("p", { style: styles.statusLine, children: !connectable
474
- // `auto` has no account: it stands in for the models the other routes
475
- // signed in for, so it counts the candidates instead.
476
- ? t('statusAuto', { count: models.filter((model) => model.visible).length })
477
- : busy
478
- ? t('statusBusy')
479
- : status.loggedIn
480
- ? t('statusConnected', { count: accounts.length })
481
- : t('statusSignedOut') }), connectable && !status.loggedIn && !busy && _jsx("p", { style: styles.statusLine, children: t('statusSignIn') }), status.lastError !== undefined && (_jsx("p", { className: "dsh-subscription-error", children: t('lastError', { message: status.lastError }) })), message?.tone === 'error' && _jsx("p", { className: "dsh-subscription-error", children: message.text }), message?.tone === 'success' && _jsx("p", { className: "dsh-subscription-success", children: message.text }), accounts.map((account) => (_jsx("div", { style: styles.accountRow, children: _jsxs("div", { style: styles.accountHeader, children: [_jsx("button", { type: "button", style: styles.starButton, title: account.isDefault ? t('defaultBadge') : t('makeDefault'), "aria-label": account.isDefault ? t('defaultBadge') : t('makeDefault'), disabled: busyAction || account.isDefault, onClick: () => { props.onSetDefault(account.account); }, children: account.isDefault ? '★' : '☆' }), _jsx("span", { style: styles.accountName, children: account.label }), account.isDefault && _jsx("span", { style: styles.badge, children: t('defaultBadge') }), account.needsLogin === true && (_jsx("span", { style: styles.badge, title: t('accountNeedsLoginHint'), children: t('accountNeedsLogin') })), _jsx("span", { style: styles.statusLine, children: account.expired
473
+ return (_jsxs("div", { style: styles.card, children: [_jsxs("div", { style: styles.cardHeader, children: [_jsx("span", { style: { ...styles.dot, background: dotColor(status) }, "aria-hidden": "true" }), _jsx("span", { style: styles.name, children: status.displayName }), _jsx("span", { style: styles.providerId, children: status.provider }), _jsx("span", { style: styles.cardSummary, children: summaryLine }), _jsx("button", { type: "button", className: "dsh-subscription-quiet", style: styles.pushRight, "aria-expanded": cardOpen, "aria-controls": `dsh-subscription-card-${status.provider}`, onClick: toggleCardOpen, children: cardOpen ? t('collapse') : t('edit') })] }), _jsxs("div", { id: `dsh-subscription-card-${status.provider}`, style: cardOpen ? styles.cardBody : { ...styles.cardBody, display: 'none' }, children: [connectable && !status.loggedIn && !busy && _jsx("p", { style: styles.statusLine, children: t('statusSignIn') }), status.lastError !== undefined && (_jsx("p", { className: "dsh-subscription-error", children: t('lastError', { message: status.lastError }) })), message?.tone === 'error' && _jsx("p", { className: "dsh-subscription-error", children: message.text }), message?.tone === 'success' && _jsx("p", { className: "dsh-subscription-success", children: message.text }), accounts.map((account) => (_jsx("div", { style: styles.accountRow, children: _jsxs("div", { style: styles.accountHeader, children: [_jsx("button", { type: "button", style: styles.starButton, title: account.isDefault ? t('defaultBadge') : t('makeDefault'), "aria-label": account.isDefault ? t('defaultBadge') : t('makeDefault'), disabled: busyAction || account.isDefault, onClick: () => { props.onSetDefault(account.account); }, children: account.isDefault ? '★' : '☆' }), _jsx("span", { style: styles.accountName, children: account.label }), account.isDefault && _jsx("span", { style: styles.badge, children: t('defaultBadge') }), account.needsLogin === true && (_jsx("span", { style: styles.badge, title: t('accountNeedsLoginHint'), children: t('accountNeedsLogin') })), _jsx("span", { style: styles.statusLine, children: account.expired
482
474
  ? t('accountExpired')
483
475
  : t('accountExpires', { time: formatTime(account.expiresAt) }) }), _jsx("button", { type: "button", className: "dsh-subscription-quiet", style: styles.pushRight, disabled: busyAction, onClick: () => { props.onLogout(account.account); }, children: t('logout') })] }) }, account.account))), status.loggedIn && (_jsxs("div", { style: styles.catalog, children: [_jsxs("div", { style: styles.catalogHeader, children: [_jsxs("button", { type: "button", className: "dsh-subscription-disclosure", style: styles.disclosure, "aria-expanded": modelsOpen, "aria-controls": `dsh-subscription-models-${status.provider}`, onClick: toggleModelsOpen, children: [_jsx("span", { style: styles.chevron, "aria-hidden": "true", children: modelsOpen ? '▾' : '▸' }), _jsx("span", { style: styles.catalogTitle, children: t('modelsTitle') })] }), _jsxs("span", { style: styles.catalogMeta, children: [t('modelsCount', { count: models.length }), ' · ', liveCatalog ? t('modelsLive') : t('modelsBuiltIn'), hiddenCount === 0 ? '' : ` ${t('modelsHiddenCount', { count: hiddenCount })}`] }), _jsx("button", { type: "button", className: "dsh-subscription-quiet", style: styles.pushRight, disabled: busyAction, onClick: props.onRefreshModels, children: busyAction ? t('refreshing') : t('refresh') }), _jsx("button", { type: "button", className: "dsh-subscription-quiet", disabled: busyAction || !connectable, title: t('modelsAddHint'), onClick: () => { setAdding((open) => !open); }, children: t('modelsAdd') })] }), adding && (_jsxs("form", { style: styles.addRow, onSubmit: (event) => {
484
476
  event.preventDefault();
package/lib/client.js CHANGED
@@ -1286,7 +1286,7 @@ function ProviderCard(props) {
1286
1286
  style: styles.providerId,
1287
1287
  children: status.provider
1288
1288
  }),
1289
- !cardOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1289
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1290
1290
  style: styles.cardSummary,
1291
1291
  children: summaryLine
1292
1292
  }),
@@ -1308,10 +1308,6 @@ function ProviderCard(props) {
1308
1308
  display: "none"
1309
1309
  },
1310
1310
  children: [
1311
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1312
- style: styles.statusLine,
1313
- children: !connectable ? t("statusAuto", { count: models.filter((model) => model.visible).length }) : busy ? t("statusBusy") : status.loggedIn ? t("statusConnected", { count: accounts.length }) : t("statusSignedOut")
1314
- }),
1315
1311
  connectable && !status.loggedIn && !busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1316
1312
  style: styles.statusLine,
1317
1313
  children: t("statusSignIn")
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["code: string","messageOf","result: Awaited<ReturnType<ConnectionHandle['rpc']['call']>>","error: unknown","template: string","styles: Record<string, CSSProperties>","window","accounts: readonly AccountStatus[]","caught: unknown"],"sources":["../src/client/locales.ts","../src/client/styles.ts","../src/protocol.ts","../src/client/subscriptions-rpc.ts","../src/client/SubscriptionsSection.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Copy dictionaries for the Subscriptions settings page.\n *\n * English is the key-set source of truth; the Chinese dictionary is typed\n * against it, so a key added to one and forgotten in the other is a compile\n * error rather than a silent fallback.\n */\n\n/** English strings. */\nexport const en = {\n nav: 'Subscriptions',\n intro: 'Sign in with a subscription account — Kimi Code, Grok (X Premium) or Google Antigravity. DeepSeek Harness keeps the tokens on this machine and streams every request through the provider\\'s own API.',\n loading: 'Checking subscriptions…',\n unavailable: 'The subscriptions page needs the web connection service, which this composition does not provide.',\n statusConnected: 'Connected · {count} account(s)',\n statusSignedOut: 'Not signed in',\n statusBusy: 'Waiting for browser approval',\n statusSignIn: 'Sign in to add this provider\\'s models to the model picker.',\n statusAuto: 'Follows {count} enabled model(s) from every provider',\n connect: 'Connect',\n edit: 'Edit',\n collapse: 'Collapse',\n addAccount: 'Add account',\n manage: 'Manage',\n cancel: 'Cancel',\n close: 'Close',\n logout: 'Sign out',\n makeDefault: 'Use by default',\n defaultBadge: 'Default',\n accountNeedsLogin: 'Sign in again',\n accountNeedsLoginHint: 'The provider refused this account\\'s grant, so its token cannot be renewed',\n accountExpired: 'token expired',\n accountExpires: 'expires {time}',\n deviceTitle: 'Approve this device',\n devicePrompt: 'Open the verification page and confirm the code below. This page updates by itself once the provider approves.',\n deviceOpen: 'Open verification page',\n deviceCopy: 'Copy code',\n deviceCopied: 'Copied',\n deviceExpires: 'The code expires at {time}.',\n openLogin: 'Open sign-in page',\n openLoginHint: 'Finish signing in in the browser tab that opened. This page updates by itself once the provider redirects back.',\n modelsTitle: 'Models',\n modelsCount: '{count} available',\n modelsLive: 'live',\n modelsBuiltIn: 'built-in',\n modelsShow: 'Show in picker',\n modelsHiddenCount: '· {count} hidden',\n modelsHidden: 'Hidden from the model picker',\n modelsEmpty: 'No models reported yet.',\n modelsAdd: 'Add model',\n modelsAddHint: 'Publish a model id this build does not know yet',\n modelsAddPlaceholder: 'model id, e.g. k3-next',\n modelsAddConfirm: 'Add',\n modelsRemove: 'Remove this hand-added model',\n modelsContext: '{tokens} context',\n modelsAuto: 'Auto',\n modelsAutoHint: 'Pinned first: moves to the next model when one is unavailable',\n modelsAutoOff: 'Off — the picker offers the models directly instead',\n modelsAutoChain: 'Auto tries these, in this order — drag to re-order',\n modelsDrag: 'Drag to re-order (or press ↑ / ↓ here)',\n modelsAutoChainOff: 'Take out of Auto',\n modelsAutoChainEmpty: 'No model is enabled, so Auto has nothing to try.',\n modelsPinned: 'pinned',\n usageTitle: 'Plan and usage',\n usagePlan: 'Plan: {plan}',\n usageRenews: 'renews {time}',\n usageReset: 'resets {time}',\n usageResetsInMinutes: 'resets in {minutes}m',\r\n usageResetsInHours: 'resets in {hours}h',\n usageResetDue: 'resets shortly',\n usageRefresh: 'Refresh usage',\n usageFetched: 'read {time}',\n usageNone: 'This provider reports no plan quota.',\n usageError: 'Could not read usage: {message}',\n usage_5h: '5-hour window',\n usage_weekly: 'Weekly window',\n usage_credits: 'Included credit',\n usage_gemini: 'Gemini allowance (rolling)',\n usage_gemini_weekly: 'Gemini allowance (weekly)',\n usage_claude: 'Claude allowance (rolling)',\n usage_claude_weekly: 'Claude allowance (weekly)',\n usage_other: 'Allowance',\n refresh: 'Refresh',\n refreshing: 'Refreshing…',\n modelsRefreshed: 'Model list refreshed.',\n refreshToken: 'Refresh token',\n tokenRefreshed: 'Token refreshed; valid until {time}.',\n hint: 'Authorization follows the account the browser is signed in with. To add a different account, switch accounts there first, or use a private window.',\n manageTitle: 'Manage {provider}',\n manageAccounts: 'Accounts',\n reload: 'Reload credentials',\n reloadHint: 'Use this after signing in from another DeepSeek Harness window.',\n detail_oauthHost: 'Authorization server',\n detail_apiBase: 'API base',\n detail_credentialFile: 'Credential file',\n detail_project: 'Cloud project',\n lastError: 'Last login attempt failed: {message}',\n loginFailed: 'Could not start the sign-in: {message}',\n actionFailed: 'Action failed: {message}',\n} as const\n\n/** The Subscriptions namespace key union. */\nexport type SubscriptionsKey = keyof typeof en\n\n/** Chinese strings. */\nexport const zh = {\n nav: '订阅',\n intro: '使用订阅账号登录 —— Kimi Code、Grok (X Premium) 或 Google Antigravity。DeepSeek Harness 将令牌保存在本机,并通过各服务自己的 API 发起请求。',\n loading: '正在检查订阅…',\n unavailable: '订阅页面需要 Web 连接服务,当前组合未提供该服务。',\n statusConnected: '已连接 {count} 个账号',\n statusSignedOut: '未登录',\n statusBusy: '等待浏览器确认',\n statusSignIn: '登录后即可在模型选择器中使用该服务的模型。',\n statusAuto: '依次使用来自各服务的 {count} 个已启用模型',\n connect: '连接',\n edit: '编辑',\n collapse: '收起',\n addAccount: '添加账号',\n manage: '管理',\n cancel: '取消',\n close: '关闭',\n logout: '退出登录',\n makeDefault: '设为默认',\n defaultBadge: '默认',\n accountNeedsLogin: '需重新登录',\n accountNeedsLoginHint: '服务方已拒绝该账号的授权,令牌无法自动续期',\n accountExpired: '令牌已过期',\n accountExpires: '过期时间 {time}',\n deviceTitle: '确认此设备',\n devicePrompt: '打开验证页面并确认下方代码,服务确认后本页面会自动更新。',\n deviceOpen: '打开验证页面',\n deviceCopy: '复制代码',\n deviceCopied: '已复制',\n deviceExpires: '代码将于 {time} 过期。',\n openLogin: '打开登录页面',\n openLoginHint: '请在打开的浏览器标签页中完成登录;服务回调后本页面会自动更新。',\n modelsTitle: '模型',\n modelsCount: '共 {count} 个',\n modelsLive: '实时',\n modelsBuiltIn: '内置',\n modelsShow: '在选择器中显示',\n modelsHiddenCount: '· 已隐藏 {count} 个',\n modelsHidden: '已从模型选择器隐藏',\n modelsEmpty: '暂未获取到模型。',\n modelsAdd: '添加模型',\n modelsAddHint: '手动添加一个本版本还不认识的模型 ID',\n modelsAddPlaceholder: '模型 ID,例如 k3-next',\n modelsAddConfirm: '添加',\n modelsRemove: '移除这个手动添加的模型',\n modelsContext: '{tokens} 上下文',\n modelsAuto: '自动',\n modelsAutoHint: '固定在首位:某个模型不可用时自动改用下一个',\n modelsAutoOff: '已关闭 —— 选择器将直接列出各个模型',\n modelsAutoChain: '自动会按这个顺序依次尝试(拖动可调整)',\n modelsDrag: '拖动调整顺序(也可在此按 ↑ / ↓)',\n modelsAutoChainOff: '从自动中移除',\n modelsAutoChainEmpty: '没有启用任何模型,自动没有可尝试的模型。',\n modelsPinned: '固定',\n usageTitle: '套餐与额度',\n usagePlan: '套餐:{plan}',\n usageRenews: '续费时间 {time}',\n usageReset: '重置时间 {time}',\n usageResetsInMinutes: '{minutes} 分钟后重置',\r\n usageResetsInHours: '{hours} 小时后重置',\n usageResetDue: '即将重置',\n usageRefresh: '刷新额度',\n usageFetched: '读取于 {time}',\n usageNone: '该服务未提供套餐额度信息。',\n usageError: '额度读取失败:{message}',\n usage_5h: '5 小时窗口',\n usage_weekly: '每周窗口',\n usage_credits: '包含额度',\n usage_gemini: 'Gemini 模型额度(滚动)',\n usage_gemini_weekly: 'Gemini 模型额度(每周)',\n usage_claude: 'Claude 模型额度(滚动)',\n usage_claude_weekly: 'Claude 模型额度(每周)',\n usage_other: '额度',\n refresh: '刷新',\n refreshing: '正在刷新…',\n modelsRefreshed: '模型列表已刷新。',\n refreshToken: '刷新令牌',\n tokenRefreshed: '令牌已刷新,有效至 {time}。',\n hint: '授权以浏览器当前登录的账号为准;要添加不同账号,请先在浏览器里切换账号,或使用无痕窗口。',\n manageTitle: '管理 {provider}',\n manageAccounts: '账号',\n reload: '重新读取凭据',\n reloadHint: '在另一个 DeepSeek Harness 窗口中登录后,请使用此操作。',\n detail_oauthHost: '授权服务器',\n detail_apiBase: 'API 地址',\n detail_credentialFile: '凭据文件',\n detail_project: '云项目',\n lastError: '上次登录失败:{message}',\n loginFailed: '无法开始登录:{message}',\n actionFailed: '操作失败:{message}',\n} satisfies Record<SubscriptionsKey, string>\n","/**\n * Scoped stylesheet for the Subscriptions page and its manage dialog.\n *\n * The host loads plugin markup without its own control classes, and a bare\n * `<button>` therefore renders with the browser's default raised chrome — which\n * reads as a stray highlight in a dark theme. Rather than invent a look, this\n * follows the control vocabulary of the sibling `dsh-plugin-subscriptions`\n * plugin (same author-facing design as the shell's settings forms): a 6 px\n * radius small control, a transparent fill, a hairline border from the theme's\n * alias tokens, and the theme's hover/active/focus tokens for state.\n *\n * The tokens all carry fallbacks, so the page still renders correctly on a host\n * build that does not define them.\n *\n * @module dsh-plugin-subscription-oauth/client/styles\n */\n\n/**\n * Everything is scoped to this plugin's own roots, so no other surface in the\n * shell can be affected by a rule here.\n */\nconst scope = ':is(.dsh-subscriptions-settings, .dsh-subscription-manager)'\n\n/** The page's and dialog's stylesheet. */\nexport const subscriptionsCss = `\n.dsh-subscriptions-settings,\n.dsh-subscription-manager {\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n /* Native controls (checkbox, dialog) follow the host theme, not the OS. */\n color-scheme: light;\n}\nbody[data-ds-dark-theme] ${scope} {\n color-scheme: dark;\n}\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}\n.dsh-subscription-manager::backdrop {\n background: var(--dsw-alias-bg-mask-1, #0006);\n backdrop-filter: var(--dsw-mask-blur, none);\n}\n${scope} h2 {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n}\n${scope} strong,\n${scope} .dsh-subscription-label {\n font-size: 13px;\n line-height: 1.5;\n font-weight: 500;\n}\n${scope} small,\n${scope} .dsh-subscription-hint,\n${scope} [role=\"status\"] {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n${scope} .dsh-subscription-error {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary, #b42318);\n}\n${scope} .dsh-subscription-success {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary, #067647);\n}\n${scope} label:has(> input[type=\"checkbox\"]) {\n cursor: pointer;\n}\n${scope} input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-brand-primary);\n}\n/*\n * A model's on/off control is a switch, not a checkbox: it takes effect\n * immediately and its state is what matters, not a tick. Drawn from the theme\n * tokens with appearance: none, so it follows the host palette in both themes\n * instead of the platform's checkbox chrome.\n */\n${scope} input[type=\"checkbox\"].dsh-subscription-switch {\n appearance: none;\n -webkit-appearance: none;\n position: relative;\n box-sizing: border-box;\n flex-shrink: 0;\n width: 34px;\n height: 20px;\n margin: 0;\n border: 0.5px solid var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2));\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary-foreground, #fff);\n box-shadow: 0 1px 2px #0003;\n transition: transform 120ms ease;\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch:checked {\n border-color: transparent;\n background: var(--dsw-alias-state-success-primary, var(--dsw-alias-brand-primary, #067647));\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch:checked::after {\n transform: translateX(14px);\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch:disabled {\n opacity: 0.4;\n cursor: default;\n}\n${scope} 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${scope} button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-3));\n}\n${scope} button:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-3));\n}\n${scope} button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n/* A control that is present but should not read as a bordered button. */\n${scope} button.dsh-subscription-quiet {\n min-height: 22px;\n padding: 0 4px;\n border-color: transparent;\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n/* The free-text field for a hand-added model id. */\n${scope} input.dsh-subscription-input {\n box-sizing: border-box;\n flex: 1 1 auto;\n min-width: 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: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n}\n${scope} input.dsh-subscription-input::placeholder {\n color: var(--dsw-alias-label-tertiary);\n}\n${scope} input.dsh-subscription-input: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/* A drag handle: no border or fill, so it reads as a grip rather than a button. */\n${scope} button.dsh-subscription-handle {\n min-height: 18px;\n height: 18px;\n padding: 0 2px;\n border-color: transparent;\n border-radius: var(--dsw-radius-sm, 6px);\n background: transparent;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n font-size: 12px;\n line-height: 18px;\n cursor: grab;\n}\n${scope} button.dsh-subscription-handle:hover:not(:disabled) {\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n${scope} button.dsh-subscription-handle:active:not(:disabled) { cursor: grabbing; }\n/* Controls inside the manage dialog are one step larger, like a form footer. */\n${scope} .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${scope} 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${scope} button.dsh-subscription-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover, var(--dsw-alias-label-secondary));\n}\n${scope} button:focus-visible,\n${scope} input[type=\"checkbox\"]:focus-visible,\n${scope} .dsh-subscription-disclosure: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/* The catalog heading is a summary-style disclosure, not a bordered button. */\n${scope} .dsh-subscription-disclosure {\n border-color: transparent;\n border-radius: var(--dsw-radius-sm, 6px);\n background: transparent;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n${scope} .dsh-subscription-disclosure:hover:not(:disabled) {\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n/* A usage meter: the track, with the fill sized by the caller. */\n${scope} .dsh-subscription-meter {\n height: 6px;\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2));\n overflow: hidden;\n}\n${scope} .dsh-subscription-meter > span {\n display: block;\n height: 100%;\n background: var(--dsw-alias-state-success-primary, #067647);\n}\n${scope} .dsh-subscription-meter > span[data-exhausted=\"true\"] {\n background: var(--dsw-alias-state-error-primary, #b42318);\n}\n`\n","/**\n * Wire contract shared by the plugin's node half (the RPC routes) and its\n * browser half (the Settings page).\n *\n * Only this module crosses the boundary: the client bundle imports the types\n * and the channel name, and every call travels as one JSON envelope over a\n * `POST /api/<prefix><endpoint>` route. One status document describes every\n * provider route the plugin serves, so the page renders one card per entry.\n *\n * @module dsh-plugin-subscription-oauth/protocol\n */\n\n/** Prefix of every RPC method this plugin serves. */\nexport const RPC_PREFIX = 'subscription-oauth.'\n\n/** Endpoints the Settings page may call. */\nexport const RPC_ENDPOINTS = [\n 'status',\n 'login',\n 'cancel',\n 'logout',\n 'setDefault',\n 'refresh',\n 'discover',\n 'setModelVisible',\n 'setModelOrder',\n 'addModel',\n 'removeModel',\n 'usage',\n 'reload',\n] as const\n\n/** One endpoint name. */\nexport type RpcEndpoint = typeof RPC_ENDPOINTS[number]\n\n/** Client → host envelope. */\nexport interface RpcRequest {\n type: 'client-request'\n rpcId: string\n method: string\n payload: unknown\n}\n\n/** Host → client envelope, carrying either the value or the failure. */\nexport interface RpcResponse {\n type: 'server-response'\n rpcId: string\n result: RpcResult\n}\n\n/** Discriminated result inside {@link RpcResponse}. */\nexport type RpcResult =\n | { ok: true, value: unknown }\n | { ok: false, error: RpcError }\n\n/** Failure detail, with the provider-neutral code when one applies. */\nexport interface RpcError {\n code: string\n message: string\n /**\n * Carrier-owned structured detail. The Connection transport models a failure\n * as `{code, message, details}`, so an empty object travels here rather than\n * an absent field the client would have to repair.\n */\n details: Record<string, unknown>\n}\n\n/**\n * One provider-owned connection fact the manage dialog shows.\n *\n * The key is a stable identifier (`oauthHost`, `apiBase`, …) that the browser\n * half localizes; the host never sends user-facing prose.\n */\nexport interface DetailRow {\n key: string\n value: string\n}\n\n/** How the browser should present one pending login. */\nexport type LoginMode =\n /** Open the URL in a new tab; the redirect completes the login. */\n | 'open-url'\n /** Show the code (and a link) while the host polls the token endpoint. */\n | 'device-code'\n\n/** What the Settings page has to show to finish a login. */\nexport interface LoginPrompt {\n /** URL the user opens (or that was opened for them). */\n readonly url: string\n /** Code the user confirms in the browser; device flows only. */\n readonly userCode?: string\n /** Epoch milliseconds after which the attempt lapses. */\n readonly expiresAt: number\n readonly mode: LoginMode\n}\n\n/** One signed-in account as the page displays it. */\nexport interface AccountStatus {\n /** Account key the store is keyed by. */\n account: string\n /** Display label (email, user id, or the key's digest). */\n label: string\n /** Epoch milliseconds when the access token lapses. */\n expiresAt: number\n /** Whether the access token is already past its expiry. */\n expired: boolean\n /** Whether this account serves requests by default. */\n isDefault: boolean\n /**\n * Whether the provider refused this account's grant outright.\n *\n * A refresh answered with `invalid_grant` means the authorization is gone — the\n * stored token can never be renewed — so the page asks for a new sign-in rather\n * than reporting the account as connected.\n */\n needsLogin?: boolean\n}\n\n/** One selectable model, as the page lists it. */\nexport interface ModelSummary {\n id: string\n name: string\n description?: string\n contextWindow: number\n inputModalities?: readonly string[]\n defaultEffort?: string\n /** Whether the session model picker offers this model. */\n visible: boolean\n /**\n * Route that owns this model, when the listing spans routes.\n *\n * The \u0007uto provider mixes models from every route, so its rows name the\n * owning route; a single-route catalog leaves it out.\n */\n source?: string\n /** Whether the user added this id by hand, so it can be removed again. */\n userAdded?: boolean\n /**\n * Whether this entry is fixed at the head of the list.\n *\n * The synthetic `auto` entry follows the user's own order, so it cannot be\n * hidden or moved; the page renders it without those controls.\n */\n pinned?: boolean\n}\n\n/** One metered allowance of a subscription plan. */\nexport interface UsageWindow {\n /** What the window meters, e.g. `weekly`, `5h`, `credits`. */\n label: string\n /** How much of the allowance is spent, when the provider states it. */\n usedPercent?: number\n /** Amount already spent, when the provider states an absolute figure. */\n used?: number\n /** Total allowance, when the provider states one. */\n limit?: number\n /** Epoch milliseconds when the window resets, when the provider states it. */\n resetsAt?: number\n}\n\n/** One account's plan and metered allowances. */\nexport interface ProviderUsage {\n /** Account the figures belong to. */\n account: string\n /** Plan name or tier, when the provider states one. */\n plan?: string\n /** Whether the plan renews on a date the provider states. */\n renewsAt?: number\n /** Metered allowances, most relevant first. */\n windows: readonly UsageWindow[]\n /** Epoch milliseconds these figures were read. */\n fetchedAt: number\n /**\n * Whether these figures are the route's substitute rather than its own accounting.\n *\n * A substitute is shown when the primary source cannot answer, and it is never\n * reused as if it were a reading: the next request asks again.\n */\n substitute?: boolean\n}\n\n/** Result of reading one route's usage. */\nexport interface UsageResult {\n provider: string\n /** Usage per account the endpoint could answer for. */\n usage: readonly ProviderUsage[]\n /** Why an account's usage is missing, when the read failed. */\n error?: string\n status: SubscriptionStatus\n}\n\n/** The full state of one provider route. */\nexport interface ProviderStatus {\n /** Provider route key, e.g. `kimi`. */\n provider: string\n displayName: string\n /** Where a user manages the underlying subscription. */\n codeUrl?: string\n /** Whether at least one account is stored. */\n loggedIn: boolean\n /**\n * Whether this route signs in at all.\n *\n * \u0007uto has no account of its own — it delegates to routes that do — so the\n * page hides the connect and manage controls for it.\n */\n connectable?: boolean\n /** Whether a login attempt is being polled. */\n busy: boolean\n /** The pending attempt, when `busy`. */\n pending?: LoginPrompt\n accounts: AccountStatus[]\n /** Account key serving requests, when one does. */\n activeAccount?: string\n /** Absolute path of the credential file, for support requests. */\n credentialFile: string\n /** Whether the live model list is consulted. */\n discovery: boolean\n /** Live catalog ids, when discovery has succeeded this session. */\n discovered?: readonly string[]\n models: readonly ModelSummary[]\n /** Model the picker preselects. */\n defaultModel?: string\n /** Last usage figures read for this route, when they were requested. */\n usage?: readonly ProviderUsage[]\n /** Why the last usage read failed, when it did. */\n usageError?: string\n /** Provider-owned connection facts shown in the manage dialog. */\n details: readonly DetailRow[]\n /** Last background failure (a login that could not complete). */\n lastError?: string\n}\n\n/** Every provider route's state, in display order. */\nexport interface SubscriptionStatus {\n providers: ProviderStatus[]\n}\n\n/** Result of starting a login. */\nexport interface LoginStart {\n prompt: LoginPrompt\n status: SubscriptionStatus\n}\n\n/** Result of a token refresh. */\nexport interface RefreshResult {\n account: string\n expiresAt: number\n status: SubscriptionStatus\n}\n\n/** Payload fields naming one provider route and optionally one account. */\nexport interface AccountRequest {\n provider: string\n account?: string\n}\n\n/** Payload of `setDefault`. */\nexport interface SetDefaultRequest {\n provider: string\n account: string\n}\n\n/** Payload of `discover`. */\nexport interface DiscoverRequest {\n provider: string\n /** Ask the endpoint for its live model list even when one is cached. */\n force?: boolean\n}\n\n/** Payload of `setModelVisible`. */\nexport interface SetModelVisibleRequest {\n provider: string\n /** Model id as the catalog reports it. */\n id: string\n /** Whether the session model picker should offer it. */\n visible: boolean\n}\n\n/** Payload of `addModel` and `removeModel`. */\nexport interface ModelIdRequest {\n provider: string\n /** Model id as the endpoint accepts it. */\n id: string\n}\n\n/** Payload of `setModelOrder`. */\nexport interface SetModelOrderRequest {\n provider: string\n /** Every catalog model id, in the order the user arranged them. */\n ids: readonly string[]\n}\n\n/** Payload naming only a provider route. */\nexport interface ProviderRequest {\n provider: string\n}\n\n/** Map an endpoint to its payload and value types. */\nexport interface RpcMap {\n status: { payload: undefined, value: SubscriptionStatus }\n login: { payload: AccountRequest, value: LoginStart }\n cancel: { payload: ProviderRequest, value: SubscriptionStatus }\n logout: { payload: AccountRequest, value: SubscriptionStatus }\n setDefault: { payload: SetDefaultRequest, value: SubscriptionStatus }\n refresh: { payload: AccountRequest, value: RefreshResult }\n discover: { payload: DiscoverRequest, value: SubscriptionStatus }\n setModelVisible: { payload: SetModelVisibleRequest, value: SubscriptionStatus }\n setModelOrder: { payload: SetModelOrderRequest, value: SubscriptionStatus }\n addModel: { payload: ModelIdRequest, value: SubscriptionStatus }\n removeModel: { payload: ModelIdRequest, value: SubscriptionStatus }\n usage: { payload: DiscoverRequest, value: UsageResult }\n reload: { payload: undefined, value: SubscriptionStatus }\n}\n","/**\n * Browser caller for the plugin's own RPC channel.\n *\n * The node half mounts one exact `POST /api/subscription-oauth.<endpoint>` route\n * per endpoint, so every call travels on the shared `/api` channel with a\n * prefixed endpoint name — the same wire the rest of the shell uses.\n *\n * @module dsh-plugin-subscription-oauth/client/subscriptions-rpc\n */\n\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\n\nimport { RPC_PREFIX } from '../protocol.js'\nimport type { RpcEndpoint, RpcMap } from '../protocol.js'\n\n/** The shared channel the node half's routes are mounted on. */\nconst CHANNEL = '/api'\n\n/** A failed call: either the transport rejected or the endpoint answered `ok: false`. */\nexport class SubscriptionsRpcError extends Error {\n constructor(message: string, readonly code: string) {\n super(message)\n this.name = 'SubscriptionsRpcError'\n }\n}\n\n/** Human-readable message for any thrown value. */\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/** Call one endpoint, unwrapping the transport result. */\nexport type SubscriptionsCall = <K extends RpcEndpoint>(\n endpoint: K,\n payload: RpcMap[K]['payload'],\n) => Promise<RpcMap[K]['value']>\n\n/**\n * Bind a caller to one connection's RPC transport.\n * @param rpc - the browser connection's RPC caller.\n * @returns a typed caller for this plugin's endpoints.\n */\nexport function createSubscriptionsCall(rpc: ConnectionHandle['rpc']): SubscriptionsCall {\n return async function call(endpoint, payload) {\n let result: Awaited<ReturnType<ConnectionHandle['rpc']['call']>>\n try {\n result = await rpc.call(CHANNEL, `${RPC_PREFIX}${endpoint}`, payload)\n } catch (error: unknown) {\n throw new SubscriptionsRpcError(messageOf(error), 'RPC_TRANSPORT')\n }\n if (!result.ok) throw new SubscriptionsRpcError(result.error.message, result.error.code)\n return result.value as never\n }\n}\n","/**\n * Subscriptions settings page.\n *\n * One card per provider route — Kimi Code, Grok (X Premium), Google Antigravity\n * — describing that route's connection, accounts, and model catalog. Every fact\n * arrives from the node half's `subscription-oauth` RPC endpoints, so this\n * component holds no credential state of its own. The status poll runs only\n * while a login is pending, so an idle page performs no requests.\n *\n * Colors resolve through `--dsw-alias-*` design tokens, so the page follows the\n * active theme; every user-visible string goes through the locale-bound `t`.\n *\n * @module dsh-plugin-subscription-oauth/client/SubscriptionsSection\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { CSSProperties } from 'react'\n\nimport { en } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\nimport { subscriptionsCss } from './styles.js'\nimport { SubscriptionsRpcError } from './subscriptions-rpc.js'\nimport type { SubscriptionsCall } from './subscriptions-rpc.js'\nimport type {\n AccountStatus,\n DetailRow,\n LoginPrompt,\n ProviderStatus,\n ProviderUsage,\n SubscriptionStatus,\n UsageWindow,\n} from '../protocol.js'\n/** Poll cadence while a login attempt is pending. */\nconst POLL_INTERVAL_MS = 2000\n\n/**\n * How often an open page re-reads every signed-in route's allowance.\n *\n * Slow on purpose: it is fast enough that a figure shown on screen is current, and\n * slow enough that leaving the page open costs one small request a minute per\n * signed-in provider.\n */\nconst USAGE_POLL_INTERVAL_MS = 60_000\n\n/**\n * Disclosures start folded, every time the page is opened.\n *\n * Nothing is remembered between visits on purpose: the section is a list of\n * providers first, and a card left open last time should not decide what this\n * visit looks like. A fold is a gesture within one visit, not a stored setting.\n */\n\n/** Horizontal room the page takes inside the settings panel. */\nconst SECTION_WIDTH = 560\n\n/** What the node half injects into this section. */\nexport interface SubscriptionsSectionInjected {\n /** Typed caller for the plugin's RPC endpoints. */\n call: SubscriptionsCall\n /** Translate a key of this plugin's settings namespace. */\n t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string\n}\n\n/** Component props: the shell supplies `close`, the plugin supplies the rest. */\nexport type SubscriptionsSectionProps = Partial<SubscriptionsSectionInjected> & {\n /** Close the settings panel (owned by the settings shell). */\n close?: () => void\n}\n\n/** One card's transient message. */\ninterface CardMessage {\n tone: 'error' | 'success'\n text: string\n}\n\n/** Minimal translator used when the locale seat is absent (standalone render). */\nfunction fallbackTranslate(key: SubscriptionsKey, params?: Record<string, unknown>): string {\n const template: string = en[key]\n if (params === undefined) return template\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n name in params ? String(params[name]) : match)\n}\n\n/** Human-readable message for any thrown value. */\nfunction messageOf(error: unknown): string {\n if (error instanceof SubscriptionsRpcError) return error.message\n return error instanceof Error ? error.message : String(error)\n}\n\n/** Local time for one epoch-millisecond instant. */\nfunction formatTime(at: number): string {\n try {\n return new Date(at).toLocaleString()\n } catch {\n return String(at)\n }\n}\n\n/** How far ahead a reset is still stated as hours rather than a date. */\nconst RESET_RELATIVE_MS = 24 * 60 * 60 * 1000\n\n/**\n * One allowance reset, in the form a reader acts on.\n *\n * How far off it is decides how it is said: minutes inside the hour, hours inside\n * the day, and the date beyond that — \"137 小时后\" would be arithmetic rather than\n * information, and a window that comes back in forty minutes is better described in\n * minutes than as \"1 小时后\". Every route's windows go through here, so all of them\n * read the same way.\n *\n * @param at - epoch milliseconds the window resets.\n * @param t - translator, so the wording follows the page language.\n * @returns the reset text.\n */\nfunction formatReset(\n at: number,\n t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string,\n): string {\n const remaining = at - Date.now()\n if (remaining <= 0) return t('usageResetDue')\n if (remaining >= RESET_RELATIVE_MS) return t('usageReset', { time: formatTime(at) })\n // Rounded, and never below one: \"0 分钟后重置\" would read as a bug rather than as\n // \"any moment now\".\n if (remaining < 60 * 60 * 1000) {\n return t('usageResetsInMinutes', { minutes: Math.max(1, Math.round(remaining / 60_000)) })\n }\n return t('usageResetsInHours', { hours: Math.max(1, Math.round(remaining / 3_600_000)) })\n}\n\n/** Compact token count for a context window. */\nfunction formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${String(Math.round(tokens / 100_000) / 10)}M`\n if (tokens >= 1_000) return `${String(Math.round(tokens / 1_000))}K`\n return String(tokens)\n}\n\n/**\n * Routes worth asking for allowances.\n *\n * A route with no account of its own — `auto` — reports itself as signed in so its\n * card reads as usable, but it holds no allowance to read: asking it every minute\n * spends a request to be told nothing. The routes it stands in for are each read\n * on their own.\n *\n * @param providers - the routes in the current status.\n * @returns the route keys to read usage for.\n */\nfunction usageTargets(providers: readonly ProviderStatus[]): string[] {\n return providers\n .filter((provider) => provider.loggedIn && provider.connectable !== false)\n .map((provider) => provider.provider)\n}\n\nconst styles: Record<string, CSSProperties> = {\n section: {\n display: 'flex', flexDirection: 'column', gap: 12, maxWidth: SECTION_WIDTH,\n color: 'var(--dsw-alias-label-primary)',\n },\n intro: { margin: 0, color: 'var(--dsw-alias-label-tertiary)', fontSize: 14, lineHeight: '22px' },\n card: {\n border: '0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))',\n borderRadius: 'var(--dsw-radius-xl, 20px)',\n background: 'var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))',\n padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 6,\n },\n cardHeader: { display: 'flex', alignItems: 'center', gap: 8 },\n /** Everything a folded card hides. */\n cardBody: { display: 'flex', flexDirection: 'column', gap: 6 },\n /** The one-line state a folded card shows in place of its body. */\n cardSummary: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n dot: { width: 8, height: 8, borderRadius: '50%', flexShrink: 0 },\n name: { fontWeight: 500, fontSize: 14, lineHeight: '22px', color: 'var(--dsw-alias-label-primary)' },\n providerId: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-dimmed)' },\n statusLine: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n errorLine: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-error-primary)' },\n successLine: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-success-primary)' },\n actions: { display: 'flex', gap: 8, marginTop: 4, alignItems: 'center', flexWrap: 'wrap' },\n accountRow: {\n display: 'flex', flexDirection: 'column', gap: 6,\n border: '0.5px solid var(--dsw-alias-border-l2)', borderRadius: 'var(--dsw-radius-lg, 16px)',\n padding: '8px 10px', marginTop: 4,\n },\n accountHeader: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' },\n starButton: {\n border: 'none', padding: 0, width: 20, background: 'transparent',\n font: 'inherit', fontSize: 14, lineHeight: '20px', cursor: 'pointer',\n color: 'var(--dsw-alias-state-warn-label)',\n },\n accountName: { fontSize: 13, lineHeight: '20px', color: 'var(--dsw-alias-label-primary)', userSelect: 'all' },\n badge: {\n fontSize: 11, lineHeight: '16px', padding: '0 6px', borderRadius: 8,\n background: 'var(--dsw-alias-bg-layer-1)', border: '0.5px solid var(--dsw-alias-border-l2)',\n color: 'var(--dsw-alias-label-secondary)',\n },\n pushRight: { marginLeft: 'auto', flexShrink: 0 },\n catalog: {\n display: 'flex', flexDirection: 'column', gap: 6, marginTop: 4,\n borderTop: '0.5px solid var(--dsw-alias-border-l2)', paddingTop: 8,\n },\n catalogHeader: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' },\n catalogTitle: { fontSize: 12, lineHeight: '18px', fontWeight: 500, color: 'var(--dsw-alias-label-secondary)' },\n catalogMeta: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n /**\n * Button surface geometry lives in the scoped stylesheet; only the layout a\n * rule cannot express stays inline.\n */\n pill: {},\n pillSmall: {},\n /** The catalog heading: a summary-style disclosure, not a bordered control. */\n disclosure: {\n display: 'inline-flex', alignItems: 'center', gap: 4, margin: 0,\n },\n chevron: { fontSize: 10, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n modelList: { display: 'flex', flexDirection: 'column', gap: 6, marginTop: 2 },\n /** One model line: a visibility toggle and the model's own metadata. */\n modelRowGrow: { display: 'flex', alignItems: 'flex-start', gap: 8, flex: '1 1 auto', minWidth: 0 },\n /** The pinned `auto` line: listed, switchable, and never part of its own chain. */\n autoRow: {\n display: 'flex', alignItems: 'flex-start', gap: 8, cursor: 'pointer',\n fontSize: 13, lineHeight: '20px', color: 'var(--dsw-alias-label-primary)',\n },\n /** The models `auto` will walk, indented under it. */\n chain: {\n display: 'flex', flexDirection: 'column', gap: 3,\n margin: '2px 0 4px 26px', paddingLeft: 8,\n borderLeft: '0.5px solid var(--dsw-alias-border-l2)',\n },\n chainTitle: { fontSize: 11, lineHeight: '16px', color: 'var(--dsw-alias-label-tertiary)' },\n /** The add-a-model-id row: the field, then confirm and cancel. */\n addRow: { display: 'flex', alignItems: 'center', gap: 6, marginTop: 2 },\n addInput: {},\n /** The remove control on a hand-added row: a bare glyph beside the row. */\n removeButton: { flexShrink: 0, alignSelf: 'center', padding: '0 6px' },\n /** One draggable chain row: the grip, then the remove-from-auto switch. */\n chainRowWrap: { display: 'flex', alignItems: 'center', gap: 4 },\n chainRow: {\n display: 'flex', alignItems: 'center', gap: 6, cursor: 'pointer', flex: '1 1 auto',\n fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-secondary)',\n },\n usage: {\n display: 'flex', flexDirection: 'column', gap: 6, marginTop: 4,\n borderTop: '0.5px solid var(--dsw-alias-border-l2)', paddingTop: 8,\n },\n usageHeader: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' },\n usageRow: { display: 'flex', flexDirection: 'column', gap: 3 },\n usageLine: { display: 'flex', alignItems: 'baseline', gap: 8, justifyContent: 'space-between' },\n usageMeter: {\n height: 6, borderRadius: 999, background: 'var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2))',\n overflow: 'hidden',\n },\n modelRow: {\n display: 'flex', alignItems: 'flex-start', gap: 8,\n cursor: 'pointer', fontSize: 13, lineHeight: '20px',\n color: 'var(--dsw-alias-label-primary)',\n },\n /** A hidden model stays listed and editable, but reads as inactive. */\n modelRowHidden: {\n display: 'flex', alignItems: 'flex-start', gap: 8,\n cursor: 'pointer', fontSize: 13, lineHeight: '20px',\n color: 'var(--dsw-alias-label-dimmed)',\n },\n modelBody: { display: 'flex', flexDirection: 'column', gap: 1, minWidth: 0 },\n modelName: { fontSize: 13, lineHeight: '20px' },\n modelMeta: { fontSize: 11, lineHeight: '16px', color: 'var(--dsw-alias-label-tertiary)', userSelect: 'all' },\n device: {\n marginTop: 4, display: 'flex', flexDirection: 'column', gap: 6,\n border: '0.5px solid var(--dsw-alias-border-l2)', borderRadius: 'var(--dsw-radius-lg, 16px)',\n padding: '10px 12px', background: 'var(--dsw-alias-bg-layer-1)',\n },\n deviceTitle: { fontWeight: 500, fontSize: 13, lineHeight: '20px', color: 'var(--dsw-alias-label-primary)' },\n deviceCode: {\n fontFamily: 'monospace', fontSize: 18, lineHeight: '24px', letterSpacing: 2,\n color: 'var(--dsw-alias-label-primary)', userSelect: 'all',\n },\n details: {\n display: 'flex', flexDirection: 'column', gap: 4,\n fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)',\n },\n detailRow: { display: 'flex', gap: 8, justifyContent: 'space-between', alignItems: 'baseline' },\n detailValue: { userSelect: 'all', overflowWrap: 'anywhere', textAlign: 'right' },\n /** Dialog layout only: its surface comes from `.dsh-subscription-manager`. */\n modal: {\n width: 440, maxWidth: '100%', maxHeight: '85vh', overflowY: 'auto',\n boxSizing: 'border-box', display: 'flex', flexDirection: 'column', gap: 10,\n padding: '16px 18px', margin: 'auto',\n },\n modalHeader: { display: 'flex', alignItems: 'center', gap: 8 },\n modalTitle: { fontWeight: 500, fontSize: 16, lineHeight: '24px', color: 'var(--dsw-alias-label-primary)' },\n modalActions: { display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 2 },\n divider: { borderTop: '0.5px solid var(--dsw-alias-border-l2)' },\n}\n\n/** Status dot color for one provider's connection state. */\nfunction dotColor(status: ProviderStatus): string {\n if (status.busy) return 'var(--dsw-alias-state-warn-label)'\n if (status.loggedIn) return 'var(--dsw-alias-state-success-primary)'\n return 'var(--dsw-alias-label-dimmed)'\n}\n\n/** Localized label for one provider-owned detail row. */\nfunction detailLabel(t: SubscriptionsSectionInjected['t'], row: DetailRow): string {\n const key = `detail_${row.key}` as SubscriptionsKey\n return key in en ? t(key) : row.key\n}\n\n/** Localized label for one metered window the provider states. */\nfunction windowLabel(t: SubscriptionsSectionInjected['t'], window: UsageWindow): string {\n const key = `usage_${window.label}` as SubscriptionsKey\n return key in en ? t(key) : window.label\n}\n\n/** How much of one window is spent, as a display string. */\nfunction windowAmount(window: UsageWindow): string {\n if (window.usedPercent !== undefined) return `${String(Math.round(window.usedPercent))}%`\n if (window.used !== undefined && window.limit !== undefined) return `${String(window.used)}/${String(window.limit)}`\n return '—'\n}\n\n/** One account's plan and metered allowances. */\nfunction UsageBlock(props: {\n usage: readonly ProviderUsage[]\n error?: string\n t: SubscriptionsSectionInjected['t']\n busyAction: boolean\n onRefresh(): void\n}) {\n const { usage, error, t, busyAction, onRefresh } = props\n return (\n <div style={styles.usage}>\n <div style={styles.usageHeader}>\n <span style={styles.catalogTitle}>{t('usageTitle')}</span>\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n disabled={busyAction}\n onClick={onRefresh}\n >\n {busyAction ? t('refreshing') : t('usageRefresh')}\n </button>\n </div>\n {error !== undefined && <p className=\"dsh-subscription-error\">{t('usageError', { message: error })}</p>}\n {usage.length === 0 && error === undefined && <p style={styles.statusLine}>{t('usageNone')}</p>}\n {usage.map((entry) => (\n <div key={entry.account} style={styles.usageRow}>\n <div style={styles.usageLine}>\n <span style={styles.modelMeta}>\n {entry.plan === undefined ? entry.account : t('usagePlan', { plan: entry.plan })}\n {entry.renewsAt === undefined ? '' : ` · ${t('usageRenews', { time: formatTime(entry.renewsAt) })}`}\n </span>\n <span style={styles.modelMeta}>{t('usageFetched', { time: formatTime(entry.fetchedAt) })}</span>\n </div>\n {entry.windows.map((window) => (\n <div key={`${entry.account}-${window.label}`} style={styles.usageRow}>\n <div style={styles.usageLine}>\n <span style={styles.modelName}>\n {windowLabel(t, window)}\n {' · '}\n {windowAmount(window)}\n </span>\n <span style={styles.modelMeta}>\n {window.resetsAt === undefined ? '' : formatReset(window.resetsAt, t)}\n </span>\n </div>\n {window.usedPercent !== undefined && (\n <div className=\"dsh-subscription-meter\">\n <span\n style={{ width: `${String(Math.min(100, Math.max(0, window.usedPercent)))}%` }}\n data-exhausted={window.usedPercent >= 90 ? 'true' : 'false'}\n />\n </div>\n )}\n </div>\n ))}\n </div>\n ))}\n </div>\n )\n}\n\n/** The pending-login block: a device code, or a link to the sign-in page. */\nfunction PendingLogin(props: {\n prompt: LoginPrompt\n t: SubscriptionsSectionInjected['t']\n copied: boolean\n onCopy(code: string): void\n}) {\n const { prompt, t, copied, onCopy } = props\n return (\n <div style={styles.device}>\n <span style={styles.deviceTitle}>\n {prompt.mode === 'device-code' ? t('deviceTitle') : t('openLogin')}\n </span>\n <span style={styles.statusLine}>\n {prompt.mode === 'device-code' ? t('devicePrompt') : t('openLoginHint')}\n </span>\n {prompt.userCode !== undefined && <span style={styles.deviceCode}>{prompt.userCode}</span>}\n <span style={styles.statusLine}>{t('deviceExpires', { time: formatTime(prompt.expiresAt) })}</span>\n <div style={styles.actions}>\n <button\n type=\"button\"\n \n onClick={() => { window.open(prompt.url, '_blank', 'noopener') }}\n >\n {prompt.mode === 'device-code' ? t('deviceOpen') : t('openLogin')}\n </button>\n {prompt.userCode !== undefined && (\n <button type=\"button\" onClick={() => { onCopy(prompt.userCode as string) }}>\n {copied ? t('deviceCopied') : t('deviceCopy')}\n </button>\n )}\n </div>\n </div>\n )\n}\n\n/** One provider's card. */\nfunction ProviderCard(props: {\n status: ProviderStatus\n t: SubscriptionsSectionInjected['t']\n busyAction: boolean\n message?: CardMessage\n onLogin(): void\n onCancel(): void\n onLogout(account: string): void\n onSetDefault(account: string): void\n onRefreshToken(account: string): void\n onRefreshModels(): void\n onSetModelVisible(id: string, visible: boolean): void\n /** Persist the chain order the user dropped into place. */\n onSetModelOrder(ids: readonly string[]): void\n /** Publish a model id the catalog does not know yet. */\n onAddModel(id: string): void\n /** Forget a hand-added model id. */\n onRemoveModel(id: string): void\n onRefreshUsage(): void\n onReload(): void\n}) {\n const { status, t, busyAction, message } = props\n const [copied, setCopied] = useState(false)\n // Both disclosures open folded, on every visit: the choice is a gesture, not a\n // stored setting. See the note beside the interval constants.\n const [modelsOpen, setModelsOpen] = useState(false)\n /** Whether this provider's whole card is unfolded. */\n const [cardOpen, setCardOpen] = useState(false)\n const [manageOpen, setManageOpen] = useState(false)\n const mounted = useRef(true)\n const dialog = useRef<HTMLDialogElement>(null)\n\n useEffect(() => {\n mounted.current = true\n return () => { mounted.current = false }\n }, [])\n\n // The dialog is a native modal, so the browser owns focus trapping and Esc.\n useEffect(() => {\n const element = dialog.current\n if (element === null || typeof element.showModal !== 'function') return\n if (manageOpen && !element.open) element.showModal()\n if (!manageOpen && element.open) element.close()\n }, [manageOpen])\n\n const copyCode = useCallback(async (code: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(code)\n if (mounted.current) {\n setCopied(true)\n setTimeout(() => { if (mounted.current) setCopied(false) }, 2000)\n }\n } catch {\n // A clipboard refusal is not worth an error banner: the code is on screen\n // and selectable, which is the fallback the user already has.\n }\n }, [])\n\n const toggleModelsOpen = useCallback((): void => {\n setModelsOpen((open) => !open)\n }, [])\n\n /** Fold or unfold this provider's card. */\n const toggleCardOpen = useCallback((): void => {\n setCardOpen((open) => !open)\n }, [])\n\n const accounts: readonly AccountStatus[] = status.accounts\n const models = status.models\n /** Whether this route signs in at all; the auto provider does not. */\n const connectable = status.connectable !== false\n const hiddenCount = models.filter((model) => !model.visible).length\n /** Whether the add-a-model-id field is open, and what has been typed. */\n const [adding, setAdding] = useState(false)\n const [draft, setDraft] = useState('')\n /** The row being dragged, so it can be dimmed while it moves. */\n const [dragFrom, setDragFrom] = useState<number | undefined>(undefined)\n /**\n * The dragged row, mirrored in a ref.\n *\n * The drop is handled by an ancestor whose handler was attached in an earlier\n * render, so it must not depend on state that was set during the drag.\n */\n const dragFromRef = useRef<number | undefined>(undefined)\n /** The row the pointer is currently over, so a drop lands where the user aims. */\n const dropTargetRef = useRef<number | undefined>(undefined)\n /** The same row in state, purely so it can be highlighted while dragging. */\n const [dropTarget, setDropTarget] = useState<number | undefined>(undefined)\n\n /**\n * Commit one dropped arrangement.\n *\n * The node half takes the full chain in its new order and appends whatever the\n * page left out, so sending just these ids is enough — and a model hidden in\n * another window is never dropped from the stored rank by a stale page.\n */\n const commitOrder = useCallback((ids: readonly string[]): void => {\n props.onSetModelOrder(ids)\n }, [props])\n\n /** Drag-and-drop plus its keyboard equivalent on the drag handle. */\n const drag = {\n start: (event: React.DragEvent, index: number): void => {\n setDragFrom(index)\n dragFromRef.current = index\n event.dataTransfer.effectAllowed = 'move'\n // Firefox refuses to start a drag without payload.\n event.dataTransfer.setData('text/plain', String(index))\n },\n over: (event: React.DragEvent, _index: number): void => {\n // A drop is only possible on a target that cancels the default.\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n const container = event.currentTarget as HTMLElement\n const to = indexAt(container, event.clientY)\n dropTargetRef.current = to\n if (to !== undefined && to !== dropTarget) setDropTarget(to)\n },\n drop: (event: React.DragEvent, index: number): void => {\n event.preventDefault()\n // The target comes from the last `dragover`, not from this event's own\n // coordinates: `drop` is not guaranteed to carry the pointer position, and a\n // zero there silently collapsed every drop onto the first row.\n const to = dropTargetRef.current ?? indexAt(event.currentTarget as HTMLElement, event.clientY) ?? index\n move(dragFromRef.current, to)\n dragFromRef.current = undefined\n dropTargetRef.current = undefined\n setDropTarget(undefined)\n setDragFrom(undefined)\n },\n /** A drop anywhere in the list lands on the row under the pointer. */\n dropAt: (event: React.DragEvent): void => {\n event.preventDefault()\n const container = event.currentTarget as HTMLElement\n const to = dropTargetRef.current ?? indexAt(container, event.clientY)\n if (to !== undefined) move(dragFromRef.current, to)\n dragFromRef.current = undefined\n dropTargetRef.current = undefined\n setDropTarget(undefined)\n setDragFrom(undefined)\n },\n end: (): void => {\n dragFromRef.current = undefined\n dropTargetRef.current = undefined\n setDropTarget(undefined)\n setDragFrom(undefined)\n },\n key: (event: React.KeyboardEvent, index: number): void => {\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n move(index, index + (event.key === 'ArrowUp' ? -1 : 1))\n },\n }\n\n /** Move one model row to another position and persist the result. */\n function move(from: number | undefined, to: number): void {\n if (from === undefined || from === to) return\n if (from < 0 || to < 0 || from >= models.length || to >= models.length) return\n const ids = models.map((model) => model.id)\n const [moved] = ids.splice(from, 1)\n if (moved === undefined) return\n ids.splice(to, 0, moved)\n commitOrder(ids)\n }\n\n /**\n * The row index a drop at this pointer position lands on.\n *\n * The drop is handled on the whole list rather than per row: rows are tall and\n * separated by gaps, so a drop between two of them hits no target at all and\n * silently does nothing. Comparing the pointer against each row's midpoint also\n * makes the gesture match what the user sees.\n */\n function indexAt(container: HTMLElement, clientY: number): number | undefined {\n const rows = Array.from(container.querySelectorAll<HTMLElement>('[data-model-index]'))\n if (rows.length === 0) return undefined\n let closest = 0\n let best = Number.POSITIVE_INFINITY\n for (const row of rows) {\n const box = row.getBoundingClientRect()\n const distance = Math.abs(clientY - (box.top + box.height / 2))\n if (distance >= best) continue\n best = distance\n closest = Number(row.dataset.modelIndex)\n }\n return closest\n }\n const busy = status.busy\n const liveCatalog = (status.discovered?.length ?? 0) > 0\n /**\n * What a folded card says about itself.\n *\n * The connection is the reason to open a card, so the folded row carries it;\n * `auto` has no account and counts the models it will actually try instead.\n */\n const summaryLine = !connectable\n ? t('statusAuto', { count: models.filter((model) => model.visible).length })\n : busy\n ? t('statusBusy')\n : status.loggedIn\n ? t('statusConnected', { count: accounts.length })\n : t('statusSignedOut')\n\n return (\n <div style={styles.card}>\n {/*\n The header is the disclosure: folded, the page is a list of providers, and\n the whole card is one row with its state and an edit affordance. The\n status dot stays visible either way, so a folded card still reports\n whether the route is signed in.\n */}\n <div style={styles.cardHeader}>\n <span style={{ ...styles.dot, background: dotColor(status) }} aria-hidden=\"true\" />\n <span style={styles.name}>{status.displayName}</span>\n <span style={styles.providerId}>{status.provider}</span>\n {!cardOpen && <span style={styles.cardSummary}>{summaryLine}</span>}\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n aria-expanded={cardOpen}\n aria-controls={`dsh-subscription-card-${status.provider}`}\n onClick={toggleCardOpen}\n >\n {cardOpen ? t('collapse') : t('edit')}\n </button>\n </div>\n <div\n id={`dsh-subscription-card-${status.provider}`}\n style={cardOpen ? styles.cardBody : { ...styles.cardBody, display: 'none' }}\n >\n <p style={styles.statusLine}>\n {!connectable\n // `auto` has no account: it stands in for the models the other routes\n // signed in for, so it counts the candidates instead.\n ? t('statusAuto', { count: models.filter((model) => model.visible).length })\n : busy\n ? t('statusBusy')\n : status.loggedIn\n ? t('statusConnected', { count: accounts.length })\n : t('statusSignedOut')}\n </p>\n {connectable && !status.loggedIn && !busy && <p style={styles.statusLine}>{t('statusSignIn')}</p>}\n {status.lastError !== undefined && (\n <p className=\"dsh-subscription-error\">{t('lastError', { message: status.lastError })}</p>\n )}\n {message?.tone === 'error' && <p className=\"dsh-subscription-error\">{message.text}</p>}\n {message?.tone === 'success' && <p className=\"dsh-subscription-success\">{message.text}</p>}\n\n {accounts.map((account) => (\n <div key={account.account} style={styles.accountRow}>\n <div style={styles.accountHeader}>\n <button\n type=\"button\"\n style={styles.starButton}\n title={account.isDefault ? t('defaultBadge') : t('makeDefault')}\n aria-label={account.isDefault ? t('defaultBadge') : t('makeDefault')}\n disabled={busyAction || account.isDefault}\n onClick={() => { props.onSetDefault(account.account) }}\n >\n {account.isDefault ? '★' : '☆'}\n </button>\n <span style={styles.accountName}>{account.label}</span>\n {account.isDefault && <span style={styles.badge}>{t('defaultBadge')}</span>}\n {/* The provider refused this grant: only a new sign-in helps. */}\n {account.needsLogin === true && (\n <span style={styles.badge} title={t('accountNeedsLoginHint')}>{t('accountNeedsLogin')}</span>\n )}\n <span style={styles.statusLine}>\n {account.expired\n ? t('accountExpired')\n : t('accountExpires', { time: formatTime(account.expiresAt) })}\n </span>\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n disabled={busyAction}\n onClick={() => { props.onLogout(account.account) }}\n >\n {t('logout')}\n </button>\n </div>\n </div>\n ))}\n\n {/* A signed-out route has nothing to configure here, and listing models it\n cannot call would only invite picker entries that fail. */}\n {status.loggedIn && (\n <div style={styles.catalog}>\n <div style={styles.catalogHeader}>\n <button\n type=\"button\"\n className=\"dsh-subscription-disclosure\"\n style={styles.disclosure}\n aria-expanded={modelsOpen}\n aria-controls={`dsh-subscription-models-${status.provider}`}\n onClick={toggleModelsOpen}\n >\n <span style={styles.chevron} aria-hidden=\"true\">{modelsOpen ? '▾' : '▸'}</span>\n <span style={styles.catalogTitle}>{t('modelsTitle')}</span>\n </button>\n <span style={styles.catalogMeta}>\n {t('modelsCount', { count: models.length })}\n {' · '}\n {liveCatalog ? t('modelsLive') : t('modelsBuiltIn')}\n {hiddenCount === 0 ? '' : ` ${t('modelsHiddenCount', { count: hiddenCount })}`}\n </span>\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n disabled={busyAction}\n onClick={props.onRefreshModels}\n >\n {busyAction ? t('refreshing') : t('refresh')}\n </button>\n {/* A model the endpoint serves but this build has never heard of: the\n id is published as a plain route, so a new release is usable at once. */}\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n disabled={busyAction || !connectable}\n title={t('modelsAddHint')}\n onClick={() => { setAdding((open) => !open) }}\n >\n {t('modelsAdd')}\n </button>\n </div>\n {adding && (\n <form\n style={styles.addRow}\n onSubmit={(event) => {\n event.preventDefault()\n const id = draft.trim()\n if (id.length === 0) return\n props.onAddModel(id)\n setDraft('')\n setAdding(false)\n }}\n >\n <input\n type=\"text\"\n className=\"dsh-subscription-input\"\n style={styles.addInput}\n value={draft}\n autoFocus\n spellCheck={false}\n placeholder={t('modelsAddPlaceholder')}\n aria-label={t('modelsAdd')}\n disabled={busyAction}\n onChange={(event) => { setDraft(event.target.value) }}\n />\n <button type=\"submit\" disabled={busyAction || draft.trim().length === 0}>{t('modelsAddConfirm')}</button>\n <button type=\"button\" className=\"dsh-subscription-quiet\" onClick={() => { setAdding(false); setDraft('') }}>\n {t('cancel')}\n </button>\n </form>\n )}\n {modelsOpen && (\n <div\n id={`dsh-subscription-models-${status.provider}`}\n style={styles.modelList}\n // The whole list is the drop target, so a release between two rows still\n // lands somewhere instead of being cancelled unnoticed.\n onDragOver={(event) => { drag.over(event, 0) }}\n onDrop={drag.dropAt}\n >\n {status.provider === 'auto' && <span style={styles.chainTitle}>{t('modelsAutoChain')}</span>}\n {/* Every provider lists its models the same way: a switch in front,\n the model's own metadata, and a grip to drag it in the order both\n the picker list and Auto's fallback follow. */}\n {models.map((model, index) => (\n <div\n key={model.id}\n data-model-index={index}\n draggable={!busyAction}\n style={{\n ...styles.modelRowWrap,\n ...dragFrom === index ? { opacity: 0.5 } : {},\n // The row a drop would land on, so the gesture is visible while it\n // happens rather than only in its result.\n ...dropTarget === index && dragFrom !== undefined && dragFrom !== index\n ? { boxShadow: 'inset 0 2px 0 0 var(--dsw-alias-brand-primary)' }\n : {},\n }}\n onDragStart={(event) => { drag.start(event, index) }}\n onDragEnd={drag.end}\n >\n {/* The grip is the affordance and the keyboard path; the drag\n itself starts on the row, because a <button> does not start an\n HTML5 drag reliably in Chromium. */}\n <button\n type=\"button\"\n className=\"dsh-subscription-handle\"\n disabled={busyAction}\n title={t('modelsDrag')}\n aria-label={`${t('modelsDrag')} · ${model.name}`}\n onKeyDown={(event) => { drag.key(event, index) }}\n >\n ⠿\n </button>\n <label\n style={model.visible\n ? { ...styles.modelRowGrow, cursor: 'pointer' }\n : { ...styles.modelRowGrow, cursor: 'pointer', color: 'var(--dsw-alias-label-dimmed)' }}\n title={model.visible ? t('modelsHidden') : t('modelsShow')}\n >\n <input\n type=\"checkbox\"\n className=\"dsh-subscription-switch\"\n role=\"switch\"\n checked={model.visible}\n disabled={busyAction}\n aria-label={`${t('modelsShow')} · ${model.name}`}\n onChange={(event) => { props.onSetModelVisible(model.id, event.target.checked) }}\n />\n <span style={styles.modelBody}>\n <span style={styles.modelName}>\n {model.name}\n {model.source === undefined ? null : <span style={styles.badge}>{model.source}</span>}\n </span>\n <span style={styles.modelMeta}>\n {model.id}\n {' · '}\n {t('modelsContext', { tokens: formatTokens(model.contextWindow) })}\n {model.defaultEffort === undefined ? '' : ` · ${model.defaultEffort}`}\n {model.inputModalities === undefined || model.inputModalities.length === 0\n ? ''\n : ` · ${model.inputModalities.join('/')}`}\n </span>\n </span>\n </label>\n {/* A hand-added id can be removed again, so a typo does not linger. */}\n {model.userAdded === true && (\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.removeButton}\n disabled={busyAction}\n title={t('modelsRemove')}\n aria-label={`${t('modelsRemove')} · ${model.name}`}\n onClick={() => { props.onRemoveModel(model.id) }}\n >\n ×\n </button>\n )}\n </div>\n ))}\n {models.length === 0 && (\n <p style={styles.statusLine}>\n {status.provider === 'auto' ? t('modelsAutoChainEmpty') : t('modelsEmpty')}\n </p>\n )}\n </div>\n )}\n </div>\n )}\n\n <UsageBlock\n usage={status.usage ?? []}\n {...status.usageError === undefined ? {} : { error: status.usageError }}\n t={t}\n busyAction={busyAction}\n onRefresh={props.onRefreshUsage}\n />\n\n {/* `auto` owns no account, so it offers no connect, cancel or manage. */}\n {connectable && (\n <div style={styles.actions}>\n {!busy && (\n <button type=\"button\" disabled={busyAction} onClick={props.onLogin}>\n {accounts.length === 0 ? t('connect') : t('addAccount')}\n </button>\n )}\n {!busy && (\n <button type=\"button\" disabled={busyAction} onClick={() => { setManageOpen(true) }}>\n {t('manage')}\n </button>\n )}\n {busy && (\n <button type=\"button\" disabled={busyAction} onClick={props.onCancel}>\n {t('cancel')}\n </button>\n )}\n </div>\n )}\n {connectable && accounts.length > 0 && <p style={styles.statusLine}>{t('hint')}</p>}\n\n {busy && status.pending !== undefined && (\n <PendingLogin prompt={status.pending} t={t} copied={copied} onCopy={(code) => { void copyCode(code) }} />\n )}\n </div>\n {/* The dialog stays outside the collapsible body: a hidden ancestor would\n keep it out of the top layer even after `showModal()`. */}\n <dialog\n ref={dialog}\n className=\"dsh-subscription-manager\"\n aria-labelledby={`dsh-subscription-manage-${status.provider}`}\n // A closed `<dialog>` is hidden by the user-agent stylesheet, and an\n // inline `display` would override that rule — so the open state has to\n // be restated here rather than left to `showModal()` alone.\n style={manageOpen ? styles.modal : { ...styles.modal, display: 'none' }}\n onClose={() => { setManageOpen(false) }}\n onCancel={() => { setManageOpen(false) }}\n >\n <div style={styles.modalHeader}>\n <span style={styles.modalTitle} id={`dsh-subscription-manage-${status.provider}`}>\n {t('manageTitle', { provider: status.displayName })}\n </span>\n </div>\n\n <span style={styles.statusLine}>{t('manageAccounts')}</span>\n {accounts.map((account) => (\n <div key={account.account} style={styles.accountRow}>\n <div style={styles.accountHeader}>\n <span style={styles.accountName}>{account.label}</span>\n {account.isDefault && <span style={styles.badge}>{t('defaultBadge')}</span>}\n </div>\n <div style={styles.actions}>\n <button\n type=\"button\"\n \n disabled={busyAction}\n onClick={() => { props.onRefreshToken(account.account) }}\n >\n {t('refreshToken')}\n </button>\n {!account.isDefault && (\n <button\n type=\"button\"\n \n disabled={busyAction}\n onClick={() => { props.onSetDefault(account.account) }}\n >\n {t('makeDefault')}\n </button>\n )}\n <button\n type=\"button\"\n \n disabled={busyAction}\n onClick={() => { props.onLogout(account.account) }}\n >\n {t('logout')}\n </button>\n </div>\n </div>\n ))}\n {accounts.length === 0 && <p style={styles.statusLine}>{t('statusSignedOut')}</p>}\n\n <div style={styles.divider} />\n <div style={styles.actions}>\n <button type=\"button\" disabled={busyAction} onClick={props.onReload}>\n {t('reload')}\n </button>\n </div>\n <p style={styles.statusLine}>{t('reloadHint')}</p>\n\n <div style={styles.divider} />\n <div style={styles.details}>\n {status.details.map((row) => (\n <div key={row.key} style={styles.detailRow}>\n <span>{detailLabel(t, row)}</span>\n <span style={styles.detailValue}>{row.value}</span>\n </div>\n ))}\n {status.discovered !== undefined && status.discovered.length > 0 && (\n <div style={styles.detailRow}>\n <span>{t('modelsLive')}</span>\n <span style={styles.detailValue}>{status.discovered.join(', ')}</span>\n </div>\n )}\n </div>\n\n <div className=\"dsh-subscription-dialog-actions\" style={styles.modalActions}>\n <button type=\"button\" onClick={() => { setManageOpen(false) }}>{t('close')}</button>\n </div>\n </dialog>\n </div>\n )\n}\n\n/**\n * The Subscriptions settings section.\n * @param props - section props (inject face plus the shell's `close`).\n * @returns the section content.\n */\nexport function SubscriptionsSection(props: SubscriptionsSectionProps) {\n const { call } = props\n const t = props.t ?? fallbackTranslate\n const [status, setStatus] = useState<SubscriptionStatus | undefined>(undefined)\n const [error, setError] = useState<string | undefined>(undefined)\n const [messages, setMessages] = useState<Record<string, CardMessage>>({})\n const [busyAction, setBusyAction] = useState(false)\n const mounted = useRef(true)\n const timer = useRef<ReturnType<typeof setInterval> | undefined>(undefined)\n\n /** Fetch the current state; a failure is shown rather than swallowed. */\n const refresh = useCallback(async (): Promise<void> => {\n if (call === undefined) return\n try {\n const next = await call('status', undefined)\n if (!mounted.current) return\n setStatus(next)\n setError(undefined)\n } catch (caught: unknown) {\n if (mounted.current) setError(t('actionFailed', { message: messageOf(caught) }))\n }\n }, [call, t])\n\n const stopPolling = useCallback((): void => {\n if (timer.current !== undefined) {\n clearInterval(timer.current)\n timer.current = undefined\n }\n }, [])\n\n const startPolling = useCallback((): void => {\n if (timer.current !== undefined) return\n // The node half clears `busy` once the attempt settles; the effect below\n // observes that and stops this interval.\n timer.current = setInterval(() => { void refresh() }, POLL_INTERVAL_MS)\n }, [refresh])\n\n useEffect(() => {\n mounted.current = true\n void refresh()\n return () => {\n mounted.current = false\n stopPolling()\n }\n }, [refresh, stopPolling])\n\n /** Every route worth reading, as of the latest render, for the usage poll. */\n const signedInRef = useRef<readonly string[]>([])\n useEffect(() => {\n signedInRef.current = usageTargets(status?.providers ?? [])\n })\n\n /**\n * Read each named route's plan and allowance, applying every answer.\n *\n * A read is not forced: the node half reuses a figure only for a few seconds and\n * never reuses a substitute, so a steady interval refreshes the figures while\n * collapsing bursts into one request per route.\n */\n const readUsage = useCallback(async (providers: readonly string[]): Promise<void> => {\n if (call === undefined) return\n for (const provider of providers) {\n try {\n const result = await call('usage', { provider })\n if (!mounted.current) return\n setStatus(result.status)\n } catch {\n // An unreadable quota is already surfaced inside the card by the status it\n // carries; the page itself stays usable.\n }\n }\n }, [call])\n\n // The figures are read as soon as the first status lands...\n const usageRequested = useRef(false)\n useEffect(() => {\n if (call === undefined || status === undefined || usageRequested.current) return\n const signedIn = usageTargets(status.providers)\n if (signedIn.length === 0) return\n usageRequested.current = true\n void readUsage(signedIn)\n }, [call, status, readUsage])\n\n // ...and then kept current while the page is open. Allowances move as the account\n // is used, so a figure that is only read on mount reports the state of a page that\n // may have been open for hours.\n useEffect(() => {\n if (call === undefined) return\n const tick = (): void => {\n // Nothing is refreshed for a page nobody is looking at.\n if (globalThis.document?.visibilityState === 'hidden') return\n void readUsage(signedInRef.current)\n }\n const interval = setInterval(tick, USAGE_POLL_INTERVAL_MS)\n return () => { clearInterval(interval) }\n }, [call, readUsage])\n\n // Poll only while some provider is waiting for browser approval.\n const anyBusy = status?.providers.some((provider) => provider.busy) === true\n useEffect(() => {\n if (anyBusy) startPolling()\n else stopPolling()\n }, [anyBusy, startPolling, stopPolling])\n\n /** Run one action for one provider, reporting its own failure. */\n const act = useCallback(async (provider: string, run: () => Promise<void>): Promise<void> => {\n setBusyAction(true)\n setMessages((current) => {\n const next = { ...current }\n delete next[provider]\n return next\n })\n try {\n await run()\n } catch (caught: unknown) {\n if (mounted.current) {\n setMessages((current) => ({ ...current, [provider]: { tone: 'error', text: t('actionFailed', { message: messageOf(caught) }) } }))\n }\n } finally {\n if (mounted.current) setBusyAction(false)\n }\n }, [t])\n\n const login = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const started = await call('login', { provider })\n if (!mounted.current) return\n setStatus(started.status)\n // A loopback flow wants the browser opened; a blocked popup still leaves\n // the link in the card, which is the fallback the user already has.\n if (started.prompt.mode === 'open-url') {\n window.open(started.prompt.url, '_blank', 'noopener')\n }\n })\n }, [act, call])\n\n const cancel = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('cancel', { provider })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const logout = useCallback((provider: string, account: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('logout', { provider, account })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const setDefault = useCallback((provider: string, account: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('setDefault', { provider, account })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const refreshToken = useCallback((provider: string, account: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const result = await call('refresh', { provider, account })\n if (!mounted.current) return\n setStatus(result.status)\n setMessages((current) => ({\n ...current,\n [provider]: { tone: 'success', text: t('tokenRefreshed', { time: formatTime(result.expiresAt) }) },\n }))\n })\n }, [act, call, t])\n\n const refreshModels = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('discover', { provider, force: true })\n if (!mounted.current) return\n setStatus(next)\n setMessages((current) => ({ ...current, [provider]: { tone: 'success', text: t('modelsRefreshed') } }))\n })\n }, [act, call, t])\n\n const setModelVisible = useCallback((provider: string, id: string, visible: boolean): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('setModelVisible', { provider, id, visible })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const refreshUsage = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const result = await call('usage', { provider, force: true })\n if (mounted.current) setStatus(result.status)\n })\n }, [act, call])\n\n const setModelOrder = useCallback((provider: string, ids: readonly string[]): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('setModelOrder', { provider, ids: [...ids] })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const addModel = useCallback((provider: string, id: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('addModel', { provider, id })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const removeModel = useCallback((provider: string, id: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('removeModel', { provider, id })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const reload = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('reload', undefined)\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n if (call === undefined) return <p style={styles.intro}>{t('unavailable')}</p>\n\n return (\n <div className=\"dsh-subscriptions-settings\" style={styles.section}>\n <style>{subscriptionsCss}</style>\n <p style={styles.intro}>{t('intro')}</p>\n {error !== undefined && <p className=\"dsh-subscription-error\">{error}</p>}\n {status === undefined && <p style={styles.statusLine}>{t('loading')}</p>}\n {status?.providers.map((provider) => (\n <ProviderCard\n key={provider.provider}\n status={provider}\n t={t}\n busyAction={busyAction}\n {...messages[provider.provider] === undefined ? {} : { message: messages[provider.provider] as CardMessage }}\n onLogin={() => { login(provider.provider) }}\n onCancel={() => { cancel(provider.provider) }}\n onLogout={(account) => { logout(provider.provider, account) }}\n onSetDefault={(account) => { setDefault(provider.provider, account) }}\n onRefreshToken={(account) => { refreshToken(provider.provider, account) }}\n onRefreshModels={() => { refreshModels(provider.provider) }}\n onSetModelVisible={(id, visible) => { setModelVisible(provider.provider, id, visible) }}\n onSetModelOrder={(ids) => { setModelOrder(provider.provider, ids) }}\n onAddModel={(id) => { addModel(provider.provider, id) }}\n onRemoveModel={(id) => { removeModel(provider.provider, id) }}\n onRefreshUsage={() => { refreshUsage(provider.provider) }}\n onReload={() => { reload(provider.provider) }}\n />\n ))}\n </div>\n )\n}\n","/**\n * Subscriptions settings page, browser half.\n *\n * Registers one `settings.section` entry titled 订阅 / Subscriptions. Every\n * connection fact arrives through the node half's `subscription-oauth` RPC\n * endpoints, so this half holds no credential state of its own, and the copy\n * rides the client locale service under the `settings.subscriptions` namespace.\n *\n * @module dsh-plugin-subscription-oauth/client\n */\n\n// Type-only: pulls the `ctx.slots` Context merge and the `settings.section`\n// SlotMap entry. These imports are erased; no runtime binding is taken.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\n\nimport { SubscriptionsSection } from './SubscriptionsSection.js'\nimport type { SubscriptionsSectionInjected } from './SubscriptionsSection.js'\nimport { createSubscriptionsCall } from './subscriptions-rpc.js'\nimport { en, zh } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\n\nexport type { SubscriptionsSectionInjected, SubscriptionsSectionProps } from './SubscriptionsSection.js'\nexport type { SubscriptionsKey } from './locales.js'\nexport { createSubscriptionsCall, SubscriptionsRpcError } from './subscriptions-rpc.js'\nexport type { SubscriptionsCall } from './subscriptions-rpc.js'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** The Subscriptions settings page copy. */\n 'settings.subscriptions': SubscriptionsKey\n }\n}\n\n/** Dictionary namespace owned by this plugin. */\nconst NS = 'settings.subscriptions'\n\n/** Settings nav position: after the shipped sections, before plugin tooling. */\nconst SECTION_ORDER = 92\n\n/**\n * Required services: `slots` carries the registration seat, `connection` the\n * RPC caller, and `locale` the copy dictionaries.\n */\nexport const inject = ['slots', 'connection', 'locale']\n\n/**\n * Register the Subscriptions settings section.\n *\n * Registration goes through `slots.inject`, so the shell's own apply order\n * relative to this one is unconstrained.\n *\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-plugin-subscription-oauth: copy dictionaries')\n // The shell's Context merge types `connection` as the host handle; in the\n // browser the same key holds the full client ConnectionHandle.\n const connection = ctx.get('connection') as unknown as ConnectionHandle\n const t = ctx.locale.bind(NS) as SubscriptionsSectionInjected['t']\n const call = createSubscriptionsCall(connection.rpc)\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'subscriptions',\n order: SECTION_ORDER,\n // A thunk re-evaluated per read, so the nav label follows the active locale.\n label: () => t('nav'),\n inject: (): SubscriptionsSectionInjected => ({ call, t }),\n }, SubscriptionsSection))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["code: string","messageOf","result: Awaited<ReturnType<ConnectionHandle['rpc']['call']>>","error: unknown","template: string","styles: Record<string, CSSProperties>","window","accounts: readonly AccountStatus[]","caught: unknown"],"sources":["../src/client/locales.ts","../src/client/styles.ts","../src/protocol.ts","../src/client/subscriptions-rpc.ts","../src/client/SubscriptionsSection.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Copy dictionaries for the Subscriptions settings page.\n *\n * English is the key-set source of truth; the Chinese dictionary is typed\n * against it, so a key added to one and forgotten in the other is a compile\n * error rather than a silent fallback.\n */\n\n/** English strings. */\nexport const en = {\n nav: 'Subscriptions',\n intro: 'Sign in with a subscription account — Kimi Code, Grok (X Premium) or Google Antigravity. DeepSeek Harness keeps the tokens on this machine and streams every request through the provider\\'s own API.',\n loading: 'Checking subscriptions…',\n unavailable: 'The subscriptions page needs the web connection service, which this composition does not provide.',\n statusConnected: 'Connected · {count} account(s)',\n statusSignedOut: 'Not signed in',\n statusBusy: 'Waiting for browser approval',\n statusSignIn: 'Sign in to add this provider\\'s models to the model picker.',\n statusAuto: 'Follows {count} enabled model(s) from every provider',\n connect: 'Connect',\n edit: 'Edit',\n collapse: 'Collapse',\n addAccount: 'Add account',\n manage: 'Manage',\n cancel: 'Cancel',\n close: 'Close',\n logout: 'Sign out',\n makeDefault: 'Use by default',\n defaultBadge: 'Default',\n accountNeedsLogin: 'Sign in again',\n accountNeedsLoginHint: 'The provider refused this account\\'s grant, so its token cannot be renewed',\n accountExpired: 'token expired',\n accountExpires: 'expires {time}',\n deviceTitle: 'Approve this device',\n devicePrompt: 'Open the verification page and confirm the code below. This page updates by itself once the provider approves.',\n deviceOpen: 'Open verification page',\n deviceCopy: 'Copy code',\n deviceCopied: 'Copied',\n deviceExpires: 'The code expires at {time}.',\n openLogin: 'Open sign-in page',\n openLoginHint: 'Finish signing in in the browser tab that opened. This page updates by itself once the provider redirects back.',\n modelsTitle: 'Models',\n modelsCount: '{count} available',\n modelsLive: 'live',\n modelsBuiltIn: 'built-in',\n modelsShow: 'Show in picker',\n modelsHiddenCount: '· {count} hidden',\n modelsHidden: 'Hidden from the model picker',\n modelsEmpty: 'No models reported yet.',\n modelsAdd: 'Add model',\n modelsAddHint: 'Publish a model id this build does not know yet',\n modelsAddPlaceholder: 'model id, e.g. k3-next',\n modelsAddConfirm: 'Add',\n modelsRemove: 'Remove this hand-added model',\n modelsContext: '{tokens} context',\n modelsAuto: 'Auto',\n modelsAutoHint: 'Pinned first: moves to the next model when one is unavailable',\n modelsAutoOff: 'Off — the picker offers the models directly instead',\n modelsAutoChain: 'Auto tries these, in this order — drag to re-order',\n modelsDrag: 'Drag to re-order (or press ↑ / ↓ here)',\n modelsAutoChainOff: 'Take out of Auto',\n modelsAutoChainEmpty: 'No model is enabled, so Auto has nothing to try.',\n modelsPinned: 'pinned',\n usageTitle: 'Plan and usage',\n usagePlan: 'Plan: {plan}',\n usageRenews: 'renews {time}',\n usageReset: 'resets {time}',\n usageResetsInMinutes: 'resets in {minutes}m',\r\n usageResetsInHours: 'resets in {hours}h',\n usageResetDue: 'resets shortly',\n usageRefresh: 'Refresh usage',\n usageFetched: 'read {time}',\n usageNone: 'This provider reports no plan quota.',\n usageError: 'Could not read usage: {message}',\n usage_5h: '5-hour window',\n usage_weekly: 'Weekly window',\n usage_credits: 'Included credit',\n usage_gemini: 'Gemini allowance (rolling)',\n usage_gemini_weekly: 'Gemini allowance (weekly)',\n usage_claude: 'Claude allowance (rolling)',\n usage_claude_weekly: 'Claude allowance (weekly)',\n usage_other: 'Allowance',\n refresh: 'Refresh',\n refreshing: 'Refreshing…',\n modelsRefreshed: 'Model list refreshed.',\n refreshToken: 'Refresh token',\n tokenRefreshed: 'Token refreshed; valid until {time}.',\n hint: 'Authorization follows the account the browser is signed in with. To add a different account, switch accounts there first, or use a private window.',\n manageTitle: 'Manage {provider}',\n manageAccounts: 'Accounts',\n reload: 'Reload credentials',\n reloadHint: 'Use this after signing in from another DeepSeek Harness window.',\n detail_oauthHost: 'Authorization server',\n detail_apiBase: 'API base',\n detail_credentialFile: 'Credential file',\n detail_project: 'Cloud project',\n lastError: 'Last login attempt failed: {message}',\n loginFailed: 'Could not start the sign-in: {message}',\n actionFailed: 'Action failed: {message}',\n} as const\n\n/** The Subscriptions namespace key union. */\nexport type SubscriptionsKey = keyof typeof en\n\n/** Chinese strings. */\nexport const zh = {\n nav: '订阅',\n intro: '使用订阅账号登录 —— Kimi Code、Grok (X Premium) 或 Google Antigravity。DeepSeek Harness 将令牌保存在本机,并通过各服务自己的 API 发起请求。',\n loading: '正在检查订阅…',\n unavailable: '订阅页面需要 Web 连接服务,当前组合未提供该服务。',\n statusConnected: '已连接 {count} 个账号',\n statusSignedOut: '未登录',\n statusBusy: '等待浏览器确认',\n statusSignIn: '登录后即可在模型选择器中使用该服务的模型。',\n statusAuto: '依次使用来自各服务的 {count} 个已启用模型',\n connect: '连接',\n edit: '编辑',\n collapse: '收起',\n addAccount: '添加账号',\n manage: '管理',\n cancel: '取消',\n close: '关闭',\n logout: '退出登录',\n makeDefault: '设为默认',\n defaultBadge: '默认',\n accountNeedsLogin: '需重新登录',\n accountNeedsLoginHint: '服务方已拒绝该账号的授权,令牌无法自动续期',\n accountExpired: '令牌已过期',\n accountExpires: '过期时间 {time}',\n deviceTitle: '确认此设备',\n devicePrompt: '打开验证页面并确认下方代码,服务确认后本页面会自动更新。',\n deviceOpen: '打开验证页面',\n deviceCopy: '复制代码',\n deviceCopied: '已复制',\n deviceExpires: '代码将于 {time} 过期。',\n openLogin: '打开登录页面',\n openLoginHint: '请在打开的浏览器标签页中完成登录;服务回调后本页面会自动更新。',\n modelsTitle: '模型',\n modelsCount: '共 {count} 个',\n modelsLive: '实时',\n modelsBuiltIn: '内置',\n modelsShow: '在选择器中显示',\n modelsHiddenCount: '· 已隐藏 {count} 个',\n modelsHidden: '已从模型选择器隐藏',\n modelsEmpty: '暂未获取到模型。',\n modelsAdd: '添加模型',\n modelsAddHint: '手动添加一个本版本还不认识的模型 ID',\n modelsAddPlaceholder: '模型 ID,例如 k3-next',\n modelsAddConfirm: '添加',\n modelsRemove: '移除这个手动添加的模型',\n modelsContext: '{tokens} 上下文',\n modelsAuto: '自动',\n modelsAutoHint: '固定在首位:某个模型不可用时自动改用下一个',\n modelsAutoOff: '已关闭 —— 选择器将直接列出各个模型',\n modelsAutoChain: '自动会按这个顺序依次尝试(拖动可调整)',\n modelsDrag: '拖动调整顺序(也可在此按 ↑ / ↓)',\n modelsAutoChainOff: '从自动中移除',\n modelsAutoChainEmpty: '没有启用任何模型,自动没有可尝试的模型。',\n modelsPinned: '固定',\n usageTitle: '套餐与额度',\n usagePlan: '套餐:{plan}',\n usageRenews: '续费时间 {time}',\n usageReset: '重置时间 {time}',\n usageResetsInMinutes: '{minutes} 分钟后重置',\r\n usageResetsInHours: '{hours} 小时后重置',\n usageResetDue: '即将重置',\n usageRefresh: '刷新额度',\n usageFetched: '读取于 {time}',\n usageNone: '该服务未提供套餐额度信息。',\n usageError: '额度读取失败:{message}',\n usage_5h: '5 小时窗口',\n usage_weekly: '每周窗口',\n usage_credits: '包含额度',\n usage_gemini: 'Gemini 模型额度(滚动)',\n usage_gemini_weekly: 'Gemini 模型额度(每周)',\n usage_claude: 'Claude 模型额度(滚动)',\n usage_claude_weekly: 'Claude 模型额度(每周)',\n usage_other: '额度',\n refresh: '刷新',\n refreshing: '正在刷新…',\n modelsRefreshed: '模型列表已刷新。',\n refreshToken: '刷新令牌',\n tokenRefreshed: '令牌已刷新,有效至 {time}。',\n hint: '授权以浏览器当前登录的账号为准;要添加不同账号,请先在浏览器里切换账号,或使用无痕窗口。',\n manageTitle: '管理 {provider}',\n manageAccounts: '账号',\n reload: '重新读取凭据',\n reloadHint: '在另一个 DeepSeek Harness 窗口中登录后,请使用此操作。',\n detail_oauthHost: '授权服务器',\n detail_apiBase: 'API 地址',\n detail_credentialFile: '凭据文件',\n detail_project: '云项目',\n lastError: '上次登录失败:{message}',\n loginFailed: '无法开始登录:{message}',\n actionFailed: '操作失败:{message}',\n} satisfies Record<SubscriptionsKey, string>\n","/**\n * Scoped stylesheet for the Subscriptions page and its manage dialog.\n *\n * The host loads plugin markup without its own control classes, and a bare\n * `<button>` therefore renders with the browser's default raised chrome — which\n * reads as a stray highlight in a dark theme. Rather than invent a look, this\n * follows the control vocabulary of the sibling `dsh-plugin-subscriptions`\n * plugin (same author-facing design as the shell's settings forms): a 6 px\n * radius small control, a transparent fill, a hairline border from the theme's\n * alias tokens, and the theme's hover/active/focus tokens for state.\n *\n * The tokens all carry fallbacks, so the page still renders correctly on a host\n * build that does not define them.\n *\n * @module dsh-plugin-subscription-oauth/client/styles\n */\n\n/**\n * Everything is scoped to this plugin's own roots, so no other surface in the\n * shell can be affected by a rule here.\n */\nconst scope = ':is(.dsh-subscriptions-settings, .dsh-subscription-manager)'\n\n/** The page's and dialog's stylesheet. */\nexport const subscriptionsCss = `\n.dsh-subscriptions-settings,\n.dsh-subscription-manager {\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n /* Native controls (checkbox, dialog) follow the host theme, not the OS. */\n color-scheme: light;\n}\nbody[data-ds-dark-theme] ${scope} {\n color-scheme: dark;\n}\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}\n.dsh-subscription-manager::backdrop {\n background: var(--dsw-alias-bg-mask-1, #0006);\n backdrop-filter: var(--dsw-mask-blur, none);\n}\n${scope} h2 {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n}\n${scope} strong,\n${scope} .dsh-subscription-label {\n font-size: 13px;\n line-height: 1.5;\n font-weight: 500;\n}\n${scope} small,\n${scope} .dsh-subscription-hint,\n${scope} [role=\"status\"] {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n${scope} .dsh-subscription-error {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary, #b42318);\n}\n${scope} .dsh-subscription-success {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary, #067647);\n}\n${scope} label:has(> input[type=\"checkbox\"]) {\n cursor: pointer;\n}\n${scope} input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-brand-primary);\n}\n/*\n * A model's on/off control is a switch, not a checkbox: it takes effect\n * immediately and its state is what matters, not a tick. Drawn from the theme\n * tokens with appearance: none, so it follows the host palette in both themes\n * instead of the platform's checkbox chrome.\n */\n${scope} input[type=\"checkbox\"].dsh-subscription-switch {\n appearance: none;\n -webkit-appearance: none;\n position: relative;\n box-sizing: border-box;\n flex-shrink: 0;\n width: 34px;\n height: 20px;\n margin: 0;\n border: 0.5px solid var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2));\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary-foreground, #fff);\n box-shadow: 0 1px 2px #0003;\n transition: transform 120ms ease;\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch:checked {\n border-color: transparent;\n background: var(--dsw-alias-state-success-primary, var(--dsw-alias-brand-primary, #067647));\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch:checked::after {\n transform: translateX(14px);\n}\n${scope} input[type=\"checkbox\"].dsh-subscription-switch:disabled {\n opacity: 0.4;\n cursor: default;\n}\n${scope} 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${scope} button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-3));\n}\n${scope} button:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-3));\n}\n${scope} button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n/* A control that is present but should not read as a bordered button. */\n${scope} button.dsh-subscription-quiet {\n min-height: 22px;\n padding: 0 4px;\n border-color: transparent;\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n/* The free-text field for a hand-added model id. */\n${scope} input.dsh-subscription-input {\n box-sizing: border-box;\n flex: 1 1 auto;\n min-width: 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: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n}\n${scope} input.dsh-subscription-input::placeholder {\n color: var(--dsw-alias-label-tertiary);\n}\n${scope} input.dsh-subscription-input: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/* A drag handle: no border or fill, so it reads as a grip rather than a button. */\n${scope} button.dsh-subscription-handle {\n min-height: 18px;\n height: 18px;\n padding: 0 2px;\n border-color: transparent;\n border-radius: var(--dsw-radius-sm, 6px);\n background: transparent;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n font-size: 12px;\n line-height: 18px;\n cursor: grab;\n}\n${scope} button.dsh-subscription-handle:hover:not(:disabled) {\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n${scope} button.dsh-subscription-handle:active:not(:disabled) { cursor: grabbing; }\n/* Controls inside the manage dialog are one step larger, like a form footer. */\n${scope} .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${scope} 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${scope} button.dsh-subscription-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover, var(--dsw-alias-label-secondary));\n}\n${scope} button:focus-visible,\n${scope} input[type=\"checkbox\"]:focus-visible,\n${scope} .dsh-subscription-disclosure: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/* The catalog heading is a summary-style disclosure, not a bordered button. */\n${scope} .dsh-subscription-disclosure {\n border-color: transparent;\n border-radius: var(--dsw-radius-sm, 6px);\n background: transparent;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n${scope} .dsh-subscription-disclosure:hover:not(:disabled) {\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n/* A usage meter: the track, with the fill sized by the caller. */\n${scope} .dsh-subscription-meter {\n height: 6px;\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2));\n overflow: hidden;\n}\n${scope} .dsh-subscription-meter > span {\n display: block;\n height: 100%;\n background: var(--dsw-alias-state-success-primary, #067647);\n}\n${scope} .dsh-subscription-meter > span[data-exhausted=\"true\"] {\n background: var(--dsw-alias-state-error-primary, #b42318);\n}\n`\n","/**\n * Wire contract shared by the plugin's node half (the RPC routes) and its\n * browser half (the Settings page).\n *\n * Only this module crosses the boundary: the client bundle imports the types\n * and the channel name, and every call travels as one JSON envelope over a\n * `POST /api/<prefix><endpoint>` route. One status document describes every\n * provider route the plugin serves, so the page renders one card per entry.\n *\n * @module dsh-plugin-subscription-oauth/protocol\n */\n\n/** Prefix of every RPC method this plugin serves. */\nexport const RPC_PREFIX = 'subscription-oauth.'\n\n/** Endpoints the Settings page may call. */\nexport const RPC_ENDPOINTS = [\n 'status',\n 'login',\n 'cancel',\n 'logout',\n 'setDefault',\n 'refresh',\n 'discover',\n 'setModelVisible',\n 'setModelOrder',\n 'addModel',\n 'removeModel',\n 'usage',\n 'reload',\n] as const\n\n/** One endpoint name. */\nexport type RpcEndpoint = typeof RPC_ENDPOINTS[number]\n\n/** Client → host envelope. */\nexport interface RpcRequest {\n type: 'client-request'\n rpcId: string\n method: string\n payload: unknown\n}\n\n/** Host → client envelope, carrying either the value or the failure. */\nexport interface RpcResponse {\n type: 'server-response'\n rpcId: string\n result: RpcResult\n}\n\n/** Discriminated result inside {@link RpcResponse}. */\nexport type RpcResult =\n | { ok: true, value: unknown }\n | { ok: false, error: RpcError }\n\n/** Failure detail, with the provider-neutral code when one applies. */\nexport interface RpcError {\n code: string\n message: string\n /**\n * Carrier-owned structured detail. The Connection transport models a failure\n * as `{code, message, details}`, so an empty object travels here rather than\n * an absent field the client would have to repair.\n */\n details: Record<string, unknown>\n}\n\n/**\n * One provider-owned connection fact the manage dialog shows.\n *\n * The key is a stable identifier (`oauthHost`, `apiBase`, …) that the browser\n * half localizes; the host never sends user-facing prose.\n */\nexport interface DetailRow {\n key: string\n value: string\n}\n\n/** How the browser should present one pending login. */\nexport type LoginMode =\n /** Open the URL in a new tab; the redirect completes the login. */\n | 'open-url'\n /** Show the code (and a link) while the host polls the token endpoint. */\n | 'device-code'\n\n/** What the Settings page has to show to finish a login. */\nexport interface LoginPrompt {\n /** URL the user opens (or that was opened for them). */\n readonly url: string\n /** Code the user confirms in the browser; device flows only. */\n readonly userCode?: string\n /** Epoch milliseconds after which the attempt lapses. */\n readonly expiresAt: number\n readonly mode: LoginMode\n}\n\n/** One signed-in account as the page displays it. */\nexport interface AccountStatus {\n /** Account key the store is keyed by. */\n account: string\n /** Display label (email, user id, or the key's digest). */\n label: string\n /** Epoch milliseconds when the access token lapses. */\n expiresAt: number\n /** Whether the access token is already past its expiry. */\n expired: boolean\n /** Whether this account serves requests by default. */\n isDefault: boolean\n /**\n * Whether the provider refused this account's grant outright.\n *\n * A refresh answered with `invalid_grant` means the authorization is gone — the\n * stored token can never be renewed — so the page asks for a new sign-in rather\n * than reporting the account as connected.\n */\n needsLogin?: boolean\n}\n\n/** One selectable model, as the page lists it. */\nexport interface ModelSummary {\n id: string\n name: string\n description?: string\n contextWindow: number\n inputModalities?: readonly string[]\n defaultEffort?: string\n /** Whether the session model picker offers this model. */\n visible: boolean\n /**\n * Route that owns this model, when the listing spans routes.\n *\n * The \u0007uto provider mixes models from every route, so its rows name the\n * owning route; a single-route catalog leaves it out.\n */\n source?: string\n /** Whether the user added this id by hand, so it can be removed again. */\n userAdded?: boolean\n /**\n * Whether this entry is fixed at the head of the list.\n *\n * The synthetic `auto` entry follows the user's own order, so it cannot be\n * hidden or moved; the page renders it without those controls.\n */\n pinned?: boolean\n}\n\n/** One metered allowance of a subscription plan. */\nexport interface UsageWindow {\n /** What the window meters, e.g. `weekly`, `5h`, `credits`. */\n label: string\n /** How much of the allowance is spent, when the provider states it. */\n usedPercent?: number\n /** Amount already spent, when the provider states an absolute figure. */\n used?: number\n /** Total allowance, when the provider states one. */\n limit?: number\n /** Epoch milliseconds when the window resets, when the provider states it. */\n resetsAt?: number\n}\n\n/** One account's plan and metered allowances. */\nexport interface ProviderUsage {\n /** Account the figures belong to. */\n account: string\n /** Plan name or tier, when the provider states one. */\n plan?: string\n /** Whether the plan renews on a date the provider states. */\n renewsAt?: number\n /** Metered allowances, most relevant first. */\n windows: readonly UsageWindow[]\n /** Epoch milliseconds these figures were read. */\n fetchedAt: number\n /**\n * Whether these figures are the route's substitute rather than its own accounting.\n *\n * A substitute is shown when the primary source cannot answer, and it is never\n * reused as if it were a reading: the next request asks again.\n */\n substitute?: boolean\n}\n\n/** Result of reading one route's usage. */\nexport interface UsageResult {\n provider: string\n /** Usage per account the endpoint could answer for. */\n usage: readonly ProviderUsage[]\n /** Why an account's usage is missing, when the read failed. */\n error?: string\n status: SubscriptionStatus\n}\n\n/** The full state of one provider route. */\nexport interface ProviderStatus {\n /** Provider route key, e.g. `kimi`. */\n provider: string\n displayName: string\n /** Where a user manages the underlying subscription. */\n codeUrl?: string\n /** Whether at least one account is stored. */\n loggedIn: boolean\n /**\n * Whether this route signs in at all.\n *\n * \u0007uto has no account of its own — it delegates to routes that do — so the\n * page hides the connect and manage controls for it.\n */\n connectable?: boolean\n /** Whether a login attempt is being polled. */\n busy: boolean\n /** The pending attempt, when `busy`. */\n pending?: LoginPrompt\n accounts: AccountStatus[]\n /** Account key serving requests, when one does. */\n activeAccount?: string\n /** Absolute path of the credential file, for support requests. */\n credentialFile: string\n /** Whether the live model list is consulted. */\n discovery: boolean\n /** Live catalog ids, when discovery has succeeded this session. */\n discovered?: readonly string[]\n models: readonly ModelSummary[]\n /** Model the picker preselects. */\n defaultModel?: string\n /** Last usage figures read for this route, when they were requested. */\n usage?: readonly ProviderUsage[]\n /** Why the last usage read failed, when it did. */\n usageError?: string\n /** Provider-owned connection facts shown in the manage dialog. */\n details: readonly DetailRow[]\n /** Last background failure (a login that could not complete). */\n lastError?: string\n}\n\n/** Every provider route's state, in display order. */\nexport interface SubscriptionStatus {\n providers: ProviderStatus[]\n}\n\n/** Result of starting a login. */\nexport interface LoginStart {\n prompt: LoginPrompt\n status: SubscriptionStatus\n}\n\n/** Result of a token refresh. */\nexport interface RefreshResult {\n account: string\n expiresAt: number\n status: SubscriptionStatus\n}\n\n/** Payload fields naming one provider route and optionally one account. */\nexport interface AccountRequest {\n provider: string\n account?: string\n}\n\n/** Payload of `setDefault`. */\nexport interface SetDefaultRequest {\n provider: string\n account: string\n}\n\n/** Payload of `discover`. */\nexport interface DiscoverRequest {\n provider: string\n /** Ask the endpoint for its live model list even when one is cached. */\n force?: boolean\n}\n\n/** Payload of `setModelVisible`. */\nexport interface SetModelVisibleRequest {\n provider: string\n /** Model id as the catalog reports it. */\n id: string\n /** Whether the session model picker should offer it. */\n visible: boolean\n}\n\n/** Payload of `addModel` and `removeModel`. */\nexport interface ModelIdRequest {\n provider: string\n /** Model id as the endpoint accepts it. */\n id: string\n}\n\n/** Payload of `setModelOrder`. */\nexport interface SetModelOrderRequest {\n provider: string\n /** Every catalog model id, in the order the user arranged them. */\n ids: readonly string[]\n}\n\n/** Payload naming only a provider route. */\nexport interface ProviderRequest {\n provider: string\n}\n\n/** Map an endpoint to its payload and value types. */\nexport interface RpcMap {\n status: { payload: undefined, value: SubscriptionStatus }\n login: { payload: AccountRequest, value: LoginStart }\n cancel: { payload: ProviderRequest, value: SubscriptionStatus }\n logout: { payload: AccountRequest, value: SubscriptionStatus }\n setDefault: { payload: SetDefaultRequest, value: SubscriptionStatus }\n refresh: { payload: AccountRequest, value: RefreshResult }\n discover: { payload: DiscoverRequest, value: SubscriptionStatus }\n setModelVisible: { payload: SetModelVisibleRequest, value: SubscriptionStatus }\n setModelOrder: { payload: SetModelOrderRequest, value: SubscriptionStatus }\n addModel: { payload: ModelIdRequest, value: SubscriptionStatus }\n removeModel: { payload: ModelIdRequest, value: SubscriptionStatus }\n usage: { payload: DiscoverRequest, value: UsageResult }\n reload: { payload: undefined, value: SubscriptionStatus }\n}\n","/**\n * Browser caller for the plugin's own RPC channel.\n *\n * The node half mounts one exact `POST /api/subscription-oauth.<endpoint>` route\n * per endpoint, so every call travels on the shared `/api` channel with a\n * prefixed endpoint name — the same wire the rest of the shell uses.\n *\n * @module dsh-plugin-subscription-oauth/client/subscriptions-rpc\n */\n\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\n\nimport { RPC_PREFIX } from '../protocol.js'\nimport type { RpcEndpoint, RpcMap } from '../protocol.js'\n\n/** The shared channel the node half's routes are mounted on. */\nconst CHANNEL = '/api'\n\n/** A failed call: either the transport rejected or the endpoint answered `ok: false`. */\nexport class SubscriptionsRpcError extends Error {\n constructor(message: string, readonly code: string) {\n super(message)\n this.name = 'SubscriptionsRpcError'\n }\n}\n\n/** Human-readable message for any thrown value. */\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/** Call one endpoint, unwrapping the transport result. */\nexport type SubscriptionsCall = <K extends RpcEndpoint>(\n endpoint: K,\n payload: RpcMap[K]['payload'],\n) => Promise<RpcMap[K]['value']>\n\n/**\n * Bind a caller to one connection's RPC transport.\n * @param rpc - the browser connection's RPC caller.\n * @returns a typed caller for this plugin's endpoints.\n */\nexport function createSubscriptionsCall(rpc: ConnectionHandle['rpc']): SubscriptionsCall {\n return async function call(endpoint, payload) {\n let result: Awaited<ReturnType<ConnectionHandle['rpc']['call']>>\n try {\n result = await rpc.call(CHANNEL, `${RPC_PREFIX}${endpoint}`, payload)\n } catch (error: unknown) {\n throw new SubscriptionsRpcError(messageOf(error), 'RPC_TRANSPORT')\n }\n if (!result.ok) throw new SubscriptionsRpcError(result.error.message, result.error.code)\n return result.value as never\n }\n}\n","/**\n * Subscriptions settings page.\n *\n * One card per provider route — Kimi Code, Grok (X Premium), Google Antigravity\n * — describing that route's connection, accounts, and model catalog. Every fact\n * arrives from the node half's `subscription-oauth` RPC endpoints, so this\n * component holds no credential state of its own. The status poll runs only\n * while a login is pending, so an idle page performs no requests.\n *\n * Colors resolve through `--dsw-alias-*` design tokens, so the page follows the\n * active theme; every user-visible string goes through the locale-bound `t`.\n *\n * @module dsh-plugin-subscription-oauth/client/SubscriptionsSection\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { CSSProperties } from 'react'\n\nimport { en } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\nimport { subscriptionsCss } from './styles.js'\nimport { SubscriptionsRpcError } from './subscriptions-rpc.js'\nimport type { SubscriptionsCall } from './subscriptions-rpc.js'\nimport type {\n AccountStatus,\n DetailRow,\n LoginPrompt,\n ProviderStatus,\n ProviderUsage,\n SubscriptionStatus,\n UsageWindow,\n} from '../protocol.js'\n/** Poll cadence while a login attempt is pending. */\nconst POLL_INTERVAL_MS = 2000\n\n/**\n * How often an open page re-reads every signed-in route's allowance.\n *\n * Slow on purpose: it is fast enough that a figure shown on screen is current, and\n * slow enough that leaving the page open costs one small request a minute per\n * signed-in provider.\n */\nconst USAGE_POLL_INTERVAL_MS = 60_000\n\n/**\n * Disclosures start folded, every time the page is opened.\n *\n * Nothing is remembered between visits on purpose: the section is a list of\n * providers first, and a card left open last time should not decide what this\n * visit looks like. A fold is a gesture within one visit, not a stored setting.\n */\n\n/** Horizontal room the page takes inside the settings panel. */\nconst SECTION_WIDTH = 560\n\n/** What the node half injects into this section. */\nexport interface SubscriptionsSectionInjected {\n /** Typed caller for the plugin's RPC endpoints. */\n call: SubscriptionsCall\n /** Translate a key of this plugin's settings namespace. */\n t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string\n}\n\n/** Component props: the shell supplies `close`, the plugin supplies the rest. */\nexport type SubscriptionsSectionProps = Partial<SubscriptionsSectionInjected> & {\n /** Close the settings panel (owned by the settings shell). */\n close?: () => void\n}\n\n/** One card's transient message. */\ninterface CardMessage {\n tone: 'error' | 'success'\n text: string\n}\n\n/** Minimal translator used when the locale seat is absent (standalone render). */\nfunction fallbackTranslate(key: SubscriptionsKey, params?: Record<string, unknown>): string {\n const template: string = en[key]\n if (params === undefined) return template\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n name in params ? String(params[name]) : match)\n}\n\n/** Human-readable message for any thrown value. */\nfunction messageOf(error: unknown): string {\n if (error instanceof SubscriptionsRpcError) return error.message\n return error instanceof Error ? error.message : String(error)\n}\n\n/** Local time for one epoch-millisecond instant. */\nfunction formatTime(at: number): string {\n try {\n return new Date(at).toLocaleString()\n } catch {\n return String(at)\n }\n}\n\n/** How far ahead a reset is still stated as hours rather than a date. */\nconst RESET_RELATIVE_MS = 24 * 60 * 60 * 1000\n\n/**\n * One allowance reset, in the form a reader acts on.\n *\n * How far off it is decides how it is said: minutes inside the hour, hours inside\n * the day, and the date beyond that — \"137 小时后\" would be arithmetic rather than\n * information, and a window that comes back in forty minutes is better described in\n * minutes than as \"1 小时后\". Every route's windows go through here, so all of them\n * read the same way.\n *\n * @param at - epoch milliseconds the window resets.\n * @param t - translator, so the wording follows the page language.\n * @returns the reset text.\n */\nfunction formatReset(\n at: number,\n t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string,\n): string {\n const remaining = at - Date.now()\n if (remaining <= 0) return t('usageResetDue')\n if (remaining >= RESET_RELATIVE_MS) return t('usageReset', { time: formatTime(at) })\n // Rounded, and never below one: \"0 分钟后重置\" would read as a bug rather than as\n // \"any moment now\".\n if (remaining < 60 * 60 * 1000) {\n return t('usageResetsInMinutes', { minutes: Math.max(1, Math.round(remaining / 60_000)) })\n }\n return t('usageResetsInHours', { hours: Math.max(1, Math.round(remaining / 3_600_000)) })\n}\n\n/** Compact token count for a context window. */\nfunction formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${String(Math.round(tokens / 100_000) / 10)}M`\n if (tokens >= 1_000) return `${String(Math.round(tokens / 1_000))}K`\n return String(tokens)\n}\n\n/**\n * Routes worth asking for allowances.\n *\n * A route with no account of its own — `auto` — reports itself as signed in so its\n * card reads as usable, but it holds no allowance to read: asking it every minute\n * spends a request to be told nothing. The routes it stands in for are each read\n * on their own.\n *\n * @param providers - the routes in the current status.\n * @returns the route keys to read usage for.\n */\nfunction usageTargets(providers: readonly ProviderStatus[]): string[] {\n return providers\n .filter((provider) => provider.loggedIn && provider.connectable !== false)\n .map((provider) => provider.provider)\n}\n\nconst styles: Record<string, CSSProperties> = {\n section: {\n display: 'flex', flexDirection: 'column', gap: 12, maxWidth: SECTION_WIDTH,\n color: 'var(--dsw-alias-label-primary)',\n },\n intro: { margin: 0, color: 'var(--dsw-alias-label-tertiary)', fontSize: 14, lineHeight: '22px' },\n card: {\n border: '0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))',\n borderRadius: 'var(--dsw-radius-xl, 20px)',\n background: 'var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))',\n padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 6,\n },\n cardHeader: { display: 'flex', alignItems: 'center', gap: 8 },\n /** Everything a folded card hides. */\n cardBody: { display: 'flex', flexDirection: 'column', gap: 6 },\n /** The one-line state a folded card shows in place of its body. */\n cardSummary: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n dot: { width: 8, height: 8, borderRadius: '50%', flexShrink: 0 },\n name: { fontWeight: 500, fontSize: 14, lineHeight: '22px', color: 'var(--dsw-alias-label-primary)' },\n providerId: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-dimmed)' },\n statusLine: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n errorLine: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-error-primary)' },\n successLine: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-success-primary)' },\n actions: { display: 'flex', gap: 8, marginTop: 4, alignItems: 'center', flexWrap: 'wrap' },\n accountRow: {\n display: 'flex', flexDirection: 'column', gap: 6,\n border: '0.5px solid var(--dsw-alias-border-l2)', borderRadius: 'var(--dsw-radius-lg, 16px)',\n padding: '8px 10px', marginTop: 4,\n },\n accountHeader: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' },\n starButton: {\n border: 'none', padding: 0, width: 20, background: 'transparent',\n font: 'inherit', fontSize: 14, lineHeight: '20px', cursor: 'pointer',\n color: 'var(--dsw-alias-state-warn-label)',\n },\n accountName: { fontSize: 13, lineHeight: '20px', color: 'var(--dsw-alias-label-primary)', userSelect: 'all' },\n badge: {\n fontSize: 11, lineHeight: '16px', padding: '0 6px', borderRadius: 8,\n background: 'var(--dsw-alias-bg-layer-1)', border: '0.5px solid var(--dsw-alias-border-l2)',\n color: 'var(--dsw-alias-label-secondary)',\n },\n pushRight: { marginLeft: 'auto', flexShrink: 0 },\n catalog: {\n display: 'flex', flexDirection: 'column', gap: 6, marginTop: 4,\n borderTop: '0.5px solid var(--dsw-alias-border-l2)', paddingTop: 8,\n },\n catalogHeader: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' },\n catalogTitle: { fontSize: 12, lineHeight: '18px', fontWeight: 500, color: 'var(--dsw-alias-label-secondary)' },\n catalogMeta: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n /**\n * Button surface geometry lives in the scoped stylesheet; only the layout a\n * rule cannot express stays inline.\n */\n pill: {},\n pillSmall: {},\n /** The catalog heading: a summary-style disclosure, not a bordered control. */\n disclosure: {\n display: 'inline-flex', alignItems: 'center', gap: 4, margin: 0,\n },\n chevron: { fontSize: 10, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n modelList: { display: 'flex', flexDirection: 'column', gap: 6, marginTop: 2 },\n /** One model line: a visibility toggle and the model's own metadata. */\n modelRowGrow: { display: 'flex', alignItems: 'flex-start', gap: 8, flex: '1 1 auto', minWidth: 0 },\n /** The pinned `auto` line: listed, switchable, and never part of its own chain. */\n autoRow: {\n display: 'flex', alignItems: 'flex-start', gap: 8, cursor: 'pointer',\n fontSize: 13, lineHeight: '20px', color: 'var(--dsw-alias-label-primary)',\n },\n /** The models `auto` will walk, indented under it. */\n chain: {\n display: 'flex', flexDirection: 'column', gap: 3,\n margin: '2px 0 4px 26px', paddingLeft: 8,\n borderLeft: '0.5px solid var(--dsw-alias-border-l2)',\n },\n chainTitle: { fontSize: 11, lineHeight: '16px', color: 'var(--dsw-alias-label-tertiary)' },\n /** The add-a-model-id row: the field, then confirm and cancel. */\n addRow: { display: 'flex', alignItems: 'center', gap: 6, marginTop: 2 },\n addInput: {},\n /** The remove control on a hand-added row: a bare glyph beside the row. */\n removeButton: { flexShrink: 0, alignSelf: 'center', padding: '0 6px' },\n /** One draggable chain row: the grip, then the remove-from-auto switch. */\n chainRowWrap: { display: 'flex', alignItems: 'center', gap: 4 },\n chainRow: {\n display: 'flex', alignItems: 'center', gap: 6, cursor: 'pointer', flex: '1 1 auto',\n fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-secondary)',\n },\n usage: {\n display: 'flex', flexDirection: 'column', gap: 6, marginTop: 4,\n borderTop: '0.5px solid var(--dsw-alias-border-l2)', paddingTop: 8,\n },\n usageHeader: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' },\n usageRow: { display: 'flex', flexDirection: 'column', gap: 3 },\n usageLine: { display: 'flex', alignItems: 'baseline', gap: 8, justifyContent: 'space-between' },\n usageMeter: {\n height: 6, borderRadius: 999, background: 'var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2))',\n overflow: 'hidden',\n },\n modelRow: {\n display: 'flex', alignItems: 'flex-start', gap: 8,\n cursor: 'pointer', fontSize: 13, lineHeight: '20px',\n color: 'var(--dsw-alias-label-primary)',\n },\n /** A hidden model stays listed and editable, but reads as inactive. */\n modelRowHidden: {\n display: 'flex', alignItems: 'flex-start', gap: 8,\n cursor: 'pointer', fontSize: 13, lineHeight: '20px',\n color: 'var(--dsw-alias-label-dimmed)',\n },\n modelBody: { display: 'flex', flexDirection: 'column', gap: 1, minWidth: 0 },\n modelName: { fontSize: 13, lineHeight: '20px' },\n modelMeta: { fontSize: 11, lineHeight: '16px', color: 'var(--dsw-alias-label-tertiary)', userSelect: 'all' },\n device: {\n marginTop: 4, display: 'flex', flexDirection: 'column', gap: 6,\n border: '0.5px solid var(--dsw-alias-border-l2)', borderRadius: 'var(--dsw-radius-lg, 16px)',\n padding: '10px 12px', background: 'var(--dsw-alias-bg-layer-1)',\n },\n deviceTitle: { fontWeight: 500, fontSize: 13, lineHeight: '20px', color: 'var(--dsw-alias-label-primary)' },\n deviceCode: {\n fontFamily: 'monospace', fontSize: 18, lineHeight: '24px', letterSpacing: 2,\n color: 'var(--dsw-alias-label-primary)', userSelect: 'all',\n },\n details: {\n display: 'flex', flexDirection: 'column', gap: 4,\n fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)',\n },\n detailRow: { display: 'flex', gap: 8, justifyContent: 'space-between', alignItems: 'baseline' },\n detailValue: { userSelect: 'all', overflowWrap: 'anywhere', textAlign: 'right' },\n /** Dialog layout only: its surface comes from `.dsh-subscription-manager`. */\n modal: {\n width: 440, maxWidth: '100%', maxHeight: '85vh', overflowY: 'auto',\n boxSizing: 'border-box', display: 'flex', flexDirection: 'column', gap: 10,\n padding: '16px 18px', margin: 'auto',\n },\n modalHeader: { display: 'flex', alignItems: 'center', gap: 8 },\n modalTitle: { fontWeight: 500, fontSize: 16, lineHeight: '24px', color: 'var(--dsw-alias-label-primary)' },\n modalActions: { display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 2 },\n divider: { borderTop: '0.5px solid var(--dsw-alias-border-l2)' },\n}\n\n/** Status dot color for one provider's connection state. */\nfunction dotColor(status: ProviderStatus): string {\n if (status.busy) return 'var(--dsw-alias-state-warn-label)'\n if (status.loggedIn) return 'var(--dsw-alias-state-success-primary)'\n return 'var(--dsw-alias-label-dimmed)'\n}\n\n/** Localized label for one provider-owned detail row. */\nfunction detailLabel(t: SubscriptionsSectionInjected['t'], row: DetailRow): string {\n const key = `detail_${row.key}` as SubscriptionsKey\n return key in en ? t(key) : row.key\n}\n\n/** Localized label for one metered window the provider states. */\nfunction windowLabel(t: SubscriptionsSectionInjected['t'], window: UsageWindow): string {\n const key = `usage_${window.label}` as SubscriptionsKey\n return key in en ? t(key) : window.label\n}\n\n/** How much of one window is spent, as a display string. */\nfunction windowAmount(window: UsageWindow): string {\n if (window.usedPercent !== undefined) return `${String(Math.round(window.usedPercent))}%`\n if (window.used !== undefined && window.limit !== undefined) return `${String(window.used)}/${String(window.limit)}`\n return '—'\n}\n\n/** One account's plan and metered allowances. */\nfunction UsageBlock(props: {\n usage: readonly ProviderUsage[]\n error?: string\n t: SubscriptionsSectionInjected['t']\n busyAction: boolean\n onRefresh(): void\n}) {\n const { usage, error, t, busyAction, onRefresh } = props\n return (\n <div style={styles.usage}>\n <div style={styles.usageHeader}>\n <span style={styles.catalogTitle}>{t('usageTitle')}</span>\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n disabled={busyAction}\n onClick={onRefresh}\n >\n {busyAction ? t('refreshing') : t('usageRefresh')}\n </button>\n </div>\n {error !== undefined && <p className=\"dsh-subscription-error\">{t('usageError', { message: error })}</p>}\n {usage.length === 0 && error === undefined && <p style={styles.statusLine}>{t('usageNone')}</p>}\n {usage.map((entry) => (\n <div key={entry.account} style={styles.usageRow}>\n <div style={styles.usageLine}>\n <span style={styles.modelMeta}>\n {entry.plan === undefined ? entry.account : t('usagePlan', { plan: entry.plan })}\n {entry.renewsAt === undefined ? '' : ` · ${t('usageRenews', { time: formatTime(entry.renewsAt) })}`}\n </span>\n <span style={styles.modelMeta}>{t('usageFetched', { time: formatTime(entry.fetchedAt) })}</span>\n </div>\n {entry.windows.map((window) => (\n <div key={`${entry.account}-${window.label}`} style={styles.usageRow}>\n <div style={styles.usageLine}>\n <span style={styles.modelName}>\n {windowLabel(t, window)}\n {' · '}\n {windowAmount(window)}\n </span>\n <span style={styles.modelMeta}>\n {window.resetsAt === undefined ? '' : formatReset(window.resetsAt, t)}\n </span>\n </div>\n {window.usedPercent !== undefined && (\n <div className=\"dsh-subscription-meter\">\n <span\n style={{ width: `${String(Math.min(100, Math.max(0, window.usedPercent)))}%` }}\n data-exhausted={window.usedPercent >= 90 ? 'true' : 'false'}\n />\n </div>\n )}\n </div>\n ))}\n </div>\n ))}\n </div>\n )\n}\n\n/** The pending-login block: a device code, or a link to the sign-in page. */\nfunction PendingLogin(props: {\n prompt: LoginPrompt\n t: SubscriptionsSectionInjected['t']\n copied: boolean\n onCopy(code: string): void\n}) {\n const { prompt, t, copied, onCopy } = props\n return (\n <div style={styles.device}>\n <span style={styles.deviceTitle}>\n {prompt.mode === 'device-code' ? t('deviceTitle') : t('openLogin')}\n </span>\n <span style={styles.statusLine}>\n {prompt.mode === 'device-code' ? t('devicePrompt') : t('openLoginHint')}\n </span>\n {prompt.userCode !== undefined && <span style={styles.deviceCode}>{prompt.userCode}</span>}\n <span style={styles.statusLine}>{t('deviceExpires', { time: formatTime(prompt.expiresAt) })}</span>\n <div style={styles.actions}>\n <button\n type=\"button\"\n \n onClick={() => { window.open(prompt.url, '_blank', 'noopener') }}\n >\n {prompt.mode === 'device-code' ? t('deviceOpen') : t('openLogin')}\n </button>\n {prompt.userCode !== undefined && (\n <button type=\"button\" onClick={() => { onCopy(prompt.userCode as string) }}>\n {copied ? t('deviceCopied') : t('deviceCopy')}\n </button>\n )}\n </div>\n </div>\n )\n}\n\n/** One provider's card. */\nfunction ProviderCard(props: {\n status: ProviderStatus\n t: SubscriptionsSectionInjected['t']\n busyAction: boolean\n message?: CardMessage\n onLogin(): void\n onCancel(): void\n onLogout(account: string): void\n onSetDefault(account: string): void\n onRefreshToken(account: string): void\n onRefreshModels(): void\n onSetModelVisible(id: string, visible: boolean): void\n /** Persist the chain order the user dropped into place. */\n onSetModelOrder(ids: readonly string[]): void\n /** Publish a model id the catalog does not know yet. */\n onAddModel(id: string): void\n /** Forget a hand-added model id. */\n onRemoveModel(id: string): void\n onRefreshUsage(): void\n onReload(): void\n}) {\n const { status, t, busyAction, message } = props\n const [copied, setCopied] = useState(false)\n // Both disclosures open folded, on every visit: the choice is a gesture, not a\n // stored setting. See the note beside the interval constants.\n const [modelsOpen, setModelsOpen] = useState(false)\n /** Whether this provider's whole card is unfolded. */\n const [cardOpen, setCardOpen] = useState(false)\n const [manageOpen, setManageOpen] = useState(false)\n const mounted = useRef(true)\n const dialog = useRef<HTMLDialogElement>(null)\n\n useEffect(() => {\n mounted.current = true\n return () => { mounted.current = false }\n }, [])\n\n // The dialog is a native modal, so the browser owns focus trapping and Esc.\n useEffect(() => {\n const element = dialog.current\n if (element === null || typeof element.showModal !== 'function') return\n if (manageOpen && !element.open) element.showModal()\n if (!manageOpen && element.open) element.close()\n }, [manageOpen])\n\n const copyCode = useCallback(async (code: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(code)\n if (mounted.current) {\n setCopied(true)\n setTimeout(() => { if (mounted.current) setCopied(false) }, 2000)\n }\n } catch {\n // A clipboard refusal is not worth an error banner: the code is on screen\n // and selectable, which is the fallback the user already has.\n }\n }, [])\n\n const toggleModelsOpen = useCallback((): void => {\n setModelsOpen((open) => !open)\n }, [])\n\n /** Fold or unfold this provider's card. */\n const toggleCardOpen = useCallback((): void => {\n setCardOpen((open) => !open)\n }, [])\n\n const accounts: readonly AccountStatus[] = status.accounts\n const models = status.models\n /** Whether this route signs in at all; the auto provider does not. */\n const connectable = status.connectable !== false\n const hiddenCount = models.filter((model) => !model.visible).length\n /** Whether the add-a-model-id field is open, and what has been typed. */\n const [adding, setAdding] = useState(false)\n const [draft, setDraft] = useState('')\n /** The row being dragged, so it can be dimmed while it moves. */\n const [dragFrom, setDragFrom] = useState<number | undefined>(undefined)\n /**\n * The dragged row, mirrored in a ref.\n *\n * The drop is handled by an ancestor whose handler was attached in an earlier\n * render, so it must not depend on state that was set during the drag.\n */\n const dragFromRef = useRef<number | undefined>(undefined)\n /** The row the pointer is currently over, so a drop lands where the user aims. */\n const dropTargetRef = useRef<number | undefined>(undefined)\n /** The same row in state, purely so it can be highlighted while dragging. */\n const [dropTarget, setDropTarget] = useState<number | undefined>(undefined)\n\n /**\n * Commit one dropped arrangement.\n *\n * The node half takes the full chain in its new order and appends whatever the\n * page left out, so sending just these ids is enough — and a model hidden in\n * another window is never dropped from the stored rank by a stale page.\n */\n const commitOrder = useCallback((ids: readonly string[]): void => {\n props.onSetModelOrder(ids)\n }, [props])\n\n /** Drag-and-drop plus its keyboard equivalent on the drag handle. */\n const drag = {\n start: (event: React.DragEvent, index: number): void => {\n setDragFrom(index)\n dragFromRef.current = index\n event.dataTransfer.effectAllowed = 'move'\n // Firefox refuses to start a drag without payload.\n event.dataTransfer.setData('text/plain', String(index))\n },\n over: (event: React.DragEvent, _index: number): void => {\n // A drop is only possible on a target that cancels the default.\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n const container = event.currentTarget as HTMLElement\n const to = indexAt(container, event.clientY)\n dropTargetRef.current = to\n if (to !== undefined && to !== dropTarget) setDropTarget(to)\n },\n drop: (event: React.DragEvent, index: number): void => {\n event.preventDefault()\n // The target comes from the last `dragover`, not from this event's own\n // coordinates: `drop` is not guaranteed to carry the pointer position, and a\n // zero there silently collapsed every drop onto the first row.\n const to = dropTargetRef.current ?? indexAt(event.currentTarget as HTMLElement, event.clientY) ?? index\n move(dragFromRef.current, to)\n dragFromRef.current = undefined\n dropTargetRef.current = undefined\n setDropTarget(undefined)\n setDragFrom(undefined)\n },\n /** A drop anywhere in the list lands on the row under the pointer. */\n dropAt: (event: React.DragEvent): void => {\n event.preventDefault()\n const container = event.currentTarget as HTMLElement\n const to = dropTargetRef.current ?? indexAt(container, event.clientY)\n if (to !== undefined) move(dragFromRef.current, to)\n dragFromRef.current = undefined\n dropTargetRef.current = undefined\n setDropTarget(undefined)\n setDragFrom(undefined)\n },\n end: (): void => {\n dragFromRef.current = undefined\n dropTargetRef.current = undefined\n setDropTarget(undefined)\n setDragFrom(undefined)\n },\n key: (event: React.KeyboardEvent, index: number): void => {\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n move(index, index + (event.key === 'ArrowUp' ? -1 : 1))\n },\n }\n\n /** Move one model row to another position and persist the result. */\n function move(from: number | undefined, to: number): void {\n if (from === undefined || from === to) return\n if (from < 0 || to < 0 || from >= models.length || to >= models.length) return\n const ids = models.map((model) => model.id)\n const [moved] = ids.splice(from, 1)\n if (moved === undefined) return\n ids.splice(to, 0, moved)\n commitOrder(ids)\n }\n\n /**\n * The row index a drop at this pointer position lands on.\n *\n * The drop is handled on the whole list rather than per row: rows are tall and\n * separated by gaps, so a drop between two of them hits no target at all and\n * silently does nothing. Comparing the pointer against each row's midpoint also\n * makes the gesture match what the user sees.\n */\n function indexAt(container: HTMLElement, clientY: number): number | undefined {\n const rows = Array.from(container.querySelectorAll<HTMLElement>('[data-model-index]'))\n if (rows.length === 0) return undefined\n let closest = 0\n let best = Number.POSITIVE_INFINITY\n for (const row of rows) {\n const box = row.getBoundingClientRect()\n const distance = Math.abs(clientY - (box.top + box.height / 2))\n if (distance >= best) continue\n best = distance\n closest = Number(row.dataset.modelIndex)\n }\n return closest\n }\n const busy = status.busy\n const liveCatalog = (status.discovered?.length ?? 0) > 0\n /**\n * What a folded card says about itself.\n *\n * The connection is the reason to open a card, so the folded row carries it;\n * `auto` has no account and counts the models it will actually try instead.\n */\n const summaryLine = !connectable\n ? t('statusAuto', { count: models.filter((model) => model.visible).length })\n : busy\n ? t('statusBusy')\n : status.loggedIn\n ? t('statusConnected', { count: accounts.length })\n : t('statusSignedOut')\n\n return (\n <div style={styles.card}>\n {/*\n The header is the disclosure: folded, the page is a list of providers, and\n the whole card is one row with its state and an edit affordance. The\n status dot stays visible either way, so a folded card still reports\n whether the route is signed in.\n */}\n <div style={styles.cardHeader}>\n <span style={{ ...styles.dot, background: dotColor(status) }} aria-hidden=\"true\" />\n <span style={styles.name}>{status.displayName}</span>\n <span style={styles.providerId}>{status.provider}</span>\n {/*\n The state stays in the header whether the card is open or folded. The\n body used to repeat the same sentence as its first line, so expanding a\n card made that text appear to jump down a line — the one thing the reader\n is watching.\n */}\n <span style={styles.cardSummary}>{summaryLine}</span>\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n aria-expanded={cardOpen}\n aria-controls={`dsh-subscription-card-${status.provider}`}\n onClick={toggleCardOpen}\n >\n {cardOpen ? t('collapse') : t('edit')}\n </button>\n </div>\n <div\n id={`dsh-subscription-card-${status.provider}`}\n style={cardOpen ? styles.cardBody : { ...styles.cardBody, display: 'none' }}\n >\n {connectable && !status.loggedIn && !busy && <p style={styles.statusLine}>{t('statusSignIn')}</p>}\n {status.lastError !== undefined && (\n <p className=\"dsh-subscription-error\">{t('lastError', { message: status.lastError })}</p>\n )}\n {message?.tone === 'error' && <p className=\"dsh-subscription-error\">{message.text}</p>}\n {message?.tone === 'success' && <p className=\"dsh-subscription-success\">{message.text}</p>}\n\n {accounts.map((account) => (\n <div key={account.account} style={styles.accountRow}>\n <div style={styles.accountHeader}>\n <button\n type=\"button\"\n style={styles.starButton}\n title={account.isDefault ? t('defaultBadge') : t('makeDefault')}\n aria-label={account.isDefault ? t('defaultBadge') : t('makeDefault')}\n disabled={busyAction || account.isDefault}\n onClick={() => { props.onSetDefault(account.account) }}\n >\n {account.isDefault ? '★' : '☆'}\n </button>\n <span style={styles.accountName}>{account.label}</span>\n {account.isDefault && <span style={styles.badge}>{t('defaultBadge')}</span>}\n {/* The provider refused this grant: only a new sign-in helps. */}\n {account.needsLogin === true && (\n <span style={styles.badge} title={t('accountNeedsLoginHint')}>{t('accountNeedsLogin')}</span>\n )}\n <span style={styles.statusLine}>\n {account.expired\n ? t('accountExpired')\n : t('accountExpires', { time: formatTime(account.expiresAt) })}\n </span>\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n disabled={busyAction}\n onClick={() => { props.onLogout(account.account) }}\n >\n {t('logout')}\n </button>\n </div>\n </div>\n ))}\n\n {/* A signed-out route has nothing to configure here, and listing models it\n cannot call would only invite picker entries that fail. */}\n {status.loggedIn && (\n <div style={styles.catalog}>\n <div style={styles.catalogHeader}>\n <button\n type=\"button\"\n className=\"dsh-subscription-disclosure\"\n style={styles.disclosure}\n aria-expanded={modelsOpen}\n aria-controls={`dsh-subscription-models-${status.provider}`}\n onClick={toggleModelsOpen}\n >\n <span style={styles.chevron} aria-hidden=\"true\">{modelsOpen ? '▾' : '▸'}</span>\n <span style={styles.catalogTitle}>{t('modelsTitle')}</span>\n </button>\n <span style={styles.catalogMeta}>\n {t('modelsCount', { count: models.length })}\n {' · '}\n {liveCatalog ? t('modelsLive') : t('modelsBuiltIn')}\n {hiddenCount === 0 ? '' : ` ${t('modelsHiddenCount', { count: hiddenCount })}`}\n </span>\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.pushRight}\n disabled={busyAction}\n onClick={props.onRefreshModels}\n >\n {busyAction ? t('refreshing') : t('refresh')}\n </button>\n {/* A model the endpoint serves but this build has never heard of: the\n id is published as a plain route, so a new release is usable at once. */}\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n disabled={busyAction || !connectable}\n title={t('modelsAddHint')}\n onClick={() => { setAdding((open) => !open) }}\n >\n {t('modelsAdd')}\n </button>\n </div>\n {adding && (\n <form\n style={styles.addRow}\n onSubmit={(event) => {\n event.preventDefault()\n const id = draft.trim()\n if (id.length === 0) return\n props.onAddModel(id)\n setDraft('')\n setAdding(false)\n }}\n >\n <input\n type=\"text\"\n className=\"dsh-subscription-input\"\n style={styles.addInput}\n value={draft}\n autoFocus\n spellCheck={false}\n placeholder={t('modelsAddPlaceholder')}\n aria-label={t('modelsAdd')}\n disabled={busyAction}\n onChange={(event) => { setDraft(event.target.value) }}\n />\n <button type=\"submit\" disabled={busyAction || draft.trim().length === 0}>{t('modelsAddConfirm')}</button>\n <button type=\"button\" className=\"dsh-subscription-quiet\" onClick={() => { setAdding(false); setDraft('') }}>\n {t('cancel')}\n </button>\n </form>\n )}\n {modelsOpen && (\n <div\n id={`dsh-subscription-models-${status.provider}`}\n style={styles.modelList}\n // The whole list is the drop target, so a release between two rows still\n // lands somewhere instead of being cancelled unnoticed.\n onDragOver={(event) => { drag.over(event, 0) }}\n onDrop={drag.dropAt}\n >\n {status.provider === 'auto' && <span style={styles.chainTitle}>{t('modelsAutoChain')}</span>}\n {/* Every provider lists its models the same way: a switch in front,\n the model's own metadata, and a grip to drag it in the order both\n the picker list and Auto's fallback follow. */}\n {models.map((model, index) => (\n <div\n key={model.id}\n data-model-index={index}\n draggable={!busyAction}\n style={{\n ...styles.modelRowWrap,\n ...dragFrom === index ? { opacity: 0.5 } : {},\n // The row a drop would land on, so the gesture is visible while it\n // happens rather than only in its result.\n ...dropTarget === index && dragFrom !== undefined && dragFrom !== index\n ? { boxShadow: 'inset 0 2px 0 0 var(--dsw-alias-brand-primary)' }\n : {},\n }}\n onDragStart={(event) => { drag.start(event, index) }}\n onDragEnd={drag.end}\n >\n {/* The grip is the affordance and the keyboard path; the drag\n itself starts on the row, because a <button> does not start an\n HTML5 drag reliably in Chromium. */}\n <button\n type=\"button\"\n className=\"dsh-subscription-handle\"\n disabled={busyAction}\n title={t('modelsDrag')}\n aria-label={`${t('modelsDrag')} · ${model.name}`}\n onKeyDown={(event) => { drag.key(event, index) }}\n >\n ⠿\n </button>\n <label\n style={model.visible\n ? { ...styles.modelRowGrow, cursor: 'pointer' }\n : { ...styles.modelRowGrow, cursor: 'pointer', color: 'var(--dsw-alias-label-dimmed)' }}\n title={model.visible ? t('modelsHidden') : t('modelsShow')}\n >\n <input\n type=\"checkbox\"\n className=\"dsh-subscription-switch\"\n role=\"switch\"\n checked={model.visible}\n disabled={busyAction}\n aria-label={`${t('modelsShow')} · ${model.name}`}\n onChange={(event) => { props.onSetModelVisible(model.id, event.target.checked) }}\n />\n <span style={styles.modelBody}>\n <span style={styles.modelName}>\n {model.name}\n {model.source === undefined ? null : <span style={styles.badge}>{model.source}</span>}\n </span>\n <span style={styles.modelMeta}>\n {model.id}\n {' · '}\n {t('modelsContext', { tokens: formatTokens(model.contextWindow) })}\n {model.defaultEffort === undefined ? '' : ` · ${model.defaultEffort}`}\n {model.inputModalities === undefined || model.inputModalities.length === 0\n ? ''\n : ` · ${model.inputModalities.join('/')}`}\n </span>\n </span>\n </label>\n {/* A hand-added id can be removed again, so a typo does not linger. */}\n {model.userAdded === true && (\n <button\n type=\"button\"\n className=\"dsh-subscription-quiet\"\n style={styles.removeButton}\n disabled={busyAction}\n title={t('modelsRemove')}\n aria-label={`${t('modelsRemove')} · ${model.name}`}\n onClick={() => { props.onRemoveModel(model.id) }}\n >\n ×\n </button>\n )}\n </div>\n ))}\n {models.length === 0 && (\n <p style={styles.statusLine}>\n {status.provider === 'auto' ? t('modelsAutoChainEmpty') : t('modelsEmpty')}\n </p>\n )}\n </div>\n )}\n </div>\n )}\n\n <UsageBlock\n usage={status.usage ?? []}\n {...status.usageError === undefined ? {} : { error: status.usageError }}\n t={t}\n busyAction={busyAction}\n onRefresh={props.onRefreshUsage}\n />\n\n {/* `auto` owns no account, so it offers no connect, cancel or manage. */}\n {connectable && (\n <div style={styles.actions}>\n {!busy && (\n <button type=\"button\" disabled={busyAction} onClick={props.onLogin}>\n {accounts.length === 0 ? t('connect') : t('addAccount')}\n </button>\n )}\n {!busy && (\n <button type=\"button\" disabled={busyAction} onClick={() => { setManageOpen(true) }}>\n {t('manage')}\n </button>\n )}\n {busy && (\n <button type=\"button\" disabled={busyAction} onClick={props.onCancel}>\n {t('cancel')}\n </button>\n )}\n </div>\n )}\n {connectable && accounts.length > 0 && <p style={styles.statusLine}>{t('hint')}</p>}\n\n {busy && status.pending !== undefined && (\n <PendingLogin prompt={status.pending} t={t} copied={copied} onCopy={(code) => { void copyCode(code) }} />\n )}\n </div>\n {/* The dialog stays outside the collapsible body: a hidden ancestor would\n keep it out of the top layer even after `showModal()`. */}\n <dialog\n ref={dialog}\n className=\"dsh-subscription-manager\"\n aria-labelledby={`dsh-subscription-manage-${status.provider}`}\n // A closed `<dialog>` is hidden by the user-agent stylesheet, and an\n // inline `display` would override that rule — so the open state has to\n // be restated here rather than left to `showModal()` alone.\n style={manageOpen ? styles.modal : { ...styles.modal, display: 'none' }}\n onClose={() => { setManageOpen(false) }}\n onCancel={() => { setManageOpen(false) }}\n >\n <div style={styles.modalHeader}>\n <span style={styles.modalTitle} id={`dsh-subscription-manage-${status.provider}`}>\n {t('manageTitle', { provider: status.displayName })}\n </span>\n </div>\n\n <span style={styles.statusLine}>{t('manageAccounts')}</span>\n {accounts.map((account) => (\n <div key={account.account} style={styles.accountRow}>\n <div style={styles.accountHeader}>\n <span style={styles.accountName}>{account.label}</span>\n {account.isDefault && <span style={styles.badge}>{t('defaultBadge')}</span>}\n </div>\n <div style={styles.actions}>\n <button\n type=\"button\"\n \n disabled={busyAction}\n onClick={() => { props.onRefreshToken(account.account) }}\n >\n {t('refreshToken')}\n </button>\n {!account.isDefault && (\n <button\n type=\"button\"\n \n disabled={busyAction}\n onClick={() => { props.onSetDefault(account.account) }}\n >\n {t('makeDefault')}\n </button>\n )}\n <button\n type=\"button\"\n \n disabled={busyAction}\n onClick={() => { props.onLogout(account.account) }}\n >\n {t('logout')}\n </button>\n </div>\n </div>\n ))}\n {accounts.length === 0 && <p style={styles.statusLine}>{t('statusSignedOut')}</p>}\n\n <div style={styles.divider} />\n <div style={styles.actions}>\n <button type=\"button\" disabled={busyAction} onClick={props.onReload}>\n {t('reload')}\n </button>\n </div>\n <p style={styles.statusLine}>{t('reloadHint')}</p>\n\n <div style={styles.divider} />\n <div style={styles.details}>\n {status.details.map((row) => (\n <div key={row.key} style={styles.detailRow}>\n <span>{detailLabel(t, row)}</span>\n <span style={styles.detailValue}>{row.value}</span>\n </div>\n ))}\n {status.discovered !== undefined && status.discovered.length > 0 && (\n <div style={styles.detailRow}>\n <span>{t('modelsLive')}</span>\n <span style={styles.detailValue}>{status.discovered.join(', ')}</span>\n </div>\n )}\n </div>\n\n <div className=\"dsh-subscription-dialog-actions\" style={styles.modalActions}>\n <button type=\"button\" onClick={() => { setManageOpen(false) }}>{t('close')}</button>\n </div>\n </dialog>\n </div>\n )\n}\n\n/**\n * The Subscriptions settings section.\n * @param props - section props (inject face plus the shell's `close`).\n * @returns the section content.\n */\nexport function SubscriptionsSection(props: SubscriptionsSectionProps) {\n const { call } = props\n const t = props.t ?? fallbackTranslate\n const [status, setStatus] = useState<SubscriptionStatus | undefined>(undefined)\n const [error, setError] = useState<string | undefined>(undefined)\n const [messages, setMessages] = useState<Record<string, CardMessage>>({})\n const [busyAction, setBusyAction] = useState(false)\n const mounted = useRef(true)\n const timer = useRef<ReturnType<typeof setInterval> | undefined>(undefined)\n\n /** Fetch the current state; a failure is shown rather than swallowed. */\n const refresh = useCallback(async (): Promise<void> => {\n if (call === undefined) return\n try {\n const next = await call('status', undefined)\n if (!mounted.current) return\n setStatus(next)\n setError(undefined)\n } catch (caught: unknown) {\n if (mounted.current) setError(t('actionFailed', { message: messageOf(caught) }))\n }\n }, [call, t])\n\n const stopPolling = useCallback((): void => {\n if (timer.current !== undefined) {\n clearInterval(timer.current)\n timer.current = undefined\n }\n }, [])\n\n const startPolling = useCallback((): void => {\n if (timer.current !== undefined) return\n // The node half clears `busy` once the attempt settles; the effect below\n // observes that and stops this interval.\n timer.current = setInterval(() => { void refresh() }, POLL_INTERVAL_MS)\n }, [refresh])\n\n useEffect(() => {\n mounted.current = true\n void refresh()\n return () => {\n mounted.current = false\n stopPolling()\n }\n }, [refresh, stopPolling])\n\n /** Every route worth reading, as of the latest render, for the usage poll. */\n const signedInRef = useRef<readonly string[]>([])\n useEffect(() => {\n signedInRef.current = usageTargets(status?.providers ?? [])\n })\n\n /**\n * Read each named route's plan and allowance, applying every answer.\n *\n * A read is not forced: the node half reuses a figure only for a few seconds and\n * never reuses a substitute, so a steady interval refreshes the figures while\n * collapsing bursts into one request per route.\n */\n const readUsage = useCallback(async (providers: readonly string[]): Promise<void> => {\n if (call === undefined) return\n for (const provider of providers) {\n try {\n const result = await call('usage', { provider })\n if (!mounted.current) return\n setStatus(result.status)\n } catch {\n // An unreadable quota is already surfaced inside the card by the status it\n // carries; the page itself stays usable.\n }\n }\n }, [call])\n\n // The figures are read as soon as the first status lands...\n const usageRequested = useRef(false)\n useEffect(() => {\n if (call === undefined || status === undefined || usageRequested.current) return\n const signedIn = usageTargets(status.providers)\n if (signedIn.length === 0) return\n usageRequested.current = true\n void readUsage(signedIn)\n }, [call, status, readUsage])\n\n // ...and then kept current while the page is open. Allowances move as the account\n // is used, so a figure that is only read on mount reports the state of a page that\n // may have been open for hours.\n useEffect(() => {\n if (call === undefined) return\n const tick = (): void => {\n // Nothing is refreshed for a page nobody is looking at.\n if (globalThis.document?.visibilityState === 'hidden') return\n void readUsage(signedInRef.current)\n }\n const interval = setInterval(tick, USAGE_POLL_INTERVAL_MS)\n return () => { clearInterval(interval) }\n }, [call, readUsage])\n\n // Poll only while some provider is waiting for browser approval.\n const anyBusy = status?.providers.some((provider) => provider.busy) === true\n useEffect(() => {\n if (anyBusy) startPolling()\n else stopPolling()\n }, [anyBusy, startPolling, stopPolling])\n\n /** Run one action for one provider, reporting its own failure. */\n const act = useCallback(async (provider: string, run: () => Promise<void>): Promise<void> => {\n setBusyAction(true)\n setMessages((current) => {\n const next = { ...current }\n delete next[provider]\n return next\n })\n try {\n await run()\n } catch (caught: unknown) {\n if (mounted.current) {\n setMessages((current) => ({ ...current, [provider]: { tone: 'error', text: t('actionFailed', { message: messageOf(caught) }) } }))\n }\n } finally {\n if (mounted.current) setBusyAction(false)\n }\n }, [t])\n\n const login = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const started = await call('login', { provider })\n if (!mounted.current) return\n setStatus(started.status)\n // A loopback flow wants the browser opened; a blocked popup still leaves\n // the link in the card, which is the fallback the user already has.\n if (started.prompt.mode === 'open-url') {\n window.open(started.prompt.url, '_blank', 'noopener')\n }\n })\n }, [act, call])\n\n const cancel = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('cancel', { provider })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const logout = useCallback((provider: string, account: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('logout', { provider, account })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const setDefault = useCallback((provider: string, account: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('setDefault', { provider, account })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const refreshToken = useCallback((provider: string, account: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const result = await call('refresh', { provider, account })\n if (!mounted.current) return\n setStatus(result.status)\n setMessages((current) => ({\n ...current,\n [provider]: { tone: 'success', text: t('tokenRefreshed', { time: formatTime(result.expiresAt) }) },\n }))\n })\n }, [act, call, t])\n\n const refreshModels = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('discover', { provider, force: true })\n if (!mounted.current) return\n setStatus(next)\n setMessages((current) => ({ ...current, [provider]: { tone: 'success', text: t('modelsRefreshed') } }))\n })\n }, [act, call, t])\n\n const setModelVisible = useCallback((provider: string, id: string, visible: boolean): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('setModelVisible', { provider, id, visible })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const refreshUsage = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const result = await call('usage', { provider, force: true })\n if (mounted.current) setStatus(result.status)\n })\n }, [act, call])\n\n const setModelOrder = useCallback((provider: string, ids: readonly string[]): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('setModelOrder', { provider, ids: [...ids] })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const addModel = useCallback((provider: string, id: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('addModel', { provider, id })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const removeModel = useCallback((provider: string, id: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('removeModel', { provider, id })\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n const reload = useCallback((provider: string): void => {\n if (call === undefined) return\n void act(provider, async () => {\n const next = await call('reload', undefined)\n if (mounted.current) setStatus(next)\n })\n }, [act, call])\n\n if (call === undefined) return <p style={styles.intro}>{t('unavailable')}</p>\n\n return (\n <div className=\"dsh-subscriptions-settings\" style={styles.section}>\n <style>{subscriptionsCss}</style>\n <p style={styles.intro}>{t('intro')}</p>\n {error !== undefined && <p className=\"dsh-subscription-error\">{error}</p>}\n {status === undefined && <p style={styles.statusLine}>{t('loading')}</p>}\n {status?.providers.map((provider) => (\n <ProviderCard\n key={provider.provider}\n status={provider}\n t={t}\n busyAction={busyAction}\n {...messages[provider.provider] === undefined ? {} : { message: messages[provider.provider] as CardMessage }}\n onLogin={() => { login(provider.provider) }}\n onCancel={() => { cancel(provider.provider) }}\n onLogout={(account) => { logout(provider.provider, account) }}\n onSetDefault={(account) => { setDefault(provider.provider, account) }}\n onRefreshToken={(account) => { refreshToken(provider.provider, account) }}\n onRefreshModels={() => { refreshModels(provider.provider) }}\n onSetModelVisible={(id, visible) => { setModelVisible(provider.provider, id, visible) }}\n onSetModelOrder={(ids) => { setModelOrder(provider.provider, ids) }}\n onAddModel={(id) => { addModel(provider.provider, id) }}\n onRemoveModel={(id) => { removeModel(provider.provider, id) }}\n onRefreshUsage={() => { refreshUsage(provider.provider) }}\n onReload={() => { reload(provider.provider) }}\n />\n ))}\n </div>\n )\n}\n","/**\n * Subscriptions settings page, browser half.\n *\n * Registers one `settings.section` entry titled 订阅 / Subscriptions. Every\n * connection fact arrives through the node half's `subscription-oauth` RPC\n * endpoints, so this half holds no credential state of its own, and the copy\n * rides the client locale service under the `settings.subscriptions` namespace.\n *\n * @module dsh-plugin-subscription-oauth/client\n */\n\n// Type-only: pulls the `ctx.slots` Context merge and the `settings.section`\n// SlotMap entry. These imports are erased; no runtime binding is taken.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\n\nimport { SubscriptionsSection } from './SubscriptionsSection.js'\nimport type { SubscriptionsSectionInjected } from './SubscriptionsSection.js'\nimport { createSubscriptionsCall } from './subscriptions-rpc.js'\nimport { en, zh } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\n\nexport type { SubscriptionsSectionInjected, SubscriptionsSectionProps } from './SubscriptionsSection.js'\nexport type { SubscriptionsKey } from './locales.js'\nexport { createSubscriptionsCall, SubscriptionsRpcError } from './subscriptions-rpc.js'\nexport type { SubscriptionsCall } from './subscriptions-rpc.js'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** The Subscriptions settings page copy. */\n 'settings.subscriptions': SubscriptionsKey\n }\n}\n\n/** Dictionary namespace owned by this plugin. */\nconst NS = 'settings.subscriptions'\n\n/** Settings nav position: after the shipped sections, before plugin tooling. */\nconst SECTION_ORDER = 92\n\n/**\n * Required services: `slots` carries the registration seat, `connection` the\n * RPC caller, and `locale` the copy dictionaries.\n */\nexport const inject = ['slots', 'connection', 'locale']\n\n/**\n * Register the Subscriptions settings section.\n *\n * Registration goes through `slots.inject`, so the shell's own apply order\n * relative to this one is unconstrained.\n *\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-plugin-subscription-oauth: copy dictionaries')\n // The shell's Context merge types `connection` as the host handle; in the\n // browser the same key holds the full client ConnectionHandle.\n const connection = ctx.get('connection') as unknown as ConnectionHandle\n const t = ctx.locale.bind(NS) as SubscriptionsSectionInjected['t']\n const call = createSubscriptionsCall(connection.rpc)\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'subscriptions',\n order: SECTION_ORDER,\n // A thunk re-evaluated per read, so the nav label follows the active locale.\n label: () => t('nav'),\n inject: (): SubscriptionsSectionInjected => ({ call, t }),\n }, SubscriptionsSection))\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-subscription-oauth",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Use subscription accounts as DeepSeek Harness LLM providers — Kimi Code (OAuth device flow), Grok / X Premium (OIDC + PKCE), Google Antigravity (Google OAuth + Cloud Code Assist) and GLM / BigModel (ZCode's browser sign-in) — with per-model visibility, drag-to-reorder Auto fallback and plan quotas from the web Settings page",
5
5
  "license": "MIT",
6
6
  "author": "EricFL1998",