@edge-sky/dsh-oauth-adapter 0.1.1-rc.9 → 0.1.2-beta.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.
- package/README.i18n.yaml +2 -2
- package/README.md +17 -3
- package/README.zh.md +17 -3
- package/lib/client.js +104 -31
- package/lib/index.d.ts +2 -0
- package/lib/index.js +77 -7
- package/lib/protocol.d.ts +22 -0
- package/lib/protocol.js +16 -0
- package/lib/types/client/locales.d.ts +1 -0
- package/lib/types/client/store.d.ts +2 -0
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/protocol.d.ts +22 -0
- package/package.json +23 -21
package/README.i18n.yaml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
# Bilingual-pair consistency record: the git blob hash of each side as of the
|
|
2
2
|
# last confirmed-consistent state. Both languages carry equal authority.
|
|
3
|
-
README.md:
|
|
4
|
-
README.zh.md:
|
|
3
|
+
README.md: c4642ceaea18fbc2482a1a121893d9e5ee2662c4
|
|
4
|
+
README.zh.md: 7641d4bdcd89a0bfa9a247a4dc59013c0614e434
|
package/README.md
CHANGED
|
@@ -4,8 +4,17 @@ English | [中文](README.zh.md)
|
|
|
4
4
|
|
|
5
5
|
An OAuth account page for the DSH Web profile. It supports:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
7
|
+
| Provider | pi-ai sign-in path |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| OpenAI Codex | Browser callback or device code |
|
|
10
|
+
| GitHub Copilot | GitHub or GitHub Enterprise device code |
|
|
11
|
+
| Anthropic | Browser callback with manual code/redirect fallback |
|
|
12
|
+
| Kimi For Coding | Device code |
|
|
13
|
+
| OpenRouter | Browser PKCE callback |
|
|
14
|
+
| Radius | Browser PKCE callback or device code |
|
|
15
|
+
| xAI | Device code |
|
|
16
|
+
|
|
17
|
+
Each account is shown only as available when the installed `@deepseek-ai/dsh-llm-pi-ai` actually registers its OAuth flow. This keeps older or differently bundled pi-ai versions fail-closed instead of exposing a login button that cannot work.
|
|
9
18
|
|
|
10
19
|
The adapter has only been tested with DSH `0.1.1-rc.2`; compatibility with future versions is not guaranteed.
|
|
11
20
|
|
|
@@ -27,9 +36,14 @@ Start DSH:
|
|
|
27
36
|
npx @deepseek-ai/dsh web
|
|
28
37
|
```
|
|
29
38
|
|
|
39
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/78a59190-8029-4c60-bc50-b763312540f7" />
|
|
40
|
+
|
|
41
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/e0cc6591-73a4-4e87-9ef6-68950126b290" />
|
|
42
|
+
|
|
43
|
+
|
|
30
44
|
## How it works
|
|
31
45
|
|
|
32
|
-
DSH integrates pi-ai through the `@deepseek-ai/dsh-llm-pi-ai` adapter, but does not provide an OAuth entry point. `@edge-sky/dsh-oauth-adapter`
|
|
46
|
+
DSH integrates pi-ai through the `@deepseek-ai/dsh-llm-pi-ai` adapter, but does not provide an OAuth entry point. `@edge-sky/dsh-oauth-adapter` exposes pi-ai's existing provider login flows through the DSH Authorization Service. Browser links, device codes, text and secret input, method selection, cancellation, and withdrawn prompts all use the same provider-neutral transport.
|
|
33
47
|
|
|
34
48
|
Because DSH does not currently mount the `ctx.authorization` service, this plugin also mounts it manually.
|
|
35
49
|
|
package/README.zh.md
CHANGED
|
@@ -4,8 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
为 DSH Web profile 提供独立的 OAuth 账户页面。当前支持:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
7
|
+
| 提供商 | pi-ai 登录路径 |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| OpenAI Codex | 浏览器回调或设备码 |
|
|
10
|
+
| GitHub Copilot | GitHub 或 GitHub Enterprise 设备码 |
|
|
11
|
+
| Anthropic | 浏览器回调,并支持手工粘贴授权码/重定向地址 |
|
|
12
|
+
| Kimi For Coding | 设备码 |
|
|
13
|
+
| OpenRouter | 浏览器 PKCE 回调 |
|
|
14
|
+
| Radius | 浏览器 PKCE 回调或设备码 |
|
|
15
|
+
| xAI | 设备码 |
|
|
16
|
+
|
|
17
|
+
只有当当前安装的 `@deepseek-ai/dsh-llm-pi-ai` 确实注册了对应 OAuth 流程时,账户才会显示为可用。这样旧版或采用不同 pi-ai bundle 的 DSH 会安全地禁用登录按钮,而不会暴露无法完成的流程。
|
|
9
18
|
|
|
10
19
|
当前仅对 DSH`0.1.1-rc.2`进行了测试,不保证未来版本的兼容性
|
|
11
20
|
|
|
@@ -27,9 +36,14 @@ npx @deepseek-ai/dsh plugin --profile web add @edge-sky/dsh-oauth-adapter
|
|
|
27
36
|
npx @deepseek-ai/dsh web
|
|
28
37
|
```
|
|
29
38
|
|
|
39
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/134ec856-e17b-4800-bb87-069851986d3e" />
|
|
40
|
+
|
|
41
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/8007002a-a036-4cf4-b015-d4e50eff25d9" />
|
|
42
|
+
|
|
43
|
+
|
|
30
44
|
## 工作原理
|
|
31
45
|
|
|
32
|
-
DSH 通过 `@deepseek-ai/dsh-llm-pi-ai` 适配器接入 pi-ai,但并没有提供 OAuth 的入口。`@edge-sky/dsh-oauth-adapter`
|
|
46
|
+
DSH 通过 `@deepseek-ai/dsh-llm-pi-ai` 适配器接入 pi-ai,但并没有提供 OAuth 的入口。`@edge-sky/dsh-oauth-adapter` 通过 DSH Authorization Service 暴露 pi-ai 已有的 provider 登录流程。浏览器链接、设备码、文本与密码输入、登录方式选择、取消和撤回提示均通过同一套 provider-neutral 传输完成。
|
|
33
47
|
|
|
34
48
|
由于 DSH 目前并没有挂载`ctx.authorization`服务,因此该插件同时手动对其进行了挂载
|
|
35
49
|
|
package/lib/client.js
CHANGED
|
@@ -6,6 +6,49 @@ window.__ModuleLoader__.load({
|
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
|
+
//#region src/protocol.ts
|
|
10
|
+
/** Shared browser/Host wire vocabulary for the OAuth account surface. */
|
|
11
|
+
const OAUTH_SOCKET_PATH = "/_edge-sky/dsh-oauth";
|
|
12
|
+
const OAUTH_SOCKET_PROTOCOL = "dsh-oauth-v1";
|
|
13
|
+
const PROVIDERS = [
|
|
14
|
+
{
|
|
15
|
+
id: "openai-codex",
|
|
16
|
+
key: "llm-pi-ai/openai-codex",
|
|
17
|
+
fallbackLabel: "OpenAI Codex",
|
|
18
|
+
modelGroupLabel: "OpenAI Codex (OAuth)"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "github-copilot",
|
|
22
|
+
key: "llm-pi-ai/github-copilot",
|
|
23
|
+
fallbackLabel: "GitHub Copilot",
|
|
24
|
+
modelGroupLabel: "GitHub Copilot (OAuth)"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "anthropic",
|
|
28
|
+
key: "llm-pi-ai/anthropic",
|
|
29
|
+
fallbackLabel: "Anthropic",
|
|
30
|
+
modelGroupLabel: "Anthropic (OAuth)"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "kimi-coding",
|
|
34
|
+
key: "llm-pi-ai/kimi-coding",
|
|
35
|
+
fallbackLabel: "Kimi For Coding",
|
|
36
|
+
modelGroupLabel: "Kimi For Coding (OAuth)"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "openrouter",
|
|
40
|
+
key: "llm-pi-ai/openrouter",
|
|
41
|
+
fallbackLabel: "OpenRouter",
|
|
42
|
+
modelGroupLabel: "OpenRouter (OAuth)"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "xai",
|
|
46
|
+
key: "llm-pi-ai/xai",
|
|
47
|
+
fallbackLabel: "xAI",
|
|
48
|
+
modelGroupLabel: "xAI (OAuth)"
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
//#endregion
|
|
9
52
|
//#region src/client/OAuthAccountsSection.tsx
|
|
10
53
|
/** OAuth account settings page. */
|
|
11
54
|
function safeHttpUrl(value) {
|
|
@@ -92,6 +135,16 @@ window.__ModuleLoader__.load({
|
|
|
92
135
|
]
|
|
93
136
|
});
|
|
94
137
|
}
|
|
138
|
+
function ErrorPanel(props) {
|
|
139
|
+
const collapsible = props.detail !== void 0 && (props.detail.includes("\n") || props.detail.length > 240);
|
|
140
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
141
|
+
className: "dsh-oauth-error",
|
|
142
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: props.message }), props.detail !== void 0 && (collapsible ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
143
|
+
className: "dsh-oauth-error-details",
|
|
144
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: props.t("technicalDetails") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: props.detail })]
|
|
145
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: props.detail }))]
|
|
146
|
+
});
|
|
147
|
+
}
|
|
95
148
|
function AttemptPanel(props) {
|
|
96
149
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
97
150
|
const url = safeHttpUrl(props.attempt.notice?.url);
|
|
@@ -125,9 +178,10 @@ window.__ModuleLoader__.load({
|
|
|
125
178
|
controller: props.controller,
|
|
126
179
|
t: props.t
|
|
127
180
|
}, props.attempt.prompt.id),
|
|
128
|
-
props.attempt.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
129
|
-
|
|
130
|
-
|
|
181
|
+
props.attempt.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorPanel, {
|
|
182
|
+
message: props.attempt.error,
|
|
183
|
+
...props.attempt.errorDetail === void 0 ? {} : { detail: props.attempt.errorDetail },
|
|
184
|
+
t: props.t
|
|
131
185
|
}),
|
|
132
186
|
props.attempt.id !== void 0 && (props.attempt.phase === "running" || props.attempt.phase === "starting") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
133
187
|
className: "dsh-oauth-button",
|
|
@@ -158,9 +212,10 @@ window.__ModuleLoader__.load({
|
|
|
158
212
|
className: "dsh-oauth-intro",
|
|
159
213
|
children: t("intro")
|
|
160
214
|
}),
|
|
161
|
-
snapshot.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
162
|
-
|
|
163
|
-
|
|
215
|
+
snapshot.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorPanel, {
|
|
216
|
+
message: snapshot.error,
|
|
217
|
+
...snapshot.errorDetail === void 0 ? {} : { detail: snapshot.errorDetail },
|
|
218
|
+
t
|
|
164
219
|
}),
|
|
165
220
|
snapshot.connection !== "open" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
166
221
|
className: "dsh-oauth-button",
|
|
@@ -177,7 +232,7 @@ window.__ModuleLoader__.load({
|
|
|
177
232
|
}),
|
|
178
233
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
179
234
|
className: "dsh-oauth-list",
|
|
180
|
-
children:
|
|
235
|
+
children: PROVIDERS.map(({ id: provider }) => {
|
|
181
236
|
const account = accountByProvider.get(provider);
|
|
182
237
|
const attempt = snapshot.attempt?.provider === provider ? snapshot.attempt : void 0;
|
|
183
238
|
const busy = account?.inFlight === true || attempt?.phase === "running" || attempt?.phase === "starting";
|
|
@@ -261,6 +316,7 @@ window.__ModuleLoader__.load({
|
|
|
261
316
|
authorized: "Sign-in completed.",
|
|
262
317
|
cancelled: "Sign-in was cancelled.",
|
|
263
318
|
failed: "Sign-in failed.",
|
|
319
|
+
technicalDetails: "Technical details",
|
|
264
320
|
submit: "Continue",
|
|
265
321
|
copy: "Copy code",
|
|
266
322
|
copied: "Copied",
|
|
@@ -292,6 +348,7 @@ window.__ModuleLoader__.load({
|
|
|
292
348
|
authorized: "登录已完成。",
|
|
293
349
|
cancelled: "登录已取消。",
|
|
294
350
|
failed: "登录失败。",
|
|
351
|
+
technicalDetails: "技术详情",
|
|
295
352
|
submit: "继续",
|
|
296
353
|
copy: "复制代码",
|
|
297
354
|
copied: "已复制",
|
|
@@ -303,11 +360,6 @@ window.__ModuleLoader__.load({
|
|
|
303
360
|
hostDisconnected: "与 DSH 的 OAuth 连接已中断。"
|
|
304
361
|
};
|
|
305
362
|
//#endregion
|
|
306
|
-
//#region src/protocol.ts
|
|
307
|
-
/** Shared browser/Host wire vocabulary for the OAuth account surface. */
|
|
308
|
-
const OAUTH_SOCKET_PATH = "/_edge-sky/dsh-oauth";
|
|
309
|
-
const OAUTH_SOCKET_PROTOCOL = "dsh-oauth-v1";
|
|
310
|
-
//#endregion
|
|
311
363
|
//#region src/client/store.ts
|
|
312
364
|
/** Browser state machine for the plugin-owned OAuth WebSocket. */
|
|
313
365
|
function socketUrl() {
|
|
@@ -355,7 +407,7 @@ window.__ModuleLoader__.load({
|
|
|
355
407
|
getSnapshot = () => this.snapshot;
|
|
356
408
|
begin(provider) {
|
|
357
409
|
if (this.snapshot.attempt?.phase === "starting" || this.snapshot.attempt?.phase === "running") return;
|
|
358
|
-
const { error: _error, ...current } = this.snapshot;
|
|
410
|
+
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
359
411
|
this.update({
|
|
360
412
|
...current,
|
|
361
413
|
attempt: {
|
|
@@ -426,7 +478,7 @@ window.__ModuleLoader__.load({
|
|
|
426
478
|
socket.addEventListener("open", () => {
|
|
427
479
|
if (this.socket !== socket) return;
|
|
428
480
|
this.reconnectDelay = 500;
|
|
429
|
-
const { error: _error, ...current } = this.snapshot;
|
|
481
|
+
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
430
482
|
this.update({
|
|
431
483
|
...current,
|
|
432
484
|
connection: "open"
|
|
@@ -442,10 +494,12 @@ window.__ModuleLoader__.load({
|
|
|
442
494
|
try {
|
|
443
495
|
value = JSON.parse(event.data);
|
|
444
496
|
} catch {
|
|
445
|
-
|
|
497
|
+
const next = {
|
|
446
498
|
...this.snapshot,
|
|
447
499
|
error: "DSH returned an invalid OAuth message."
|
|
448
|
-
}
|
|
500
|
+
};
|
|
501
|
+
delete next.errorDetail;
|
|
502
|
+
this.update(next);
|
|
449
503
|
return;
|
|
450
504
|
}
|
|
451
505
|
if (isServerMessage(value)) this.receive(value);
|
|
@@ -461,7 +515,7 @@ window.__ModuleLoader__.load({
|
|
|
461
515
|
return;
|
|
462
516
|
}
|
|
463
517
|
const attempt = this.snapshot.attempt;
|
|
464
|
-
|
|
518
|
+
const interrupted = {
|
|
465
519
|
...this.snapshot,
|
|
466
520
|
connection: "reconnecting",
|
|
467
521
|
error: "The OAuth connection to DSH was interrupted.",
|
|
@@ -470,7 +524,10 @@ window.__ModuleLoader__.load({
|
|
|
470
524
|
phase: "failed",
|
|
471
525
|
error: "The OAuth connection to DSH was interrupted."
|
|
472
526
|
} }
|
|
473
|
-
}
|
|
527
|
+
};
|
|
528
|
+
delete interrupted.errorDetail;
|
|
529
|
+
if (interrupted.attempt?.error === "The OAuth connection to DSH was interrupted.") delete interrupted.attempt.errorDetail;
|
|
530
|
+
this.update(interrupted);
|
|
474
531
|
const delay = this.reconnectDelay;
|
|
475
532
|
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 5e3);
|
|
476
533
|
this.reconnectTimer = window.setTimeout(() => {
|
|
@@ -482,10 +539,12 @@ window.__ModuleLoader__.load({
|
|
|
482
539
|
}
|
|
483
540
|
send(command) {
|
|
484
541
|
if (this.socket?.readyState !== WebSocket.OPEN) {
|
|
485
|
-
|
|
542
|
+
const next = {
|
|
486
543
|
...this.snapshot,
|
|
487
544
|
error: "The OAuth connection to DSH is not ready."
|
|
488
|
-
}
|
|
545
|
+
};
|
|
546
|
+
delete next.errorDetail;
|
|
547
|
+
this.update(next);
|
|
489
548
|
return;
|
|
490
549
|
}
|
|
491
550
|
this.socket.send(JSON.stringify(command));
|
|
@@ -504,7 +563,7 @@ window.__ModuleLoader__.load({
|
|
|
504
563
|
this.update(nextSnapshot);
|
|
505
564
|
return;
|
|
506
565
|
case "started":
|
|
507
|
-
const { error: _error, ...current } = this.snapshot;
|
|
566
|
+
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
508
567
|
this.update({
|
|
509
568
|
...current,
|
|
510
569
|
attempt: {
|
|
@@ -567,17 +626,26 @@ window.__ModuleLoader__.load({
|
|
|
567
626
|
}
|
|
568
627
|
case "error": {
|
|
569
628
|
const attempt = this.snapshot.attempt;
|
|
570
|
-
if (message.attemptId !== void 0 && attempt?.id === message.attemptId)
|
|
571
|
-
|
|
572
|
-
attempt: {
|
|
629
|
+
if (message.attemptId !== void 0 && attempt?.id === message.attemptId) {
|
|
630
|
+
const nextAttempt = {
|
|
573
631
|
...attempt,
|
|
574
632
|
error: message.message
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
633
|
+
};
|
|
634
|
+
if (message.detail === void 0) delete nextAttempt.errorDetail;
|
|
635
|
+
else nextAttempt.errorDetail = message.detail;
|
|
636
|
+
this.update({
|
|
637
|
+
...this.snapshot,
|
|
638
|
+
attempt: nextAttempt
|
|
639
|
+
});
|
|
640
|
+
} else {
|
|
641
|
+
const next = {
|
|
642
|
+
...this.snapshot,
|
|
643
|
+
error: message.message
|
|
644
|
+
};
|
|
645
|
+
if (message.detail === void 0) delete next.errorDetail;
|
|
646
|
+
else next.errorDetail = message.detail;
|
|
647
|
+
this.update(next);
|
|
648
|
+
}
|
|
581
649
|
return;
|
|
582
650
|
}
|
|
583
651
|
case "ack": return;
|
|
@@ -595,7 +663,7 @@ window.__ModuleLoader__.load({
|
|
|
595
663
|
.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}
|
|
596
664
|
.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}
|
|
597
665
|
.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
|
|
598
|
-
.dsh-oauth-error{margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
|
|
666
|
+
.dsh-oauth-error{display:flex;flex-direction:column;gap:6px;margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.dsh-oauth-error p{margin:0}.dsh-oauth-error pre{box-sizing:border-box;max-width:100%;max-height:320px;margin:0;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;overflow:auto;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:11px/17px ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.dsh-oauth-error-details summary{cursor:pointer;color:var(--dsw-alias-label-secondary);user-select:none}.dsh-oauth-error-details[open] summary{margin-bottom:6px}
|
|
599
667
|
.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}
|
|
600
668
|
.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}
|
|
601
669
|
.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
@@ -607,6 +675,7 @@ window.__ModuleLoader__.load({
|
|
|
607
675
|
//#endregion
|
|
608
676
|
//#region src/client/index.ts
|
|
609
677
|
const NS = "settings.oauth-accounts";
|
|
678
|
+
const MODEL_SETTINGS_VISIBILITY = "modelSettingsVisibility";
|
|
610
679
|
/** Required browser services for settings placement and localized copy. */
|
|
611
680
|
const inject = ["slots", "locale"];
|
|
612
681
|
/** Register the OAuth account page and its app-lifetime connection controller. */
|
|
@@ -628,6 +697,10 @@ window.__ModuleLoader__.load({
|
|
|
628
697
|
ctx.effect(() => () => {
|
|
629
698
|
controller.dispose();
|
|
630
699
|
}, "dsh-oauth-adapter: controller");
|
|
700
|
+
ctx.inject([MODEL_SETTINGS_VISIBILITY], (scope) => {
|
|
701
|
+
const visibility = scope.get(MODEL_SETTINGS_VISIBILITY);
|
|
702
|
+
scope.effect(() => visibility.registerHiddenProviders(PROVIDERS.map((provider) => provider.id)), "dsh-oauth-adapter: hide OAuth providers from Models settings");
|
|
703
|
+
});
|
|
631
704
|
const t = ctx.locale.bind(NS);
|
|
632
705
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
633
706
|
name: "settings.section",
|
package/lib/index.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export declare function isLoopbackAddress(address: string | undefined): boolean;
|
|
|
33
33
|
export declare function safeNoticeUrl(value: string | undefined): string | undefined;
|
|
34
34
|
/** Validate the browser handshake before `ws` takes ownership of the socket. */
|
|
35
35
|
export declare function acceptsBrowserUpgrade(request: IncomingMessage): boolean;
|
|
36
|
+
/** Format one Host failure for browser diagnostics without forwarding credentials or unbounded data. */
|
|
37
|
+
export declare function formatErrorDetail(error: unknown): string;
|
|
36
38
|
/** Mount the loopback-only OAuth WebSocket over official rc2 services. */
|
|
37
39
|
export declare function apply(ctx: OAuthContext, config: Config): () => Promise<void>;
|
|
38
40
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @module @edge-sky/dsh-oauth-adapter
|
|
5
5
|
*/
|
|
6
6
|
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import { inspect } from 'node:util';
|
|
7
8
|
import { settingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
8
9
|
import z from '@deepseek-ai/schemastery';
|
|
9
10
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
@@ -55,6 +56,13 @@ function promptView(prompt, provider) {
|
|
|
55
56
|
: {},
|
|
56
57
|
};
|
|
57
58
|
}
|
|
59
|
+
function providerPromptAnswer(prompt, provider, value) {
|
|
60
|
+
if (provider === 'github-copilot' && prompt.kind === 'text'
|
|
61
|
+
&& prompt.message === GITHUB_DOMAIN_PROMPT && value.trim().length === 0) {
|
|
62
|
+
return 'github.com';
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
58
66
|
/** Whether a socket address belongs to the local host. */
|
|
59
67
|
export function isLoopbackAddress(address) {
|
|
60
68
|
return address === '127.0.0.1' || address === '::1' || address === '::ffff:127.0.0.1';
|
|
@@ -101,6 +109,67 @@ function rawLength(raw) {
|
|
|
101
109
|
return raw.reduce((total, chunk) => total + chunk.byteLength, 0);
|
|
102
110
|
return raw.byteLength;
|
|
103
111
|
}
|
|
112
|
+
const MAX_ERROR_DETAIL_LENGTH = 12 * 1024;
|
|
113
|
+
const MAX_ERROR_CAUSE_DEPTH = 6;
|
|
114
|
+
function redactErrorDetail(value) {
|
|
115
|
+
return value
|
|
116
|
+
.replace(/(\bAuthorization\b\s*["']?\s*[:=]\s*["']?)(?:Bearer\s+)?([^"'\s,}&]+)/giu, '$1[REDACTED]')
|
|
117
|
+
.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/giu, 'Bearer [REDACTED]')
|
|
118
|
+
.replace(/(\b(?:access[_-]?token|refresh[_-]?token|id[_-]?token|client[_-]?secret|api[_-]?key)\b\s*["']?\s*[:=]\s*["']?)([^"'\s,}&]+)/giu, '$1[REDACTED]')
|
|
119
|
+
.replace(/\b(?:github_pat_|gh[opusr]_|sk-)[A-Za-z0-9_-]{12,}\b/gu, '[REDACTED]');
|
|
120
|
+
}
|
|
121
|
+
function errorProperties(value) {
|
|
122
|
+
const record = value;
|
|
123
|
+
const properties = ['code', 'status', 'statusCode']
|
|
124
|
+
.flatMap((key) => {
|
|
125
|
+
const entry = record[key];
|
|
126
|
+
return typeof entry === 'string' || typeof entry === 'number' ? [`${key}: ${String(entry)}`] : [];
|
|
127
|
+
});
|
|
128
|
+
return properties.length === 0 ? undefined : properties.join(', ');
|
|
129
|
+
}
|
|
130
|
+
/** Format one Host failure for browser diagnostics without forwarding credentials or unbounded data. */
|
|
131
|
+
export function formatErrorDetail(error) {
|
|
132
|
+
const sections = [];
|
|
133
|
+
const seen = new Set();
|
|
134
|
+
let current = error;
|
|
135
|
+
for (let depth = 0; current !== undefined && depth < MAX_ERROR_CAUSE_DEPTH; depth += 1) {
|
|
136
|
+
if (typeof current === 'object' && current !== null) {
|
|
137
|
+
if (seen.has(current)) {
|
|
138
|
+
sections.push('Caused by: [circular error cause]');
|
|
139
|
+
current = undefined;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
seen.add(current);
|
|
143
|
+
}
|
|
144
|
+
const prefix = depth === 0 ? '' : 'Caused by: ';
|
|
145
|
+
if (current instanceof Error) {
|
|
146
|
+
const properties = errorProperties(current);
|
|
147
|
+
const rendered = current.stack ?? `${current.name}: ${current.message}`;
|
|
148
|
+
sections.push(`${prefix}${rendered}${properties === undefined ? '' : `\n${properties}`}`);
|
|
149
|
+
current = current.cause;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
sections.push(prefix + (typeof current === 'string'
|
|
153
|
+
? current
|
|
154
|
+
: inspect(current, {
|
|
155
|
+
breakLength: 120,
|
|
156
|
+
compact: false,
|
|
157
|
+
customInspect: false,
|
|
158
|
+
depth: 4,
|
|
159
|
+
maxArrayLength: 40,
|
|
160
|
+
maxStringLength: 4096,
|
|
161
|
+
sorted: true,
|
|
162
|
+
})));
|
|
163
|
+
current = undefined;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
if (current !== undefined)
|
|
167
|
+
sections.push('Caused by: [additional causes omitted]');
|
|
168
|
+
const redacted = redactErrorDetail(sections.join('\n'));
|
|
169
|
+
if (redacted.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
170
|
+
return redacted;
|
|
171
|
+
return `${redacted.slice(0, MAX_ERROR_DETAIL_LENGTH)}\n[diagnostic truncated]`;
|
|
172
|
+
}
|
|
104
173
|
/** One ownership-scoped browser authorization connection. */
|
|
105
174
|
class OAuthConnection {
|
|
106
175
|
ctx;
|
|
@@ -124,7 +193,7 @@ class OAuthConnection {
|
|
|
124
193
|
this.queue = this.queue.then(() => this.receive(raw.toString())).catch((error) => {
|
|
125
194
|
this.ctx.logger.warn('dsh-oauth-adapter: command handling failed');
|
|
126
195
|
this.ctx.logger.warn(error);
|
|
127
|
-
this.sendError('operation-failed', 'the OAuth operation failed');
|
|
196
|
+
this.sendError('operation-failed', 'the OAuth operation failed', undefined, undefined, formatErrorDetail(error));
|
|
128
197
|
});
|
|
129
198
|
});
|
|
130
199
|
socket.on('close', () => {
|
|
@@ -150,11 +219,12 @@ class OAuthConnection {
|
|
|
150
219
|
if (this.socket.readyState === WebSocket.OPEN)
|
|
151
220
|
this.socket.send(JSON.stringify(message));
|
|
152
221
|
}
|
|
153
|
-
sendError(code, message, requestId, attemptId) {
|
|
222
|
+
sendError(code, message, requestId, attemptId, detail) {
|
|
154
223
|
this.send({
|
|
155
224
|
type: 'error', code, message,
|
|
156
225
|
...requestId === undefined ? {} : { requestId },
|
|
157
226
|
...attemptId === undefined ? {} : { attemptId },
|
|
227
|
+
...detail === undefined ? {} : { detail },
|
|
158
228
|
});
|
|
159
229
|
}
|
|
160
230
|
async receive(raw) {
|
|
@@ -226,7 +296,7 @@ class OAuthConnection {
|
|
|
226
296
|
catch (error) {
|
|
227
297
|
this.ctx.logger.warn('dsh-oauth-adapter: credential status read failed');
|
|
228
298
|
this.ctx.logger.warn(error);
|
|
229
|
-
this.sendError('operation-failed', 'account status is unavailable', requestId);
|
|
299
|
+
this.sendError('operation-failed', 'account status is unavailable', requestId, undefined, formatErrorDetail(error));
|
|
230
300
|
}
|
|
231
301
|
}
|
|
232
302
|
begin(command) {
|
|
@@ -278,14 +348,14 @@ class OAuthConnection {
|
|
|
278
348
|
catch (error) {
|
|
279
349
|
this.ctx.logger.warn('dsh-oauth-adapter: model route activation failed for %s', provider.id);
|
|
280
350
|
this.ctx.logger.warn(error);
|
|
281
|
-
this.sendError('model-route-unavailable', 'sign-in completed, but the OAuth model route could not be enabled', undefined, attempt.id);
|
|
351
|
+
this.sendError('model-route-unavailable', 'sign-in completed, but the OAuth model route could not be enabled', undefined, attempt.id, formatErrorDetail(error));
|
|
282
352
|
}
|
|
283
353
|
}
|
|
284
354
|
this.finish(attempt, outcome.status);
|
|
285
355
|
}, (error) => {
|
|
286
356
|
this.ctx.logger.warn('dsh-oauth-adapter: provider sign-in failed for %s', attempt.provider);
|
|
287
357
|
this.ctx.logger.warn(error);
|
|
288
|
-
this.sendError('sign-in-failed', 'sign-in failed
|
|
358
|
+
this.sendError('sign-in-failed', 'sign-in failed', undefined, attempt.id, formatErrorDetail(error));
|
|
289
359
|
this.finish(attempt, 'failed');
|
|
290
360
|
});
|
|
291
361
|
}
|
|
@@ -310,7 +380,7 @@ class OAuthConnection {
|
|
|
310
380
|
});
|
|
311
381
|
};
|
|
312
382
|
attempt.prompts.set(promptId, {
|
|
313
|
-
resolve: value => { finish(() => { resolve(value); }); },
|
|
383
|
+
resolve: value => { finish(() => { resolve(providerPromptAnswer(prompt, attempt.provider, value)); }); },
|
|
314
384
|
reject: reason => { finish(() => { reject(reason); }); },
|
|
315
385
|
});
|
|
316
386
|
prompt.signal?.addEventListener('abort', withdraw, { once: true });
|
|
@@ -370,7 +440,7 @@ class OAuthConnection {
|
|
|
370
440
|
catch (error) {
|
|
371
441
|
this.ctx.logger.warn('dsh-oauth-adapter: sign-out failed for %s', provider.id);
|
|
372
442
|
this.ctx.logger.warn(error);
|
|
373
|
-
this.sendError('operation-failed', 'sign-out failed
|
|
443
|
+
this.sendError('operation-failed', 'sign-out failed', command.requestId, undefined, formatErrorDetail(error));
|
|
374
444
|
}
|
|
375
445
|
}
|
|
376
446
|
finish(attempt, status) {
|
package/lib/protocol.d.ts
CHANGED
|
@@ -13,6 +13,26 @@ export declare const PROVIDERS: readonly [{
|
|
|
13
13
|
readonly key: "llm-pi-ai/github-copilot";
|
|
14
14
|
readonly fallbackLabel: "GitHub Copilot";
|
|
15
15
|
readonly modelGroupLabel: "GitHub Copilot (OAuth)";
|
|
16
|
+
}, {
|
|
17
|
+
readonly id: "anthropic";
|
|
18
|
+
readonly key: "llm-pi-ai/anthropic";
|
|
19
|
+
readonly fallbackLabel: "Anthropic";
|
|
20
|
+
readonly modelGroupLabel: "Anthropic (OAuth)";
|
|
21
|
+
}, {
|
|
22
|
+
readonly id: "kimi-coding";
|
|
23
|
+
readonly key: "llm-pi-ai/kimi-coding";
|
|
24
|
+
readonly fallbackLabel: "Kimi For Coding";
|
|
25
|
+
readonly modelGroupLabel: "Kimi For Coding (OAuth)";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "openrouter";
|
|
28
|
+
readonly key: "llm-pi-ai/openrouter";
|
|
29
|
+
readonly fallbackLabel: "OpenRouter";
|
|
30
|
+
readonly modelGroupLabel: "OpenRouter (OAuth)";
|
|
31
|
+
}, {
|
|
32
|
+
readonly id: "xai";
|
|
33
|
+
readonly key: "llm-pi-ai/xai";
|
|
34
|
+
readonly fallbackLabel: "xAI";
|
|
35
|
+
readonly modelGroupLabel: "xAI (OAuth)";
|
|
16
36
|
}];
|
|
17
37
|
export type ProviderId = (typeof PROVIDERS)[number]['id'];
|
|
18
38
|
export interface AccountView {
|
|
@@ -104,6 +124,8 @@ export type ServerMessage = {
|
|
|
104
124
|
attemptId?: string;
|
|
105
125
|
code: OAuthErrorCode;
|
|
106
126
|
message: string;
|
|
127
|
+
/** Bounded, credential-redacted Host diagnostic for optional UI expansion. */
|
|
128
|
+
detail?: string;
|
|
107
129
|
};
|
|
108
130
|
export type CommandParseResult = {
|
|
109
131
|
ok: true;
|
package/lib/protocol.js
CHANGED
|
@@ -12,6 +12,22 @@ export const PROVIDERS = [
|
|
|
12
12
|
id: 'github-copilot', key: 'llm-pi-ai/github-copilot', fallbackLabel: 'GitHub Copilot',
|
|
13
13
|
modelGroupLabel: 'GitHub Copilot (OAuth)',
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
id: 'anthropic', key: 'llm-pi-ai/anthropic', fallbackLabel: 'Anthropic',
|
|
17
|
+
modelGroupLabel: 'Anthropic (OAuth)',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'kimi-coding', key: 'llm-pi-ai/kimi-coding', fallbackLabel: 'Kimi For Coding',
|
|
21
|
+
modelGroupLabel: 'Kimi For Coding (OAuth)',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'openrouter', key: 'llm-pi-ai/openrouter', fallbackLabel: 'OpenRouter',
|
|
25
|
+
modelGroupLabel: 'OpenRouter (OAuth)',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'xai', key: 'llm-pi-ai/xai', fallbackLabel: 'xAI',
|
|
29
|
+
modelGroupLabel: 'xAI (OAuth)',
|
|
30
|
+
},
|
|
15
31
|
];
|
|
16
32
|
const ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
17
33
|
function isRecord(value) {
|
|
@@ -19,6 +19,7 @@ export declare const en: {
|
|
|
19
19
|
readonly authorized: "Sign-in completed.";
|
|
20
20
|
readonly cancelled: "Sign-in was cancelled.";
|
|
21
21
|
readonly failed: "Sign-in failed.";
|
|
22
|
+
readonly technicalDetails: "Technical details";
|
|
22
23
|
readonly submit: "Continue";
|
|
23
24
|
readonly copy: "Copy code";
|
|
24
25
|
readonly copied: "Copied";
|
|
@@ -16,12 +16,14 @@ export interface AttemptView {
|
|
|
16
16
|
notice?: NoticeView;
|
|
17
17
|
prompt?: ActivePromptView;
|
|
18
18
|
error?: string;
|
|
19
|
+
errorDetail?: string;
|
|
19
20
|
}
|
|
20
21
|
export interface OAuthAccountsSnapshot {
|
|
21
22
|
connection: 'connecting' | 'open' | 'reconnecting' | 'closed';
|
|
22
23
|
accounts: readonly AccountView[];
|
|
23
24
|
attempt?: AttemptView;
|
|
24
25
|
error?: string;
|
|
26
|
+
errorDetail?: string;
|
|
25
27
|
}
|
|
26
28
|
type Listener = () => void;
|
|
27
29
|
/** Remove interaction-only content once an authorization attempt settles. */
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Plugin-owned styles, injected and removed with the browser Cordis fiber. */
|
|
2
|
-
export declare const styles = "\n.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}\n.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}\n.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}\n.dsh-oauth-error{margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}\n.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}\n.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}\n.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}\n.dsh-oauth-dot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dsh-oauth-state[data-state=ready] .dsh-oauth-dot{background:var(--dsw-alias-state-success-primary)}.dsh-oauth-state[data-state=warning] .dsh-oauth-dot{background:var(--dsw-alias-state-error-primary)}.dsh-oauth-state[data-state=authorizing] .dsh-oauth-dot{background:var(--dsw-alias-button-info-fill)}\n.dsh-oauth-actions{display:flex;gap:6px;margin-left:auto}.dsh-oauth-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:30px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:15px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px;cursor:pointer}.dsh-oauth-button[data-variant=primary]{border-color:transparent;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]{border-color:transparent;color:var(--dsw-alias-state-error-primary)}.dsh-oauth-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-button[data-variant=primary]:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.dsh-oauth-button:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.dsh-oauth-button:disabled{cursor:not-allowed;opacity:.4}\n.dsh-oauth-flow{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l3);font-size:13px;line-height:20px}.dsh-oauth-link{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);text-decoration:none}.dsh-oauth-link:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-link-label{font-weight:500}.dsh-oauth-link-host{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsh-oauth-link-icon{color:var(--dsw-alias-brand-text)}.dsh-oauth-code{display:flex;align-items:center;gap:8px}.dsh-oauth-code code{padding:5px 8px;border-radius:6px;background:var(--dsw-alias-bg-module-platform);font-size:14px;letter-spacing:.08em}\n.dsh-oauth-prompt{display:flex;flex-direction:column;gap:7px}.dsh-oauth-input,.dsh-oauth-select{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}\n";
|
|
2
|
+
export declare const styles = "\n.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}\n.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}\n.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}\n.dsh-oauth-error{display:flex;flex-direction:column;gap:6px;margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.dsh-oauth-error p{margin:0}.dsh-oauth-error pre{box-sizing:border-box;max-width:100%;max-height:320px;margin:0;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;overflow:auto;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:11px/17px ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.dsh-oauth-error-details summary{cursor:pointer;color:var(--dsw-alias-label-secondary);user-select:none}.dsh-oauth-error-details[open] summary{margin-bottom:6px}\n.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}\n.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}\n.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}\n.dsh-oauth-dot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dsh-oauth-state[data-state=ready] .dsh-oauth-dot{background:var(--dsw-alias-state-success-primary)}.dsh-oauth-state[data-state=warning] .dsh-oauth-dot{background:var(--dsw-alias-state-error-primary)}.dsh-oauth-state[data-state=authorizing] .dsh-oauth-dot{background:var(--dsw-alias-button-info-fill)}\n.dsh-oauth-actions{display:flex;gap:6px;margin-left:auto}.dsh-oauth-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:30px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:15px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px;cursor:pointer}.dsh-oauth-button[data-variant=primary]{border-color:transparent;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]{border-color:transparent;color:var(--dsw-alias-state-error-primary)}.dsh-oauth-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-button[data-variant=primary]:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.dsh-oauth-button:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.dsh-oauth-button:disabled{cursor:not-allowed;opacity:.4}\n.dsh-oauth-flow{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l3);font-size:13px;line-height:20px}.dsh-oauth-link{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);text-decoration:none}.dsh-oauth-link:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-link-label{font-weight:500}.dsh-oauth-link-host{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsh-oauth-link-icon{color:var(--dsw-alias-brand-text)}.dsh-oauth-code{display:flex;align-items:center;gap:8px}.dsh-oauth-code code{padding:5px 8px;border-radius:6px;background:var(--dsw-alias-bg-module-platform);font-size:14px;letter-spacing:.08em}\n.dsh-oauth-prompt{display:flex;flex-direction:column;gap:7px}.dsh-oauth-input,.dsh-oauth-select{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}\n";
|
|
3
3
|
//# sourceMappingURL=styles.d.ts.map
|
package/lib/types/protocol.d.ts
CHANGED
|
@@ -13,6 +13,26 @@ export declare const PROVIDERS: readonly [{
|
|
|
13
13
|
readonly key: "llm-pi-ai/github-copilot";
|
|
14
14
|
readonly fallbackLabel: "GitHub Copilot";
|
|
15
15
|
readonly modelGroupLabel: "GitHub Copilot (OAuth)";
|
|
16
|
+
}, {
|
|
17
|
+
readonly id: "anthropic";
|
|
18
|
+
readonly key: "llm-pi-ai/anthropic";
|
|
19
|
+
readonly fallbackLabel: "Anthropic";
|
|
20
|
+
readonly modelGroupLabel: "Anthropic (OAuth)";
|
|
21
|
+
}, {
|
|
22
|
+
readonly id: "kimi-coding";
|
|
23
|
+
readonly key: "llm-pi-ai/kimi-coding";
|
|
24
|
+
readonly fallbackLabel: "Kimi For Coding";
|
|
25
|
+
readonly modelGroupLabel: "Kimi For Coding (OAuth)";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "openrouter";
|
|
28
|
+
readonly key: "llm-pi-ai/openrouter";
|
|
29
|
+
readonly fallbackLabel: "OpenRouter";
|
|
30
|
+
readonly modelGroupLabel: "OpenRouter (OAuth)";
|
|
31
|
+
}, {
|
|
32
|
+
readonly id: "xai";
|
|
33
|
+
readonly key: "llm-pi-ai/xai";
|
|
34
|
+
readonly fallbackLabel: "xAI";
|
|
35
|
+
readonly modelGroupLabel: "xAI (OAuth)";
|
|
16
36
|
}];
|
|
17
37
|
export type ProviderId = (typeof PROVIDERS)[number]['id'];
|
|
18
38
|
export interface AccountView {
|
|
@@ -104,6 +124,8 @@ export type ServerMessage = {
|
|
|
104
124
|
attemptId?: string;
|
|
105
125
|
code: OAuthErrorCode;
|
|
106
126
|
message: string;
|
|
127
|
+
/** Bounded, credential-redacted Host diagnostic for optional UI expansion. */
|
|
128
|
+
detail?: string;
|
|
107
129
|
};
|
|
108
130
|
export type CommandParseResult = {
|
|
109
131
|
ok: true;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edge-sky/dsh-oauth-adapter",
|
|
3
3
|
"description": "Web OAuth account surface for official DSH authorization flows",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2-beta.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "edge-sky",
|
|
7
7
|
"url": "https://github.com/edge-sky"
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "git+https://github.com/edge-sky/dsh-oauth.git"
|
|
14
|
+
"url": "git+https://github.com/edge-sky/dsh-oauth-adapter.git"
|
|
15
15
|
},
|
|
16
|
+
"packageManager": "pnpm@11.7.0",
|
|
16
17
|
"engines": {
|
|
17
18
|
"node": "^22.19.0 || >=24.0.0"
|
|
18
19
|
},
|
|
@@ -44,6 +45,13 @@
|
|
|
44
45
|
"lib/**/*.js",
|
|
45
46
|
"lib/**/*.d.ts"
|
|
46
47
|
],
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsdown && pnpm run build:host && pnpm run build:client:types",
|
|
50
|
+
"build:host": "tsc -p tsconfig.json",
|
|
51
|
+
"build:client:types": "tsc -p tsconfig.client.json",
|
|
52
|
+
"test": "pnpm run build && vitest run",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit"
|
|
54
|
+
},
|
|
47
55
|
"license": "MIT",
|
|
48
56
|
"dsh": {
|
|
49
57
|
"bundle": {
|
|
@@ -60,16 +68,17 @@
|
|
|
60
68
|
},
|
|
61
69
|
"peerDependencies": {
|
|
62
70
|
"@deepseek-ai/cordis": ">=4.0.1",
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/dsh-client-
|
|
65
|
-
"@deepseek-ai/dsh-client-
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-
|
|
67
|
-
"@deepseek-ai/dsh-
|
|
68
|
-
"@deepseek-ai/dsh-
|
|
69
|
-
"@deepseek-ai/dsh-
|
|
70
|
-
"@deepseek-ai/dsh-
|
|
71
|
-
"@deepseek-ai/dsh-llm
|
|
72
|
-
"@deepseek-ai/dsh-
|
|
71
|
+
"@deepseek-ai/dsh-authorization": ">=0.1.1-rc.2 <0.2.0-0",
|
|
72
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.1-rc.2 <0.2.0-0",
|
|
73
|
+
"@deepseek-ai/dsh-client-runtime": ">=0.1.1-rc.2 <0.2.0-0",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.1-rc.2 <0.2.0-0",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.1-rc.2 <0.2.0-0",
|
|
76
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.1-rc.2 <0.2.0-0",
|
|
77
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.1-rc.2 <0.2.0-0",
|
|
78
|
+
"@deepseek-ai/dsh-invariants": ">=0.1.1-rc.2 <0.2.0-0",
|
|
79
|
+
"@deepseek-ai/dsh-llm": ">=0.1.1-rc.2 <0.2.0-0",
|
|
80
|
+
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.1-rc.2 <0.2.0-0",
|
|
81
|
+
"@deepseek-ai/dsh-settings": ">=0.1.1-rc.2 <0.2.0-0",
|
|
73
82
|
"react": ">=18.2.0"
|
|
74
83
|
},
|
|
75
84
|
"peerDependenciesMeta": {
|
|
@@ -111,12 +120,12 @@
|
|
|
111
120
|
}
|
|
112
121
|
},
|
|
113
122
|
"dependencies": {
|
|
114
|
-
"@deepseek-ai/dsh-authorization": ">=0.1.1-rc.2",
|
|
115
123
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
116
124
|
"ws": "^8.18.3"
|
|
117
125
|
},
|
|
118
126
|
"devDependencies": {
|
|
119
127
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
128
|
+
"@deepseek-ai/dsh-authorization": "0.1.1-rc.2",
|
|
120
129
|
"@deepseek-ai/dsh-client-locale": "0.1.1-rc.2",
|
|
121
130
|
"@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
|
|
122
131
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
|
|
@@ -136,12 +145,5 @@
|
|
|
136
145
|
"tsdown": "^0.22.2",
|
|
137
146
|
"typescript": "^6.0.3",
|
|
138
147
|
"vitest": "^4.1.8"
|
|
139
|
-
},
|
|
140
|
-
"scripts": {
|
|
141
|
-
"build": "tsdown && pnpm run build:host && pnpm run build:client:types",
|
|
142
|
-
"build:host": "tsc -p tsconfig.json",
|
|
143
|
-
"build:client:types": "tsc -p tsconfig.client.json",
|
|
144
|
-
"test": "pnpm run build && vitest run",
|
|
145
|
-
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit"
|
|
146
148
|
}
|
|
147
|
-
}
|
|
149
|
+
}
|