@edge-sky/dsh-oauth-adapter 0.1.2-dev.2 → 0.1.3-beta.3
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 +33 -58
- package/README.zh.md +33 -57
- package/lib/client.js +242 -162
- package/lib/index.d.ts +5 -2
- package/lib/index.js +11 -2
- package/lib/model-catalog.js +5 -4
- package/lib/model-service.d.ts +7 -5
- package/lib/model-service.js +19 -15
- package/lib/model-types.d.ts +2 -0
- package/lib/protocol.js +2 -2
- package/lib/types/client/locales.d.ts +4 -3
- package/lib/types/client/store.d.ts +1 -1
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/model-types.d.ts +2 -0
- package/package.json +64 -43
package/lib/client.js
CHANGED
|
@@ -98,6 +98,7 @@ window.__ModuleLoader__.load({
|
|
|
98
98
|
},
|
|
99
99
|
children: [
|
|
100
100
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("modelId"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
101
|
+
className: "dsh-oauth-input",
|
|
101
102
|
required: true,
|
|
102
103
|
maxLength: 256,
|
|
103
104
|
value: id,
|
|
@@ -105,12 +106,14 @@ window.__ModuleLoader__.load({
|
|
|
105
106
|
onChange: (event) => setId(event.target.value)
|
|
106
107
|
})] }),
|
|
107
108
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("modelName"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
109
|
+
className: "dsh-oauth-input",
|
|
108
110
|
maxLength: 256,
|
|
109
111
|
value: name,
|
|
110
112
|
onChange: (event) => setName(event.target.value),
|
|
111
113
|
placeholder: id
|
|
112
114
|
})] }),
|
|
113
115
|
choices.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("modelProtocol"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
116
|
+
className: "dsh-oauth-select",
|
|
114
117
|
value: api,
|
|
115
118
|
onChange: (event) => setApi(event.target.value),
|
|
116
119
|
children: choices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
@@ -123,11 +126,13 @@ window.__ModuleLoader__.load({
|
|
|
123
126
|
children: t("manualModelHint")
|
|
124
127
|
}),
|
|
125
128
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
129
|
+
className: "dsh-oauth-button",
|
|
126
130
|
type: "submit",
|
|
127
131
|
disabled: busy || !validManual(provider, model),
|
|
128
132
|
children: t("saveModel")
|
|
129
133
|
}),
|
|
130
134
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
135
|
+
className: "dsh-oauth-button",
|
|
131
136
|
type: "button",
|
|
132
137
|
disabled: busy,
|
|
133
138
|
onClick: close,
|
|
@@ -137,6 +142,7 @@ window.__ModuleLoader__.load({
|
|
|
137
142
|
});
|
|
138
143
|
}
|
|
139
144
|
function ProviderModels({ page, controller, busy, error, t }) {
|
|
145
|
+
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
140
146
|
const [editing, setEditing] = (0, react.useState)();
|
|
141
147
|
const [submitted, setSubmitted] = (0, react.useState)(false);
|
|
142
148
|
const [confirmMigration, setConfirmMigration] = (0, react.useState)(false);
|
|
@@ -155,144 +161,184 @@ window.__ModuleLoader__.load({
|
|
|
155
161
|
const disabled = busy || !page.connected || !page.writable;
|
|
156
162
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
157
163
|
className: "dsh-oauth-model-provider",
|
|
158
|
-
children: [
|
|
159
|
-
|
|
160
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
161
|
-
|
|
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")
|
|
164
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
165
|
+
className: "dsh-oauth-model-header",
|
|
166
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
167
|
+
className: "dsh-oauth-name",
|
|
168
|
+
children: PROVIDERS.find((p) => p.id === page.provider)?.modelGroupLabel
|
|
212
169
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
170
|
+
className: "dsh-oauth-button",
|
|
171
|
+
type: "button",
|
|
172
|
+
"aria-expanded": expanded,
|
|
173
|
+
"aria-controls": `dsh-oauth-models-${page.provider}`,
|
|
174
|
+
onClick: () => setExpanded(!expanded),
|
|
175
|
+
children: t(expanded ? "collapseModels" : "editModel")
|
|
176
|
+
})]
|
|
177
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
178
|
+
className: "dsh-oauth-model-details",
|
|
179
|
+
id: `dsh-oauth-models-${page.provider}`,
|
|
180
|
+
hidden: !expanded,
|
|
181
|
+
children: [
|
|
182
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
183
|
+
className: "dsh-oauth-muted",
|
|
184
|
+
children: [
|
|
185
|
+
page.connected ? t("modelConnected") : t("disconnected"),
|
|
186
|
+
" · ",
|
|
187
|
+
page.source === "account" ? t("accountCatalog") : t("builtinCatalog")
|
|
188
|
+
]
|
|
189
|
+
}),
|
|
190
|
+
page.syncedAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
191
|
+
className: "dsh-oauth-muted",
|
|
192
|
+
children: [
|
|
193
|
+
t("lastModelSync"),
|
|
194
|
+
": ",
|
|
195
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
|
|
196
|
+
dateTime: page.syncedAt,
|
|
197
|
+
children: new Date(page.syncedAt).toLocaleString()
|
|
198
|
+
})
|
|
199
|
+
]
|
|
200
|
+
}),
|
|
201
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
202
|
+
className: "dsh-oauth-muted",
|
|
203
|
+
children: [
|
|
204
|
+
t("matchedModels"),
|
|
205
|
+
": ",
|
|
206
|
+
page.counts.matched,
|
|
207
|
+
" · ",
|
|
208
|
+
t("manualModels"),
|
|
209
|
+
": ",
|
|
210
|
+
page.counts.manual
|
|
211
|
+
]
|
|
212
|
+
}),
|
|
213
|
+
(error || page.error) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
214
|
+
className: "dsh-oauth-error",
|
|
215
|
+
role: "alert",
|
|
216
|
+
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] })]
|
|
217
|
+
}),
|
|
218
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
219
|
+
className: "dsh-oauth-model-actions",
|
|
220
|
+
children: page.migration ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
221
|
+
className: "dsh-oauth-button",
|
|
222
|
+
disabled,
|
|
223
|
+
onClick: () => setConfirmMigration(!confirmMigration),
|
|
224
|
+
children: t("reviewMigration")
|
|
225
|
+
}), confirmMigration && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
226
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("migrationDescription") }),
|
|
227
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
228
|
+
page.migration.fields.join(", "),
|
|
229
|
+
" · ",
|
|
230
|
+
page.migration.models,
|
|
231
|
+
" ",
|
|
232
|
+
t("modelsTitle")
|
|
233
|
+
] }),
|
|
234
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
235
|
+
className: "dsh-oauth-button",
|
|
236
|
+
disabled,
|
|
237
|
+
onClick: () => controller.migrateModels(page.provider),
|
|
238
|
+
children: t("confirmMigration")
|
|
239
|
+
})
|
|
240
|
+
] })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
241
|
+
className: "dsh-oauth-button",
|
|
242
|
+
disabled: disabled || !page.managed,
|
|
243
|
+
onClick: () => controller.syncModels(page.provider),
|
|
244
|
+
children: busy ? t("modelWorking") : t("syncModels")
|
|
245
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
246
|
+
className: "dsh-oauth-button",
|
|
247
|
+
disabled: disabled || !page.managed,
|
|
248
|
+
onClick: () => setEditing(null),
|
|
249
|
+
children: t("addModel")
|
|
250
|
+
})] })
|
|
251
|
+
}),
|
|
252
|
+
editing === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelForm, {
|
|
253
|
+
provider: page.provider,
|
|
254
|
+
busy,
|
|
255
|
+
t,
|
|
256
|
+
save: (model) => {
|
|
257
|
+
setSubmitted(true);
|
|
258
|
+
controller.saveModel(page.provider, model);
|
|
259
|
+
},
|
|
260
|
+
close: () => setEditing(void 0)
|
|
261
|
+
}, "new"),
|
|
262
|
+
["manual", "matched"].map((source) => {
|
|
263
|
+
const label = t(source === "manual" ? "manualModels" : "matchedModels");
|
|
264
|
+
const rows = page.rows.filter((row) => source === "manual" ? row.source === "manual" : row.source === "catalog" || row.source === "matched");
|
|
265
|
+
const offset = source === "manual" ? page.manualOffset : page.offset;
|
|
266
|
+
const total = page.counts[source];
|
|
267
|
+
const move = (next) => controller.readModels(page.provider, source === "matched" ? next : page.offset, source === "manual" ? next : page.manualOffset);
|
|
268
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
269
|
+
className: "dsh-oauth-model-group",
|
|
270
|
+
"aria-label": label,
|
|
271
|
+
children: [
|
|
272
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: label }),
|
|
273
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
274
|
+
className: "dsh-oauth-model-list",
|
|
275
|
+
children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: source === "manual" && editing?.id === row.id ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelForm, {
|
|
276
|
+
provider: page.provider,
|
|
277
|
+
initial: editing,
|
|
278
|
+
busy,
|
|
279
|
+
t,
|
|
280
|
+
save: (model) => {
|
|
281
|
+
setSubmitted(true);
|
|
282
|
+
controller.saveModel(page.provider, model);
|
|
283
|
+
},
|
|
284
|
+
close: () => setEditing(void 0)
|
|
285
|
+
}, row.id) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
286
|
+
className: "dsh-oauth-model-identity",
|
|
287
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: row.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: row.id })]
|
|
288
|
+
}), source === "manual" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
289
|
+
className: "dsh-oauth-model-actions",
|
|
290
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
291
|
+
className: "dsh-oauth-button",
|
|
292
|
+
disabled,
|
|
293
|
+
onClick: () => setEditing({
|
|
294
|
+
id: row.id,
|
|
295
|
+
name: row.name,
|
|
296
|
+
...MODEL_PROTOCOLS[page.provider].length > 1 ? { api: row.api } : {}
|
|
297
|
+
}),
|
|
298
|
+
children: t("editModel")
|
|
299
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
300
|
+
className: "dsh-oauth-button",
|
|
301
|
+
"data-variant": "danger",
|
|
302
|
+
disabled,
|
|
303
|
+
onClick: () => controller.deleteModel(page.provider, row.id),
|
|
304
|
+
children: t("deleteModel")
|
|
305
|
+
})]
|
|
306
|
+
})] }) }, row.id))
|
|
254
307
|
}),
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
})
|
|
262
|
-
children:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
]
|
|
308
|
+
total === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
309
|
+
className: "dsh-oauth-muted",
|
|
310
|
+
children: t("noModels")
|
|
311
|
+
}),
|
|
312
|
+
total > 10 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
313
|
+
className: "dsh-oauth-pagination",
|
|
314
|
+
"aria-label": `${label} · ${t("modelsPagination")}`,
|
|
315
|
+
children: [
|
|
316
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
317
|
+
className: "dsh-oauth-button",
|
|
318
|
+
disabled: offset === 0 || busy,
|
|
319
|
+
onClick: () => move(Math.max(0, offset - 10)),
|
|
320
|
+
children: t("previousModels")
|
|
321
|
+
}),
|
|
322
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
323
|
+
offset + 1,
|
|
324
|
+
"–",
|
|
325
|
+
Math.min(offset + 10, total),
|
|
326
|
+
" / ",
|
|
327
|
+
total
|
|
328
|
+
] }),
|
|
329
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
330
|
+
className: "dsh-oauth-button",
|
|
331
|
+
disabled: offset + 10 >= total || busy,
|
|
332
|
+
onClick: () => move(offset + 10),
|
|
333
|
+
children: t("nextModels")
|
|
334
|
+
})
|
|
335
|
+
]
|
|
336
|
+
})
|
|
337
|
+
]
|
|
338
|
+
}, source);
|
|
339
|
+
})
|
|
340
|
+
]
|
|
341
|
+
})]
|
|
296
342
|
});
|
|
297
343
|
}
|
|
298
344
|
function OAuthModelsSection(props) {
|
|
@@ -311,8 +357,14 @@ window.__ModuleLoader__.load({
|
|
|
311
357
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
312
358
|
className: "dsh-oauth-section",
|
|
313
359
|
children: [
|
|
314
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
315
|
-
|
|
360
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
361
|
+
className: "dsh-oauth-title",
|
|
362
|
+
children: t("modelsTitle")
|
|
363
|
+
}),
|
|
364
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
365
|
+
className: "dsh-oauth-intro",
|
|
366
|
+
children: t("modelsIntro")
|
|
367
|
+
}),
|
|
316
368
|
snapshot.connection !== "open" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
317
369
|
role: "status",
|
|
318
370
|
children: t("hostDisconnected")
|
|
@@ -320,7 +372,7 @@ window.__ModuleLoader__.load({
|
|
|
320
372
|
PROVIDERS.map((provider) => {
|
|
321
373
|
const page = snapshot.modelPages?.[provider.id];
|
|
322
374
|
if (!page) return null;
|
|
323
|
-
if (!page.connected
|
|
375
|
+
if (!page.connected || !snapshot.accounts.some((account) => account.provider === provider.id && account.configured)) return null;
|
|
324
376
|
const error = snapshot.modelErrors?.[provider.id];
|
|
325
377
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderModels, {
|
|
326
378
|
page,
|
|
@@ -588,7 +640,7 @@ window.__ModuleLoader__.load({
|
|
|
588
640
|
modelRouteConflict: "This provider is owned by an existing configuration. Review the details before migration.",
|
|
589
641
|
loginSyncFailed: "Sign-in succeeded, but model synchronization failed. Open Models to retry.",
|
|
590
642
|
modelsTitle: "OAuth models",
|
|
591
|
-
modelsIntro: "
|
|
643
|
+
modelsIntro: "Models are automatically matched against the pi-ai catalog built into DSH. If a model you need is not matched, try adding it manually.",
|
|
592
644
|
modelId: "Model ID",
|
|
593
645
|
modelName: "Display name",
|
|
594
646
|
modelProtocol: "Request protocol",
|
|
@@ -598,7 +650,7 @@ window.__ModuleLoader__.load({
|
|
|
598
650
|
accountCatalog: "Account-synchronized list",
|
|
599
651
|
builtinCatalog: "Built-in list · account access unverified",
|
|
600
652
|
lastModelSync: "Last successful synchronization",
|
|
601
|
-
matchedModels: "
|
|
653
|
+
matchedModels: "Automatic matches",
|
|
602
654
|
pendingModels: "Needs configuration",
|
|
603
655
|
manualModels: "Manual",
|
|
604
656
|
modelConflict: "Models changed elsewhere. The list was refreshed; review it and retry.",
|
|
@@ -611,8 +663,9 @@ window.__ModuleLoader__.load({
|
|
|
611
663
|
addModel: "Add model",
|
|
612
664
|
configureModel: "Configure",
|
|
613
665
|
editModel: "Edit",
|
|
666
|
+
collapseModels: "Collapse",
|
|
614
667
|
deleteModel: "Delete manual entry",
|
|
615
|
-
noModels: "No
|
|
668
|
+
noModels: "No models in this group.",
|
|
616
669
|
modelsPagination: "OAuth model pages",
|
|
617
670
|
previousModels: "Previous",
|
|
618
671
|
nextModels: "Next",
|
|
@@ -654,7 +707,7 @@ window.__ModuleLoader__.load({
|
|
|
654
707
|
modelRouteConflict: "该供应商由现有配置管理,请查看详情后再迁移。",
|
|
655
708
|
loginSyncFailed: "登录成功,但模型同步失败。请前往模型页面重试。",
|
|
656
709
|
modelsTitle: "OAuth 模型",
|
|
657
|
-
modelsIntro: "
|
|
710
|
+
modelsIntro: "模型由 DSH 内置 pi-ai 自动匹配。若未匹配到你需要的模型,请尝试手动添加。",
|
|
658
711
|
modelId: "模型 ID",
|
|
659
712
|
modelName: "显示名称",
|
|
660
713
|
modelProtocol: "调用协议",
|
|
@@ -664,9 +717,9 @@ window.__ModuleLoader__.load({
|
|
|
664
717
|
accountCatalog: "已同步账号列表",
|
|
665
718
|
builtinCatalog: "内置列表 · 尚未验证账号权限",
|
|
666
719
|
lastModelSync: "最近成功同步",
|
|
667
|
-
matchedModels: "
|
|
720
|
+
matchedModels: "自动匹配",
|
|
668
721
|
pendingModels: "待配置",
|
|
669
|
-
manualModels: "
|
|
722
|
+
manualModels: "手动配置",
|
|
670
723
|
modelConflict: "模型已被其他操作修改。列表已刷新,请确认后重试。",
|
|
671
724
|
modelOperationFailed: "模型操作失败,请查看详情后重试。",
|
|
672
725
|
reviewMigration: "预览迁移",
|
|
@@ -677,8 +730,9 @@ window.__ModuleLoader__.load({
|
|
|
677
730
|
addModel: "手动添加",
|
|
678
731
|
configureModel: "补充配置",
|
|
679
732
|
editModel: "编辑",
|
|
733
|
+
collapseModels: "收起",
|
|
680
734
|
deleteModel: "删除手动项",
|
|
681
|
-
noModels: "
|
|
735
|
+
noModels: "此分组暂无模型。",
|
|
682
736
|
modelsPagination: "OAuth 模型分页",
|
|
683
737
|
previousModels: "上一页",
|
|
684
738
|
nextModels: "下一页",
|
|
@@ -811,9 +865,9 @@ window.__ModuleLoader__.load({
|
|
|
811
865
|
}
|
|
812
866
|
loadModels() {
|
|
813
867
|
this.modelsVisible = true;
|
|
814
|
-
for (const provider of this.snapshot.accounts) this.readModels(provider.provider);
|
|
868
|
+
for (const provider of this.snapshot.accounts) if (provider.configured) this.readModels(provider.provider);
|
|
815
869
|
}
|
|
816
|
-
readModels(provider, offset = 0) {
|
|
870
|
+
readModels(provider, offset = 0, manualOffset = 0) {
|
|
817
871
|
if (this.snapshot.connection !== "open") return;
|
|
818
872
|
const requestId = crypto.randomUUID();
|
|
819
873
|
this.latestModelReads.set(provider, requestId);
|
|
@@ -825,7 +879,8 @@ window.__ModuleLoader__.load({
|
|
|
825
879
|
type: "models-list",
|
|
826
880
|
requestId,
|
|
827
881
|
provider,
|
|
828
|
-
offset
|
|
882
|
+
offset,
|
|
883
|
+
manualOffset
|
|
829
884
|
});
|
|
830
885
|
}
|
|
831
886
|
syncModels(provider) {
|
|
@@ -977,12 +1032,12 @@ window.__ModuleLoader__.load({
|
|
|
977
1032
|
receive(message) {
|
|
978
1033
|
switch (message.type) {
|
|
979
1034
|
case "models-changed":
|
|
980
|
-
if (this.modelsVisible) this.readModels(message.provider, this.snapshot.modelPages?.[message.provider]?.offset ?? 0);
|
|
1035
|
+
if (this.modelsVisible) this.readModels(message.provider, this.snapshot.modelPages?.[message.provider]?.offset ?? 0, this.snapshot.modelPages?.[message.provider]?.manualOffset ?? 0);
|
|
981
1036
|
return;
|
|
982
1037
|
case "models-page": {
|
|
983
1038
|
const request = this.modelRequests.get(message.requestId);
|
|
984
1039
|
this.modelRequests.delete(message.requestId);
|
|
985
|
-
if (!request) return;
|
|
1040
|
+
if (!request || !this.snapshot.accounts.some((account) => account.provider === request.provider && account.configured)) return;
|
|
986
1041
|
if (!request.write && this.latestModelReads.get(request.provider) !== message.requestId) return;
|
|
987
1042
|
const current = this.snapshot.modelPages?.[request.provider];
|
|
988
1043
|
if (current && message.page.revision < current.revision) {
|
|
@@ -1011,7 +1066,7 @@ window.__ModuleLoader__.load({
|
|
|
1011
1066
|
case "models-error": {
|
|
1012
1067
|
const request = this.modelRequests.get(message.requestId);
|
|
1013
1068
|
this.modelRequests.delete(message.requestId);
|
|
1014
|
-
if (!request) return;
|
|
1069
|
+
if (!request || !this.snapshot.accounts.some((account) => account.provider === request.provider && account.configured)) return;
|
|
1015
1070
|
if (!request.write && this.latestModelReads.get(request.provider) !== message.requestId) return;
|
|
1016
1071
|
this.update({
|
|
1017
1072
|
...this.snapshot,
|
|
@@ -1033,14 +1088,30 @@ window.__ModuleLoader__.load({
|
|
|
1033
1088
|
case "snapshot":
|
|
1034
1089
|
const accounts = [...message.accounts];
|
|
1035
1090
|
const reconciled = reconcileAttemptView(this.snapshot.attempt, accounts);
|
|
1091
|
+
const modelPages = { ...this.snapshot.modelPages };
|
|
1092
|
+
const modelBusy = { ...this.snapshot.modelBusy };
|
|
1093
|
+
const modelErrors = { ...this.snapshot.modelErrors };
|
|
1094
|
+
for (const account of accounts) {
|
|
1095
|
+
if (account.configured) continue;
|
|
1096
|
+
delete modelPages[account.provider];
|
|
1097
|
+
delete modelBusy[account.provider];
|
|
1098
|
+
delete modelErrors[account.provider];
|
|
1099
|
+
this.latestModelReads.delete(account.provider);
|
|
1100
|
+
for (const [id, request] of this.modelRequests) if (request.provider === account.provider) this.modelRequests.delete(id);
|
|
1101
|
+
}
|
|
1036
1102
|
const nextSnapshot = {
|
|
1037
1103
|
...this.snapshot,
|
|
1038
|
-
accounts
|
|
1104
|
+
accounts,
|
|
1105
|
+
modelPages,
|
|
1106
|
+
modelBusy,
|
|
1107
|
+
modelErrors
|
|
1039
1108
|
};
|
|
1040
1109
|
if (reconciled === void 0) delete nextSnapshot.attempt;
|
|
1041
1110
|
else nextSnapshot.attempt = reconciled;
|
|
1042
1111
|
this.update(nextSnapshot);
|
|
1043
|
-
if (this.modelsVisible)
|
|
1112
|
+
if (this.modelsVisible) {
|
|
1113
|
+
for (const account of accounts) if (account.configured) this.readModels(account.provider, this.snapshot.modelPages?.[account.provider]?.offset ?? 0, this.snapshot.modelPages?.[account.provider]?.manualOffset ?? 0);
|
|
1114
|
+
}
|
|
1044
1115
|
return;
|
|
1045
1116
|
case "started":
|
|
1046
1117
|
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
@@ -1152,14 +1223,23 @@ window.__ModuleLoader__.load({
|
|
|
1152
1223
|
.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
1224
|
.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
1225
|
|
|
1155
|
-
.dsh-oauth-model-provider
|
|
1156
|
-
.dsh-oauth-model-
|
|
1157
|
-
.dsh-oauth-model-
|
|
1158
|
-
.dsh-oauth-model-
|
|
1159
|
-
.dsh-oauth-model-
|
|
1160
|
-
.dsh-oauth-model-
|
|
1161
|
-
.dsh-oauth-model-
|
|
1162
|
-
.dsh-oauth-model-
|
|
1226
|
+
.dsh-oauth-model-provider{display:flex;flex-direction:column;gap:10px;min-width:0;padding:14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}
|
|
1227
|
+
.dsh-oauth-model-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.dsh-oauth-model-header h3{min-width:0;overflow-wrap:anywhere}.dsh-oauth-model-header button{flex-shrink:0}
|
|
1228
|
+
.dsh-oauth-model-details{display:flex;flex-direction:column;gap:10px}.dsh-oauth-model-details[hidden]{display:none}
|
|
1229
|
+
.dsh-oauth-model-provider h3,.dsh-oauth-model-provider h4{margin:0;line-height:22px;font-weight:500}
|
|
1230
|
+
.dsh-oauth-model-provider h4{font-size:13px;color:var(--dsw-alias-label-secondary)}
|
|
1231
|
+
.dsh-oauth-model-actions{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
|
|
1232
|
+
.dsh-oauth-model-group{display:flex;flex-direction:column;gap:8px;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2)}
|
|
1233
|
+
.dsh-oauth-model-list{display:flex;flex-direction:column;gap:0;margin:0;padding:0;list-style:none}
|
|
1234
|
+
.dsh-oauth-model-list li{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;padding:10px 0;min-width:0}
|
|
1235
|
+
.dsh-oauth-model-list li>.dsh-oauth-model-form{box-sizing:border-box;width:100%;min-width:0}
|
|
1236
|
+
.dsh-oauth-model-list li+li{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
1237
|
+
.dsh-oauth-model-identity{display:flex;flex-direction:column;gap:3px;min-width:0;overflow-wrap:anywhere}
|
|
1238
|
+
.dsh-oauth-model-identity strong{font-size:13px;line-height:20px;font-weight:500}
|
|
1239
|
+
.dsh-oauth-model-identity code{font:12px/18px ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere}
|
|
1240
|
+
.dsh-oauth-model-form{display:flex;flex-direction:column;gap:10px;padding:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px}
|
|
1241
|
+
.dsh-oauth-model-form label{display:flex;flex-direction:column;gap:5px;font-size:13px;line-height:20px}
|
|
1242
|
+
.dsh-oauth-pagination{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;color:var(--dsw-alias-label-tertiary)}
|
|
1163
1243
|
`;
|
|
1164
1244
|
//#endregion
|
|
1165
1245
|
//#region src/client/index.ts
|
package/lib/index.d.ts
CHANGED
|
@@ -5,13 +5,16 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type ModelContext } from './model-service.js';
|
|
7
7
|
import type { IncomingMessage } from 'node:http';
|
|
8
|
+
import type { Volatile } from '@deepseek-ai/cordis';
|
|
8
9
|
import type { AuthorizationService } from '@deepseek-ai/dsh-authorization';
|
|
9
10
|
import type { CredentialProvider } from '@deepseek-ai/dsh-credentials';
|
|
10
11
|
import type { WebServer } from '@deepseek-ai/dsh-host-webserver';
|
|
11
|
-
import
|
|
12
|
+
import type SettingsForms from '@deepseek-ai/dsh-settings';
|
|
12
13
|
import z from '@deepseek-ai/schemastery';
|
|
14
|
+
import { type ModelStore } from './model-catalog.js';
|
|
13
15
|
/** Plugin configuration. */
|
|
14
16
|
export interface Config {
|
|
17
|
+
modelStore: Volatile<ModelStore>;
|
|
15
18
|
/** Emit secret-free transport lifecycle diagnostics. */
|
|
16
19
|
debug?: boolean;
|
|
17
20
|
modelSyncTimeoutMs?: number;
|
|
@@ -28,7 +31,7 @@ export declare const inject: string[];
|
|
|
28
31
|
type OAuthContext = ModelContext & {
|
|
29
32
|
authorization: AuthorizationService;
|
|
30
33
|
credentials: CredentialProvider;
|
|
31
|
-
settings:
|
|
34
|
+
settings: SettingsForms;
|
|
32
35
|
webServer: WebServer;
|
|
33
36
|
};
|
|
34
37
|
/** Whether a socket address belongs to the local host. */
|
package/lib/index.js
CHANGED
|
@@ -10,8 +10,10 @@ import { inspect } from 'node:util';
|
|
|
10
10
|
import z from '@deepseek-ai/schemastery';
|
|
11
11
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
12
12
|
import { MAX_FRAME_BYTES, OAUTH_SOCKET_PATH, OAUTH_SOCKET_PROTOCOL, PROVIDERS, parseClientCommand, } from './protocol.js';
|
|
13
|
+
import { validateModelStore } from './model-catalog.js';
|
|
13
14
|
/** Runtime-validated plugin configuration. */
|
|
14
15
|
export const Config = z.object({
|
|
16
|
+
modelStore: z.object({ version: z.const(1).default(1), providers: z.dict(z.any()).default({}) }).default({ version: 1, providers: {} }).volatile(),
|
|
15
17
|
debug: z.boolean().default(false),
|
|
16
18
|
modelSyncTimeoutMs: z.number().min(1).max(2147483647).step(1).default(30000),
|
|
17
19
|
modelSyncMaxResponseBytes: z.number().min(1024).step(1).default(4194304),
|
|
@@ -274,7 +276,7 @@ class OAuthConnection {
|
|
|
274
276
|
}
|
|
275
277
|
if (!this.closed)
|
|
276
278
|
this.send({ type: 'models-page', requestId: command.requestId,
|
|
277
|
-
page: await this.models.page(command.provider, command.type === 'models-list' ? command.offset : 0) });
|
|
279
|
+
page: await this.models.page(command.provider, command.type === 'models-list' ? command.offset : 0, command.type === 'models-list' ? command.manualOffset : 0) });
|
|
278
280
|
}
|
|
279
281
|
catch (error) {
|
|
280
282
|
if (!this.closed)
|
|
@@ -464,6 +466,13 @@ class OAuthConnection {
|
|
|
464
466
|
}
|
|
465
467
|
/** Mount the loopback-only OAuth WebSocket over official rc services. */
|
|
466
468
|
export function apply(ctx, config) {
|
|
469
|
+
validateModelStore(config.modelStore.get());
|
|
470
|
+
ctx.on('internal/config', function (_raw, next) {
|
|
471
|
+
const raw = next();
|
|
472
|
+
if (this === ctx.fiber)
|
|
473
|
+
validateModelStore(Config(raw).modelStore.get());
|
|
474
|
+
return raw;
|
|
475
|
+
});
|
|
467
476
|
const debug = config.debug === true
|
|
468
477
|
? (message) => { ctx.logger.debug('dsh-oauth-adapter: %s', message); }
|
|
469
478
|
: () => { };
|
|
@@ -474,7 +483,7 @@ export function apply(ctx, config) {
|
|
|
474
483
|
maxPages: config.modelSyncMaxPages ?? 100,
|
|
475
484
|
codexClientVersion: config.codexClientVersion ?? '0.149.0',
|
|
476
485
|
}, provider => { for (const connection of connections)
|
|
477
|
-
connection.modelChanged(provider); });
|
|
486
|
+
connection.modelChanged(provider); }, config.modelStore);
|
|
478
487
|
const server = new WebSocketServer({
|
|
479
488
|
noServer: true,
|
|
480
489
|
maxPayload: MAX_FRAME_BYTES,
|