@edge-sky/dsh-oauth-adapter 0.1.2-beta.1 → 0.1.2-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ export const MODEL_PAGE_SIZE = 10;
2
+ export const MODEL_PROTOCOLS = {
3
+ 'github-copilot': ['openai-completions', 'openai-responses', 'anthropic-messages'],
4
+ openrouter: ['openai-completions', 'anthropic-messages'],
5
+ 'openai-codex': ['openai-codex-responses'],
6
+ xai: ['openai-responses'],
7
+ anthropic: ['anthropic-messages'],
8
+ 'kimi-coding': ['anthropic-messages'],
9
+ };
10
+ export function modelText(value) {
11
+ return typeof value === 'string' && value.length > 0 && value.length <= 256 && value.trim() === value && !/[\u0000-\u001f\u007f]/u.test(value);
12
+ }
13
+ /** Validate at the wire and durable-data boundaries; fixed-protocol routes accept no override. */
14
+ export function validManual(provider, value) {
15
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
16
+ return false;
17
+ const m = value;
18
+ if (Object.keys(m).some(k => !['id', 'name', 'api'].includes(k)) || !modelText(m.id))
19
+ return false;
20
+ if (m.name !== undefined && !modelText(m.name))
21
+ return false;
22
+ const choices = MODEL_PROTOCOLS[provider];
23
+ return choices.length === 1 ? m.api === undefined : typeof m.api === 'string' && choices.includes(m.api);
24
+ }
25
+ //# sourceMappingURL=model-types.js.map
package/lib/protocol.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /** Shared browser/Host wire vocabulary for the OAuth account surface. */
2
+ import type { ModelCommand, ModelMessage } from './model-types.js';
2
3
  export declare const OAUTH_SOCKET_PATH = "/_edge-sky/dsh-oauth";
3
4
  export declare const OAUTH_SOCKET_PROTOCOL = "dsh-oauth-v1";
4
5
  export declare const MAX_FRAME_BYTES: number;
@@ -64,7 +65,7 @@ export type PromptView = {
64
65
  description?: string;
65
66
  }[];
66
67
  };
67
- export type ClientCommand = {
68
+ export type ClientCommand = ModelCommand | {
68
69
  type: 'refresh';
69
70
  requestId: string;
70
71
  } | {
@@ -87,7 +88,7 @@ export type ClientCommand = {
87
88
  provider: ProviderId;
88
89
  };
89
90
  export type OAuthErrorCode = 'invalid-message' | 'unsupported-provider' | 'authorization-unavailable' | 'busy' | 'invalid-attempt' | 'invalid-prompt' | 'credential-read-only' | 'model-route-unavailable' | 'sign-in-failed' | 'operation-failed';
90
- export type ServerMessage = {
91
+ export type ServerMessage = ModelMessage | {
91
92
  type: 'snapshot';
92
93
  requestId?: string;
93
94
  accounts: readonly AccountView[];
package/lib/protocol.js CHANGED
@@ -1,4 +1,5 @@
1
1
  /** Shared browser/Host wire vocabulary for the OAuth account surface. */
2
+ import { validManual, modelText } from './model-types.js';
2
3
  export const OAUTH_SOCKET_PATH = '/_edge-sky/dsh-oauth';
3
4
  export const OAUTH_SOCKET_PROTOCOL = 'dsh-oauth-v1';
4
5
  export const MAX_FRAME_BYTES = 16 * 1024;
@@ -59,6 +60,32 @@ export function parseClientCommand(raw) {
59
60
  const requestId = isId(candidate.requestId) ? candidate.requestId : undefined;
60
61
  if (requestId === undefined)
61
62
  return { ok: false, message: 'requestId is invalid' };
63
+ if (candidate.type.startsWith('models-')) {
64
+ if (!isProviderId(candidate.provider))
65
+ return { ok: false, requestId, message: 'provider is unsupported' };
66
+ const provider = candidate.provider;
67
+ const fail = { ok: false, requestId, message: 'model command fields are invalid' };
68
+ if (candidate.type === 'models-list') {
69
+ return exactKeys(candidate, ['type', 'requestId', 'provider', 'offset']) && Number.isSafeInteger(candidate.offset) && Number(candidate.offset) >= 0
70
+ ? { ok: true, value: { type: 'models-list', requestId, provider, offset: Number(candidate.offset) } } : fail;
71
+ }
72
+ if (!Number.isSafeInteger(candidate.revision) || Number(candidate.revision) < 0)
73
+ return fail;
74
+ const revision = Number(candidate.revision);
75
+ if (candidate.type === 'models-sync' || candidate.type === 'models-migrate') {
76
+ return exactKeys(candidate, ['type', 'requestId', 'provider', 'revision'])
77
+ ? { ok: true, value: { type: candidate.type, requestId, provider, revision } } : fail;
78
+ }
79
+ if (candidate.type === 'models-save') {
80
+ return exactKeys(candidate, ['type', 'requestId', 'provider', 'revision', 'model']) && validManual(provider, candidate.model)
81
+ ? { ok: true, value: { type: 'models-save', requestId, provider, revision, model: candidate.model } } : fail;
82
+ }
83
+ if (candidate.type === 'models-delete') {
84
+ return exactKeys(candidate, ['type', 'requestId', 'provider', 'revision', 'id']) && modelText(candidate.id)
85
+ ? { ok: true, value: { type: 'models-delete', requestId, provider, revision, id: candidate.id } } : fail;
86
+ }
87
+ return fail;
88
+ }
62
89
  switch (candidate.type) {
63
90
  case 'refresh':
64
91
  return exactKeys(candidate, ['requestId', 'type'])
@@ -0,0 +1,11 @@
1
+ import type { OAuthAccountsController } from './store.js';
2
+ import type { OAuthLocaleKey } from './locales.js';
3
+ import type { InjectFace } from '@deepseek-ai/dsh-client-ui-slots';
4
+ export interface OAuthModelsInjected {
5
+ controller: OAuthAccountsController;
6
+ t: (key: OAuthLocaleKey) => string;
7
+ }
8
+ type Props = InjectFace<OAuthModelsInjected>;
9
+ export declare function OAuthModelsSection(props: Props): JSX.Element | null;
10
+ export {};
11
+ //# sourceMappingURL=OAuthModelsSection.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /** Browser half of the standalone DSH OAuth Accounts page. */
2
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import type { Context } from '@deepseek-ai/cordis';
3
3
  import { type OAuthLocaleKey } from './locales.js';
4
4
  export { OAuthAccountsSection } from './OAuthAccountsSection.js';
5
5
  export { OAuthAccountsController } from './store.js';
@@ -12,5 +12,5 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
12
12
  /** Required browser services for settings placement and localized copy. */
13
13
  export declare const inject: string[];
14
14
  /** Register the OAuth account page and its app-lifetime connection controller. */
15
- export declare function apply(ctx: ClientContext): void;
15
+ export declare function apply(ctx: Context): void;
16
16
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,39 @@
1
1
  /** English copy for the OAuth accounts page. */
2
2
  export declare const en: {
3
+ readonly modelUnsupported: "This provider does not support account discovery with the current credential. You can still add models manually.";
4
+ readonly modelAuthFailed: "Model discovery was denied. Reconnect or check this account’s permissions. The previous list was retained.";
5
+ readonly modelTimedOut: "Model synchronization timed out. The previous list was retained.";
6
+ readonly modelRouteConflict: "This provider is owned by an existing configuration. Review the details before migration.";
7
+ readonly loginSyncFailed: "Sign-in succeeded, but model synchronization failed. Open Models to retry.";
8
+ readonly modelsTitle: "OAuth models";
9
+ readonly modelsIntro: "Synchronize account-visible models or add a model manually. Manual models survive synchronization.";
10
+ readonly modelId: "Model ID";
11
+ readonly modelName: "Display name";
12
+ readonly modelProtocol: "Request protocol";
13
+ readonly manualModelHint: "Saving configures a request; it does not verify account access or model capabilities.";
14
+ readonly saveModel: "Save model";
15
+ readonly modelConnected: "Connected";
16
+ readonly accountCatalog: "Account-synchronized list";
17
+ readonly builtinCatalog: "Built-in list · account access unverified";
18
+ readonly lastModelSync: "Last successful synchronization";
19
+ readonly matchedModels: "Matched";
20
+ readonly pendingModels: "Needs configuration";
21
+ readonly manualModels: "Manual";
22
+ readonly modelConflict: "Models changed elsewhere. The list was refreshed; review it and retry.";
23
+ readonly modelOperationFailed: "The model operation failed. Review the details before retrying.";
24
+ readonly reviewMigration: "Review migration";
25
+ readonly migrationDescription: "Move this OAuth provider configuration to plugin management while preserving its ID and credentials. The following configuration fields will be retained:";
26
+ readonly confirmMigration: "Migrate this provider";
27
+ readonly modelWorking: "Working…";
28
+ readonly syncModels: "Synchronize models";
29
+ readonly addModel: "Add model";
30
+ readonly configureModel: "Configure";
31
+ readonly editModel: "Edit";
32
+ readonly deleteModel: "Delete manual entry";
33
+ readonly noModels: "No selectable models. Configure an unmatched model or add one manually.";
34
+ readonly modelsPagination: "OAuth model pages";
35
+ readonly previousModels: "Previous";
36
+ readonly nextModels: "Next";
3
37
  readonly nav: "OAuth Accounts";
4
38
  readonly title: "OAuth Accounts";
5
39
  readonly intro: "Connect subscription-backed providers. Their models appear in separate OAuth groups, apart from API-key providers.";
@@ -1,5 +1,6 @@
1
1
  /** Browser state machine for the plugin-owned OAuth WebSocket. */
2
2
  import type { AccountView, PromptView, ProviderId, ServerMessage } from '../protocol.js';
3
+ import type { ModelPage, ManualModel } from '../model-types.js';
3
4
  export interface NoticeView {
4
5
  message: string;
5
6
  url?: string;
@@ -21,6 +22,12 @@ export interface AttemptView {
21
22
  export interface OAuthAccountsSnapshot {
22
23
  connection: 'connecting' | 'open' | 'reconnecting' | 'closed';
23
24
  accounts: readonly AccountView[];
25
+ modelPages?: Partial<Record<ProviderId, ModelPage>>;
26
+ modelBusy?: Partial<Record<ProviderId, boolean>>;
27
+ modelErrors?: Partial<Record<ProviderId, {
28
+ code: string;
29
+ message: string;
30
+ }>>;
24
31
  attempt?: AttemptView;
25
32
  error?: string;
26
33
  errorDetail?: string;
@@ -40,6 +47,9 @@ export declare class OAuthAccountsController {
40
47
  private reconnectTimer;
41
48
  private reconnectDelay;
42
49
  private disposed;
50
+ private modelsVisible;
51
+ private readonly modelRequests;
52
+ private readonly latestModelReads;
43
53
  constructor();
44
54
  readonly subscribe: (listener: Listener) => (() => void);
45
55
  readonly getSnapshot: () => OAuthAccountsSnapshot;
@@ -47,6 +57,13 @@ export declare class OAuthAccountsController {
47
57
  respond(attemptId: string, promptId: string, value: string): void;
48
58
  cancel(attemptId: string): void;
49
59
  forget(provider: ProviderId): void;
60
+ loadModels(): void;
61
+ readModels(provider: ProviderId, offset?: number): void;
62
+ syncModels(provider: ProviderId): void;
63
+ migrateModels(provider: ProviderId): void;
64
+ saveModel(provider: ProviderId, model: ManualModel): void;
65
+ deleteModel(provider: ProviderId, id: string): void;
66
+ private writeModels;
50
67
  retry(): void;
51
68
  dispose(): void;
52
69
  private connect;
@@ -1,3 +1,3 @@
1
1
  /** Plugin-owned styles, injected and removed with the browser Cordis fiber. */
2
- export declare const styles = "\n.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}\n.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}\n.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}\n.dsh-oauth-error{display:flex;flex-direction:column;gap:6px;margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.dsh-oauth-error p{margin:0}.dsh-oauth-error pre{box-sizing:border-box;max-width:100%;max-height:320px;margin:0;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;overflow:auto;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:11px/17px ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.dsh-oauth-error-details summary{cursor:pointer;color:var(--dsw-alias-label-secondary);user-select:none}.dsh-oauth-error-details[open] summary{margin-bottom:6px}\n.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}\n.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}\n.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}\n.dsh-oauth-dot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dsh-oauth-state[data-state=ready] .dsh-oauth-dot{background:var(--dsw-alias-state-success-primary)}.dsh-oauth-state[data-state=warning] .dsh-oauth-dot{background:var(--dsw-alias-state-error-primary)}.dsh-oauth-state[data-state=authorizing] .dsh-oauth-dot{background:var(--dsw-alias-button-info-fill)}\n.dsh-oauth-actions{display:flex;gap:6px;margin-left:auto}.dsh-oauth-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:30px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:15px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px;cursor:pointer}.dsh-oauth-button[data-variant=primary]{border-color:transparent;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]{border-color:transparent;color:var(--dsw-alias-state-error-primary)}.dsh-oauth-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-button[data-variant=primary]:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.dsh-oauth-button:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.dsh-oauth-button:disabled{cursor:not-allowed;opacity:.4}\n.dsh-oauth-flow{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l3);font-size:13px;line-height:20px}.dsh-oauth-link{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);text-decoration:none}.dsh-oauth-link:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-link-label{font-weight:500}.dsh-oauth-link-host{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsh-oauth-link-icon{color:var(--dsw-alias-brand-text)}.dsh-oauth-code{display:flex;align-items:center;gap:8px}.dsh-oauth-code code{padding:5px 8px;border-radius:6px;background:var(--dsw-alias-bg-module-platform);font-size:14px;letter-spacing:.08em}\n.dsh-oauth-prompt{display:flex;flex-direction:column;gap:7px}.dsh-oauth-input,.dsh-oauth-select{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}\n";
2
+ export declare const styles = "\n.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}\n.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}\n.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}\n.dsh-oauth-error{display:flex;flex-direction:column;gap:6px;margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.dsh-oauth-error p{margin:0}.dsh-oauth-error pre{box-sizing:border-box;max-width:100%;max-height:320px;margin:0;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;overflow:auto;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:11px/17px ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.dsh-oauth-error-details summary{cursor:pointer;color:var(--dsw-alias-label-secondary);user-select:none}.dsh-oauth-error-details[open] summary{margin-bottom:6px}\n.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}\n.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}\n.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}\n.dsh-oauth-dot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dsh-oauth-state[data-state=ready] .dsh-oauth-dot{background:var(--dsw-alias-state-success-primary)}.dsh-oauth-state[data-state=warning] .dsh-oauth-dot{background:var(--dsw-alias-state-error-primary)}.dsh-oauth-state[data-state=authorizing] .dsh-oauth-dot{background:var(--dsw-alias-button-info-fill)}\n.dsh-oauth-actions{display:flex;gap:6px;margin-left:auto}.dsh-oauth-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:30px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:15px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px;cursor:pointer}.dsh-oauth-button[data-variant=primary]{border-color:transparent;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]{border-color:transparent;color:var(--dsw-alias-state-error-primary)}.dsh-oauth-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-button[data-variant=primary]:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.dsh-oauth-button:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.dsh-oauth-button:disabled{cursor:not-allowed;opacity:.4}\n.dsh-oauth-flow{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l3);font-size:13px;line-height:20px}.dsh-oauth-link{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);text-decoration:none}.dsh-oauth-link:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-link-label{font-weight:500}.dsh-oauth-link-host{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsh-oauth-link-icon{color:var(--dsw-alias-brand-text)}.dsh-oauth-code{display:flex;align-items:center;gap:8px}.dsh-oauth-code code{padding:5px 8px;border-radius:6px;background:var(--dsw-alias-bg-module-platform);font-size:14px;letter-spacing:.08em}\n.dsh-oauth-prompt{display:flex;flex-direction:column;gap:7px}.dsh-oauth-input,.dsh-oauth-select{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}\n\n.dsh-oauth-model-provider { border: 1px solid var(--border-color, currentColor); border-radius: 8px; padding: 16px; margin-block: 16px; }\n.dsh-oauth-model-provider button { margin: 4px; }\n.dsh-oauth-model-list { padding: 0; list-style: none; }\n.dsh-oauth-model-list li { padding-block: 8px; border-bottom: 1px solid var(--border-color, currentColor); overflow-wrap: anywhere; }\n.dsh-oauth-model-list code { margin-inline: 8px; }\n.dsh-oauth-model-form { display: grid; gap: 12px; margin-block: 12px; }\n.dsh-oauth-model-form label { display: grid; gap: 4px; }\n.dsh-oauth-model-provider nav { display: flex; align-items: center; gap: 8px; }\n";
3
3
  //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1,92 @@
1
+ /** Model-management messages shared by the browser and Host. No credentials travel here. */
2
+ import type { ProviderId } from './protocol.js';
3
+ export declare const MODEL_PAGE_SIZE = 10;
4
+ export declare const MODEL_PROTOCOLS: {
5
+ readonly 'github-copilot': readonly ["openai-completions", "openai-responses", "anthropic-messages"];
6
+ readonly openrouter: readonly ["openai-completions", "anthropic-messages"];
7
+ readonly 'openai-codex': readonly ["openai-codex-responses"];
8
+ readonly xai: readonly ["openai-responses"];
9
+ readonly anthropic: readonly ["anthropic-messages"];
10
+ readonly 'kimi-coding': readonly ["anthropic-messages"];
11
+ };
12
+ export type ModelProtocol = (typeof MODEL_PROTOCOLS)[ProviderId][number];
13
+ export interface ManualModel {
14
+ id: string;
15
+ name?: string;
16
+ api?: ModelProtocol;
17
+ }
18
+ export interface DiscoveredModel {
19
+ id: string;
20
+ name?: string;
21
+ }
22
+ export interface ModelRow {
23
+ id: string;
24
+ name: string;
25
+ source: 'catalog' | 'matched' | 'pending' | 'manual';
26
+ api?: string;
27
+ }
28
+ export interface ModelPage {
29
+ provider: ProviderId;
30
+ revision: number;
31
+ offset: number;
32
+ total: number;
33
+ rows: ModelRow[];
34
+ source: 'catalog' | 'account';
35
+ counts: {
36
+ matched: number;
37
+ pending: number;
38
+ manual: number;
39
+ };
40
+ connected: boolean;
41
+ writable: boolean;
42
+ managed: boolean;
43
+ busy: boolean;
44
+ syncedAt?: string;
45
+ error?: string;
46
+ errorCode?: string;
47
+ migration?: {
48
+ fields: string[];
49
+ models: number;
50
+ };
51
+ }
52
+ export type ModelCommand = {
53
+ type: 'models-list';
54
+ requestId: string;
55
+ provider: ProviderId;
56
+ offset: number;
57
+ } | {
58
+ type: 'models-sync' | 'models-migrate';
59
+ requestId: string;
60
+ provider: ProviderId;
61
+ revision: number;
62
+ } | {
63
+ type: 'models-save';
64
+ requestId: string;
65
+ provider: ProviderId;
66
+ revision: number;
67
+ model: ManualModel;
68
+ } | {
69
+ type: 'models-delete';
70
+ requestId: string;
71
+ provider: ProviderId;
72
+ revision: number;
73
+ id: string;
74
+ };
75
+ export type ModelMessage = {
76
+ type: 'models-page';
77
+ requestId: string;
78
+ page: ModelPage;
79
+ } | {
80
+ type: 'models-changed';
81
+ provider: ProviderId;
82
+ } | {
83
+ type: 'models-error';
84
+ requestId: string;
85
+ provider: ProviderId;
86
+ code: string;
87
+ message: string;
88
+ };
89
+ export declare function modelText(value: unknown): value is string;
90
+ /** Validate at the wire and durable-data boundaries; fixed-protocol routes accept no override. */
91
+ export declare function validManual(provider: ProviderId, value: unknown): value is ManualModel;
92
+ //# sourceMappingURL=model-types.d.ts.map
@@ -1,4 +1,5 @@
1
1
  /** Shared browser/Host wire vocabulary for the OAuth account surface. */
2
+ import type { ModelCommand, ModelMessage } from './model-types.js';
2
3
  export declare const OAUTH_SOCKET_PATH = "/_edge-sky/dsh-oauth";
3
4
  export declare const OAUTH_SOCKET_PROTOCOL = "dsh-oauth-v1";
4
5
  export declare const MAX_FRAME_BYTES: number;
@@ -64,7 +65,7 @@ export type PromptView = {
64
65
  description?: string;
65
66
  }[];
66
67
  };
67
- export type ClientCommand = {
68
+ export type ClientCommand = ModelCommand | {
68
69
  type: 'refresh';
69
70
  requestId: string;
70
71
  } | {
@@ -87,7 +88,7 @@ export type ClientCommand = {
87
88
  provider: ProviderId;
88
89
  };
89
90
  export type OAuthErrorCode = 'invalid-message' | 'unsupported-provider' | 'authorization-unavailable' | 'busy' | 'invalid-attempt' | 'invalid-prompt' | 'credential-read-only' | 'model-route-unavailable' | 'sign-in-failed' | 'operation-failed';
90
- export type ServerMessage = {
91
+ export type ServerMessage = ModelMessage | {
91
92
  type: 'snapshot';
92
93
  requestId?: string;
93
94
  accounts: readonly AccountView[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@edge-sky/dsh-oauth-adapter",
3
3
  "description": "Web OAuth account surface for official DSH authorization flows",
4
- "version": "0.1.2-beta.1",
4
+ "version": "0.1.2-dev.2",
5
5
  "author": {
6
6
  "name": "edge-sky",
7
7
  "url": "https://github.com/edge-sky"
@@ -50,7 +50,8 @@
50
50
  "build:host": "tsc -p tsconfig.json",
51
51
  "build:client:types": "tsc -p tsconfig.client.json",
52
52
  "test": "pnpm run build && vitest run",
53
- "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit"
53
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
54
+ "prepack": "pnpm run typecheck && pnpm test"
54
55
  },
55
56
  "license": "MIT",
56
57
  "dsh": {
@@ -59,27 +60,30 @@
59
60
  },
60
61
  "client": {
61
62
  "inject": [
62
- "@deepseek-ai/dsh-client-runtime",
63
63
  "@deepseek-ai/dsh-client-ui-settings",
64
- "@deepseek-ai/dsh-client-locale"
64
+ "@deepseek-ai/dsh-client-locale",
65
+ "@deepseek-ai/dsh-client-ui-settings-models"
65
66
  ],
66
67
  "platform": "web"
67
68
  }
68
69
  },
69
70
  "peerDependencies": {
70
- "@deepseek-ai/cordis": ">=4.0.1",
71
- "@deepseek-ai/dsh-authorization": ">=0.1.1-rc.2 <0.2.0-0",
72
- "@deepseek-ai/dsh-client-locale": ">=0.1.1-rc.2 <0.2.0-0",
73
- "@deepseek-ai/dsh-client-runtime": ">=0.1.1-rc.2 <0.2.0-0",
74
- "@deepseek-ai/dsh-client-ui-settings": ">=0.1.1-rc.2 <0.2.0-0",
75
- "@deepseek-ai/dsh-client-ui-slots": ">=0.1.1-rc.2 <0.2.0-0",
76
- "@deepseek-ai/dsh-credentials": ">=0.1.1-rc.2 <0.2.0-0",
77
- "@deepseek-ai/dsh-host-webserver": ">=0.1.1-rc.2 <0.2.0-0",
78
- "@deepseek-ai/dsh-invariants": ">=0.1.1-rc.2 <0.2.0-0",
79
- "@deepseek-ai/dsh-llm": ">=0.1.1-rc.2 <0.2.0-0",
80
- "@deepseek-ai/dsh-llm-pi-ai": ">=0.1.1-rc.2 <0.2.0-0",
81
- "@deepseek-ai/dsh-settings": ">=0.1.1-rc.2 <0.2.0-0",
82
- "react": ">=18.2.0"
71
+ "@deepseek-ai/cordis": ">=4.0.2",
72
+ "@deepseek-ai/dsh-authorization": ">=0.1.2-rc.1 <0.2.0-0",
73
+ "@deepseek-ai/dsh-client-locale": ">=0.1.2-rc.1 <0.2.0-0",
74
+ "@deepseek-ai/dsh-client-ui-settings": ">=0.1.2-rc.1 <0.2.0-0",
75
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.2-rc.1 <0.2.0-0",
76
+ "@deepseek-ai/dsh-credentials": ">=0.1.2-rc.1 <0.2.0-0",
77
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.2-rc.1 <0.2.0-0",
78
+ "@deepseek-ai/dsh-invariants": ">=0.1.2-rc.1 <0.2.0-0",
79
+ "@deepseek-ai/dsh-llm": ">=0.1.2-rc.1 <0.2.0-0",
80
+ "@deepseek-ai/dsh-llm-pi-ai": ">=0.1.2-rc.1 <0.2.0-0",
81
+ "@deepseek-ai/dsh-settings": ">=0.1.2-rc.1 <0.2.0-0",
82
+ "react": ">=18.2.0",
83
+ "@deepseek-ai/dsh-client-ui-settings-models": ">=0.1.2-rc.1 <0.2.0-0",
84
+ "@deepseek-ai/dsh-attachment": ">=0.1.2-rc.1 <0.2.0-0",
85
+ "@deepseek-ai/dsh-fs": ">=0.1.2-rc.1 <0.2.0-0",
86
+ "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.2-rc.1 <0.2.0-0"
83
87
  },
84
88
  "peerDependenciesMeta": {
85
89
  "@deepseek-ai/cordis": {
@@ -88,9 +92,6 @@
88
92
  "@deepseek-ai/dsh-client-locale": {
89
93
  "optional": true
90
94
  },
91
- "@deepseek-ai/dsh-client-runtime": {
92
- "optional": true
93
- },
94
95
  "@deepseek-ai/dsh-client-ui-settings": {
95
96
  "optional": true
96
97
  },
@@ -117,25 +118,37 @@
117
118
  },
118
119
  "react": {
119
120
  "optional": true
121
+ },
122
+ "@deepseek-ai/dsh-client-ui-settings-models": {
123
+ "optional": true
124
+ },
125
+ "@deepseek-ai/dsh-attachment": {
126
+ "optional": true
127
+ },
128
+ "@deepseek-ai/dsh-fs": {
129
+ "optional": true
130
+ },
131
+ "@deepseek-ai/dsh-client-ui-renderer": {
132
+ "optional": true
120
133
  }
121
134
  },
122
135
  "dependencies": {
123
- "@deepseek-ai/schemastery": "^3.18.1",
124
- "ws": "^8.18.3"
136
+ "@deepseek-ai/schemastery": "^3.18.2",
137
+ "ws": "^8.18.3",
138
+ "@earendil-works/pi-ai": "0.84.4"
125
139
  },
126
140
  "devDependencies": {
127
- "@deepseek-ai/cordis": "^4.0.1",
128
- "@deepseek-ai/dsh-authorization": "0.1.1-rc.2",
129
- "@deepseek-ai/dsh-client-locale": "0.1.1-rc.2",
130
- "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
131
- "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
132
- "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
133
- "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
134
- "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
135
- "@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
136
- "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
137
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.1-rc.2",
138
- "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
141
+ "@deepseek-ai/cordis": "^4.0.2",
142
+ "@deepseek-ai/dsh-authorization": "0.1.2-rc.1",
143
+ "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
144
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
145
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
146
+ "@deepseek-ai/dsh-credentials": "0.1.2-rc.1",
147
+ "@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1",
148
+ "@deepseek-ai/dsh-invariants": "0.1.2-rc.1",
149
+ "@deepseek-ai/dsh-llm": "0.1.2-rc.1",
150
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1",
151
+ "@deepseek-ai/dsh-settings": "0.1.2-rc.1",
139
152
  "@types/node": "^22.20.0",
140
153
  "@types/react": "~18.3.1",
141
154
  "@types/react-dom": "~18.3.1",
@@ -144,6 +157,20 @@
144
157
  "react-dom": "^18.2.0",
145
158
  "tsdown": "^0.22.2",
146
159
  "typescript": "^6.0.3",
147
- "vitest": "^4.1.8"
160
+ "vitest": "^4.1.8",
161
+ "@deepseek-ai/dsh-client-ui-settings-models": "0.1.2-rc.1",
162
+ "@deepseek-ai/dsh-attachment": "0.1.2-rc.1",
163
+ "@deepseek-ai/dsh-fs": "0.1.2-rc.1",
164
+ "@deepseek-ai/dsh-settings-file": "0.1.2-rc.1",
165
+ "@deepseek-ai/dsh-credentials-local": "0.1.2-rc.1",
166
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.2-rc.1",
167
+ "jsdom": "^26.1.0",
168
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
169
+ "@deepseek-ai/dsh-client-store": "0.1.2-rc.1",
170
+ "@deepseek-ai/dsh-atomic-write": "0.1.2-rc.1",
171
+ "@deepseek-ai/dsh-home-paths": "0.1.2-rc.1",
172
+ "@deepseek-ai/dsh-launch-environment": "0.1.2-rc.1",
173
+ "@deepseek-ai/dsh-session": "0.1.2-rc.1",
174
+ "@deepseek-ai/dsh-scope": "0.1.2-rc.1"
148
175
  }
149
176
  }