dsh-plugin-subscription-oauth 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@
8
8
  /** English strings. */
9
9
  export declare const en: {
10
10
  readonly nav: "Subscriptions";
11
- readonly 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.";
11
+ readonly intro: "Sign in with the AI subscriptions you already pay for — no API key. Pick a provider below, connect once, and its models join the model picker with live plan usage. Tokens stay on this machine.";
12
12
  readonly loading: "Checking subscriptions…";
13
13
  readonly unavailable: "The subscriptions page needs the web connection service, which this composition does not provide.";
14
14
  readonly statusConnected: "Connected · {count} account(s)";
@@ -26,6 +26,7 @@ export declare const en: {
26
26
  readonly logout: "Sign out";
27
27
  readonly makeDefault: "Use by default";
28
28
  readonly defaultBadge: "Default";
29
+ readonly badgeLive: "Live";
29
30
  readonly accountNeedsLogin: "Sign in again";
30
31
  readonly accountNeedsLoginHint: "The provider refused this account's grant, so its token cannot be renewed";
31
32
  readonly accountExpired: "token expired";
@@ -122,6 +123,7 @@ export declare const zh: {
122
123
  logout: string;
123
124
  makeDefault: string;
124
125
  defaultBadge: string;
126
+ badgeLive: string;
125
127
  accountNeedsLogin: string;
126
128
  accountNeedsLoginHint: string;
127
129
  accountExpired: string;
@@ -8,7 +8,7 @@
8
8
  /** English strings. */
9
9
  export const en = {
10
10
  nav: 'Subscriptions',
11
- 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.',
11
+ intro: 'Sign in with the AI subscriptions you already pay for — no API key. Pick a provider below, connect once, and its models join the model picker with live plan usage. Tokens stay on this machine.',
12
12
  loading: 'Checking subscriptions…',
13
13
  unavailable: 'The subscriptions page needs the web connection service, which this composition does not provide.',
14
14
  statusConnected: 'Connected · {count} account(s)',
@@ -26,6 +26,7 @@ export const en = {
26
26
  logout: 'Sign out',
27
27
  makeDefault: 'Use by default',
28
28
  defaultBadge: 'Default',
29
+ badgeLive: 'Live',
29
30
  accountNeedsLogin: 'Sign in again',
30
31
  accountNeedsLoginHint: 'The provider refused this account\'s grant, so its token cannot be renewed',
31
32
  accountExpired: 'token expired',
@@ -102,7 +103,7 @@ export const en = {
102
103
  /** Chinese strings. */
103
104
  export const zh = {
104
105
  nav: '订阅',
105
- intro: '使用订阅账号登录 —— Kimi Code、Grok (X Premium) 或 Google Antigravity。DeepSeek Harness 将令牌保存在本机,并通过各服务自己的 API 发起请求。',
106
+ intro: '使用你已付费的 AI 订阅 —— 无需 API Key。在下方选择服务,连接一次,其模型即进入模型选择器并显示实时额度。令牌仅保存在本机。',
106
107
  loading: '正在检查订阅…',
107
108
  unavailable: '订阅页面需要 Web 连接服务,当前组合未提供该服务。',
108
109
  statusConnected: '已连接 {count} 个账号',
@@ -120,6 +121,7 @@ export const zh = {
120
121
  logout: '退出登录',
121
122
  makeDefault: '设为默认',
122
123
  defaultBadge: '默认',
124
+ badgeLive: '已连接',
123
125
  accountNeedsLogin: '需重新登录',
124
126
  accountNeedsLoginHint: '服务方已拒绝该账号的授权,令牌无法自动续期',
125
127
  accountExpired: '令牌已过期',
package/lib/client.js CHANGED
@@ -39,7 +39,7 @@ react_jsx_runtime = __toESM(react_jsx_runtime);
39
39
  /** English strings. */
40
40
  const en = {
41
41
  nav: "Subscriptions",
42
- 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.",
42
+ intro: "Sign in with the AI subscriptions you already pay for — no API key. Pick a provider below, connect once, and its models join the model picker with live plan usage. Tokens stay on this machine.",
43
43
  loading: "Checking subscriptions…",
44
44
  unavailable: "The subscriptions page needs the web connection service, which this composition does not provide.",
45
45
  statusConnected: "Connected · {count} account(s)",
@@ -57,6 +57,7 @@ const en = {
57
57
  logout: "Sign out",
58
58
  makeDefault: "Use by default",
59
59
  defaultBadge: "Default",
60
+ badgeLive: "Live",
60
61
  accountNeedsLogin: "Sign in again",
61
62
  accountNeedsLoginHint: "The provider refused this account's grant, so its token cannot be renewed",
62
63
  accountExpired: "token expired",
@@ -133,7 +134,7 @@ const en = {
133
134
  /** Chinese strings. */
134
135
  const zh = {
135
136
  nav: "订阅",
136
- intro: "使用订阅账号登录 —— Kimi Code、Grok (X Premium) 或 Google Antigravity。DeepSeek Harness 将令牌保存在本机,并通过各服务自己的 API 发起请求。",
137
+ intro: "使用你已付费的 AI 订阅 —— 无需 API Key。在下方选择服务,连接一次,其模型即进入模型选择器并显示实时额度。令牌仅保存在本机。",
137
138
  loading: "正在检查订阅…",
138
139
  unavailable: "订阅页面需要 Web 连接服务,当前组合未提供该服务。",
139
140
  statusConnected: "已连接 {count} 个账号",
@@ -151,6 +152,7 @@ const zh = {
151
152
  logout: "退出登录",
152
153
  makeDefault: "设为默认",
153
154
  defaultBadge: "默认",
155
+ badgeLive: "已连接",
154
156
  accountNeedsLogin: "需重新登录",
155
157
  accountNeedsLoginHint: "服务方已拒绝该账号的授权,令牌无法自动续期",
156
158
  accountExpired: "令牌已过期",
@@ -877,30 +879,52 @@ const styles = {
877
879
  maxWidth: SECTION_WIDTH,
878
880
  color: "var(--dsw-alias-label-primary)"
879
881
  },
882
+ sectionHeader: {
883
+ display: "flex",
884
+ flexDirection: "column",
885
+ gap: 4,
886
+ marginBottom: 2
887
+ },
888
+ heading: {
889
+ margin: 0,
890
+ fontSize: 18,
891
+ lineHeight: "26px",
892
+ fontWeight: 600,
893
+ color: "var(--dsw-alias-label-primary)"
894
+ },
880
895
  intro: {
881
896
  margin: 0,
882
897
  color: "var(--dsw-alias-label-tertiary)",
883
- fontSize: 14,
884
- lineHeight: "22px"
898
+ fontSize: 13,
899
+ lineHeight: "20px",
900
+ maxWidth: 560
885
901
  },
886
902
  card: {
887
903
  border: "0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))",
888
- borderRadius: "var(--dsw-radius-xl, 20px)",
904
+ borderRadius: "var(--dsw-radius-xl, 16px)",
889
905
  background: "var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))",
890
- padding: "12px 14px",
906
+ padding: "14px 16px",
891
907
  display: "flex",
892
908
  flexDirection: "column",
893
- gap: 6
909
+ gap: 8,
910
+ transition: "border-color 120ms ease, background 120ms ease"
911
+ },
912
+ cardOpen: {
913
+ borderColor: "var(--dsw-alias-border-l2, var(--dsw-alias-border-l3))",
914
+ background: "var(--dsw-alias-settings-card-fill-hover, var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2)))"
894
915
  },
895
916
  cardHeader: {
896
917
  display: "flex",
897
918
  alignItems: "center",
898
- gap: 8
919
+ gap: 10,
920
+ cursor: "pointer",
921
+ userSelect: "none"
899
922
  },
900
923
  cardBody: {
901
924
  display: "flex",
902
925
  flexDirection: "column",
903
- gap: 6
926
+ gap: 10,
927
+ marginTop: 2
904
928
  },
905
929
  cardSummary: {
906
930
  fontSize: 12,
@@ -911,18 +935,23 @@ const styles = {
911
935
  width: 8,
912
936
  height: 8,
913
937
  borderRadius: "50%",
914
- flexShrink: 0
938
+ flexShrink: 0,
939
+ boxShadow: "0 0 0 3px var(--dsw-alias-state-success-primary, transparent)"
915
940
  },
916
941
  name: {
917
- fontWeight: 500,
942
+ fontWeight: 600,
918
943
  fontSize: 14,
919
944
  lineHeight: "22px",
920
945
  color: "var(--dsw-alias-label-primary)"
921
946
  },
922
947
  providerId: {
923
- fontSize: 12,
924
- lineHeight: "18px",
925
- color: "var(--dsw-alias-label-dimmed)"
948
+ fontSize: 11,
949
+ lineHeight: "16px",
950
+ color: "var(--dsw-alias-label-dimmed)",
951
+ padding: "1px 6px",
952
+ borderRadius: 999,
953
+ background: "var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-1))",
954
+ fontFamily: "monospace"
926
955
  },
927
956
  statusLine: {
928
957
  margin: 0,
@@ -954,9 +983,9 @@ const styles = {
954
983
  flexDirection: "column",
955
984
  gap: 6,
956
985
  border: "0.5px solid var(--dsw-alias-border-l2)",
957
- borderRadius: "var(--dsw-radius-lg, 16px)",
958
- padding: "8px 10px",
959
- marginTop: 4
986
+ borderRadius: "var(--dsw-radius-lg, 12px)",
987
+ padding: "10px 12px",
988
+ background: "var(--dsw-alias-bg-layer-1)"
960
989
  },
961
990
  accountHeader: {
962
991
  display: "flex",
@@ -982,14 +1011,33 @@ const styles = {
982
1011
  userSelect: "all"
983
1012
  },
984
1013
  badge: {
985
- fontSize: 11,
986
- lineHeight: "16px",
987
- padding: "0 6px",
988
- borderRadius: 8,
989
- background: "var(--dsw-alias-bg-layer-1)",
1014
+ fontSize: 10,
1015
+ lineHeight: "14px",
1016
+ padding: "1px 7px",
1017
+ borderRadius: 999,
1018
+ fontWeight: 500,
1019
+ background: "var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-1))",
990
1020
  border: "0.5px solid var(--dsw-alias-border-l2)",
991
1021
  color: "var(--dsw-alias-label-secondary)"
992
1022
  },
1023
+ badgeDefault: {
1024
+ fontSize: 10,
1025
+ lineHeight: "14px",
1026
+ padding: "1px 7px",
1027
+ borderRadius: 999,
1028
+ fontWeight: 500,
1029
+ background: "var(--dsw-alias-state-success-primary, #067647)",
1030
+ color: "var(--dsw-alias-label-primary-foreground, #fff)"
1031
+ },
1032
+ badgeWarn: {
1033
+ fontSize: 10,
1034
+ lineHeight: "14px",
1035
+ padding: "1px 7px",
1036
+ borderRadius: 999,
1037
+ fontWeight: 500,
1038
+ background: "var(--dsw-alias-state-warn-primary, #f5a524)",
1039
+ color: "var(--dsw-alias-label-primary-foreground, #fff)"
1040
+ },
993
1041
  pushRight: {
994
1042
  marginLeft: "auto",
995
1043
  flexShrink: 0
@@ -1097,10 +1145,10 @@ const styles = {
1097
1145
  usage: {
1098
1146
  display: "flex",
1099
1147
  flexDirection: "column",
1100
- gap: 6,
1101
- marginTop: 4,
1148
+ gap: 8,
1149
+ marginTop: 2,
1102
1150
  borderTop: "0.5px solid var(--dsw-alias-border-l2)",
1103
- paddingTop: 8
1151
+ paddingTop: 10
1104
1152
  },
1105
1153
  usageHeader: {
1106
1154
  display: "flex",
@@ -1111,7 +1159,7 @@ const styles = {
1111
1159
  usageRow: {
1112
1160
  display: "flex",
1113
1161
  flexDirection: "column",
1114
- gap: 3
1162
+ gap: 4
1115
1163
  },
1116
1164
  usageLine: {
1117
1165
  display: "flex",
@@ -1123,7 +1171,17 @@ const styles = {
1123
1171
  height: 6,
1124
1172
  borderRadius: 999,
1125
1173
  background: "var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2))",
1126
- overflow: "hidden"
1174
+ overflow: "hidden",
1175
+ boxShadow: "inset 0 0 0 1px #8a8f9833"
1176
+ },
1177
+ usageAccount: {
1178
+ display: "flex",
1179
+ flexDirection: "column",
1180
+ gap: 6,
1181
+ padding: "8px 10px",
1182
+ borderRadius: "var(--dsw-radius-md, 10px)",
1183
+ background: "var(--dsw-alias-bg-layer-1)",
1184
+ border: "0.5px solid var(--dsw-alias-border-l2)"
1127
1185
  },
1128
1186
  modelRow: {
1129
1187
  display: "flex",
@@ -1284,7 +1342,7 @@ function UsageBlock(props) {
1284
1342
  children: t("usageNone")
1285
1343
  }),
1286
1344
  usage.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1287
- style: styles.usageRow,
1345
+ style: styles.usageAccount,
1288
1346
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1289
1347
  style: styles.usageLine,
1290
1348
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -1522,10 +1580,23 @@ function ProviderCard(props) {
1522
1580
  */
1523
1581
  const summaryLine = !connectable ? t("statusAuto", { count: models.filter((model) => model.visible).length }) : busy ? t("statusBusy") : status.loggedIn ? t("statusConnected", { count: accounts.length }) : t("statusSignedOut");
1524
1582
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1525
- style: styles.card,
1583
+ style: cardOpen ? {
1584
+ ...styles.card,
1585
+ ...styles.cardOpen
1586
+ } : styles.card,
1526
1587
  children: [
1527
1588
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1528
1589
  style: styles.cardHeader,
1590
+ role: "button",
1591
+ tabIndex: 0,
1592
+ "aria-expanded": cardOpen,
1593
+ onClick: toggleCardOpen,
1594
+ onKeyDown: (event) => {
1595
+ if (event.key === "Enter" || event.key === " ") {
1596
+ event.preventDefault();
1597
+ toggleCardOpen();
1598
+ }
1599
+ },
1529
1600
  children: [
1530
1601
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1531
1602
  style: {
@@ -1542,6 +1613,10 @@ function ProviderCard(props) {
1542
1613
  style: styles.providerId,
1543
1614
  children: status.provider
1544
1615
  }),
1616
+ status.loggedIn && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1617
+ style: styles.badgeDefault,
1618
+ children: t("badgeLive")
1619
+ }),
1545
1620
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1546
1621
  style: styles.cardSummary,
1547
1622
  children: summaryLine
@@ -1552,7 +1627,10 @@ function ProviderCard(props) {
1552
1627
  style: styles.pushRight,
1553
1628
  "aria-expanded": cardOpen,
1554
1629
  "aria-controls": `dsh-subscription-card-${status.provider}`,
1555
- onClick: toggleCardOpen,
1630
+ onClick: (event) => {
1631
+ event.stopPropagation();
1632
+ toggleCardOpen();
1633
+ },
1556
1634
  children: cardOpen ? t("collapse") : t("edit")
1557
1635
  })
1558
1636
  ]
@@ -1601,11 +1679,11 @@ function ProviderCard(props) {
1601
1679
  children: account.label
1602
1680
  }),
1603
1681
  account.isDefault && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1604
- style: styles.badge,
1682
+ style: styles.badgeDefault,
1605
1683
  children: t("defaultBadge")
1606
1684
  }),
1607
1685
  account.needsLogin === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1608
- style: styles.badge,
1686
+ style: styles.badgeWarn,
1609
1687
  title: t("accountNeedsLoginHint"),
1610
1688
  children: t("accountNeedsLogin")
1611
1689
  }),
@@ -2079,6 +2157,20 @@ function SubscriptionsSection(props) {
2079
2157
  startPolling,
2080
2158
  stopPolling
2081
2159
  ]);
2160
+ /**
2161
+ * Signed-in providers read first: a route with a live account is the one a
2162
+ * reader most likely wants, and `auto` (which owns no account) leads the rest.
2163
+ * The sort is stable, so equal ranks keep the host's configured order.
2164
+ */
2165
+ const orderedProviders = (0, react.useMemo)(() => {
2166
+ const providers = status?.providers ?? [];
2167
+ const rank = (provider) => {
2168
+ if (provider.provider === "auto") return 0;
2169
+ if (provider.loggedIn) return 1;
2170
+ return 2;
2171
+ };
2172
+ return [...providers].sort((left, right) => rank(left) - rank(right));
2173
+ }, [status?.providers]);
2082
2174
  /** Run one action for one provider, reporting its own failure. */
2083
2175
  const act = (0, react.useCallback)(async (provider, run) => {
2084
2176
  setBusyAction(true);
@@ -2248,9 +2340,15 @@ function SubscriptionsSection(props) {
2248
2340
  style: styles.section,
2249
2341
  children: [
2250
2342
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: subscriptionsCss }),
2251
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2252
- style: styles.intro,
2253
- children: t("intro")
2343
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2344
+ style: styles.sectionHeader,
2345
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
2346
+ style: styles.heading,
2347
+ children: t("nav")
2348
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2349
+ style: styles.intro,
2350
+ children: t("intro")
2351
+ })]
2254
2352
  }),
2255
2353
  error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2256
2354
  className: "dsh-subscription-error",
@@ -2260,7 +2358,7 @@ function SubscriptionsSection(props) {
2260
2358
  style: styles.statusLine,
2261
2359
  children: t("loading")
2262
2360
  }),
2263
- status?.providers.map((provider) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderCard, {
2361
+ orderedProviders.map((provider) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderCard, {
2264
2362
  status: provider,
2265
2363
  t,
2266
2364
  busyAction,