dsh-plugin-subscription-oauth 0.11.0 → 0.12.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/lib/client.js CHANGED
@@ -91,6 +91,7 @@ const en = {
91
91
  modelsDrag: "Drag to re-order (or press ↑ / ↓ here)",
92
92
  modelsAutoChainOff: "Take out of Auto",
93
93
  modelsAutoChainEmpty: "No model is enabled, so Auto has nothing to try.",
94
+ autoSwitchLabel: "Offer Auto in the model picker",
94
95
  modelsPinned: "pinned",
95
96
  usageTitle: "Plan and usage",
96
97
  usagePlan: "Plan: {plan}",
@@ -186,6 +187,7 @@ const zh = {
186
187
  modelsDrag: "拖动调整顺序(也可在此按 ↑ / ↓)",
187
188
  modelsAutoChainOff: "从自动中移除",
188
189
  modelsAutoChainEmpty: "没有启用任何模型,自动没有可尝试的模型。",
190
+ autoSwitchLabel: "在模型选择器中提供 Auto",
189
191
  modelsPinned: "固定",
190
192
  usageTitle: "套餐与额度",
191
193
  usagePlan: "套餐:{plan}",
@@ -936,7 +938,16 @@ const styles = {
936
938
  height: 8,
937
939
  borderRadius: "50%",
938
940
  flexShrink: 0,
939
- boxShadow: "0 0 0 3px var(--dsw-alias-state-success-primary, transparent)"
941
+ border: "1.5px solid var(--dsw-alias-label-dimmed)",
942
+ background: "transparent"
943
+ },
944
+ dotLive: {
945
+ borderColor: "var(--dsw-alias-state-success-primary, #067647)",
946
+ background: "var(--dsw-alias-state-success-primary, #067647)"
947
+ },
948
+ dotBusy: {
949
+ borderColor: "var(--dsw-alias-state-warn-primary, #f5a524)",
950
+ background: "var(--dsw-alias-state-warn-primary, #f5a524)"
940
951
  },
941
952
  name: {
942
953
  fontWeight: 600,
@@ -944,15 +955,6 @@ const styles = {
944
955
  lineHeight: "22px",
945
956
  color: "var(--dsw-alias-label-primary)"
946
957
  },
947
- providerId: {
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"
955
- },
956
958
  statusLine: {
957
959
  margin: 0,
958
960
  fontSize: 12,
@@ -1183,6 +1185,18 @@ const styles = {
1183
1185
  background: "var(--dsw-alias-bg-layer-1)",
1184
1186
  border: "0.5px solid var(--dsw-alias-border-l2)"
1185
1187
  },
1188
+ usageInline: {
1189
+ display: "flex",
1190
+ flexDirection: "column",
1191
+ gap: 6,
1192
+ marginTop: 4
1193
+ },
1194
+ autoSwitchRow: {
1195
+ display: "flex",
1196
+ alignItems: "center",
1197
+ gap: 8,
1198
+ justifyContent: "space-between"
1199
+ },
1186
1200
  modelRow: {
1187
1201
  display: "flex",
1188
1202
  alignItems: "flex-start",
@@ -1291,11 +1305,11 @@ const styles = {
1291
1305
  },
1292
1306
  divider: { borderTop: "0.5px solid var(--dsw-alias-border-l2)" }
1293
1307
  };
1294
- /** Status dot color for one provider's connection state. */
1295
- function dotColor(status) {
1296
- if (status.busy) return "var(--dsw-alias-state-warn-label)";
1297
- if (status.loggedIn) return "var(--dsw-alias-state-success-primary)";
1298
- return "var(--dsw-alias-label-dimmed)";
1308
+ /** Status dot style for one provider's connection state. */
1309
+ function dotStyle(status) {
1310
+ if (status.busy) return styles.dotBusy;
1311
+ if (status.loggedIn) return styles.dotLive;
1312
+ return {};
1299
1313
  }
1300
1314
  /** Localized label for one provider-owned detail row. */
1301
1315
  function detailLabel(t, row) {
@@ -1313,70 +1327,38 @@ function windowAmount(window$1) {
1313
1327
  if (window$1.used !== void 0 && window$1.limit !== void 0) return `${String(window$1.used)}/${String(window$1.limit)}`;
1314
1328
  return "—";
1315
1329
  }
1316
- /** One account's plan and metered allowances. */
1317
- function UsageBlock(props) {
1318
- const { usage, error, t, busyAction, onRefresh } = props;
1330
+ /** One account's metered windows, rendered under its account row. */
1331
+ function AccountUsage(props) {
1332
+ const { entry, t } = props;
1333
+ if (entry === void 0) return null;
1319
1334
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1320
- style: styles.usage,
1321
- children: [
1322
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1323
- style: styles.usageHeader,
1324
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1325
- style: styles.catalogTitle,
1326
- children: t("usageTitle")
1327
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1328
- type: "button",
1329
- className: "dsh-subscription-quiet",
1330
- style: styles.pushRight,
1331
- disabled: busyAction,
1332
- onClick: onRefresh,
1333
- children: busyAction ? t("refreshing") : t("usageRefresh")
1335
+ style: styles.usageInline,
1336
+ children: [entry.windows.map((window$1) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1337
+ style: styles.usageRow,
1338
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1339
+ style: styles.usageLine,
1340
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1341
+ style: styles.modelName,
1342
+ children: [
1343
+ windowLabel(t, window$1),
1344
+ " · ",
1345
+ windowAmount(window$1)
1346
+ ]
1347
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1348
+ style: styles.modelMeta,
1349
+ children: window$1.resetsAt === void 0 ? "" : formatReset$1(window$1.resetsAt, t)
1334
1350
  })]
1335
- }),
1336
- error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1337
- className: "dsh-subscription-error",
1338
- children: t("usageError", { message: error })
1339
- }),
1340
- usage.length === 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1341
- style: styles.statusLine,
1342
- children: t("usageNone")
1343
- }),
1344
- usage.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1345
- style: styles.usageAccount,
1346
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1347
- style: styles.usageLine,
1348
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1349
- style: styles.modelMeta,
1350
- children: [entry.plan === void 0 ? entry.account : t("usagePlan", { plan: entry.plan }), entry.renewsAt === void 0 ? "" : ` · ${t("usageRenews", { time: formatTime(entry.renewsAt) })}`]
1351
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1352
- style: styles.modelMeta,
1353
- children: t("usageFetched", { time: formatTime(entry.fetchedAt) })
1354
- })]
1355
- }), entry.windows.map((window$1) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1356
- style: styles.usageRow,
1357
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1358
- style: styles.usageLine,
1359
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1360
- style: styles.modelName,
1361
- children: [
1362
- windowLabel(t, window$1),
1363
- " · ",
1364
- windowAmount(window$1)
1365
- ]
1366
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1367
- style: styles.modelMeta,
1368
- children: window$1.resetsAt === void 0 ? "" : formatReset$1(window$1.resetsAt, t)
1369
- })]
1370
- }), window$1.usedPercent !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1371
- className: "dsh-subscription-meter",
1372
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1373
- style: { width: `${String(Math.min(100, Math.max(0, window$1.usedPercent)))}%` },
1374
- "data-exhausted": window$1.usedPercent >= 90 ? "true" : "false"
1375
- })
1376
- })]
1377
- }, `${entry.account}-${window$1.label}`))]
1378
- }, entry.account))
1379
- ]
1351
+ }), window$1.usedPercent !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1352
+ className: "dsh-subscription-meter",
1353
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1354
+ style: { width: `${String(Math.min(100, Math.max(0, window$1.usedPercent)))}%` },
1355
+ "data-exhausted": window$1.usedPercent >= 90 ? "true" : "false"
1356
+ })
1357
+ })]
1358
+ }, `${entry.account}-${window$1.label}`)), entry.windows.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1359
+ style: styles.statusLine,
1360
+ children: t("usageNone")
1361
+ })]
1380
1362
  });
1381
1363
  }
1382
1364
  /** The pending-login block: a device code, or a link to the sign-in page. */
@@ -1601,7 +1583,7 @@ function ProviderCard(props) {
1601
1583
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1602
1584
  style: {
1603
1585
  ...styles.dot,
1604
- background: dotColor(status)
1586
+ ...dotStyle(status)
1605
1587
  },
1606
1588
  "aria-hidden": "true"
1607
1589
  }),
@@ -1609,10 +1591,6 @@ function ProviderCard(props) {
1609
1591
  style: styles.name,
1610
1592
  children: status.displayName
1611
1593
  }),
1612
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1613
- style: styles.providerId,
1614
- children: status.provider
1615
- }),
1616
1594
  status.loggedIn && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1617
1595
  style: styles.badgeDefault,
1618
1596
  children: t("badgeLive")
@@ -1658,52 +1636,77 @@ function ProviderCard(props) {
1658
1636
  className: "dsh-subscription-success",
1659
1637
  children: message.text
1660
1638
  }),
1661
- accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1662
- style: styles.accountRow,
1663
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1664
- style: styles.accountHeader,
1665
- children: [
1666
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1667
- type: "button",
1668
- style: styles.starButton,
1669
- title: account.isDefault ? t("defaultBadge") : t("makeDefault"),
1670
- "aria-label": account.isDefault ? t("defaultBadge") : t("makeDefault"),
1671
- disabled: busyAction || account.isDefault,
1672
- onClick: () => {
1673
- props.onSetDefault(account.account);
1674
- },
1675
- children: account.isDefault ? "★" : "☆"
1676
- }),
1677
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1678
- style: styles.accountName,
1679
- children: account.label
1680
- }),
1681
- account.isDefault && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1682
- style: styles.badgeDefault,
1683
- children: t("defaultBadge")
1684
- }),
1685
- account.needsLogin === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1686
- style: styles.badgeWarn,
1687
- title: t("accountNeedsLoginHint"),
1688
- children: t("accountNeedsLogin")
1689
- }),
1690
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1691
- style: styles.statusLine,
1692
- children: account.expired ? t("accountExpired") : t("accountExpires", { time: formatTime(account.expiresAt) })
1693
- }),
1694
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1695
- type: "button",
1696
- className: "dsh-subscription-quiet",
1697
- style: styles.pushRight,
1698
- disabled: busyAction,
1699
- onClick: () => {
1700
- props.onLogout(account.account);
1701
- },
1702
- children: t("logout")
1703
- })
1704
- ]
1705
- })
1706
- }, account.account)),
1639
+ status.provider === "auto" && props.onSetAutoOn !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1640
+ style: styles.autoSwitchRow,
1641
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1642
+ style: styles.modelName,
1643
+ children: t("autoSwitchLabel")
1644
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1645
+ type: "checkbox",
1646
+ className: "dsh-subscription-switch",
1647
+ checked: props.autoOn ?? true,
1648
+ disabled: busyAction,
1649
+ onChange: (event) => {
1650
+ props.onSetAutoOn?.(event.target.checked);
1651
+ }
1652
+ })]
1653
+ }),
1654
+ accounts.map((account) => {
1655
+ const usageEntry = (status.usage ?? []).find((entry) => entry.account === account.account);
1656
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1657
+ style: styles.accountRow,
1658
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1659
+ style: styles.accountHeader,
1660
+ children: [
1661
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1662
+ type: "button",
1663
+ style: styles.starButton,
1664
+ title: account.isDefault ? t("defaultBadge") : t("makeDefault"),
1665
+ "aria-label": account.isDefault ? t("defaultBadge") : t("makeDefault"),
1666
+ disabled: busyAction || account.isDefault,
1667
+ onClick: () => {
1668
+ props.onSetDefault(account.account);
1669
+ },
1670
+ children: account.isDefault ? "★" : "☆"
1671
+ }),
1672
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1673
+ style: styles.accountName,
1674
+ children: account.label
1675
+ }),
1676
+ account.isDefault && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1677
+ style: styles.badgeDefault,
1678
+ children: t("defaultBadge")
1679
+ }),
1680
+ account.needsLogin === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1681
+ style: styles.badgeWarn,
1682
+ title: t("accountNeedsLoginHint"),
1683
+ children: t("accountNeedsLogin")
1684
+ }),
1685
+ usageEntry?.plan !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1686
+ style: styles.badge,
1687
+ children: t("usagePlan", { plan: usageEntry.plan })
1688
+ }),
1689
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1690
+ style: styles.statusLine,
1691
+ children: account.expired ? t("accountExpired") : t("accountExpires", { time: formatTime(account.expiresAt) })
1692
+ }),
1693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1694
+ type: "button",
1695
+ className: "dsh-subscription-quiet",
1696
+ style: styles.pushRight,
1697
+ disabled: busyAction,
1698
+ onClick: () => {
1699
+ props.onLogout(account.account);
1700
+ },
1701
+ children: t("logout")
1702
+ })
1703
+ ]
1704
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountUsage, {
1705
+ entry: usageEntry,
1706
+ t
1707
+ })]
1708
+ }, account.account);
1709
+ }),
1707
1710
  status.loggedIn && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1708
1711
  style: styles.catalog,
1709
1712
  children: [
@@ -1894,13 +1897,6 @@ function ProviderCard(props) {
1894
1897
  })
1895
1898
  ]
1896
1899
  }),
1897
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBlock, {
1898
- usage: status.usage ?? [],
1899
- ...status.usageError === void 0 ? {} : { error: status.usageError },
1900
- t,
1901
- busyAction,
1902
- onRefresh: props.onRefreshUsage
1903
- }),
1904
1900
  connectable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1905
1901
  style: styles.actions,
1906
1902
  children: [
@@ -2071,8 +2067,20 @@ function SubscriptionsSection(props) {
2071
2067
  const [error, setError] = (0, react.useState)(void 0);
2072
2068
  const [messages, setMessages] = (0, react.useState)({});
2073
2069
  const [busyAction, setBusyAction] = (0, react.useState)(false);
2070
+ const [autoOn, setAutoOn] = (0, react.useState)(true);
2074
2071
  const mounted = (0, react.useRef)(true);
2075
2072
  const timer = (0, react.useRef)(void 0);
2073
+ /** Read whether the `auto` provider is offered, so its card can render the switch. */
2074
+ (0, react.useEffect)(() => {
2075
+ if (call === void 0) return;
2076
+ let live = true;
2077
+ call("auto-state", void 0).then((result) => {
2078
+ if (live) setAutoOn(result.enabled);
2079
+ }).catch(() => {});
2080
+ return () => {
2081
+ live = false;
2082
+ };
2083
+ }, [call]);
2076
2084
  /** Fetch the current state; a failure is shown rather than swallowed. */
2077
2085
  const refresh = (0, react.useCallback)(async () => {
2078
2086
  if (call === void 0) return;
@@ -2085,6 +2093,25 @@ function SubscriptionsSection(props) {
2085
2093
  if (mounted.current) setError(t("actionFailed", { message: messageOf(caught) }));
2086
2094
  }
2087
2095
  }, [call, t]);
2096
+ /** Flip the `auto` provider on or off. */
2097
+ const setAuto = (0, react.useCallback)(async (enabled) => {
2098
+ if (call === void 0) return;
2099
+ setBusyAction(true);
2100
+ try {
2101
+ const result = await call("setAutoOn", { enabled });
2102
+ if (!mounted.current) return;
2103
+ setAutoOn(result.enabled);
2104
+ await refresh();
2105
+ } catch (caught) {
2106
+ if (mounted.current) setError(t("actionFailed", { message: messageOf(caught) }));
2107
+ } finally {
2108
+ if (mounted.current) setBusyAction(false);
2109
+ }
2110
+ }, [
2111
+ call,
2112
+ refresh,
2113
+ t
2114
+ ]);
2088
2115
  const stopPolling = (0, react.useCallback)(() => {
2089
2116
  if (timer.current !== void 0) {
2090
2117
  clearInterval(timer.current);
@@ -2398,6 +2425,12 @@ function SubscriptionsSection(props) {
2398
2425
  },
2399
2426
  onReload: () => {
2400
2427
  reload(provider.provider);
2428
+ },
2429
+ ...provider.provider !== "auto" ? {} : {
2430
+ autoOn,
2431
+ onSetAutoOn: (enabled) => {
2432
+ setAuto(enabled);
2433
+ }
2401
2434
  }
2402
2435
  }, provider.provider))
2403
2436
  ]
@@ -2566,10 +2599,16 @@ function mergeAccountWindows(readings) {
2566
2599
  const withPercent = list.filter((window$1) => window$1.usedPercent !== void 0);
2567
2600
  if (withPercent.length === 0) continue;
2568
2601
  const usedPercent = withPercent.reduce((sum, window$1) => sum + (window$1.usedPercent ?? 0), 0) / withPercent.length;
2602
+ const used = list.reduce((sum, window$1) => sum + (window$1.used ?? 0), 0);
2603
+ const limit = list.reduce((sum, window$1) => sum + (window$1.limit ?? 0), 0);
2569
2604
  const resets = list.map((window$1) => window$1.resetsAt).filter((at) => typeof at === "number");
2570
2605
  merged.push({
2571
2606
  label,
2572
2607
  usedPercent: Math.max(0, Math.min(100, usedPercent)),
2608
+ ...limit > 0 ? {
2609
+ used,
2610
+ limit
2611
+ } : {},
2573
2612
  ...resets.length === 0 ? {} : { resetsAt: Math.min(...resets) }
2574
2613
  });
2575
2614
  }
@@ -2826,7 +2865,7 @@ function UsageChip({ call, t, isOwnProvider, accountBalance, ccSwitchBalance, us
2826
2865
  children: shortWindow(window$1.label)
2827
2866
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2828
2867
  className: "dsh-subscription-usage-chip-value",
2829
- children: `${String(Math.round(window$1.usedPercent ?? 0))}%`
2868
+ children: window$1.used !== void 0 && window$1.limit !== void 0 ? `${String(window$1.used)}/${String(window$1.limit)}` : `${String(Math.round(window$1.usedPercent ?? 0))}%`
2830
2869
  })]
2831
2870
  }, window$1.label))]
2832
2871
  }),