@edge-sky/dsh-oauth-adapter 0.1.2-dev.2 → 0.1.2-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +27 -63
- package/README.zh.md +27 -63
- package/lib/client.js +7 -500
- package/lib/index.d.ts +3 -7
- package/lib/index.js +78 -82
- package/lib/protocol.d.ts +2 -3
- package/lib/protocol.js +0 -27
- package/lib/types/client/index.d.ts +2 -2
- package/lib/types/client/locales.d.ts +0 -34
- package/lib/types/client/store.d.ts +0 -17
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/protocol.d.ts +2 -3
- package/package.json +35 -62
- package/lib/model-auth.d.ts +0 -8
- package/lib/model-auth.js +0 -48
- package/lib/model-catalog.d.ts +0 -27
- package/lib/model-catalog.js +0 -145
- package/lib/model-discovery.d.ts +0 -22
- package/lib/model-discovery.js +0 -147
- package/lib/model-service.d.ts +0 -64
- package/lib/model-service.js +0 -371
- package/lib/model-types.d.ts +0 -92
- package/lib/model-types.js +0 -25
- package/lib/types/client/OAuthModelsSection.d.ts +0 -11
- package/lib/types/model-types.d.ts +0 -92
package/lib/client.js
CHANGED
|
@@ -6,37 +6,8 @@ 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/model-types.ts
|
|
10
|
-
const MODEL_PROTOCOLS = {
|
|
11
|
-
"github-copilot": [
|
|
12
|
-
"openai-completions",
|
|
13
|
-
"openai-responses",
|
|
14
|
-
"anthropic-messages"
|
|
15
|
-
],
|
|
16
|
-
openrouter: ["openai-completions", "anthropic-messages"],
|
|
17
|
-
"openai-codex": ["openai-codex-responses"],
|
|
18
|
-
xai: ["openai-responses"],
|
|
19
|
-
anthropic: ["anthropic-messages"],
|
|
20
|
-
"kimi-coding": ["anthropic-messages"]
|
|
21
|
-
};
|
|
22
|
-
function modelText(value) {
|
|
23
|
-
return typeof value === "string" && value.length > 0 && value.length <= 256 && value.trim() === value && !/[\u0000-\u001f\u007f]/u.test(value);
|
|
24
|
-
}
|
|
25
|
-
/** Validate at the wire and durable-data boundaries; fixed-protocol routes accept no override. */
|
|
26
|
-
function validManual(provider, value) {
|
|
27
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
28
|
-
const m = value;
|
|
29
|
-
if (Object.keys(m).some((k) => ![
|
|
30
|
-
"id",
|
|
31
|
-
"name",
|
|
32
|
-
"api"
|
|
33
|
-
].includes(k)) || !modelText(m.id)) return false;
|
|
34
|
-
if (m.name !== void 0 && !modelText(m.name)) return false;
|
|
35
|
-
const choices = MODEL_PROTOCOLS[provider];
|
|
36
|
-
return choices.length === 1 ? m.api === void 0 : typeof m.api === "string" && choices.includes(m.api);
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
9
|
//#region src/protocol.ts
|
|
10
|
+
/** Shared browser/Host wire vocabulary for the OAuth account surface. */
|
|
40
11
|
const OAUTH_SOCKET_PATH = "/_edge-sky/dsh-oauth";
|
|
41
12
|
const OAUTH_SOCKET_PROTOCOL = "dsh-oauth-v1";
|
|
42
13
|
const PROVIDERS = [
|
|
@@ -78,262 +49,6 @@ window.__ModuleLoader__.load({
|
|
|
78
49
|
}
|
|
79
50
|
];
|
|
80
51
|
//#endregion
|
|
81
|
-
//#region src/client/OAuthModelsSection.tsx
|
|
82
|
-
/** OAuth-specific model management mounted inside the existing Models settings page. */
|
|
83
|
-
function ModelForm({ provider, initial, busy, t, save, close }) {
|
|
84
|
-
const [id, setId] = (0, react.useState)(initial?.id ?? "");
|
|
85
|
-
const [name, setName] = (0, react.useState)(initial?.name ?? "");
|
|
86
|
-
const choices = MODEL_PROTOCOLS[provider];
|
|
87
|
-
const [api, setApi] = (0, react.useState)(initial?.api ?? choices[0]);
|
|
88
|
-
const model = {
|
|
89
|
-
id: id.trim(),
|
|
90
|
-
...name.trim() ? { name: name.trim() } : {},
|
|
91
|
-
...choices.length > 1 ? { api } : {}
|
|
92
|
-
};
|
|
93
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
94
|
-
className: "dsh-oauth-model-form",
|
|
95
|
-
onSubmit: (event) => {
|
|
96
|
-
event.preventDefault();
|
|
97
|
-
if (validManual(provider, model)) save(model);
|
|
98
|
-
},
|
|
99
|
-
children: [
|
|
100
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("modelId"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
101
|
-
required: true,
|
|
102
|
-
maxLength: 256,
|
|
103
|
-
value: id,
|
|
104
|
-
readOnly: initial !== void 0,
|
|
105
|
-
onChange: (event) => setId(event.target.value)
|
|
106
|
-
})] }),
|
|
107
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("modelName"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
108
|
-
maxLength: 256,
|
|
109
|
-
value: name,
|
|
110
|
-
onChange: (event) => setName(event.target.value),
|
|
111
|
-
placeholder: id
|
|
112
|
-
})] }),
|
|
113
|
-
choices.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("modelProtocol"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
114
|
-
value: api,
|
|
115
|
-
onChange: (event) => setApi(event.target.value),
|
|
116
|
-
children: choices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
117
|
-
value: choice,
|
|
118
|
-
children: choice === "openai-completions" ? "Chat Completions" : choice === "openai-responses" ? "Responses" : choice === "openai-codex-responses" ? "Codex Responses" : "Anthropic Messages"
|
|
119
|
-
}, choice))
|
|
120
|
-
})] }),
|
|
121
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
122
|
-
className: "dsh-oauth-muted",
|
|
123
|
-
children: t("manualModelHint")
|
|
124
|
-
}),
|
|
125
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
126
|
-
type: "submit",
|
|
127
|
-
disabled: busy || !validManual(provider, model),
|
|
128
|
-
children: t("saveModel")
|
|
129
|
-
}),
|
|
130
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
131
|
-
type: "button",
|
|
132
|
-
disabled: busy,
|
|
133
|
-
onClick: close,
|
|
134
|
-
children: t("cancel")
|
|
135
|
-
})
|
|
136
|
-
]
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
function ProviderModels({ page, controller, busy, error, t }) {
|
|
140
|
-
const [editing, setEditing] = (0, react.useState)();
|
|
141
|
-
const [submitted, setSubmitted] = (0, react.useState)(false);
|
|
142
|
-
const [confirmMigration, setConfirmMigration] = (0, react.useState)(false);
|
|
143
|
-
(0, react.useEffect)(() => {
|
|
144
|
-
if (submitted && !busy) {
|
|
145
|
-
if (!error) setEditing(void 0);
|
|
146
|
-
setSubmitted(false);
|
|
147
|
-
}
|
|
148
|
-
}, [
|
|
149
|
-
busy,
|
|
150
|
-
error,
|
|
151
|
-
submitted
|
|
152
|
-
]);
|
|
153
|
-
const errorCode = error?.code ?? page.errorCode;
|
|
154
|
-
const errorLabel = errorCode === "settings-conflict" ? "modelConflict" : errorCode === "discovery-unsupported" ? "modelUnsupported" : errorCode === "discovery-auth" ? "modelAuthFailed" : errorCode === "discovery-timeout" ? "modelTimedOut" : errorCode === "route-conflict" ? "modelRouteConflict" : "modelOperationFailed";
|
|
155
|
-
const disabled = busy || !page.connected || !page.writable;
|
|
156
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
157
|
-
className: "dsh-oauth-model-provider",
|
|
158
|
-
children: [
|
|
159
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: PROVIDERS.find((p) => p.id === page.provider)?.modelGroupLabel }),
|
|
160
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
161
|
-
page.connected ? t("modelConnected") : t("disconnected"),
|
|
162
|
-
" · ",
|
|
163
|
-
page.source === "account" ? t("accountCatalog") : t("builtinCatalog")
|
|
164
|
-
] }),
|
|
165
|
-
page.syncedAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
166
|
-
t("lastModelSync"),
|
|
167
|
-
": ",
|
|
168
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
|
|
169
|
-
dateTime: page.syncedAt,
|
|
170
|
-
children: new Date(page.syncedAt).toLocaleString()
|
|
171
|
-
})
|
|
172
|
-
] }),
|
|
173
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
174
|
-
t("matchedModels"),
|
|
175
|
-
": ",
|
|
176
|
-
page.counts.matched,
|
|
177
|
-
" · ",
|
|
178
|
-
t("pendingModels"),
|
|
179
|
-
": ",
|
|
180
|
-
page.counts.pending,
|
|
181
|
-
" · ",
|
|
182
|
-
t("manualModels"),
|
|
183
|
-
": ",
|
|
184
|
-
page.counts.manual
|
|
185
|
-
] }),
|
|
186
|
-
(error || page.error) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
187
|
-
role: "alert",
|
|
188
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t(errorLabel) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("technicalDetails") }), error?.message ?? page.error] })]
|
|
189
|
-
}),
|
|
190
|
-
page.migration ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
191
|
-
disabled,
|
|
192
|
-
onClick: () => setConfirmMigration(!confirmMigration),
|
|
193
|
-
children: t("reviewMigration")
|
|
194
|
-
}), confirmMigration && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
195
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("migrationDescription") }),
|
|
196
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
197
|
-
page.migration.fields.join(", "),
|
|
198
|
-
" · ",
|
|
199
|
-
page.migration.models,
|
|
200
|
-
" ",
|
|
201
|
-
t("modelsTitle")
|
|
202
|
-
] }),
|
|
203
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
204
|
-
disabled,
|
|
205
|
-
onClick: () => controller.migrateModels(page.provider),
|
|
206
|
-
children: t("confirmMigration")
|
|
207
|
-
})
|
|
208
|
-
] })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
209
|
-
disabled: disabled || !page.managed,
|
|
210
|
-
onClick: () => controller.syncModels(page.provider),
|
|
211
|
-
children: busy ? t("modelWorking") : t("syncModels")
|
|
212
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
213
|
-
disabled: disabled || !page.managed,
|
|
214
|
-
onClick: () => setEditing(null),
|
|
215
|
-
children: t("addModel")
|
|
216
|
-
})] }),
|
|
217
|
-
editing !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelForm, {
|
|
218
|
-
provider: page.provider,
|
|
219
|
-
...editing === null ? {} : { initial: editing },
|
|
220
|
-
busy,
|
|
221
|
-
t,
|
|
222
|
-
save: (model) => {
|
|
223
|
-
setSubmitted(true);
|
|
224
|
-
controller.saveModel(page.provider, model);
|
|
225
|
-
},
|
|
226
|
-
close: () => setEditing(void 0)
|
|
227
|
-
}, editing?.id ?? "new"),
|
|
228
|
-
[
|
|
229
|
-
"matched",
|
|
230
|
-
"pending",
|
|
231
|
-
"manual"
|
|
232
|
-
].map((source) => {
|
|
233
|
-
const rows = page.rows.filter((row) => (row.source === "catalog" ? "matched" : row.source) === source);
|
|
234
|
-
if (!rows.length) return null;
|
|
235
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
236
|
-
"aria-label": t(source === "pending" ? "pendingModels" : source === "manual" ? "manualModels" : "matchedModels"),
|
|
237
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t(source === "pending" ? "pendingModels" : source === "manual" ? "manualModels" : "matchedModels") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
238
|
-
className: "dsh-oauth-model-list",
|
|
239
|
-
children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
240
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
241
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: row.name }),
|
|
242
|
-
" ",
|
|
243
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: row.id }),
|
|
244
|
-
" ",
|
|
245
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(row.source === "pending" ? "pendingModels" : row.source === "manual" ? "manualModels" : "matchedModels") })
|
|
246
|
-
] }),
|
|
247
|
-
row.source === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
248
|
-
disabled: disabled || !page.managed,
|
|
249
|
-
onClick: () => setEditing({
|
|
250
|
-
id: row.id,
|
|
251
|
-
name: row.name
|
|
252
|
-
}),
|
|
253
|
-
children: t("configureModel")
|
|
254
|
-
}),
|
|
255
|
-
row.source === "manual" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
256
|
-
disabled,
|
|
257
|
-
onClick: () => setEditing({
|
|
258
|
-
id: row.id,
|
|
259
|
-
name: row.name,
|
|
260
|
-
...MODEL_PROTOCOLS[page.provider].length > 1 ? { api: row.api } : {}
|
|
261
|
-
}),
|
|
262
|
-
children: t("editModel")
|
|
263
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
264
|
-
disabled,
|
|
265
|
-
onClick: () => controller.deleteModel(page.provider, row.id),
|
|
266
|
-
children: t("deleteModel")
|
|
267
|
-
})] })
|
|
268
|
-
] }, row.id))
|
|
269
|
-
})]
|
|
270
|
-
}, source);
|
|
271
|
-
}),
|
|
272
|
-
page.total === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("noModels") }),
|
|
273
|
-
page.total > 10 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
274
|
-
"aria-label": t("modelsPagination"),
|
|
275
|
-
children: [
|
|
276
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
277
|
-
disabled: page.offset === 0 || busy,
|
|
278
|
-
onClick: () => controller.readModels(page.provider, Math.max(0, page.offset - 10)),
|
|
279
|
-
children: t("previousModels")
|
|
280
|
-
}),
|
|
281
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
282
|
-
page.offset + 1,
|
|
283
|
-
"–",
|
|
284
|
-
Math.min(page.offset + 10, page.total),
|
|
285
|
-
" / ",
|
|
286
|
-
page.total
|
|
287
|
-
] }),
|
|
288
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
289
|
-
disabled: page.offset + 10 >= page.total || busy,
|
|
290
|
-
onClick: () => controller.readModels(page.provider, page.offset + 10),
|
|
291
|
-
children: t("nextModels")
|
|
292
|
-
})
|
|
293
|
-
]
|
|
294
|
-
})
|
|
295
|
-
]
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
function OAuthModelsSection(props) {
|
|
299
|
-
const { controller, t } = props;
|
|
300
|
-
if (!controller || !t) return null;
|
|
301
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OAuthModels, {
|
|
302
|
-
controller,
|
|
303
|
-
t
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
function OAuthModels({ controller, t }) {
|
|
307
|
-
const snapshot = (0, react.useSyncExternalStore)(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
|
|
308
|
-
(0, react.useEffect)(() => {
|
|
309
|
-
controller.loadModels();
|
|
310
|
-
}, [controller]);
|
|
311
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
312
|
-
className: "dsh-oauth-section",
|
|
313
|
-
children: [
|
|
314
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: t("modelsTitle") }),
|
|
315
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("modelsIntro") }),
|
|
316
|
-
snapshot.connection !== "open" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
317
|
-
role: "status",
|
|
318
|
-
children: t("hostDisconnected")
|
|
319
|
-
}),
|
|
320
|
-
PROVIDERS.map((provider) => {
|
|
321
|
-
const page = snapshot.modelPages?.[provider.id];
|
|
322
|
-
if (!page) return null;
|
|
323
|
-
if (!page.connected && !page.managed && page.counts.manual === 0) return null;
|
|
324
|
-
const error = snapshot.modelErrors?.[provider.id];
|
|
325
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderModels, {
|
|
326
|
-
page,
|
|
327
|
-
controller,
|
|
328
|
-
t,
|
|
329
|
-
busy: snapshot.connection !== "open" || snapshot.modelBusy?.[provider.id] === true || page.busy,
|
|
330
|
-
...error ? { error } : {}
|
|
331
|
-
}, provider.id);
|
|
332
|
-
})
|
|
333
|
-
]
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
//#endregion
|
|
337
52
|
//#region src/client/OAuthAccountsSection.tsx
|
|
338
53
|
/** OAuth account settings page. */
|
|
339
54
|
function safeHttpUrl(value) {
|
|
@@ -464,7 +179,7 @@ window.__ModuleLoader__.load({
|
|
|
464
179
|
t: props.t
|
|
465
180
|
}, props.attempt.prompt.id),
|
|
466
181
|
props.attempt.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorPanel, {
|
|
467
|
-
message: props.attempt.
|
|
182
|
+
message: props.attempt.error,
|
|
468
183
|
...props.attempt.errorDetail === void 0 ? {} : { detail: props.attempt.errorDetail },
|
|
469
184
|
t: props.t
|
|
470
185
|
}),
|
|
@@ -582,40 +297,6 @@ window.__ModuleLoader__.load({
|
|
|
582
297
|
//#region src/client/locales.ts
|
|
583
298
|
/** English copy for the OAuth accounts page. */
|
|
584
299
|
const en = {
|
|
585
|
-
modelUnsupported: "This provider does not support account discovery with the current credential. You can still add models manually.",
|
|
586
|
-
modelAuthFailed: "Model discovery was denied. Reconnect or check this account’s permissions. The previous list was retained.",
|
|
587
|
-
modelTimedOut: "Model synchronization timed out. The previous list was retained.",
|
|
588
|
-
modelRouteConflict: "This provider is owned by an existing configuration. Review the details before migration.",
|
|
589
|
-
loginSyncFailed: "Sign-in succeeded, but model synchronization failed. Open Models to retry.",
|
|
590
|
-
modelsTitle: "OAuth models",
|
|
591
|
-
modelsIntro: "Synchronize account-visible models or add a model manually. Manual models survive synchronization.",
|
|
592
|
-
modelId: "Model ID",
|
|
593
|
-
modelName: "Display name",
|
|
594
|
-
modelProtocol: "Request protocol",
|
|
595
|
-
manualModelHint: "Saving configures a request; it does not verify account access or model capabilities.",
|
|
596
|
-
saveModel: "Save model",
|
|
597
|
-
modelConnected: "Connected",
|
|
598
|
-
accountCatalog: "Account-synchronized list",
|
|
599
|
-
builtinCatalog: "Built-in list · account access unverified",
|
|
600
|
-
lastModelSync: "Last successful synchronization",
|
|
601
|
-
matchedModels: "Matched",
|
|
602
|
-
pendingModels: "Needs configuration",
|
|
603
|
-
manualModels: "Manual",
|
|
604
|
-
modelConflict: "Models changed elsewhere. The list was refreshed; review it and retry.",
|
|
605
|
-
modelOperationFailed: "The model operation failed. Review the details before retrying.",
|
|
606
|
-
reviewMigration: "Review migration",
|
|
607
|
-
migrationDescription: "Move this OAuth provider configuration to plugin management while preserving its ID and credentials. The following configuration fields will be retained:",
|
|
608
|
-
confirmMigration: "Migrate this provider",
|
|
609
|
-
modelWorking: "Working…",
|
|
610
|
-
syncModels: "Synchronize models",
|
|
611
|
-
addModel: "Add model",
|
|
612
|
-
configureModel: "Configure",
|
|
613
|
-
editModel: "Edit",
|
|
614
|
-
deleteModel: "Delete manual entry",
|
|
615
|
-
noModels: "No selectable models. Configure an unmatched model or add one manually.",
|
|
616
|
-
modelsPagination: "OAuth model pages",
|
|
617
|
-
previousModels: "Previous",
|
|
618
|
-
nextModels: "Next",
|
|
619
300
|
nav: "OAuth Accounts",
|
|
620
301
|
title: "OAuth Accounts",
|
|
621
302
|
intro: "Connect subscription-backed providers. Their models appear in separate OAuth groups, apart from API-key providers.",
|
|
@@ -648,40 +329,6 @@ window.__ModuleLoader__.load({
|
|
|
648
329
|
};
|
|
649
330
|
/** Simplified Chinese copy for the OAuth accounts page. */
|
|
650
331
|
const zh = {
|
|
651
|
-
modelUnsupported: "当前凭据不支持查询该供应商的账号模型列表,仍可手动添加模型。",
|
|
652
|
-
modelAuthFailed: "模型查询被拒绝,请重新连接或检查账号权限。已保留之前的列表。",
|
|
653
|
-
modelTimedOut: "模型同步超时,已保留之前的列表。",
|
|
654
|
-
modelRouteConflict: "该供应商由现有配置管理,请查看详情后再迁移。",
|
|
655
|
-
loginSyncFailed: "登录成功,但模型同步失败。请前往模型页面重试。",
|
|
656
|
-
modelsTitle: "OAuth 模型",
|
|
657
|
-
modelsIntro: "同步账号可见模型,或手动添加模型。同步时会保留手动模型。",
|
|
658
|
-
modelId: "模型 ID",
|
|
659
|
-
modelName: "显示名称",
|
|
660
|
-
modelProtocol: "调用协议",
|
|
661
|
-
manualModelHint: "保存后可以尝试调用,但不代表已经验证账号权限或模型能力。",
|
|
662
|
-
saveModel: "保存模型",
|
|
663
|
-
modelConnected: "已连接",
|
|
664
|
-
accountCatalog: "已同步账号列表",
|
|
665
|
-
builtinCatalog: "内置列表 · 尚未验证账号权限",
|
|
666
|
-
lastModelSync: "最近成功同步",
|
|
667
|
-
matchedModels: "已匹配",
|
|
668
|
-
pendingModels: "待配置",
|
|
669
|
-
manualModels: "手动模型",
|
|
670
|
-
modelConflict: "模型已被其他操作修改。列表已刷新,请确认后重试。",
|
|
671
|
-
modelOperationFailed: "模型操作失败,请查看详情后重试。",
|
|
672
|
-
reviewMigration: "预览迁移",
|
|
673
|
-
migrationDescription: "将此 OAuth 供应商配置迁移到插件管理,保留供应商 ID 和凭据。以下配置字段将被保留:",
|
|
674
|
-
confirmMigration: "迁移此供应商",
|
|
675
|
-
modelWorking: "正在处理…",
|
|
676
|
-
syncModels: "同步模型",
|
|
677
|
-
addModel: "手动添加",
|
|
678
|
-
configureModel: "补充配置",
|
|
679
|
-
editModel: "编辑",
|
|
680
|
-
deleteModel: "删除手动项",
|
|
681
|
-
noModels: "暂无可选模型,请补充待配置项或手动添加。",
|
|
682
|
-
modelsPagination: "OAuth 模型分页",
|
|
683
|
-
previousModels: "上一页",
|
|
684
|
-
nextModels: "下一页",
|
|
685
332
|
nav: "OAuth 账户",
|
|
686
333
|
title: "OAuth 账户",
|
|
687
334
|
intro: "连接订阅型模型服务。OAuth 模型会以独立分组显示,与 API 密钥提供商分开。",
|
|
@@ -748,9 +395,6 @@ window.__ModuleLoader__.load({
|
|
|
748
395
|
reconnectTimer;
|
|
749
396
|
reconnectDelay = 500;
|
|
750
397
|
disposed = false;
|
|
751
|
-
modelsVisible = false;
|
|
752
|
-
modelRequests = /* @__PURE__ */ new Map();
|
|
753
|
-
latestModelReads = /* @__PURE__ */ new Map();
|
|
754
398
|
constructor() {
|
|
755
399
|
this.connect();
|
|
756
400
|
}
|
|
@@ -809,69 +453,6 @@ window.__ModuleLoader__.load({
|
|
|
809
453
|
provider
|
|
810
454
|
});
|
|
811
455
|
}
|
|
812
|
-
loadModels() {
|
|
813
|
-
this.modelsVisible = true;
|
|
814
|
-
for (const provider of this.snapshot.accounts) this.readModels(provider.provider);
|
|
815
|
-
}
|
|
816
|
-
readModels(provider, offset = 0) {
|
|
817
|
-
if (this.snapshot.connection !== "open") return;
|
|
818
|
-
const requestId = crypto.randomUUID();
|
|
819
|
-
this.latestModelReads.set(provider, requestId);
|
|
820
|
-
this.modelRequests.set(requestId, {
|
|
821
|
-
provider,
|
|
822
|
-
write: false
|
|
823
|
-
});
|
|
824
|
-
this.send({
|
|
825
|
-
type: "models-list",
|
|
826
|
-
requestId,
|
|
827
|
-
provider,
|
|
828
|
-
offset
|
|
829
|
-
});
|
|
830
|
-
}
|
|
831
|
-
syncModels(provider) {
|
|
832
|
-
this.writeModels(provider, { type: "models-sync" });
|
|
833
|
-
}
|
|
834
|
-
migrateModels(provider) {
|
|
835
|
-
this.writeModels(provider, { type: "models-migrate" });
|
|
836
|
-
}
|
|
837
|
-
saveModel(provider, model) {
|
|
838
|
-
this.writeModels(provider, {
|
|
839
|
-
type: "models-save",
|
|
840
|
-
model
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
deleteModel(provider, id) {
|
|
844
|
-
this.writeModels(provider, {
|
|
845
|
-
type: "models-delete",
|
|
846
|
-
id
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
writeModels(provider, operation) {
|
|
850
|
-
const page = this.snapshot.modelPages?.[provider];
|
|
851
|
-
if (!page || this.snapshot.modelBusy?.[provider] || this.snapshot.connection !== "open") return;
|
|
852
|
-
const requestId = crypto.randomUUID();
|
|
853
|
-
this.modelRequests.set(requestId, {
|
|
854
|
-
provider,
|
|
855
|
-
write: true
|
|
856
|
-
});
|
|
857
|
-
this.update({
|
|
858
|
-
...this.snapshot,
|
|
859
|
-
modelBusy: {
|
|
860
|
-
...this.snapshot.modelBusy,
|
|
861
|
-
[provider]: true
|
|
862
|
-
},
|
|
863
|
-
modelErrors: {
|
|
864
|
-
...this.snapshot.modelErrors,
|
|
865
|
-
[provider]: void 0
|
|
866
|
-
}
|
|
867
|
-
});
|
|
868
|
-
this.send({
|
|
869
|
-
...operation,
|
|
870
|
-
requestId,
|
|
871
|
-
provider,
|
|
872
|
-
revision: page.revision
|
|
873
|
-
});
|
|
874
|
-
}
|
|
875
456
|
retry() {
|
|
876
457
|
if (this.socket?.readyState === WebSocket.OPEN || this.socket?.readyState === WebSocket.CONNECTING) return;
|
|
877
458
|
if (this.reconnectTimer !== void 0) window.clearTimeout(this.reconnectTimer);
|
|
@@ -902,12 +483,6 @@ window.__ModuleLoader__.load({
|
|
|
902
483
|
...current,
|
|
903
484
|
connection: "open"
|
|
904
485
|
});
|
|
905
|
-
this.modelRequests.clear();
|
|
906
|
-
this.latestModelReads.clear();
|
|
907
|
-
this.update({
|
|
908
|
-
...this.snapshot,
|
|
909
|
-
modelBusy: {}
|
|
910
|
-
});
|
|
911
486
|
this.send({
|
|
912
487
|
type: "refresh",
|
|
913
488
|
requestId: crypto.randomUUID()
|
|
@@ -976,60 +551,6 @@ window.__ModuleLoader__.load({
|
|
|
976
551
|
}
|
|
977
552
|
receive(message) {
|
|
978
553
|
switch (message.type) {
|
|
979
|
-
case "models-changed":
|
|
980
|
-
if (this.modelsVisible) this.readModels(message.provider, this.snapshot.modelPages?.[message.provider]?.offset ?? 0);
|
|
981
|
-
return;
|
|
982
|
-
case "models-page": {
|
|
983
|
-
const request = this.modelRequests.get(message.requestId);
|
|
984
|
-
this.modelRequests.delete(message.requestId);
|
|
985
|
-
if (!request) return;
|
|
986
|
-
if (!request.write && this.latestModelReads.get(request.provider) !== message.requestId) return;
|
|
987
|
-
const current = this.snapshot.modelPages?.[request.provider];
|
|
988
|
-
if (current && message.page.revision < current.revision) {
|
|
989
|
-
if (request.write) this.update({
|
|
990
|
-
...this.snapshot,
|
|
991
|
-
modelBusy: {
|
|
992
|
-
...this.snapshot.modelBusy,
|
|
993
|
-
[request.provider]: false
|
|
994
|
-
}
|
|
995
|
-
});
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
this.update({
|
|
999
|
-
...this.snapshot,
|
|
1000
|
-
modelPages: {
|
|
1001
|
-
...this.snapshot.modelPages,
|
|
1002
|
-
[request.provider]: message.page
|
|
1003
|
-
},
|
|
1004
|
-
modelBusy: {
|
|
1005
|
-
...this.snapshot.modelBusy,
|
|
1006
|
-
...request.write ? { [request.provider]: false } : {}
|
|
1007
|
-
}
|
|
1008
|
-
});
|
|
1009
|
-
return;
|
|
1010
|
-
}
|
|
1011
|
-
case "models-error": {
|
|
1012
|
-
const request = this.modelRequests.get(message.requestId);
|
|
1013
|
-
this.modelRequests.delete(message.requestId);
|
|
1014
|
-
if (!request) return;
|
|
1015
|
-
if (!request.write && this.latestModelReads.get(request.provider) !== message.requestId) return;
|
|
1016
|
-
this.update({
|
|
1017
|
-
...this.snapshot,
|
|
1018
|
-
modelBusy: {
|
|
1019
|
-
...this.snapshot.modelBusy,
|
|
1020
|
-
...request.write ? { [request.provider]: false } : {}
|
|
1021
|
-
},
|
|
1022
|
-
modelErrors: {
|
|
1023
|
-
...this.snapshot.modelErrors,
|
|
1024
|
-
[request.provider]: {
|
|
1025
|
-
code: message.code,
|
|
1026
|
-
message: message.message
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
});
|
|
1030
|
-
if (request.write) this.readModels(request.provider);
|
|
1031
|
-
return;
|
|
1032
|
-
}
|
|
1033
554
|
case "snapshot":
|
|
1034
555
|
const accounts = [...message.accounts];
|
|
1035
556
|
const reconciled = reconcileAttemptView(this.snapshot.attempt, accounts);
|
|
@@ -1040,7 +561,6 @@ window.__ModuleLoader__.load({
|
|
|
1040
561
|
if (reconciled === void 0) delete nextSnapshot.attempt;
|
|
1041
562
|
else nextSnapshot.attempt = reconciled;
|
|
1042
563
|
this.update(nextSnapshot);
|
|
1043
|
-
if (this.modelsVisible) for (const account of accounts) this.readModels(account.provider, this.snapshot.modelPages?.[account.provider]?.offset ?? 0);
|
|
1044
564
|
return;
|
|
1045
565
|
case "started":
|
|
1046
566
|
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
@@ -1151,19 +671,11 @@ window.__ModuleLoader__.load({
|
|
|
1151
671
|
.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}
|
|
1152
672
|
.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}
|
|
1153
673
|
.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)}
|
|
1154
|
-
|
|
1155
|
-
.dsh-oauth-model-provider { border: 1px solid var(--border-color, currentColor); border-radius: 8px; padding: 16px; margin-block: 16px; }
|
|
1156
|
-
.dsh-oauth-model-provider button { margin: 4px; }
|
|
1157
|
-
.dsh-oauth-model-list { padding: 0; list-style: none; }
|
|
1158
|
-
.dsh-oauth-model-list li { padding-block: 8px; border-bottom: 1px solid var(--border-color, currentColor); overflow-wrap: anywhere; }
|
|
1159
|
-
.dsh-oauth-model-list code { margin-inline: 8px; }
|
|
1160
|
-
.dsh-oauth-model-form { display: grid; gap: 12px; margin-block: 12px; }
|
|
1161
|
-
.dsh-oauth-model-form label { display: grid; gap: 4px; }
|
|
1162
|
-
.dsh-oauth-model-provider nav { display: flex; align-items: center; gap: 8px; }
|
|
1163
674
|
`;
|
|
1164
675
|
//#endregion
|
|
1165
676
|
//#region src/client/index.ts
|
|
1166
677
|
const NS = "settings.oauth-accounts";
|
|
678
|
+
const MODEL_SETTINGS_VISIBILITY = "modelSettingsVisibility";
|
|
1167
679
|
/** Required browser services for settings placement and localized copy. */
|
|
1168
680
|
const inject = ["slots", "locale"];
|
|
1169
681
|
/** Register the OAuth account page and its app-lifetime connection controller. */
|
|
@@ -1185,16 +697,11 @@ window.__ModuleLoader__.load({
|
|
|
1185
697
|
ctx.effect(() => () => {
|
|
1186
698
|
controller.dispose();
|
|
1187
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
|
+
});
|
|
1188
704
|
const t = ctx.locale.bind(NS);
|
|
1189
|
-
ctx.slots.inject("settings.models.footer", () => ctx.slots.register({
|
|
1190
|
-
name: "settings.models.footer",
|
|
1191
|
-
id: "oauth-models",
|
|
1192
|
-
order: 10,
|
|
1193
|
-
inject: () => ({
|
|
1194
|
-
controller,
|
|
1195
|
-
t
|
|
1196
|
-
})
|
|
1197
|
-
}, OAuthModelsSection));
|
|
1198
705
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
1199
706
|
name: "settings.section",
|
|
1200
707
|
id: "oauth-accounts",
|
package/lib/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* `dsh-llm-pi-ai` plugin.
|
|
4
4
|
* @module @edge-sky/dsh-oauth-adapter
|
|
5
5
|
*/
|
|
6
|
-
import { type ModelContext } from './model-service.js';
|
|
7
6
|
import type { IncomingMessage } from 'node:http';
|
|
7
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
8
8
|
import type { AuthorizationService } from '@deepseek-ai/dsh-authorization';
|
|
9
9
|
import type { CredentialProvider } from '@deepseek-ai/dsh-credentials';
|
|
10
10
|
import type { WebServer } from '@deepseek-ai/dsh-host-webserver';
|
|
@@ -14,10 +14,6 @@ import z from '@deepseek-ai/schemastery';
|
|
|
14
14
|
export interface Config {
|
|
15
15
|
/** Emit secret-free transport lifecycle diagnostics. */
|
|
16
16
|
debug?: boolean;
|
|
17
|
-
modelSyncTimeoutMs?: number;
|
|
18
|
-
modelSyncMaxResponseBytes?: number;
|
|
19
|
-
modelSyncMaxPages?: number;
|
|
20
|
-
codexClientVersion?: string;
|
|
21
17
|
}
|
|
22
18
|
/** Runtime-validated plugin configuration. */
|
|
23
19
|
export declare const Config: z<Config>;
|
|
@@ -25,7 +21,7 @@ export declare const Config: z<Config>;
|
|
|
25
21
|
export declare const name = "dsh-oauth-adapter";
|
|
26
22
|
/** Official services required by the OAuth account surface. */
|
|
27
23
|
export declare const inject: string[];
|
|
28
|
-
type OAuthContext =
|
|
24
|
+
type OAuthContext = Context & {
|
|
29
25
|
authorization: AuthorizationService;
|
|
30
26
|
credentials: CredentialProvider;
|
|
31
27
|
settings: SettingsProvider;
|
|
@@ -39,7 +35,7 @@ export declare function safeNoticeUrl(value: string | undefined): string | undef
|
|
|
39
35
|
export declare function acceptsBrowserUpgrade(request: IncomingMessage): boolean;
|
|
40
36
|
/** Format one Host failure for browser diagnostics without forwarding credentials or unbounded data. */
|
|
41
37
|
export declare function formatErrorDetail(error: unknown): string;
|
|
42
|
-
/** Mount the loopback-only OAuth WebSocket over official
|
|
38
|
+
/** Mount the loopback-only OAuth WebSocket over official rc2 services. */
|
|
43
39
|
export declare function apply(ctx: OAuthContext, config: Config): () => Promise<void>;
|
|
44
40
|
export {};
|
|
45
41
|
//# sourceMappingURL=index.d.ts.map
|