@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/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.phase === "authorized" ? props.t("loginSyncFailed") : props.attempt.error,
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 = ModelContext & {
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 rc services. */
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