dsh-plugin-subscriptions 0.5.0 → 0.5.1

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.
@@ -19,6 +19,10 @@ export declare const en: {
19
19
  manualPlaceholder: string;
20
20
  submit: string;
21
21
  loginMissingUrl: string;
22
+ deviceCodePrompt: string;
23
+ deviceCodeCopy: string;
24
+ deviceCodeCopied: string;
25
+ deviceCodeOpenPage: string;
22
26
  usageTitle: string;
23
27
  usageRefresh: string;
24
28
  usageLoading: string;
@@ -68,6 +72,10 @@ export declare const zh: {
68
72
  manualPlaceholder: string;
69
73
  submit: string;
70
74
  loginMissingUrl: string;
75
+ deviceCodePrompt: string;
76
+ deviceCodeCopy: string;
77
+ deviceCodeCopied: string;
78
+ deviceCodeOpenPage: string;
71
79
  usageTitle: string;
72
80
  usageRefresh: string;
73
81
  usageLoading: string;
@@ -19,6 +19,10 @@ export const en = {
19
19
  manualPlaceholder: 'Paste the callback URL or code',
20
20
  submit: 'Submit',
21
21
  loginMissingUrl: 'login answered without an authorizeUrl',
22
+ deviceCodePrompt: 'Enter this code on the GitHub verification page:',
23
+ deviceCodeCopy: 'Copy code',
24
+ deviceCodeCopied: 'Copied',
25
+ deviceCodeOpenPage: 'Open GitHub verification page',
22
26
  usageTitle: 'Usage',
23
27
  usageRefresh: 'Refresh',
24
28
  usageLoading: 'Loading usage…',
@@ -68,6 +72,10 @@ export const zh = {
68
72
  manualPlaceholder: '粘贴回调 URL 或授权码',
69
73
  submit: '提交',
70
74
  loginMissingUrl: 'login 响应缺少 authorizeUrl',
75
+ deviceCodePrompt: '在 GitHub 验证页面输入此验证码:',
76
+ deviceCodeCopy: '复制验证码',
77
+ deviceCodeCopied: '已复制',
78
+ deviceCodeOpenPage: '打开 GitHub 验证页面',
71
79
  usageTitle: '用量',
72
80
  usageRefresh: '刷新',
73
81
  usageLoading: '用量加载中…',
package/lib/client.js CHANGED
@@ -52,6 +52,10 @@ const en = {
52
52
  manualPlaceholder: "Paste the callback URL or code",
53
53
  submit: "Submit",
54
54
  loginMissingUrl: "login answered without an authorizeUrl",
55
+ deviceCodePrompt: "Enter this code on the GitHub verification page:",
56
+ deviceCodeCopy: "Copy code",
57
+ deviceCodeCopied: "Copied",
58
+ deviceCodeOpenPage: "Open GitHub verification page",
55
59
  usageTitle: "Usage",
56
60
  usageRefresh: "Refresh",
57
61
  usageLoading: "Loading usage…",
@@ -101,6 +105,10 @@ const zh = {
101
105
  manualPlaceholder: "粘贴回调 URL 或授权码",
102
106
  submit: "提交",
103
107
  loginMissingUrl: "login 响应缺少 authorizeUrl",
108
+ deviceCodePrompt: "在 GitHub 验证页面输入此验证码:",
109
+ deviceCodeCopy: "复制验证码",
110
+ deviceCodeCopied: "已复制",
111
+ deviceCodeOpenPage: "打开 GitHub 验证页面",
104
112
  usageTitle: "用量",
105
113
  usageRefresh: "刷新",
106
114
  usageLoading: "用量加载中…",
@@ -150,6 +158,10 @@ const PROVIDERS = [
150
158
  {
151
159
  id: "grok",
152
160
  name: "Grok (X Premium)"
161
+ },
162
+ {
163
+ id: "copilot",
164
+ name: "GitHub Copilot"
153
165
  }
154
166
  ];
155
167
  /** Business error returned by the `/subscriptions-auth` channel (error branch message). */
@@ -350,6 +362,24 @@ const styles$4 = {
350
362
  lineHeight: "22px",
351
363
  background: "var(--dsw-alias-bg-layer-1)",
352
364
  color: "var(--dsw-alias-label-primary)"
365
+ },
366
+ deviceCode: {
367
+ marginTop: 4,
368
+ display: "flex",
369
+ flexDirection: "column",
370
+ gap: 6,
371
+ border: "1px solid var(--dsw-alias-border-l2)",
372
+ borderRadius: 8,
373
+ padding: "10px 12px",
374
+ background: "var(--dsw-alias-bg-layer-1)"
375
+ },
376
+ deviceCodeText: {
377
+ fontFamily: "monospace",
378
+ fontSize: 18,
379
+ lineHeight: "24px",
380
+ letterSpacing: 2,
381
+ color: "var(--dsw-alias-label-primary)",
382
+ userSelect: "all"
353
383
  }
354
384
  };
355
385
  /** Status dot color for one provider state. */
@@ -407,8 +437,12 @@ function SubscriptionsSection(props) {
407
437
  const [manualDrafts, setManualDrafts] = (0, react.useState)({
408
438
  codex: "",
409
439
  claude: "",
410
- grok: ""
440
+ grok: "",
441
+ copilot: ""
411
442
  });
443
+ /** Pending device-flow codes (copilot), shown while the attempt polls. */
444
+ const [deviceCodes, setDeviceCodes] = (0, react.useState)({});
445
+ const [copiedCode, setCopiedCode] = (0, react.useState)(void 0);
412
446
  const [usages, setUsages] = (0, react.useState)({});
413
447
  const [usageErrors, setUsageErrors] = (0, react.useState)({});
414
448
  const [usageLoading, setUsageLoading] = (0, react.useState)({});
@@ -445,7 +479,15 @@ function SubscriptionsSection(props) {
445
479
  setStatuses(response.providers);
446
480
  for (const { id } of PROVIDERS) {
447
481
  const status = response.providers[id];
448
- if (status.loggedIn || !status.busy) stopPolling(id);
482
+ if (status.loggedIn || !status.busy) {
483
+ stopPolling(id);
484
+ setDeviceCodes((prev) => {
485
+ if (prev[id] === void 0) return prev;
486
+ const next = { ...prev };
487
+ delete next[id];
488
+ return next;
489
+ });
490
+ }
449
491
  }
450
492
  }, [rpc, stopPolling]);
451
493
  const startPolling = (0, react.useCallback)((provider) => {
@@ -536,7 +578,6 @@ function SubscriptionsSection(props) {
536
578
  return;
537
579
  }
538
580
  if (typeof response.authorizeUrl !== "string") throw new SubscriptionsAuthError(t("loginMissingUrl"));
539
- window.open(response.authorizeUrl, "_blank", "noopener");
540
581
  if (!mountedRef.current) return;
541
582
  setStatuses((prev) => ({
542
583
  ...prev,
@@ -546,6 +587,14 @@ function SubscriptionsSection(props) {
546
587
  loggedIn: false
547
588
  }
548
589
  }));
590
+ if (typeof response.userCode === "string" && response.userCode.length > 0) setDeviceCodes((prev) => ({
591
+ ...prev,
592
+ [provider]: {
593
+ userCode: response.userCode,
594
+ verificationUrl: response.authorizeUrl
595
+ }
596
+ }));
597
+ else window.open(response.authorizeUrl, "_blank", "noopener");
549
598
  startPolling(provider);
550
599
  } catch (error) {
551
600
  setProviderError(provider, messageOf(error));
@@ -611,6 +660,15 @@ function SubscriptionsSection(props) {
611
660
  setProviderError,
612
661
  refresh
613
662
  ]);
663
+ const copyDeviceCode = (0, react.useCallback)((provider, userCode) => {
664
+ navigator.clipboard?.writeText(userCode).then(() => {
665
+ if (!mountedRef.current) return;
666
+ setCopiedCode(provider);
667
+ setTimeout(() => {
668
+ if (mountedRef.current) setCopiedCode((current) => current === provider ? void 0 : current);
669
+ }, 1500);
670
+ }).catch(() => void 0);
671
+ }, []);
614
672
  if (rpc === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
615
673
  style: styles$4.intro,
616
674
  children: t("unavailable")
@@ -623,6 +681,7 @@ function SubscriptionsSection(props) {
623
681
  }), PROVIDERS.map(({ id, name }) => {
624
682
  const status = statuses[id];
625
683
  const busy = status?.busy === true;
684
+ const deviceCode = deviceCodes[id];
626
685
  const usage = usages[id];
627
686
  const usageError = usageErrors[id];
628
687
  const showUsage = status?.loggedIn === true && usage?.supported !== false && (usage !== void 0 || usageError !== void 0 || usageLoading[id] === true);
@@ -742,7 +801,38 @@ function SubscriptionsSection(props) {
742
801
  })
743
802
  ]
744
803
  }),
745
- busy && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
804
+ busy && deviceCode !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
805
+ style: styles$4.deviceCode,
806
+ children: [
807
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
808
+ style: styles$4.statusLine,
809
+ children: t("deviceCodePrompt")
810
+ }),
811
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
812
+ style: styles$4.deviceCodeText,
813
+ children: deviceCode.userCode
814
+ }),
815
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
816
+ style: styles$4.actions,
817
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
818
+ type: "button",
819
+ style: styles$4.button,
820
+ onClick: () => {
821
+ copyDeviceCode(id, deviceCode.userCode);
822
+ },
823
+ children: copiedCode === id ? t("deviceCodeCopied") : t("deviceCodeCopy")
824
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
825
+ type: "button",
826
+ style: styles$4.button,
827
+ onClick: () => {
828
+ window.open(deviceCode.verificationUrl, "_blank", "noopener");
829
+ },
830
+ children: t("deviceCodeOpenPage")
831
+ })]
832
+ })
833
+ ]
834
+ }),
835
+ busy && deviceCode === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
746
836
  style: styles$4.manual,
747
837
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("manualSummary") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
748
838
  style: styles$4.manualRow,