dsh-plugin-subscriptions 0.1.0 → 0.1.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/LICENSE +21 -0
- package/README.md +22 -1
- package/README.zh.md +23 -2
- package/lib/auth/rpc.d.ts +14 -0
- package/lib/auth/rpc.js +40 -3
- package/lib/client/ImageGenerateToolview.d.ts +48 -0
- package/lib/client/ImageGenerateToolview.js +137 -0
- package/lib/client/index.d.ts +1 -0
- package/lib/client/index.js +11 -0
- package/lib/client/locales.d.ts +16 -0
- package/lib/client/locales.js +16 -0
- package/lib/client.js +237 -31
- package/lib/client.js.map +1 -1
- package/lib/index.js +178 -20
- package/lib/providers/codex.js +9 -1
- package/lib/providers/grok.js +9 -1
- package/lib/tools/image-generate.d.ts +11 -2
- package/lib/tools/image-generate.js +118 -10
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -27,6 +27,10 @@ let react = require("react");
|
|
|
27
27
|
react = __toESM(react);
|
|
28
28
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
29
29
|
react_jsx_runtime = __toESM(react_jsx_runtime);
|
|
30
|
+
let __deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
31
|
+
__deepseek_ai_dsh_client_ui_primitives = __toESM(__deepseek_ai_dsh_client_ui_primitives);
|
|
32
|
+
let __deepseek_ai_dsh_client_ui_attachment = require("@deepseek-ai/dsh-client-ui-attachment");
|
|
33
|
+
__deepseek_ai_dsh_client_ui_attachment = __toESM(__deepseek_ai_dsh_client_ui_attachment);
|
|
30
34
|
|
|
31
35
|
//#region src/client/locales.ts
|
|
32
36
|
/** Copy dictionaries for the Subscriptions settings section. */
|
|
@@ -49,7 +53,15 @@ const en = {
|
|
|
49
53
|
manualSummary: "Browser flow not working? Paste the callback URL or code",
|
|
50
54
|
manualPlaceholder: "Paste the callback URL or code",
|
|
51
55
|
submit: "Submit",
|
|
52
|
-
loginMissingUrl: "login answered without an authorizeUrl"
|
|
56
|
+
loginMissingUrl: "login answered without an authorizeUrl",
|
|
57
|
+
generating: "Generating image…",
|
|
58
|
+
image: "image",
|
|
59
|
+
viewImage: "View image",
|
|
60
|
+
viewImageNamed: "View {name}",
|
|
61
|
+
imageLoading: "Loading…",
|
|
62
|
+
imageLoadFailed: "Retry",
|
|
63
|
+
imagePreview: "Image preview",
|
|
64
|
+
imageClose: "Close"
|
|
53
65
|
};
|
|
54
66
|
/** zh strings, one per {@link en} key. */
|
|
55
67
|
const zh = {
|
|
@@ -70,13 +82,21 @@ const zh = {
|
|
|
70
82
|
manualSummary: "浏览器流程无法完成?粘贴回调 URL 或授权码",
|
|
71
83
|
manualPlaceholder: "粘贴回调 URL 或授权码",
|
|
72
84
|
submit: "提交",
|
|
73
|
-
loginMissingUrl: "login 响应缺少 authorizeUrl"
|
|
85
|
+
loginMissingUrl: "login 响应缺少 authorizeUrl",
|
|
86
|
+
generating: "正在生成图片…",
|
|
87
|
+
image: "图片",
|
|
88
|
+
viewImage: "查看图片",
|
|
89
|
+
viewImageNamed: "查看 {name}",
|
|
90
|
+
imageLoading: "加载中…",
|
|
91
|
+
imageLoadFailed: "重试",
|
|
92
|
+
imagePreview: "图片预览",
|
|
93
|
+
imageClose: "关闭"
|
|
74
94
|
};
|
|
75
95
|
|
|
76
96
|
//#endregion
|
|
77
97
|
//#region src/client/SubscriptionsSection.tsx
|
|
78
98
|
/** Logical RPC channel served by the node half of this plugin. */
|
|
79
|
-
const SUBSCRIPTIONS_AUTH_CHANNEL = "/subscriptions-auth";
|
|
99
|
+
const SUBSCRIPTIONS_AUTH_CHANNEL$1 = "/subscriptions-auth";
|
|
80
100
|
/** Poll cadence while a provider login attempt is busy. */
|
|
81
101
|
const POLL_INTERVAL_MS = 2e3;
|
|
82
102
|
/** Card display metadata, in page order (names are brand names, not translated). */
|
|
@@ -103,10 +123,10 @@ var SubscriptionsAuthError = class extends Error {};
|
|
|
103
123
|
* @param payload - channel-owned request payload.
|
|
104
124
|
* @returns the success value, cast by the caller to the endpoint's shape.
|
|
105
125
|
*/
|
|
106
|
-
async function callSubscriptionsAuth(rpc, endpoint, payload) {
|
|
126
|
+
async function callSubscriptionsAuth$1(rpc, endpoint, payload) {
|
|
107
127
|
let result;
|
|
108
128
|
try {
|
|
109
|
-
result = await rpc.call(SUBSCRIPTIONS_AUTH_CHANNEL, endpoint, payload);
|
|
129
|
+
result = await rpc.call(SUBSCRIPTIONS_AUTH_CHANNEL$1, endpoint, payload);
|
|
110
130
|
} catch (error) {
|
|
111
131
|
throw new SubscriptionsAuthError(error instanceof Error ? error.message : String(error));
|
|
112
132
|
}
|
|
@@ -124,12 +144,12 @@ function messageOf(error) {
|
|
|
124
144
|
* @param params - `{name}` template params.
|
|
125
145
|
* @returns the template with params substituted.
|
|
126
146
|
*/
|
|
127
|
-
function fallbackTranslate(key, params) {
|
|
147
|
+
function fallbackTranslate$1(key, params) {
|
|
128
148
|
let text = en[key];
|
|
129
149
|
for (const [name, value] of Object.entries(params ?? {})) text = text.replaceAll(`{${name}}`, String(value));
|
|
130
150
|
return text;
|
|
131
151
|
}
|
|
132
|
-
const styles = {
|
|
152
|
+
const styles$1 = {
|
|
133
153
|
section: {
|
|
134
154
|
display: "flex",
|
|
135
155
|
flexDirection: "column",
|
|
@@ -261,7 +281,7 @@ function statusText(t, status) {
|
|
|
261
281
|
*/
|
|
262
282
|
function SubscriptionsSection(props) {
|
|
263
283
|
const { rpc } = props;
|
|
264
|
-
const t = props.t ?? fallbackTranslate;
|
|
284
|
+
const t = props.t ?? fallbackTranslate$1;
|
|
265
285
|
const [statuses, setStatuses] = (0, react.useState)({});
|
|
266
286
|
const [errors, setErrors] = (0, react.useState)({});
|
|
267
287
|
const [manualDrafts, setManualDrafts] = (0, react.useState)({
|
|
@@ -292,7 +312,7 @@ function SubscriptionsSection(props) {
|
|
|
292
312
|
if (rpc === void 0) return;
|
|
293
313
|
let response;
|
|
294
314
|
try {
|
|
295
|
-
response = await callSubscriptionsAuth(rpc, "status", {});
|
|
315
|
+
response = await callSubscriptionsAuth$1(rpc, "status", {});
|
|
296
316
|
} catch {
|
|
297
317
|
return;
|
|
298
318
|
}
|
|
@@ -328,7 +348,7 @@ function SubscriptionsSection(props) {
|
|
|
328
348
|
if (rpc === void 0) return;
|
|
329
349
|
setProviderError(provider, void 0);
|
|
330
350
|
try {
|
|
331
|
-
const response = await callSubscriptionsAuth(rpc, "login", { provider });
|
|
351
|
+
const response = await callSubscriptionsAuth$1(rpc, "login", { provider });
|
|
332
352
|
if (typeof response.authorizeUrl !== "string" || response.authorizeUrl === "") throw new SubscriptionsAuthError(t("loginMissingUrl"));
|
|
333
353
|
window.open(response.authorizeUrl, "_blank", "noopener");
|
|
334
354
|
if (!mountedRef.current) return;
|
|
@@ -354,7 +374,7 @@ function SubscriptionsSection(props) {
|
|
|
354
374
|
if (rpc === void 0) return;
|
|
355
375
|
stopPolling(provider);
|
|
356
376
|
try {
|
|
357
|
-
await callSubscriptionsAuth(rpc, "cancel", { provider });
|
|
377
|
+
await callSubscriptionsAuth$1(rpc, "cancel", { provider });
|
|
358
378
|
} catch (error) {
|
|
359
379
|
setProviderError(provider, messageOf(error));
|
|
360
380
|
}
|
|
@@ -371,7 +391,7 @@ function SubscriptionsSection(props) {
|
|
|
371
391
|
if (input === "") return;
|
|
372
392
|
setProviderError(provider, void 0);
|
|
373
393
|
try {
|
|
374
|
-
await callSubscriptionsAuth(rpc, "manual", {
|
|
394
|
+
await callSubscriptionsAuth$1(rpc, "manual", {
|
|
375
395
|
provider,
|
|
376
396
|
input
|
|
377
397
|
});
|
|
@@ -394,7 +414,7 @@ function SubscriptionsSection(props) {
|
|
|
394
414
|
if (!window.confirm(t("logoutConfirm", { provider: name }))) return;
|
|
395
415
|
setProviderError(provider, void 0);
|
|
396
416
|
try {
|
|
397
|
-
await callSubscriptionsAuth(rpc, "logout", { provider });
|
|
417
|
+
await callSubscriptionsAuth$1(rpc, "logout", { provider });
|
|
398
418
|
} catch (error) {
|
|
399
419
|
setProviderError(provider, messageOf(error));
|
|
400
420
|
}
|
|
@@ -406,48 +426,48 @@ function SubscriptionsSection(props) {
|
|
|
406
426
|
refresh
|
|
407
427
|
]);
|
|
408
428
|
if (rpc === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
409
|
-
style: styles.intro,
|
|
429
|
+
style: styles$1.intro,
|
|
410
430
|
children: t("unavailable")
|
|
411
431
|
});
|
|
412
432
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
413
|
-
style: styles.section,
|
|
433
|
+
style: styles$1.section,
|
|
414
434
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
415
|
-
style: styles.intro,
|
|
435
|
+
style: styles$1.intro,
|
|
416
436
|
children: t("intro")
|
|
417
437
|
}), PROVIDERS.map(({ id, name }) => {
|
|
418
438
|
const status = statuses[id];
|
|
419
439
|
const busy = status?.busy === true;
|
|
420
440
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
421
|
-
style: styles.card,
|
|
441
|
+
style: styles$1.card,
|
|
422
442
|
children: [
|
|
423
443
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
424
|
-
style: styles.cardHeader,
|
|
444
|
+
style: styles$1.cardHeader,
|
|
425
445
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
|
|
426
|
-
...styles.dot,
|
|
446
|
+
...styles$1.dot,
|
|
427
447
|
background: dotColor(status)
|
|
428
448
|
} }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
429
|
-
style: styles.name,
|
|
449
|
+
style: styles$1.name,
|
|
430
450
|
children: name
|
|
431
451
|
})]
|
|
432
452
|
}),
|
|
433
453
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
434
|
-
style: styles.statusLine,
|
|
454
|
+
style: styles$1.statusLine,
|
|
435
455
|
children: statusText(t, status)
|
|
436
456
|
}),
|
|
437
457
|
status?.detail !== void 0 && status.detail !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
438
|
-
style: styles.statusLine,
|
|
458
|
+
style: styles$1.statusLine,
|
|
439
459
|
children: status.detail
|
|
440
460
|
}),
|
|
441
461
|
errors[id] !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
442
|
-
style: styles.errorLine,
|
|
462
|
+
style: styles$1.errorLine,
|
|
443
463
|
children: errors[id]
|
|
444
464
|
}),
|
|
445
465
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
446
|
-
style: styles.actions,
|
|
466
|
+
style: styles$1.actions,
|
|
447
467
|
children: [
|
|
448
468
|
!busy && status?.loggedIn !== true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
449
469
|
type: "button",
|
|
450
|
-
style: styles.button,
|
|
470
|
+
style: styles$1.button,
|
|
451
471
|
onClick: () => {
|
|
452
472
|
login(id);
|
|
453
473
|
},
|
|
@@ -455,7 +475,7 @@ function SubscriptionsSection(props) {
|
|
|
455
475
|
}),
|
|
456
476
|
busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
457
477
|
type: "button",
|
|
458
|
-
style: styles.button,
|
|
478
|
+
style: styles$1.button,
|
|
459
479
|
onClick: () => {
|
|
460
480
|
cancel(id);
|
|
461
481
|
},
|
|
@@ -463,7 +483,7 @@ function SubscriptionsSection(props) {
|
|
|
463
483
|
}),
|
|
464
484
|
status?.loggedIn === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
465
485
|
type: "button",
|
|
466
|
-
style: styles.button,
|
|
486
|
+
style: styles$1.button,
|
|
467
487
|
onClick: () => {
|
|
468
488
|
logout(id, name);
|
|
469
489
|
},
|
|
@@ -472,11 +492,11 @@ function SubscriptionsSection(props) {
|
|
|
472
492
|
]
|
|
473
493
|
}),
|
|
474
494
|
busy && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
475
|
-
style: styles.manual,
|
|
495
|
+
style: styles$1.manual,
|
|
476
496
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("manualSummary") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
477
|
-
style: styles.manualRow,
|
|
497
|
+
style: styles$1.manualRow,
|
|
478
498
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
479
|
-
style: styles.manualInput,
|
|
499
|
+
style: styles$1.manualInput,
|
|
480
500
|
value: manualDrafts[id],
|
|
481
501
|
placeholder: t("manualPlaceholder"),
|
|
482
502
|
onChange: (event) => setManualDrafts((prev) => ({
|
|
@@ -485,7 +505,7 @@ function SubscriptionsSection(props) {
|
|
|
485
505
|
}))
|
|
486
506
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
487
507
|
type: "button",
|
|
488
|
-
style: styles.button,
|
|
508
|
+
style: styles$1.button,
|
|
489
509
|
onClick: () => {
|
|
490
510
|
submitManual(id);
|
|
491
511
|
},
|
|
@@ -499,6 +519,185 @@ function SubscriptionsSection(props) {
|
|
|
499
519
|
});
|
|
500
520
|
}
|
|
501
521
|
|
|
522
|
+
//#endregion
|
|
523
|
+
//#region src/client/ImageGenerateToolview.tsx
|
|
524
|
+
/** Logical RPC channel served by the node half of this plugin. */
|
|
525
|
+
const SUBSCRIPTIONS_AUTH_CHANNEL = "/subscriptions-auth";
|
|
526
|
+
/** Title prompt truncation budget (characters). */
|
|
527
|
+
const PROMPT_MAX_LENGTH = 60;
|
|
528
|
+
/**
|
|
529
|
+
* Call one `/subscriptions-auth` endpoint and unwrap the business result.
|
|
530
|
+
* @param rpc - Connection RPC caller.
|
|
531
|
+
* @param endpoint - channel-relative endpoint.
|
|
532
|
+
* @param payload - channel-owned request payload.
|
|
533
|
+
* @returns the success value, cast by the caller to the endpoint's shape.
|
|
534
|
+
*/
|
|
535
|
+
async function callSubscriptionsAuth(rpc, endpoint, payload) {
|
|
536
|
+
const result = await rpc.call(SUBSCRIPTIONS_AUTH_CHANNEL, endpoint, payload);
|
|
537
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
538
|
+
return result.value;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Build the ImageGallery loader over the `image` endpoint.
|
|
542
|
+
* @param rpc - Connection RPC caller.
|
|
543
|
+
* @returns loader resolving an attachment ref to a data URL.
|
|
544
|
+
*/
|
|
545
|
+
function createImageLoader(rpc) {
|
|
546
|
+
return (attachment) => callSubscriptionsAuth(rpc, "image", { ...attachment }).then((result) => `data:${result.mediaType};base64,${result.dataBase64}`);
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* English-dictionary fallback for a missing locale seat (standalone renders);
|
|
550
|
+
* the framework always supplies the namespace-bound one.
|
|
551
|
+
* @param key - dictionary key.
|
|
552
|
+
* @param params - `{name}` template params.
|
|
553
|
+
* @returns the template with params substituted.
|
|
554
|
+
*/
|
|
555
|
+
function fallbackTranslate(key, params) {
|
|
556
|
+
let text = en[key];
|
|
557
|
+
for (const [name, value] of Object.entries(params ?? {})) text = text.replaceAll(`{${name}}`, String(value));
|
|
558
|
+
return text;
|
|
559
|
+
}
|
|
560
|
+
/** Extract the prompt from the call's raw args JSON; falls back to the first string value, then the raw line. */
|
|
561
|
+
function derivePrompt(argsRaw) {
|
|
562
|
+
let parsed;
|
|
563
|
+
try {
|
|
564
|
+
parsed = JSON.parse(argsRaw);
|
|
565
|
+
} catch {
|
|
566
|
+
parsed = void 0;
|
|
567
|
+
}
|
|
568
|
+
let prompt;
|
|
569
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
570
|
+
const args = parsed;
|
|
571
|
+
if (typeof args.prompt === "string" && args.prompt !== "") prompt = args.prompt;
|
|
572
|
+
else for (const value of Object.values(args)) if (typeof value === "string" && value !== "") {
|
|
573
|
+
prompt = value;
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const line = (prompt ?? argsRaw).split("\n", 1)[0] ?? "";
|
|
578
|
+
return line.length > PROMPT_MAX_LENGTH ? `${line.slice(0, PROMPT_MAX_LENGTH)}…` : line;
|
|
579
|
+
}
|
|
580
|
+
/** Flatten a settled result's text blocks (the degraded text-only route and the error line). */
|
|
581
|
+
function resultText(block) {
|
|
582
|
+
if (!("kind" in block)) return "";
|
|
583
|
+
const parts = [];
|
|
584
|
+
for (const part of block.content) if (part.type === "text") parts.push(part.text);
|
|
585
|
+
if (parts.length === 0 && block.error !== void 0) parts.push(`${block.error.name}: ${block.error.code}`);
|
|
586
|
+
return parts.join("\n");
|
|
587
|
+
}
|
|
588
|
+
/** Image attachments of a settled result; empty while running or on the text-only route. */
|
|
589
|
+
function resultImages(block) {
|
|
590
|
+
if (!("kind" in block)) return [];
|
|
591
|
+
const images = [];
|
|
592
|
+
for (const part of block.content) if (part.type === "image") images.push({ attachment: part.attachment });
|
|
593
|
+
return images;
|
|
594
|
+
}
|
|
595
|
+
const styles = {
|
|
596
|
+
container: {
|
|
597
|
+
display: "flex",
|
|
598
|
+
flexDirection: "column",
|
|
599
|
+
gap: 6,
|
|
600
|
+
padding: "4px 0"
|
|
601
|
+
},
|
|
602
|
+
row: {
|
|
603
|
+
display: "flex",
|
|
604
|
+
alignItems: "center",
|
|
605
|
+
gap: 6,
|
|
606
|
+
minWidth: 0
|
|
607
|
+
},
|
|
608
|
+
icon: {
|
|
609
|
+
display: "inline-flex",
|
|
610
|
+
flexShrink: 0,
|
|
611
|
+
color: "var(--dsw-alias-label-tertiary)"
|
|
612
|
+
},
|
|
613
|
+
title: {
|
|
614
|
+
fontSize: 13,
|
|
615
|
+
lineHeight: "20px",
|
|
616
|
+
color: "var(--dsw-alias-label-primary)",
|
|
617
|
+
overflow: "hidden",
|
|
618
|
+
textOverflow: "ellipsis",
|
|
619
|
+
whiteSpace: "nowrap"
|
|
620
|
+
},
|
|
621
|
+
subtle: {
|
|
622
|
+
margin: 0,
|
|
623
|
+
fontSize: 12,
|
|
624
|
+
lineHeight: "18px",
|
|
625
|
+
color: "var(--dsw-alias-label-tertiary)"
|
|
626
|
+
},
|
|
627
|
+
output: {
|
|
628
|
+
margin: 0,
|
|
629
|
+
fontSize: 12,
|
|
630
|
+
lineHeight: "18px",
|
|
631
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
632
|
+
whiteSpace: "pre-wrap",
|
|
633
|
+
overflowWrap: "anywhere"
|
|
634
|
+
},
|
|
635
|
+
error: {
|
|
636
|
+
margin: 0,
|
|
637
|
+
fontSize: 12,
|
|
638
|
+
lineHeight: "18px",
|
|
639
|
+
color: "var(--dsw-alias-state-error-primary)"
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
/**
|
|
643
|
+
* The `image_generate` keyed toolview component.
|
|
644
|
+
* @param props - owner share, inject face, and locale seat (spread flat).
|
|
645
|
+
* @returns the call row plus, once settled, the gallery / text / error body.
|
|
646
|
+
*/
|
|
647
|
+
function ImageGenerateToolview(props) {
|
|
648
|
+
const { block, load } = props;
|
|
649
|
+
const t = props.t ?? fallbackTranslate;
|
|
650
|
+
if (block === void 0) return null;
|
|
651
|
+
const settled = "kind" in block;
|
|
652
|
+
const title = `image_generate: ${derivePrompt((settled ? block.call?.argsRaw : block.argsRaw) ?? "")}`;
|
|
653
|
+
const images = resultImages(block);
|
|
654
|
+
const text = settled ? resultText(block) : "";
|
|
655
|
+
const labels = {
|
|
656
|
+
image: t("image"),
|
|
657
|
+
open: t("viewImage"),
|
|
658
|
+
openNamed: (name) => t("viewImageNamed", { name }),
|
|
659
|
+
loading: t("imageLoading"),
|
|
660
|
+
loadFailed: t("imageLoadFailed"),
|
|
661
|
+
lightbox: {
|
|
662
|
+
dialog: t("imagePreview"),
|
|
663
|
+
close: t("imageClose")
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
667
|
+
style: styles.container,
|
|
668
|
+
children: [
|
|
669
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
670
|
+
style: styles.row,
|
|
671
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
672
|
+
style: styles.icon,
|
|
673
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconSparkle16, { size: 14 })
|
|
674
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
675
|
+
style: styles.title,
|
|
676
|
+
children: title
|
|
677
|
+
})]
|
|
678
|
+
}),
|
|
679
|
+
!settled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
680
|
+
style: styles.subtle,
|
|
681
|
+
children: t("generating")
|
|
682
|
+
}),
|
|
683
|
+
settled && block.isError && text !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
684
|
+
style: styles.error,
|
|
685
|
+
children: text.split("\n", 1)[0]
|
|
686
|
+
}),
|
|
687
|
+
settled && !block.isError && images.length > 0 && load !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_attachment.ImageGallery, {
|
|
688
|
+
images,
|
|
689
|
+
load,
|
|
690
|
+
align: "start",
|
|
691
|
+
labels
|
|
692
|
+
}),
|
|
693
|
+
settled && !block.isError && images.length === 0 && text !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
694
|
+
style: styles.output,
|
|
695
|
+
children: text
|
|
696
|
+
})
|
|
697
|
+
]
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
|
|
502
701
|
//#endregion
|
|
503
702
|
//#region src/client/index.ts
|
|
504
703
|
/** Dictionary namespace owned by this plugin. */
|
|
@@ -537,6 +736,13 @@ function apply(ctx) {
|
|
|
537
736
|
label: () => t("nav"),
|
|
538
737
|
inject: injected
|
|
539
738
|
}, SubscriptionsSection));
|
|
739
|
+
const toolviewInjected = () => ({ load: createImageLoader(connection.rpc) });
|
|
740
|
+
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
741
|
+
name: "tool.call.toolview",
|
|
742
|
+
key: "image_generate",
|
|
743
|
+
locale: NS,
|
|
744
|
+
inject: toolviewInjected
|
|
745
|
+
}, ImageGenerateToolview));
|
|
540
746
|
}
|
|
541
747
|
|
|
542
748
|
//#endregion
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["PROVIDERS: readonly { id: SubscriptionProvider; name: string }[]","result: RpcResult<unknown>","text: string","styles: Record<string, CSSProperties>","params: Record<string, unknown>","response: StatusResponse"],"sources":["../src/client/locales.ts","../src/client/SubscriptionsSection.tsx","../src/client/index.ts"],"sourcesContent":["/** Copy dictionaries for the Subscriptions settings section. */\n\n/** English strings (the key-set source of truth for this pair). */\nexport const en = {\n nav: 'Subscriptions',\n intro: 'Log a subscription provider in or out. Login opens the provider’s authorization page in a new tab; headless setups can paste the callback URL or code instead.',\n unavailable: 'Connection unavailable; subscription status cannot be loaded.',\n checking: 'Checking…',\n loginInProgress: 'Login in progress…',\n loggedIn: 'Logged in',\n loggedInAccount: 'Logged in as {account}',\n loggedInExpires: 'Logged in · expires {date}',\n loggedInAccountExpires: 'Logged in as {account} · expires {date}',\n notLoggedIn: 'Not logged in',\n login: 'Log in',\n cancel: 'Cancel',\n logout: 'Log out',\n logoutConfirm: 'Log out of {provider}?',\n manualSummary: 'Browser flow not working? Paste the callback URL or code',\n manualPlaceholder: 'Paste the callback URL or code',\n submit: 'Submit',\n loginMissingUrl: 'login answered without an authorizeUrl',\n} satisfies Record<string, string>\n\n/** zh strings, one per {@link en} key. */\nexport const zh = {\n nav: '订阅',\n intro: '在此登录或退出订阅服务商。点击登录会在新标签页打开服务商的授权页面;无浏览器环境可改为粘贴回调 URL 或授权码。',\n unavailable: '连接不可用,无法加载订阅状态。',\n checking: '查询中…',\n loginInProgress: '登录中…',\n loggedIn: '已登录',\n loggedInAccount: '已登录:{account}',\n loggedInExpires: '已登录 · 过期时间 {date}',\n loggedInAccountExpires: '已登录:{account} · 过期时间 {date}',\n notLoggedIn: '未登录',\n login: '登录',\n cancel: '取消',\n logout: '退出登录',\n logoutConfirm: '确定退出 {provider} 的登录吗?',\n manualSummary: '浏览器流程无法完成?粘贴回调 URL 或授权码',\n manualPlaceholder: '粘贴回调 URL 或授权码',\n submit: '提交',\n loginMissingUrl: 'login 响应缺少 authorizeUrl',\n} satisfies Record<keyof typeof en, string>\n\n/** The Subscriptions namespace key union (en is the key-set source of truth). */\nexport type SubscriptionsKey = keyof typeof en\n","/**\n * Subscriptions settings section: one card per subscription provider with an\n * OAuth login/logout flow driven by the node half's `/subscriptions-auth` RPC\n * channel. Login state lives server-side; the page polls `status` only while\n * a login attempt is busy, so an idle page never polls. All state is local\n * React state — the page has no store.\n *\n * Every color resolves through a `--dsw-alias-*` design token (the ui-theme\n * design-platform.css values flip under `body[data-ds-dark-theme]`), and\n * every user-visible string goes through the locale-bound `t` of the\n * 'settings.subscriptions' namespace. Buttons and inputs take the\n * ModelsSection vocabulary minus hover rules, which inline styles cannot\n * express.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { CSSProperties } from 'react'\nimport type { ConnectionHandle, RpcResult } from '@deepseek-ai/dsh-api-remotes/client'\nimport { en } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\n\n/** Logical RPC channel served by the node half of this plugin. */\nconst SUBSCRIPTIONS_AUTH_CHANNEL = '/subscriptions-auth'\n\n/** Poll cadence while a provider login attempt is busy. */\nconst POLL_INTERVAL_MS = 2000\n\n/** Subscription provider ids, fixed by the node half's OAuth adapters. */\nexport type SubscriptionProvider = 'codex' | 'claude' | 'grok'\n\n/** One provider's login state as answered by the `status` endpoint. */\nexport interface ProviderStatus {\n loggedIn: boolean\n busy: boolean\n expiresAt?: number\n account?: string\n detail?: string\n}\n\n/** `status` endpoint value: the node half owns this shape. */\ninterface StatusResponse {\n providers: Record<SubscriptionProvider, ProviderStatus>\n}\n\n/** `login` endpoint value: the URL the user completes OAuth at. */\ninterface LoginResponse {\n authorizeUrl: string\n}\n\n/** Injected dependencies of {@link SubscriptionsSection} (slot `inject`). */\nexport interface SubscriptionsSectionInjected {\n /** Generic logical-RPC caller over the Connection transport. */\n rpc: ConnectionHandle['rpc']\n /** Section copy: translate a 'settings.subscriptions' key with `{name}` template params. */\n t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string\n}\n\n/**\n * Props delivered by the slot outlet: the inject face spread flat (the\n * renderer erases the share boundary at the render call).\n */\nexport type SubscriptionsSectionProps = Partial<SubscriptionsSectionInjected>\n\n/** Card display metadata, in page order (names are brand names, not translated). */\nconst PROVIDERS: readonly { id: SubscriptionProvider; name: string }[] = [\n { id: 'codex', name: 'Codex (ChatGPT)' },\n { id: 'claude', name: 'Claude' },\n { id: 'grok', name: 'Grok (X Premium)' },\n]\n\n/** Business error returned by the `/subscriptions-auth` channel (error branch message). */\nclass SubscriptionsAuthError extends Error {}\n\n/**\n * Call one `/subscriptions-auth` endpoint and unwrap the business result.\n * @param rpc - Connection RPC caller.\n * @param endpoint - channel-relative endpoint.\n * @param payload - channel-owned request payload.\n * @returns the success value, cast by the caller to the endpoint's shape.\n */\nasync function callSubscriptionsAuth<T>(rpc: ConnectionHandle['rpc'], endpoint: string, payload: unknown): Promise<T> {\n let result: RpcResult<unknown>\n try {\n result = await rpc.call(SUBSCRIPTIONS_AUTH_CHANNEL, endpoint, payload)\n } catch (error) {\n // The transport rejected rather than answering; surface the same way.\n throw new SubscriptionsAuthError(error instanceof Error ? error.message : String(error))\n }\n if (!result.ok) throw new SubscriptionsAuthError(result.error.message)\n return result.value as T\n}\n\n/** Human text of an action failure, SubscriptionsAuthError or not. */\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/**\n * English-dictionary fallback for a missing inject `t` (standalone renders);\n * the slot inject always supplies the locale-bound one.\n * @param key - dictionary key.\n * @param params - `{name}` template params.\n * @returns the template with params substituted.\n */\nfunction fallbackTranslate(key: SubscriptionsKey, params?: Record<string, unknown>): string {\n let text: string = en[key]\n for (const [name, value] of Object.entries(params ?? {})) {\n text = text.replaceAll(`{${name}}`, String(value))\n }\n return text\n}\n\nconst styles: Record<string, CSSProperties> = {\n section: {\n display: 'flex', flexDirection: 'column', gap: 12, maxWidth: 560,\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: '1px solid var(--dsw-alias-border-l2)', borderRadius: 12,\n padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 6,\n },\n cardHeader: { display: 'flex', alignItems: 'center', gap: 8 },\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 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 actions: { display: 'flex', gap: 8, marginTop: 4, alignItems: 'center', flexWrap: 'wrap' },\n button: {\n boxSizing: 'border-box', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',\n height: 28, padding: '0 10px', borderRadius: 14,\n border: '1px solid var(--dsw-alias-border-l2)', background: 'transparent',\n color: 'var(--dsw-alias-label-primary)', font: 'inherit', fontSize: 12, lineHeight: '18px',\n cursor: 'pointer',\n },\n manual: { marginTop: 4, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-secondary)' },\n manualRow: { display: 'flex', gap: 8, marginTop: 6 },\n manualInput: {\n flex: 1, height: 32, boxSizing: 'border-box',\n border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8,\n padding: '0 10px', font: 'inherit', fontSize: 14, lineHeight: '22px',\n background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)',\n },\n}\n\n/** Status dot color for one provider state. */\nfunction dotColor(status: ProviderStatus | undefined): string {\n if (status?.busy === true) return 'var(--dsw-alias-state-warn-label)'\n if (status?.loggedIn === true) return 'var(--dsw-alias-state-success-primary)'\n return 'var(--dsw-alias-label-dimmed)'\n}\n\n/**\n * One-line status text for one provider state.\n * @param t - section translate.\n * @param status - the provider's last reported state.\n * @returns the localized status line.\n */\nfunction statusText(t: SubscriptionsSectionInjected['t'], status: ProviderStatus | undefined): string {\n if (status === undefined) return t('checking')\n if (status.busy) return t('loginInProgress')\n if (status.loggedIn) {\n const params: Record<string, unknown> = {}\n if (status.account !== undefined) params.account = status.account\n if (status.expiresAt !== undefined) params.date = new Date(status.expiresAt).toLocaleString()\n if (params.account !== undefined && params.date !== undefined) return t('loggedInAccountExpires', params)\n if (params.account !== undefined) return t('loggedInAccount', params)\n if (params.date !== undefined) return t('loggedInExpires', params)\n return t('loggedIn')\n }\n return t('notLoggedIn')\n}\n\n/**\n * The Subscriptions settings page component.\n * @param props - the slot inject face ({@link SubscriptionsSectionInjected}).\n * @returns the section body, or a notice while the RPC face is absent.\n */\nexport function SubscriptionsSection(props: SubscriptionsSectionProps) {\n const { rpc } = props\n const t = props.t ?? fallbackTranslate\n const [statuses, setStatuses] = useState<Partial<Record<SubscriptionProvider, ProviderStatus>>>({})\n const [errors, setErrors] = useState<Partial<Record<SubscriptionProvider, string>>>({})\n const [manualDrafts, setManualDrafts] = useState<Record<SubscriptionProvider, string>>({\n codex: '', claude: '', grok: '',\n })\n const mountedRef = useRef(true)\n const pollersRef = useRef(new Map<SubscriptionProvider, ReturnType<typeof setInterval>>())\n\n const setProviderError = useCallback((provider: SubscriptionProvider, message: string | undefined): void => {\n if (!mountedRef.current) return\n setErrors((prev) => {\n const next = { ...prev }\n if (message === undefined) delete next[provider]\n else next[provider] = message\n return next\n })\n }, [])\n\n const stopPolling = useCallback((provider: SubscriptionProvider): void => {\n const poller = pollersRef.current.get(provider)\n if (poller !== undefined) {\n clearInterval(poller)\n pollersRef.current.delete(provider)\n }\n }, [])\n\n /** Refetch every provider's status; stop a provider's poller once its attempt settles. */\n const refresh = useCallback(async (): Promise<void> => {\n if (rpc === undefined) return\n let response: StatusResponse\n try {\n response = await callSubscriptionsAuth<StatusResponse>(rpc, 'status', {})\n } catch {\n // A failed poll must not kill the page; busy providers keep polling and\n // the action paths report their own errors.\n return\n }\n if (!mountedRef.current) return\n setStatuses(response.providers)\n for (const { id } of PROVIDERS) {\n const status = response.providers[id]\n if (status.loggedIn || !status.busy) stopPolling(id)\n }\n }, [rpc, stopPolling])\n\n const startPolling = useCallback((provider: SubscriptionProvider): void => {\n if (pollersRef.current.has(provider)) return\n pollersRef.current.set(provider, setInterval(() => { void refresh() }, POLL_INTERVAL_MS))\n }, [refresh])\n\n // Initial load; every busy provider (e.g. an attempt started before a page\n // reload) resumes polling. Teardown clears pollers and the mounted guard.\n useEffect(() => {\n mountedRef.current = true\n void refresh().then(() => {\n if (!mountedRef.current) return\n setStatuses((current) => {\n for (const { id } of PROVIDERS) {\n if (current[id]?.busy === true) startPolling(id)\n }\n return current\n })\n })\n return () => {\n mountedRef.current = false\n for (const poller of pollersRef.current.values()) clearInterval(poller)\n pollersRef.current.clear()\n }\n }, [refresh, startPolling])\n\n const login = useCallback(async (provider: SubscriptionProvider): Promise<void> => {\n if (rpc === undefined) return\n setProviderError(provider, undefined)\n try {\n const response = await callSubscriptionsAuth<LoginResponse>(rpc, 'login', { provider })\n if (typeof response.authorizeUrl !== 'string' || response.authorizeUrl === '') {\n throw new SubscriptionsAuthError(t('loginMissingUrl'))\n }\n window.open(response.authorizeUrl, '_blank', 'noopener')\n if (!mountedRef.current) return\n // Optimistic busy so Cancel and the manual fallback appear before the first poll tick.\n setStatuses(prev => ({ ...prev, [provider]: { ...prev[provider], busy: true, loggedIn: false } }))\n startPolling(provider)\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n }, [rpc, t, setProviderError, startPolling])\n\n const cancel = useCallback(async (provider: SubscriptionProvider): Promise<void> => {\n if (rpc === undefined) return\n stopPolling(provider)\n try {\n await callSubscriptionsAuth<{ ok: true }>(rpc, 'cancel', { provider })\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n await refresh()\n }, [rpc, stopPolling, setProviderError, refresh])\n\n const submitManual = useCallback(async (provider: SubscriptionProvider): Promise<void> => {\n if (rpc === undefined) return\n const input = manualDrafts[provider].trim()\n if (input === '') return\n setProviderError(provider, undefined)\n try {\n await callSubscriptionsAuth<{ ok: true }>(rpc, 'manual', { provider, input })\n if (mountedRef.current) setManualDrafts(prev => ({ ...prev, [provider]: '' }))\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n await refresh()\n }, [rpc, manualDrafts, setProviderError, refresh])\n\n const logout = useCallback(async (provider: SubscriptionProvider, name: string): Promise<void> => {\n if (rpc === undefined) return\n if (!window.confirm(t('logoutConfirm', { provider: name }))) return\n setProviderError(provider, undefined)\n try {\n await callSubscriptionsAuth<{ ok: true }>(rpc, 'logout', { provider })\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n await refresh()\n }, [rpc, t, setProviderError, refresh])\n\n if (rpc === undefined) {\n return <p style={styles.intro}>{t('unavailable')}</p>\n }\n\n return (\n <div style={styles.section}>\n <p style={styles.intro}>{t('intro')}</p>\n {PROVIDERS.map(({ id, name }) => {\n const status = statuses[id]\n const busy = status?.busy === true\n return (\n <div key={id} style={styles.card}>\n <div style={styles.cardHeader}>\n <span style={{ ...styles.dot, background: dotColor(status) }} />\n <span style={styles.name}>{name}</span>\n </div>\n <p style={styles.statusLine}>{statusText(t, status)}</p>\n {status?.detail !== undefined && status.detail !== '' && (\n <p style={styles.statusLine}>{status.detail}</p>\n )}\n {errors[id] !== undefined && <p style={styles.errorLine}>{errors[id]}</p>}\n <div style={styles.actions}>\n {!busy && status?.loggedIn !== true && (\n <button type=\"button\" style={styles.button} onClick={() => { void login(id) }}>\n {t('login')}\n </button>\n )}\n {busy && (\n <button type=\"button\" style={styles.button} onClick={() => { void cancel(id) }}>\n {t('cancel')}\n </button>\n )}\n {status?.loggedIn === true && (\n <button type=\"button\" style={styles.button} onClick={() => { void logout(id, name) }}>\n {t('logout')}\n </button>\n )}\n </div>\n {busy && (\n <details style={styles.manual}>\n <summary>{t('manualSummary')}</summary>\n <div style={styles.manualRow}>\n <input\n style={styles.manualInput}\n value={manualDrafts[id]}\n placeholder={t('manualPlaceholder')}\n onChange={event => setManualDrafts(prev => ({ ...prev, [id]: event.target.value }))}\n />\n <button type=\"button\" style={styles.button} onClick={() => { void submitManual(id) }}>\n {t('submit')}\n </button>\n </div>\n </details>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n","/**\n * Subscription OAuth login page, browser half. Registers the Subscriptions\n * settings section; every login state fact arrives through the node half's\n * `/subscriptions-auth` RPC channel — this plugin holds no credential state of its\n * own. Section copy rides the client locale service: one 'settings.subscriptions'\n * namespace with zh/en dictionaries, rebound per read so the nav label and\n * page text follow the active locale.\n */\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\n// Type-only: pulls the shell's SlotMap merge (the 'settings.section' entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// `.js` extension: this package's tsconfig lacks the reference repo's\n// allowImportingTsExtensions/rewriteRelativeImportExtensions pair; under\n// nodenext the .js specifier resolves to the .tsx source (see README note).\nimport { SubscriptionsSection } from './SubscriptionsSection.js'\nimport type { SubscriptionsSectionInjected } from './SubscriptionsSection.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'\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/**\n * Required services (cordis fiber inject): `slots` carries the registration\n * seat, `connection` the `/subscriptions-auth` RPC caller, and `locale` the copy\n * dictionaries.\n */\nexport const inject = ['slots', 'connection', 'locale']\n\n/**\n * Register the Subscriptions section once the `settings.section` declaration\n * is on the ledger (the shell's apply order relative to this one is NOT\n * constrained; registration depends on the slot through `slots.inject()`).\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-plugin-subscriptions: copy dictionaries')\n // The client-runtime Context merge types `connection` as the host handle;\n // in the browser shell 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 injected = (): SubscriptionsSectionInjected => ({ rpc: connection.rpc, t })\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'subscriptions',\n order: 90,\n // A thunk re-evaluated per read, so the nav label follows the active locale.\n label: () => t('nav'),\n inject: injected,\n }, SubscriptionsSection))\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,MAAa,KAAK;CAChB,KAAK;CACL,OAAO;CACP,aAAa;CACb,UAAU;CACV,iBAAiB;CACjB,UAAU;CACV,iBAAiB;CACjB,iBAAiB;CACjB,wBAAwB;CACxB,aAAa;CACb,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,eAAe;CACf,eAAe;CACf,mBAAmB;CACnB,QAAQ;CACR,iBAAiB;CAClB;;AAGD,MAAa,KAAK;CAChB,KAAK;CACL,OAAO;CACP,aAAa;CACb,UAAU;CACV,iBAAiB;CACjB,UAAU;CACV,iBAAiB;CACjB,iBAAiB;CACjB,wBAAwB;CACxB,aAAa;CACb,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,eAAe;CACf,eAAe;CACf,mBAAmB;CACnB,QAAQ;CACR,iBAAiB;CAClB;;;;;ACvBD,MAAM,6BAA6B;;AAGnC,MAAM,mBAAmB;;AAuCzB,MAAMA,YAAmE;CACvE;EAAE,IAAI;EAAS,MAAM;EAAmB;CACxC;EAAE,IAAI;EAAU,MAAM;EAAU;CAChC;EAAE,IAAI;EAAQ,MAAM;EAAoB;CACzC;;AAGD,IAAM,yBAAN,cAAqC,MAAM;;;;;;;;AAS3C,eAAe,sBAAyB,KAA8B,UAAkB,SAA8B;CACpH,IAAIC;AACJ,KAAI;AACF,WAAS,MAAM,IAAI,KAAK,4BAA4B,UAAU,QAAQ;UAC/D,OAAO;AAEd,QAAM,IAAI,uBAAuB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC;;AAE1F,KAAI,CAAC,OAAO,GAAI,OAAM,IAAI,uBAAuB,OAAO,MAAM,QAAQ;AACtE,QAAO,OAAO;;;AAIhB,SAAS,UAAU,OAAwB;AACzC,QAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;;;;;;;;AAU/D,SAAS,kBAAkB,KAAuB,QAA0C;CAC1F,IAAIC,OAAe,GAAG;AACtB,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,UAAU,EAAE,CAAC,CACtD,QAAO,KAAK,WAAW,IAAI,KAAK,IAAI,OAAO,MAAM,CAAC;AAEpD,QAAO;;AAGT,MAAMC,SAAwC;CAC5C,SAAS;EACP,SAAS;EAAQ,eAAe;EAAU,KAAK;EAAI,UAAU;EAC7D,OAAO;EACR;CACD,OAAO;EAAE,QAAQ;EAAG,OAAO;EAAmC,UAAU;EAAI,YAAY;EAAQ;CAChG,MAAM;EACJ,QAAQ;EAAwC,cAAc;EAC9D,SAAS;EAAa,SAAS;EAAQ,eAAe;EAAU,KAAK;EACtE;CACD,YAAY;EAAE,SAAS;EAAQ,YAAY;EAAU,KAAK;EAAG;CAC7D,KAAK;EAAE,OAAO;EAAG,QAAQ;EAAG,cAAc;EAAO,YAAY;EAAG;CAChE,MAAM;EAAE,YAAY;EAAK,UAAU;EAAI,YAAY;EAAQ,OAAO;EAAkC;CACpG,YAAY;EAAE,QAAQ;EAAG,UAAU;EAAI,YAAY;EAAQ,OAAO;EAAmC;CACrG,WAAW;EAAE,QAAQ;EAAG,UAAU;EAAI,YAAY;EAAQ,OAAO;EAAwC;CACzG,SAAS;EAAE,SAAS;EAAQ,KAAK;EAAG,WAAW;EAAG,YAAY;EAAU,UAAU;EAAQ;CAC1F,QAAQ;EACN,WAAW;EAAc,SAAS;EAAe,YAAY;EAAU,gBAAgB;EACvF,QAAQ;EAAI,SAAS;EAAU,cAAc;EAC7C,QAAQ;EAAwC,YAAY;EAC5D,OAAO;EAAkC,MAAM;EAAW,UAAU;EAAI,YAAY;EACpF,QAAQ;EACT;CACD,QAAQ;EAAE,WAAW;EAAG,UAAU;EAAI,YAAY;EAAQ,OAAO;EAAoC;CACrG,WAAW;EAAE,SAAS;EAAQ,KAAK;EAAG,WAAW;EAAG;CACpD,aAAa;EACX,MAAM;EAAG,QAAQ;EAAI,WAAW;EAChC,QAAQ;EAAwC,cAAc;EAC9D,SAAS;EAAU,MAAM;EAAW,UAAU;EAAI,YAAY;EAC9D,YAAY;EAA+B,OAAO;EACnD;CACF;;AAGD,SAAS,SAAS,QAA4C;AAC5D,KAAI,QAAQ,SAAS,KAAM,QAAO;AAClC,KAAI,QAAQ,aAAa,KAAM,QAAO;AACtC,QAAO;;;;;;;;AAST,SAAS,WAAW,GAAsC,QAA4C;AACpG,KAAI,WAAW,OAAW,QAAO,EAAE,WAAW;AAC9C,KAAI,OAAO,KAAM,QAAO,EAAE,kBAAkB;AAC5C,KAAI,OAAO,UAAU;EACnB,MAAMC,SAAkC,EAAE;AAC1C,MAAI,OAAO,YAAY,OAAW,QAAO,UAAU,OAAO;AAC1D,MAAI,OAAO,cAAc,OAAW,QAAO,OAAO,IAAI,KAAK,OAAO,UAAU,CAAC,gBAAgB;AAC7F,MAAI,OAAO,YAAY,UAAa,OAAO,SAAS,OAAW,QAAO,EAAE,0BAA0B,OAAO;AACzG,MAAI,OAAO,YAAY,OAAW,QAAO,EAAE,mBAAmB,OAAO;AACrE,MAAI,OAAO,SAAS,OAAW,QAAO,EAAE,mBAAmB,OAAO;AAClE,SAAO,EAAE,WAAW;;AAEtB,QAAO,EAAE,cAAc;;;;;;;AAQzB,SAAgB,qBAAqB,OAAkC;CACrE,MAAM,EAAE,QAAQ;CAChB,MAAM,IAAI,MAAM,KAAK;CACrB,MAAM,CAAC,UAAU,mCAA+E,EAAE,CAAC;CACnG,MAAM,CAAC,QAAQ,iCAAqE,EAAE,CAAC;CACvF,MAAM,CAAC,cAAc,uCAAkE;EACrF,OAAO;EAAI,QAAQ;EAAI,MAAM;EAC9B,CAAC;CACF,MAAM,+BAAoB,KAAK;CAC/B,MAAM,+CAAoB,IAAI,KAA2D,CAAC;CAE1F,MAAM,2CAAgC,UAAgC,YAAsC;AAC1G,MAAI,CAAC,WAAW,QAAS;AACzB,aAAW,SAAS;GAClB,MAAM,OAAO,EAAE,GAAG,MAAM;AACxB,OAAI,YAAY,OAAW,QAAO,KAAK;OAClC,MAAK,YAAY;AACtB,UAAO;IACP;IACD,EAAE,CAAC;CAEN,MAAM,sCAA2B,aAAyC;EACxE,MAAM,SAAS,WAAW,QAAQ,IAAI,SAAS;AAC/C,MAAI,WAAW,QAAW;AACxB,iBAAc,OAAO;AACrB,cAAW,QAAQ,OAAO,SAAS;;IAEpC,EAAE,CAAC;;CAGN,MAAM,iCAAsB,YAA2B;AACrD,MAAI,QAAQ,OAAW;EACvB,IAAIC;AACJ,MAAI;AACF,cAAW,MAAM,sBAAsC,KAAK,UAAU,EAAE,CAAC;UACnE;AAGN;;AAEF,MAAI,CAAC,WAAW,QAAS;AACzB,cAAY,SAAS,UAAU;AAC/B,OAAK,MAAM,EAAE,QAAQ,WAAW;GAC9B,MAAM,SAAS,SAAS,UAAU;AAClC,OAAI,OAAO,YAAY,CAAC,OAAO,KAAM,aAAY,GAAG;;IAErD,CAAC,KAAK,YAAY,CAAC;CAEtB,MAAM,uCAA4B,aAAyC;AACzE,MAAI,WAAW,QAAQ,IAAI,SAAS,CAAE;AACtC,aAAW,QAAQ,IAAI,UAAU,kBAAkB;AAAE,GAAK,SAAS;KAAI,iBAAiB,CAAC;IACxF,CAAC,QAAQ,CAAC;AAIb,4BAAgB;AACd,aAAW,UAAU;AACrB,EAAK,SAAS,CAAC,WAAW;AACxB,OAAI,CAAC,WAAW,QAAS;AACzB,gBAAa,YAAY;AACvB,SAAK,MAAM,EAAE,QAAQ,UACnB,KAAI,QAAQ,KAAK,SAAS,KAAM,cAAa,GAAG;AAElD,WAAO;KACP;IACF;AACF,eAAa;AACX,cAAW,UAAU;AACrB,QAAK,MAAM,UAAU,WAAW,QAAQ,QAAQ,CAAE,eAAc,OAAO;AACvE,cAAW,QAAQ,OAAO;;IAE3B,CAAC,SAAS,aAAa,CAAC;CAE3B,MAAM,+BAAoB,OAAO,aAAkD;AACjF,MAAI,QAAQ,OAAW;AACvB,mBAAiB,UAAU,OAAU;AACrC,MAAI;GACF,MAAM,WAAW,MAAM,sBAAqC,KAAK,SAAS,EAAE,UAAU,CAAC;AACvF,OAAI,OAAO,SAAS,iBAAiB,YAAY,SAAS,iBAAiB,GACzE,OAAM,IAAI,uBAAuB,EAAE,kBAAkB,CAAC;AAExD,UAAO,KAAK,SAAS,cAAc,UAAU,WAAW;AACxD,OAAI,CAAC,WAAW,QAAS;AAEzB,gBAAY,UAAS;IAAE,GAAG;KAAO,WAAW;KAAE,GAAG,KAAK;KAAW,MAAM;KAAM,UAAU;KAAO;IAAE,EAAE;AAClG,gBAAa,SAAS;WACf,OAAO;AACd,oBAAiB,UAAU,UAAU,MAAM,CAAC;;IAE7C;EAAC;EAAK;EAAG;EAAkB;EAAa,CAAC;CAE5C,MAAM,gCAAqB,OAAO,aAAkD;AAClF,MAAI,QAAQ,OAAW;AACvB,cAAY,SAAS;AACrB,MAAI;AACF,SAAM,sBAAoC,KAAK,UAAU,EAAE,UAAU,CAAC;WAC/D,OAAO;AACd,oBAAiB,UAAU,UAAU,MAAM,CAAC;;AAE9C,QAAM,SAAS;IACd;EAAC;EAAK;EAAa;EAAkB;EAAQ,CAAC;CAEjD,MAAM,sCAA2B,OAAO,aAAkD;AACxF,MAAI,QAAQ,OAAW;EACvB,MAAM,QAAQ,aAAa,UAAU,MAAM;AAC3C,MAAI,UAAU,GAAI;AAClB,mBAAiB,UAAU,OAAU;AACrC,MAAI;AACF,SAAM,sBAAoC,KAAK,UAAU;IAAE;IAAU;IAAO,CAAC;AAC7E,OAAI,WAAW,QAAS,kBAAgB,UAAS;IAAE,GAAG;KAAO,WAAW;IAAI,EAAE;WACvE,OAAO;AACd,oBAAiB,UAAU,UAAU,MAAM,CAAC;;AAE9C,QAAM,SAAS;IACd;EAAC;EAAK;EAAc;EAAkB;EAAQ,CAAC;CAElD,MAAM,gCAAqB,OAAO,UAAgC,SAAgC;AAChG,MAAI,QAAQ,OAAW;AACvB,MAAI,CAAC,OAAO,QAAQ,EAAE,iBAAiB,EAAE,UAAU,MAAM,CAAC,CAAC,CAAE;AAC7D,mBAAiB,UAAU,OAAU;AACrC,MAAI;AACF,SAAM,sBAAoC,KAAK,UAAU,EAAE,UAAU,CAAC;WAC/D,OAAO;AACd,oBAAiB,UAAU,UAAU,MAAM,CAAC;;AAE9C,QAAM,SAAS;IACd;EAAC;EAAK;EAAG;EAAkB;EAAQ,CAAC;AAEvC,KAAI,QAAQ,OACV,QAAO,2CAAC;EAAE,OAAO,OAAO;YAAQ,EAAE,cAAc;GAAK;AAGvD,QACE,4CAAC;EAAI,OAAO,OAAO;aACjB,2CAAC;GAAE,OAAO,OAAO;aAAQ,EAAE,QAAQ;IAAK,EACvC,UAAU,KAAK,EAAE,IAAI,WAAW;GAC/B,MAAM,SAAS,SAAS;GACxB,MAAM,OAAO,QAAQ,SAAS;AAC9B,UACE,4CAAC;IAAa,OAAO,OAAO;;KAC1B,4CAAC;MAAI,OAAO,OAAO;iBACjB,2CAAC,UAAK,OAAO;OAAE,GAAG,OAAO;OAAK,YAAY,SAAS,OAAO;OAAE,GAAI,EAChE,2CAAC;OAAK,OAAO,OAAO;iBAAO;QAAY;OACnC;KACN,2CAAC;MAAE,OAAO,OAAO;gBAAa,WAAW,GAAG,OAAO;OAAK;KACvD,QAAQ,WAAW,UAAa,OAAO,WAAW,MACjD,2CAAC;MAAE,OAAO,OAAO;gBAAa,OAAO;OAAW;KAEjD,OAAO,QAAQ,UAAa,2CAAC;MAAE,OAAO,OAAO;gBAAY,OAAO;OAAQ;KACzE,4CAAC;MAAI,OAAO,OAAO;;OAChB,CAAC,QAAQ,QAAQ,aAAa,QAC7B,2CAAC;QAAO,MAAK;QAAS,OAAO,OAAO;QAAQ,eAAe;AAAE,SAAK,MAAM,GAAG;;kBACxE,EAAE,QAAQ;SACJ;OAEV,QACC,2CAAC;QAAO,MAAK;QAAS,OAAO,OAAO;QAAQ,eAAe;AAAE,SAAK,OAAO,GAAG;;kBACzE,EAAE,SAAS;SACL;OAEV,QAAQ,aAAa,QACpB,2CAAC;QAAO,MAAK;QAAS,OAAO,OAAO;QAAQ,eAAe;AAAE,SAAK,OAAO,IAAI,KAAK;;kBAC/E,EAAE,SAAS;SACL;;OAEP;KACL,QACC,4CAAC;MAAQ,OAAO,OAAO;iBACrB,2CAAC,uBAAS,EAAE,gBAAgB,GAAW,EACvC,4CAAC;OAAI,OAAO,OAAO;kBACjB,2CAAC;QACC,OAAO,OAAO;QACd,OAAO,aAAa;QACpB,aAAa,EAAE,oBAAoB;QACnC,WAAU,UAAS,iBAAgB,UAAS;SAAE,GAAG;UAAO,KAAK,MAAM,OAAO;SAAO,EAAE;SACnF,EACF,2CAAC;QAAO,MAAK;QAAS,OAAO,OAAO;QAAQ,eAAe;AAAE,SAAK,aAAa,GAAG;;kBAC/E,EAAE,SAAS;SACL;QACL;OACE;;MAzCJ,GA2CJ;IAER;GACE;;;;;;ACzUV,MAAM,KAAK;;;;;;AAOX,MAAa,SAAS;CAAC;CAAS;CAAc;CAAS;;;;;;;AAQvD,SAAgB,MAAM,KAA0B;AAC9C,KAAI,aAAa,IAAI,OAAO,SAAS,IAAI;EAAE;EAAI;EAAI,CAAC,EAAE,8CAA8C;CAGpG,MAAM,aAAa,IAAI,IAAI,aAAa;CACxC,MAAM,IAAI,IAAI,OAAO,KAAK,GAAG;CAC7B,MAAM,kBAAgD;EAAE,KAAK,WAAW;EAAK;EAAG;AAChF,KAAI,MAAM,OAAO,0BAA0B,IAAI,MAAM,SAAS;EAC5D,MAAM;EACN,IAAI;EACJ,OAAO;EAEP,aAAa,EAAE,MAAM;EACrB,QAAQ;EACT,EAAE,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["SUBSCRIPTIONS_AUTH_CHANNEL","PROVIDERS: readonly { id: SubscriptionProvider; name: string }[]","callSubscriptionsAuth","result: RpcResult<unknown>","fallbackTranslate","text: string","styles: Record<string, CSSProperties>","params: Record<string, unknown>","response: StatusResponse","styles","result: RpcResult<unknown>","text: string","parsed: unknown","prompt: string | undefined","parts: string[]","images: { attachment: ImageAttachmentRef }[]","styles: Record<string, CSSProperties>","labels: MessageImageLabels","IconSparkle16","ImageGallery"],"sources":["../src/client/locales.ts","../src/client/SubscriptionsSection.tsx","../src/client/ImageGenerateToolview.tsx","../src/client/index.ts"],"sourcesContent":["/** Copy dictionaries for the Subscriptions settings section. */\n\n/** English strings (the key-set source of truth for this pair). */\nexport const en = {\n nav: 'Subscriptions',\n intro: 'Log a subscription provider in or out. Login opens the provider’s authorization page in a new tab; headless setups can paste the callback URL or code instead.',\n unavailable: 'Connection unavailable; subscription status cannot be loaded.',\n checking: 'Checking…',\n loginInProgress: 'Login in progress…',\n loggedIn: 'Logged in',\n loggedInAccount: 'Logged in as {account}',\n loggedInExpires: 'Logged in · expires {date}',\n loggedInAccountExpires: 'Logged in as {account} · expires {date}',\n notLoggedIn: 'Not logged in',\n login: 'Log in',\n cancel: 'Cancel',\n logout: 'Log out',\n logoutConfirm: 'Log out of {provider}?',\n manualSummary: 'Browser flow not working? Paste the callback URL or code',\n manualPlaceholder: 'Paste the callback URL or code',\n submit: 'Submit',\n loginMissingUrl: 'login answered without an authorizeUrl',\n generating: 'Generating image…',\n image: 'image',\n viewImage: 'View image',\n viewImageNamed: 'View {name}',\n imageLoading: 'Loading…',\n imageLoadFailed: 'Retry',\n imagePreview: 'Image preview',\n imageClose: 'Close',\n} satisfies Record<string, string>\n\n/** zh strings, one per {@link en} key. */\nexport const zh = {\n nav: '订阅',\n intro: '在此登录或退出订阅服务商。点击登录会在新标签页打开服务商的授权页面;无浏览器环境可改为粘贴回调 URL 或授权码。',\n unavailable: '连接不可用,无法加载订阅状态。',\n checking: '查询中…',\n loginInProgress: '登录中…',\n loggedIn: '已登录',\n loggedInAccount: '已登录:{account}',\n loggedInExpires: '已登录 · 过期时间 {date}',\n loggedInAccountExpires: '已登录:{account} · 过期时间 {date}',\n notLoggedIn: '未登录',\n login: '登录',\n cancel: '取消',\n logout: '退出登录',\n logoutConfirm: '确定退出 {provider} 的登录吗?',\n manualSummary: '浏览器流程无法完成?粘贴回调 URL 或授权码',\n manualPlaceholder: '粘贴回调 URL 或授权码',\n submit: '提交',\n loginMissingUrl: 'login 响应缺少 authorizeUrl',\n generating: '正在生成图片…',\n image: '图片',\n viewImage: '查看图片',\n viewImageNamed: '查看 {name}',\n imageLoading: '加载中…',\n imageLoadFailed: '重试',\n imagePreview: '图片预览',\n imageClose: '关闭',\n} satisfies Record<keyof typeof en, string>\n\n/** The Subscriptions namespace key union (en is the key-set source of truth). */\nexport type SubscriptionsKey = keyof typeof en\n","/**\n * Subscriptions settings section: one card per subscription provider with an\n * OAuth login/logout flow driven by the node half's `/subscriptions-auth` RPC\n * channel. Login state lives server-side; the page polls `status` only while\n * a login attempt is busy, so an idle page never polls. All state is local\n * React state — the page has no store.\n *\n * Every color resolves through a `--dsw-alias-*` design token (the ui-theme\n * design-platform.css values flip under `body[data-ds-dark-theme]`), and\n * every user-visible string goes through the locale-bound `t` of the\n * 'settings.subscriptions' namespace. Buttons and inputs take the\n * ModelsSection vocabulary minus hover rules, which inline styles cannot\n * express.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { CSSProperties } from 'react'\nimport type { ConnectionHandle, RpcResult } from '@deepseek-ai/dsh-api-remotes/client'\nimport { en } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\n\n/** Logical RPC channel served by the node half of this plugin. */\nconst SUBSCRIPTIONS_AUTH_CHANNEL = '/subscriptions-auth'\n\n/** Poll cadence while a provider login attempt is busy. */\nconst POLL_INTERVAL_MS = 2000\n\n/** Subscription provider ids, fixed by the node half's OAuth adapters. */\nexport type SubscriptionProvider = 'codex' | 'claude' | 'grok'\n\n/** One provider's login state as answered by the `status` endpoint. */\nexport interface ProviderStatus {\n loggedIn: boolean\n busy: boolean\n expiresAt?: number\n account?: string\n detail?: string\n}\n\n/** `status` endpoint value: the node half owns this shape. */\ninterface StatusResponse {\n providers: Record<SubscriptionProvider, ProviderStatus>\n}\n\n/** `login` endpoint value: the URL the user completes OAuth at. */\ninterface LoginResponse {\n authorizeUrl: string\n}\n\n/** Injected dependencies of {@link SubscriptionsSection} (slot `inject`). */\nexport interface SubscriptionsSectionInjected {\n /** Generic logical-RPC caller over the Connection transport. */\n rpc: ConnectionHandle['rpc']\n /** Section copy: translate a 'settings.subscriptions' key with `{name}` template params. */\n t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string\n}\n\n/**\n * Props delivered by the slot outlet: the inject face spread flat (the\n * renderer erases the share boundary at the render call).\n */\nexport type SubscriptionsSectionProps = Partial<SubscriptionsSectionInjected>\n\n/** Card display metadata, in page order (names are brand names, not translated). */\nconst PROVIDERS: readonly { id: SubscriptionProvider; name: string }[] = [\n { id: 'codex', name: 'Codex (ChatGPT)' },\n { id: 'claude', name: 'Claude' },\n { id: 'grok', name: 'Grok (X Premium)' },\n]\n\n/** Business error returned by the `/subscriptions-auth` channel (error branch message). */\nclass SubscriptionsAuthError extends Error {}\n\n/**\n * Call one `/subscriptions-auth` endpoint and unwrap the business result.\n * @param rpc - Connection RPC caller.\n * @param endpoint - channel-relative endpoint.\n * @param payload - channel-owned request payload.\n * @returns the success value, cast by the caller to the endpoint's shape.\n */\nasync function callSubscriptionsAuth<T>(rpc: ConnectionHandle['rpc'], endpoint: string, payload: unknown): Promise<T> {\n let result: RpcResult<unknown>\n try {\n result = await rpc.call(SUBSCRIPTIONS_AUTH_CHANNEL, endpoint, payload)\n } catch (error) {\n // The transport rejected rather than answering; surface the same way.\n throw new SubscriptionsAuthError(error instanceof Error ? error.message : String(error))\n }\n if (!result.ok) throw new SubscriptionsAuthError(result.error.message)\n return result.value as T\n}\n\n/** Human text of an action failure, SubscriptionsAuthError or not. */\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/**\n * English-dictionary fallback for a missing inject `t` (standalone renders);\n * the slot inject always supplies the locale-bound one.\n * @param key - dictionary key.\n * @param params - `{name}` template params.\n * @returns the template with params substituted.\n */\nfunction fallbackTranslate(key: SubscriptionsKey, params?: Record<string, unknown>): string {\n let text: string = en[key]\n for (const [name, value] of Object.entries(params ?? {})) {\n text = text.replaceAll(`{${name}}`, String(value))\n }\n return text\n}\n\nconst styles: Record<string, CSSProperties> = {\n section: {\n display: 'flex', flexDirection: 'column', gap: 12, maxWidth: 560,\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: '1px solid var(--dsw-alias-border-l2)', borderRadius: 12,\n padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 6,\n },\n cardHeader: { display: 'flex', alignItems: 'center', gap: 8 },\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 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 actions: { display: 'flex', gap: 8, marginTop: 4, alignItems: 'center', flexWrap: 'wrap' },\n button: {\n boxSizing: 'border-box', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',\n height: 28, padding: '0 10px', borderRadius: 14,\n border: '1px solid var(--dsw-alias-border-l2)', background: 'transparent',\n color: 'var(--dsw-alias-label-primary)', font: 'inherit', fontSize: 12, lineHeight: '18px',\n cursor: 'pointer',\n },\n manual: { marginTop: 4, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-secondary)' },\n manualRow: { display: 'flex', gap: 8, marginTop: 6 },\n manualInput: {\n flex: 1, height: 32, boxSizing: 'border-box',\n border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8,\n padding: '0 10px', font: 'inherit', fontSize: 14, lineHeight: '22px',\n background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)',\n },\n}\n\n/** Status dot color for one provider state. */\nfunction dotColor(status: ProviderStatus | undefined): string {\n if (status?.busy === true) return 'var(--dsw-alias-state-warn-label)'\n if (status?.loggedIn === true) return 'var(--dsw-alias-state-success-primary)'\n return 'var(--dsw-alias-label-dimmed)'\n}\n\n/**\n * One-line status text for one provider state.\n * @param t - section translate.\n * @param status - the provider's last reported state.\n * @returns the localized status line.\n */\nfunction statusText(t: SubscriptionsSectionInjected['t'], status: ProviderStatus | undefined): string {\n if (status === undefined) return t('checking')\n if (status.busy) return t('loginInProgress')\n if (status.loggedIn) {\n const params: Record<string, unknown> = {}\n if (status.account !== undefined) params.account = status.account\n if (status.expiresAt !== undefined) params.date = new Date(status.expiresAt).toLocaleString()\n if (params.account !== undefined && params.date !== undefined) return t('loggedInAccountExpires', params)\n if (params.account !== undefined) return t('loggedInAccount', params)\n if (params.date !== undefined) return t('loggedInExpires', params)\n return t('loggedIn')\n }\n return t('notLoggedIn')\n}\n\n/**\n * The Subscriptions settings page component.\n * @param props - the slot inject face ({@link SubscriptionsSectionInjected}).\n * @returns the section body, or a notice while the RPC face is absent.\n */\nexport function SubscriptionsSection(props: SubscriptionsSectionProps) {\n const { rpc } = props\n const t = props.t ?? fallbackTranslate\n const [statuses, setStatuses] = useState<Partial<Record<SubscriptionProvider, ProviderStatus>>>({})\n const [errors, setErrors] = useState<Partial<Record<SubscriptionProvider, string>>>({})\n const [manualDrafts, setManualDrafts] = useState<Record<SubscriptionProvider, string>>({\n codex: '', claude: '', grok: '',\n })\n const mountedRef = useRef(true)\n const pollersRef = useRef(new Map<SubscriptionProvider, ReturnType<typeof setInterval>>())\n\n const setProviderError = useCallback((provider: SubscriptionProvider, message: string | undefined): void => {\n if (!mountedRef.current) return\n setErrors((prev) => {\n const next = { ...prev }\n if (message === undefined) delete next[provider]\n else next[provider] = message\n return next\n })\n }, [])\n\n const stopPolling = useCallback((provider: SubscriptionProvider): void => {\n const poller = pollersRef.current.get(provider)\n if (poller !== undefined) {\n clearInterval(poller)\n pollersRef.current.delete(provider)\n }\n }, [])\n\n /** Refetch every provider's status; stop a provider's poller once its attempt settles. */\n const refresh = useCallback(async (): Promise<void> => {\n if (rpc === undefined) return\n let response: StatusResponse\n try {\n response = await callSubscriptionsAuth<StatusResponse>(rpc, 'status', {})\n } catch {\n // A failed poll must not kill the page; busy providers keep polling and\n // the action paths report their own errors.\n return\n }\n if (!mountedRef.current) return\n setStatuses(response.providers)\n for (const { id } of PROVIDERS) {\n const status = response.providers[id]\n if (status.loggedIn || !status.busy) stopPolling(id)\n }\n }, [rpc, stopPolling])\n\n const startPolling = useCallback((provider: SubscriptionProvider): void => {\n if (pollersRef.current.has(provider)) return\n pollersRef.current.set(provider, setInterval(() => { void refresh() }, POLL_INTERVAL_MS))\n }, [refresh])\n\n // Initial load; every busy provider (e.g. an attempt started before a page\n // reload) resumes polling. Teardown clears pollers and the mounted guard.\n useEffect(() => {\n mountedRef.current = true\n void refresh().then(() => {\n if (!mountedRef.current) return\n setStatuses((current) => {\n for (const { id } of PROVIDERS) {\n if (current[id]?.busy === true) startPolling(id)\n }\n return current\n })\n })\n return () => {\n mountedRef.current = false\n for (const poller of pollersRef.current.values()) clearInterval(poller)\n pollersRef.current.clear()\n }\n }, [refresh, startPolling])\n\n const login = useCallback(async (provider: SubscriptionProvider): Promise<void> => {\n if (rpc === undefined) return\n setProviderError(provider, undefined)\n try {\n const response = await callSubscriptionsAuth<LoginResponse>(rpc, 'login', { provider })\n if (typeof response.authorizeUrl !== 'string' || response.authorizeUrl === '') {\n throw new SubscriptionsAuthError(t('loginMissingUrl'))\n }\n window.open(response.authorizeUrl, '_blank', 'noopener')\n if (!mountedRef.current) return\n // Optimistic busy so Cancel and the manual fallback appear before the first poll tick.\n setStatuses(prev => ({ ...prev, [provider]: { ...prev[provider], busy: true, loggedIn: false } }))\n startPolling(provider)\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n }, [rpc, t, setProviderError, startPolling])\n\n const cancel = useCallback(async (provider: SubscriptionProvider): Promise<void> => {\n if (rpc === undefined) return\n stopPolling(provider)\n try {\n await callSubscriptionsAuth<{ ok: true }>(rpc, 'cancel', { provider })\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n await refresh()\n }, [rpc, stopPolling, setProviderError, refresh])\n\n const submitManual = useCallback(async (provider: SubscriptionProvider): Promise<void> => {\n if (rpc === undefined) return\n const input = manualDrafts[provider].trim()\n if (input === '') return\n setProviderError(provider, undefined)\n try {\n await callSubscriptionsAuth<{ ok: true }>(rpc, 'manual', { provider, input })\n if (mountedRef.current) setManualDrafts(prev => ({ ...prev, [provider]: '' }))\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n await refresh()\n }, [rpc, manualDrafts, setProviderError, refresh])\n\n const logout = useCallback(async (provider: SubscriptionProvider, name: string): Promise<void> => {\n if (rpc === undefined) return\n if (!window.confirm(t('logoutConfirm', { provider: name }))) return\n setProviderError(provider, undefined)\n try {\n await callSubscriptionsAuth<{ ok: true }>(rpc, 'logout', { provider })\n } catch (error) {\n setProviderError(provider, messageOf(error))\n }\n await refresh()\n }, [rpc, t, setProviderError, refresh])\n\n if (rpc === undefined) {\n return <p style={styles.intro}>{t('unavailable')}</p>\n }\n\n return (\n <div style={styles.section}>\n <p style={styles.intro}>{t('intro')}</p>\n {PROVIDERS.map(({ id, name }) => {\n const status = statuses[id]\n const busy = status?.busy === true\n return (\n <div key={id} style={styles.card}>\n <div style={styles.cardHeader}>\n <span style={{ ...styles.dot, background: dotColor(status) }} />\n <span style={styles.name}>{name}</span>\n </div>\n <p style={styles.statusLine}>{statusText(t, status)}</p>\n {status?.detail !== undefined && status.detail !== '' && (\n <p style={styles.statusLine}>{status.detail}</p>\n )}\n {errors[id] !== undefined && <p style={styles.errorLine}>{errors[id]}</p>}\n <div style={styles.actions}>\n {!busy && status?.loggedIn !== true && (\n <button type=\"button\" style={styles.button} onClick={() => { void login(id) }}>\n {t('login')}\n </button>\n )}\n {busy && (\n <button type=\"button\" style={styles.button} onClick={() => { void cancel(id) }}>\n {t('cancel')}\n </button>\n )}\n {status?.loggedIn === true && (\n <button type=\"button\" style={styles.button} onClick={() => { void logout(id, name) }}>\n {t('logout')}\n </button>\n )}\n </div>\n {busy && (\n <details style={styles.manual}>\n <summary>{t('manualSummary')}</summary>\n <div style={styles.manualRow}>\n <input\n style={styles.manualInput}\n value={manualDrafts[id]}\n placeholder={t('manualPlaceholder')}\n onChange={event => setManualDrafts(prev => ({ ...prev, [id]: event.target.value }))}\n />\n <button type=\"button\" style={styles.button} onClick={() => { void submitManual(id) }}>\n {t('submit')}\n </button>\n </div>\n </details>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n","/**\n * Keyed toolview for the `image_generate` tool: renders generated images\n * inline in the conversation. The row shows the call's prompt while running\n * and after settling; a settled result with image blocks renders them through\n * the platform ImageGallery, whose bytes load through the node half's\n * `/subscriptions-auth` RPC channel (the durable ImageAttachmentRef is never\n * a fetchable URL on its own). A text-only settled result (degraded route)\n * renders its text; an error result renders the first error line.\n *\n * The 'tool.call.toolview' slot contract is owned by ui-tool\n * (packages/client/ui-tool/src/client/contract/slots.ts), which this package\n * does not resolve; the SlotMap merge and ToolCallOwnerProps below mirror it\n * structurally (same discipline as platform-modules.d.ts).\n */\nimport type { CSSProperties } from 'react'\nimport type { ConnectionHandle, RpcResult } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { ToolCallBlock } from '@deepseek-ai/dsh-client-runtime/client'\nimport { IconSparkle16 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { ImageGallery } from '@deepseek-ai/dsh-client-ui-attachment'\nimport type { ImageAttachmentRef, ImageLoader, MessageImageLabels } from '@deepseek-ai/dsh-client-ui-attachment'\nimport { en } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\n\n/** Logical RPC channel served by the node half of this plugin. */\nconst SUBSCRIPTIONS_AUTH_CHANNEL = '/subscriptions-auth'\n\n/** Title prompt truncation budget (characters). */\nconst PROMPT_MAX_LENGTH = 60\n\n/** Mirror of ui-tool's ToolCallOwnerProps (see the module header). */\ninterface ToolCallOwnerProps {\n callId: string\n toolName: string\n block: ToolCallBlock\n cwd?: string | undefined\n openFile: (path: string) => void\n inspect?: (() => void) | undefined\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n /** Mirror of ui-tool's keyed atomic Tool view declaration (see the module header). */\n 'tool.call.toolview': { kind: 'keyed'; scope: 'session'; owner: ToolCallOwnerProps }\n }\n}\n\n/** Injected dependencies of {@link ImageGenerateToolview} (slot `inject`). */\nexport interface ImageGenerateToolviewInjected {\n /** Session-authorized image URL loader riding the `/subscriptions-auth` channel. */\n load: ImageLoader\n}\n\n/**\n * Props delivered by the toolview outlet: the owner share plus the inject\n * face and the framework locale seat, spread flat.\n */\nexport type ImageGenerateToolviewProps =\n Partial<ToolCallOwnerProps>\n & Partial<ImageGenerateToolviewInjected>\n & { t?: ((key: SubscriptionsKey, params?: Record<string, unknown>) => string) | undefined }\n\n/** `image` endpoint result: the node half owns this shape. */\ninterface ImageEndpointResult {\n mediaType: string\n dataBase64: string\n}\n\n/**\n * Call one `/subscriptions-auth` endpoint and unwrap the business result.\n * @param rpc - Connection RPC caller.\n * @param endpoint - channel-relative endpoint.\n * @param payload - channel-owned request payload.\n * @returns the success value, cast by the caller to the endpoint's shape.\n */\nasync function callSubscriptionsAuth<T>(rpc: ConnectionHandle['rpc'], endpoint: string, payload: unknown): Promise<T> {\n const result: RpcResult<unknown> = await rpc.call(SUBSCRIPTIONS_AUTH_CHANNEL, endpoint, payload)\n if (!result.ok) throw new Error(result.error.message)\n return result.value as T\n}\n\n/**\n * Build the ImageGallery loader over the `image` endpoint.\n * @param rpc - Connection RPC caller.\n * @returns loader resolving an attachment ref to a data URL.\n */\nexport function createImageLoader(rpc: ConnectionHandle['rpc']): ImageLoader {\n // The host validates a full ImageAttachmentRef payload (readImage takes the\n // whole ref), so forward the attachment verbatim.\n return attachment =>\n callSubscriptionsAuth<ImageEndpointResult>(rpc, 'image', { ...attachment })\n .then(result => `data:${result.mediaType};base64,${result.dataBase64}`)\n}\n\n/**\n * English-dictionary fallback for a missing locale seat (standalone renders);\n * the framework always supplies the namespace-bound one.\n * @param key - dictionary key.\n * @param params - `{name}` template params.\n * @returns the template with params substituted.\n */\nfunction fallbackTranslate(key: SubscriptionsKey, params?: Record<string, unknown>): string {\n let text: string = en[key]\n for (const [name, value] of Object.entries(params ?? {})) {\n text = text.replaceAll(`{${name}}`, String(value))\n }\n return text\n}\n\n/** Extract the prompt from the call's raw args JSON; falls back to the first string value, then the raw line. */\nfunction derivePrompt(argsRaw: string): string {\n let parsed: unknown\n try {\n parsed = JSON.parse(argsRaw)\n } catch {\n // Non-JSON args (mid-stream truncation): fall back to the raw string below.\n parsed = undefined\n }\n let prompt: string | undefined\n if (typeof parsed === 'object' && parsed !== null) {\n const args = parsed as Record<string, unknown>\n if (typeof args.prompt === 'string' && args.prompt !== '') prompt = args.prompt\n else {\n for (const value of Object.values(args)) {\n if (typeof value === 'string' && value !== '') { prompt = value; break }\n }\n }\n }\n const line = (prompt ?? argsRaw).split('\\n', 1)[0] ?? ''\n return line.length > PROMPT_MAX_LENGTH ? `${line.slice(0, PROMPT_MAX_LENGTH)}…` : line\n}\n\n/** Flatten a settled result's text blocks (the degraded text-only route and the error line). */\nfunction resultText(block: ToolCallBlock): string {\n if (!('kind' in block)) return ''\n const parts: string[] = []\n for (const part of block.content) {\n if (part.type === 'text') parts.push(part.text)\n }\n if (parts.length === 0 && block.error !== undefined) parts.push(`${block.error.name}: ${block.error.code}`)\n return parts.join('\\n')\n}\n\n/** Image attachments of a settled result; empty while running or on the text-only route. */\nfunction resultImages(block: ToolCallBlock): { attachment: ImageAttachmentRef }[] {\n if (!('kind' in block)) return []\n const images: { attachment: ImageAttachmentRef }[] = []\n for (const part of block.content) {\n if (part.type === 'image') images.push({ attachment: part.attachment as ImageAttachmentRef })\n }\n return images\n}\n\nconst styles: Record<string, CSSProperties> = {\n container: { display: 'flex', flexDirection: 'column', gap: 6, padding: '4px 0' },\n row: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 },\n icon: { display: 'inline-flex', flexShrink: 0, color: 'var(--dsw-alias-label-tertiary)' },\n title: {\n fontSize: 13, lineHeight: '20px', color: 'var(--dsw-alias-label-primary)',\n overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',\n },\n subtle: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },\n output: {\n margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-secondary)',\n whiteSpace: 'pre-wrap', overflowWrap: 'anywhere',\n },\n error: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-error-primary)' },\n}\n\n/**\n * The `image_generate` keyed toolview component.\n * @param props - owner share, inject face, and locale seat (spread flat).\n * @returns the call row plus, once settled, the gallery / text / error body.\n */\nexport function ImageGenerateToolview(props: ImageGenerateToolviewProps) {\n const { block, load } = props\n const t = props.t ?? fallbackTranslate\n if (block === undefined) return null\n const settled = 'kind' in block\n const argsRaw = (settled ? block.call?.argsRaw : block.argsRaw) ?? ''\n const title = `image_generate: ${derivePrompt(argsRaw)}`\n const images = resultImages(block)\n const text = settled ? resultText(block) : ''\n const labels: MessageImageLabels = {\n image: t('image'),\n open: t('viewImage'),\n openNamed: name => t('viewImageNamed', { name }),\n loading: t('imageLoading'),\n loadFailed: t('imageLoadFailed'),\n lightbox: { dialog: t('imagePreview'), close: t('imageClose') },\n }\n return (\n <div style={styles.container}>\n <div style={styles.row}>\n <span style={styles.icon}><IconSparkle16 size={14} /></span>\n <span style={styles.title}>{title}</span>\n </div>\n {!settled && <p style={styles.subtle}>{t('generating')}</p>}\n {settled && block.isError && text !== '' && (\n <p style={styles.error}>{text.split('\\n', 1)[0]}</p>\n )}\n {settled && !block.isError && images.length > 0 && load !== undefined && (\n <ImageGallery images={images} load={load} align=\"start\" labels={labels} />\n )}\n {settled && !block.isError && images.length === 0 && text !== '' && (\n <p style={styles.output}>{text}</p>\n )}\n </div>\n )\n}\n","/**\n * Subscription OAuth login page, browser half. Registers the Subscriptions\n * settings section; every login state fact arrives through the node half's\n * `/subscriptions-auth` RPC channel — this plugin holds no credential state of its\n * own. Section copy rides the client locale service: one 'settings.subscriptions'\n * namespace with zh/en dictionaries, rebound per read so the nav label and\n * page text follow the active locale.\n */\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\n// Type-only: pulls the shell's SlotMap merge (the 'settings.section' entry).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// `.js` extension: this package's tsconfig lacks the reference repo's\n// allowImportingTsExtensions/rewriteRelativeImportExtensions pair; under\n// nodenext the .js specifier resolves to the .tsx source (see README note).\nimport { SubscriptionsSection } from './SubscriptionsSection.js'\nimport type { SubscriptionsSectionInjected } from './SubscriptionsSection.js'\nimport { ImageGenerateToolview, createImageLoader } from './ImageGenerateToolview.js'\nimport type { ImageGenerateToolviewInjected } from './ImageGenerateToolview.js'\nimport { en, zh } from './locales.js'\nimport type { SubscriptionsKey } from './locales.js'\n\nexport type { SubscriptionsSectionInjected, SubscriptionsSectionProps } from './SubscriptionsSection.js'\nexport type { ImageGenerateToolviewInjected, ImageGenerateToolviewProps } from './ImageGenerateToolview.js'\nexport type { SubscriptionsKey } from './locales.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/**\n * Required services (cordis fiber inject): `slots` carries the registration\n * seat, `connection` the `/subscriptions-auth` RPC caller, and `locale` the copy\n * dictionaries.\n */\nexport const inject = ['slots', 'connection', 'locale']\n\n/**\n * Register the Subscriptions section once the `settings.section` declaration\n * is on the ledger (the shell's apply order relative to this one is NOT\n * constrained; registration depends on the slot through `slots.inject()`).\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-plugin-subscriptions: copy dictionaries')\n // The client-runtime Context merge types `connection` as the host handle;\n // in the browser shell 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 injected = (): SubscriptionsSectionInjected => ({ rpc: connection.rpc, t })\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'subscriptions',\n order: 90,\n // A thunk re-evaluated per read, so the nav label follows the active locale.\n label: () => t('nav'),\n inject: injected,\n }, SubscriptionsSection))\n\n // The image_generate keyed toolview owns how image calls render inline; its\n // gallery bytes ride the same channel through the injected loader. The\n // framework synthesizes the toolview's own `t` seat from `locale: NS`.\n const toolviewInjected = (): ImageGenerateToolviewInjected => ({ load: createImageLoader(connection.rpc) })\n ctx.slots.inject('tool.call.toolview', () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'image_generate',\n locale: NS,\n inject: toolviewInjected,\n }, ImageGenerateToolview))\n}\n"],"mappings":"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"}
|