dsh-coding-subscription-oauth 0.5.8 → 0.6.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.
Files changed (148) hide show
  1. package/CHANGELOG.md +217 -188
  2. package/CONTRIBUTING.md +120 -120
  3. package/INSTALL.md +241 -209
  4. package/LICENSE +19 -19
  5. package/NOTICE +11 -11
  6. package/README.de.md +298 -294
  7. package/README.es.md +299 -295
  8. package/README.fr.md +299 -295
  9. package/README.ja.md +299 -295
  10. package/README.ko.md +299 -295
  11. package/README.md +313 -307
  12. package/README.pt-BR.md +299 -295
  13. package/README.ru.md +299 -295
  14. package/README.zh-CN.md +311 -305
  15. package/compatibility/dsh-bom.json +30 -0
  16. package/cordis.patch.yml +13 -13
  17. package/docs/00-project-rules.md +195 -195
  18. package/docs/02-architecture.md +134 -129
  19. package/docs/02-architecture.zh-CN.md +134 -129
  20. package/lib/adapter.d.ts.map +1 -1
  21. package/lib/alias-adapter.d.ts +3 -1
  22. package/lib/alias-adapter.d.ts.map +1 -1
  23. package/lib/auth-routes.d.ts +8 -15
  24. package/lib/auth-routes.d.ts.map +1 -1
  25. package/lib/bin.js +746 -1402
  26. package/lib/bin.js.map +4 -4
  27. package/lib/capability-routes.d.ts +3 -3
  28. package/lib/capability-routes.d.ts.map +1 -1
  29. package/lib/capability-settings.d.ts +5 -4
  30. package/lib/capability-settings.d.ts.map +1 -1
  31. package/lib/client.js +27 -8
  32. package/lib/client.js.map +4 -4
  33. package/lib/compatibility.d.ts +46 -0
  34. package/lib/compatibility.d.ts.map +1 -0
  35. package/lib/dsh-host-adapter.d.ts +18 -0
  36. package/lib/dsh-host-adapter.d.ts.map +1 -0
  37. package/lib/gateway-auth.d.ts +1 -2
  38. package/lib/gateway-auth.d.ts.map +1 -1
  39. package/lib/gateway-routes.d.ts +3 -4
  40. package/lib/gateway-routes.d.ts.map +1 -1
  41. package/lib/gateway.d.ts +4 -0
  42. package/lib/gateway.d.ts.map +1 -1
  43. package/lib/ids.d.ts +3 -32
  44. package/lib/ids.d.ts.map +1 -1
  45. package/lib/imagine-routes.d.ts +2 -0
  46. package/lib/imagine-routes.d.ts.map +1 -1
  47. package/lib/index.d.ts +19 -4
  48. package/lib/index.d.ts.map +1 -1
  49. package/lib/index.js +26627 -1047
  50. package/lib/index.js.map +4 -4
  51. package/lib/invariant.js.map +1 -1
  52. package/lib/oauth-import-routes.d.ts +3 -4
  53. package/lib/oauth-import-routes.d.ts.map +1 -1
  54. package/lib/proxy.d.ts +3 -16
  55. package/lib/proxy.d.ts.map +1 -1
  56. package/lib/web-origin.d.ts +28 -4
  57. package/lib/web-origin.d.ts.map +1 -1
  58. package/lib/web-routes.d.ts.map +1 -1
  59. package/media/en/settings_accounts.png +0 -0
  60. package/media/en/settings_capabilities.png +0 -0
  61. package/media/en/settings_gateway.png +0 -0
  62. package/media/settings_accounts.png +0 -0
  63. package/media/settings_capabilities.png +0 -0
  64. package/media/settings_gateway.png +0 -0
  65. package/media/settings_overview.png +0 -0
  66. package/media/zh-CN/settings_accounts.png +0 -0
  67. package/media/zh-CN/settings_capabilities.png +0 -0
  68. package/media/zh-CN/settings_gateway.png +0 -0
  69. package/package.json +211 -174
  70. package/patches/dsh-agy@0.1.2.patch +25 -25
  71. package/scripts/release.mjs +186 -170
  72. package/scripts/smoke-deployed-routes.mjs +146 -146
  73. package/scripts/verify-deployed-catalog.mjs +87 -87
  74. package/src/adapter.ts +329 -268
  75. package/src/alias-adapter.ts +141 -147
  76. package/src/auth-routes.ts +921 -871
  77. package/src/auth.ts +67 -67
  78. package/src/bin.ts +350 -350
  79. package/src/capability-routes.ts +279 -275
  80. package/src/capability-runtime.ts +313 -313
  81. package/src/capability-settings.ts +658 -657
  82. package/src/capability-tools.ts +666 -666
  83. package/src/catalog.ts +271 -271
  84. package/src/client/GrokBuildSettings.tsx +770 -718
  85. package/src/client/api.ts +88 -88
  86. package/src/client/components/AboutTab.tsx +30 -30
  87. package/src/client/components/AccountsTab.tsx +241 -224
  88. package/src/client/components/Badge.tsx +33 -33
  89. package/src/client/components/CapabilitiesTab.tsx +265 -227
  90. package/src/client/components/CliPullPreview.tsx +116 -107
  91. package/src/client/components/CopyButton.tsx +57 -57
  92. package/src/client/components/GatewayTab.tsx +469 -409
  93. package/src/client/components/NoticeBanner.tsx +46 -46
  94. package/src/client/components/ProgressBar.tsx +53 -53
  95. package/src/client/components/ProviderCard.tsx +606 -502
  96. package/src/client/components/SettingsTabs.tsx +75 -75
  97. package/src/client/components/ToggleSwitch.tsx +71 -62
  98. package/src/client/constants.ts +224 -206
  99. package/src/client/display.ts +61 -61
  100. package/src/client/dshClientAdapter.ts +127 -0
  101. package/src/client/gatewaySnippets.ts +37 -36
  102. package/src/client/index.tsx +156 -37
  103. package/src/client/locales.ts +535 -491
  104. package/src/client/microStyles.ts +52 -33
  105. package/src/client/parsers.ts +396 -386
  106. package/src/client/styles.ts +325 -307
  107. package/src/client/types.ts +197 -185
  108. package/src/codex-http.ts +447 -447
  109. package/src/codex-images.ts +485 -485
  110. package/src/codex-model-capabilities.ts +320 -320
  111. package/src/codex-search.ts +245 -245
  112. package/src/codex-usage.ts +263 -263
  113. package/src/compatibility.ts +55 -0
  114. package/src/dsh-host-adapter.ts +173 -0
  115. package/src/gateway-anthropic-messages.ts +84 -84
  116. package/src/gateway-auth.ts +102 -100
  117. package/src/gateway-backend.ts +274 -274
  118. package/src/gateway-body.ts +49 -49
  119. package/src/gateway-config.ts +76 -76
  120. package/src/gateway-http.ts +104 -104
  121. package/src/gateway-openai-chat.ts +124 -124
  122. package/src/gateway-openai-responses.ts +53 -53
  123. package/src/gateway-parse.ts +224 -224
  124. package/src/gateway-protocol.ts +52 -52
  125. package/src/gateway-routes.ts +158 -152
  126. package/src/gateway.ts +258 -242
  127. package/src/grok-errors.ts +24 -24
  128. package/src/grok-imagine.ts +1627 -1627
  129. package/src/grok-import.ts +151 -151
  130. package/src/http-json.ts +82 -82
  131. package/src/ids.ts +59 -45
  132. package/src/imagine-routes.ts +463 -461
  133. package/src/index.ts +729 -592
  134. package/src/invariant.ts +17 -17
  135. package/src/kimi-errors.ts +26 -26
  136. package/src/media-store.ts +927 -927
  137. package/src/oauth-import-routes.ts +324 -314
  138. package/src/oauth-providers.ts +152 -152
  139. package/src/oauth-session.ts +183 -183
  140. package/src/oauth-sources.ts +1104 -1104
  141. package/src/oauth.ts +620 -620
  142. package/src/provider.ts +128 -128
  143. package/src/proxy.ts +11 -99
  144. package/src/redact.ts +72 -72
  145. package/src/session.ts +218 -218
  146. package/src/store.ts +217 -217
  147. package/src/web-origin.ts +296 -60
  148. package/src/web-routes.ts +38 -75
@@ -1,153 +1,147 @@
1
- /**
2
- * Harness route aliases over a native-id PiAiAdapter.
3
- * @module dsh-coding-subscription-oauth/alias-adapter
4
- */
5
-
6
- import type {
7
- GenerateOptions,
8
- LlmModelInfo,
9
- LlmProviderInfo,
10
- LlmResolvedModelInfo,
11
- ResolvedRetryPolicy,
12
- StreamChunk,
13
- } from "@deepseek-ai/dsh-llm";
14
- import { LlmAdapter, LlmError } from "@deepseek-ai/dsh-llm";
15
- import { remapXaiCapacityFailure } from "./grok-errors.ts";
16
- import { remapAuthFailureIfContextOverflow } from "./kimi-errors.ts";
17
-
18
- export interface AliasLlmRoutePolicy {
19
- /** User-facing provider name shown above models in the model selector. */
20
- displayName?: string;
21
- /** Return false to hide every model for this route from discovery. */
22
- isAuthenticated?: () => Promise<boolean>;
23
- /**
24
- * After authentication, keep only models this predicate accepts.
25
- * Used by opt-in routes (e.g. Codex Fast) so ineligible ids stay hidden
26
- * without hiding the whole authenticated catalog.
27
- */
28
- includeModel?: (modelId: string) => boolean;
29
- /**
30
- * Called once when a stream for this route finishes with an AUTH failure
31
- * (upstream rejected a locally-valid token). Implementations backdate the
32
- * stored credential's expiry so the retried step refreshes before reuse.
33
- * Awaiting it here keeps invalidation ordered before the retry executor
34
- * reruns the step; failures are swallowed so the original AUTH surfaces.
35
- */
36
- onAuthFailure?: () => Promise<void>;
37
- }
38
-
39
- function routePiAiReplayState(value: unknown, route: string): unknown {
40
- if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
41
- const state = value as Record<string, unknown>;
42
- if (state["kind"] !== "pi-ai" || state["provider"] === route) return value;
43
- return { ...state, provider: route };
44
- }
45
-
46
- function normalizeReplayForRoute(
1
+ /**
2
+ * Harness route aliases over a native-id PiAiAdapter.
3
+ * @module dsh-coding-subscription-oauth/alias-adapter
4
+ */
5
+
6
+ import type {
7
+ GenerateOptions,
8
+ LlmModelInfo,
9
+ LlmProviderInfo,
10
+ LlmResolvedModelInfo,
11
+ ResolvedRetryPolicy,
12
+ StreamChunk,
13
+ } from "@deepseek-ai/dsh-llm";
14
+ import { LlmAdapter, LlmError } from "@deepseek-ai/dsh-llm";
15
+ import { remapXaiCapacityFailure } from "./grok-errors.ts";
16
+ import { remapAuthFailureIfContextOverflow } from "./kimi-errors.ts";
17
+
18
+ export interface AliasLlmRoutePolicy {
19
+ /** User-facing provider name shown above models in the model selector. */
20
+ displayName?: string;
21
+ /** Return false to hide every model for this route from discovery. */
22
+ isAuthenticated?: () => Promise<boolean>;
23
+ /**
24
+ * After authentication, keep only models this predicate accepts.
25
+ * Used by opt-in routes (e.g. Codex Fast) so ineligible ids stay hidden
26
+ * without hiding the whole authenticated catalog.
27
+ */
28
+ includeModel?: (modelId: string) => boolean;
29
+ /**
30
+ * Called once when a stream for this route finishes with an AUTH failure
31
+ * (upstream rejected a locally-valid token). Implementations backdate the
32
+ * stored credential's expiry so the retried step refreshes before reuse.
33
+ * Awaiting it here keeps invalidation ordered before the retry executor
34
+ * reruns the step; failures are swallowed so the original AUTH surfaces.
35
+ */
36
+ onAuthFailure?: () => Promise<void>;
37
+ }
38
+
39
+ export function normalizeReplayForRoute(
47
40
  message: GenerateOptions["messages"][number],
48
41
  route: string,
49
- ): GenerateOptions["messages"][number] {
50
- if (message.role !== "assistant" || message.source.kind !== "model") return message;
51
- if (message.source.provider !== route) {
52
- if (message.source.replayState === undefined) return message;
53
- const { replayState: _foreignReplay, ...source } = message.source;
54
- return { ...message, source };
55
- }
56
- const replayState = routePiAiReplayState(message.source.replayState, route);
57
- if (replayState === message.source.replayState) return message;
58
- return { ...message, source: { ...message.source, replayState } };
59
- }
60
-
61
- /**
62
- * Keeps pi-ai model.provider identities native while exposing collision-free
63
- * Harness route names. Every public operation translates exactly once.
64
- */
65
- export class AliasLlmAdapter extends LlmAdapter {
42
+ nativeReplayProvider: string,
43
+ ): GenerateOptions["messages"][number] {
44
+ if (message.role !== "assistant" || message.source.kind !== "model") return message;
45
+ if (message.source.provider !== route) {
46
+ if (message.source.replayState === undefined) return message;
47
+ const { replayState: _foreignReplay, ...source } = message.source;
48
+ return { ...message, source };
49
+ }
50
+ // The rc.2 envelope stays entirely opaque. PiAiAdapter only keys replay
51
+ // validation from source.provider, so restore the native provider identity
52
+ // without inspecting or changing replayState.
53
+ return { ...message, source: { ...message.source, provider: nativeReplayProvider } };
54
+ }
55
+
56
+ /**
57
+ * Keeps pi-ai model.provider identities native while exposing collision-free
58
+ * Harness route names. Every public operation translates exactly once.
59
+ */
60
+ export class AliasLlmAdapter extends LlmAdapter {
66
61
  constructor(
67
62
  private readonly inner: LlmAdapter,
68
63
  private readonly aliases: ReadonlyMap<string, string>,
69
64
  private readonly policies: ReadonlyMap<string, AliasLlmRoutePolicy> = new Map(),
70
- ) {
71
- super();
72
- }
73
-
74
- private nativeProvider(route: string): string {
75
- const provider = this.aliases.get(route);
76
- if (provider === undefined) throw new LlmError(`OAuth adapter does not own provider "${route}"`, "NO_ADAPTER");
77
- return provider;
78
- }
79
-
80
- providerInfo(provider: string): LlmProviderInfo {
81
- const native = this.nativeProvider(provider);
82
- const info = this.inner.providerInfo(native);
83
- const displayName = this.policies.get(provider)?.displayName;
84
- return { ...info, id: provider, ...(displayName === undefined ? {} : { name: displayName }) };
85
- }
86
-
87
- providerRetryPolicy(provider: string): ResolvedRetryPolicy | undefined {
88
- return this.inner.providerRetryPolicy(this.nativeProvider(provider));
89
- }
90
-
91
- async listModels(provider: string): Promise<readonly LlmModelInfo[]> {
92
- const native = this.nativeProvider(provider);
93
- const isAuthenticated = this.policies.get(provider)?.isAuthenticated;
94
- if (isAuthenticated !== undefined) {
95
- try {
96
- if (!(await isAuthenticated())) return [];
97
- } catch {
98
- // A corrupt/unreadable credential must hide models instead of breaking
99
- // the entire model picker or presenting a route that cannot be used.
100
- return [];
101
- }
102
- }
103
- const listed = (await this.inner.listModels(native)).map((model) => ({ ...model, provider }));
104
- const includeModel = this.policies.get(provider)?.includeModel;
105
- return includeModel === undefined ? listed : listed.filter((model) => includeModel(model.id));
106
- }
107
-
108
- async resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo> {
109
- const native = this.nativeProvider(provider);
110
- return { ...(await this.inner.resolveModel(native, model, signal)), provider };
111
- }
112
-
113
- async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
114
- const route = options.provider;
115
- const native = this.nativeProvider(route);
116
- const messages = options.messages.map((message) => normalizeReplayForRoute(message, route));
117
- let authFailureNotified = false;
118
- for await (const raw of this.inner.stream({ ...options, provider: native, messages })) {
119
- const chunk =
120
- raw.type === "finish" && raw.reason.kind === "error"
121
- ? {
122
- ...raw,
123
- reason: {
124
- ...raw.reason,
125
- failure: remapXaiCapacityFailure(remapAuthFailureIfContextOverflow(raw.reason.failure)),
126
- },
127
- }
128
- : raw;
129
- if (
130
- !authFailureNotified &&
131
- chunk.type === "finish" &&
132
- chunk.reason.kind === "error" &&
133
- chunk.reason.failure.code === "AUTH"
134
- ) {
135
- authFailureNotified = true;
136
- const onAuthFailure = this.policies.get(route)?.onAuthFailure;
137
- if (onAuthFailure !== undefined) {
138
- try {
139
- await onAuthFailure();
140
- } catch {
141
- // Invalidation is best-effort: the original AUTH failure must
142
- // surface unchanged even when the credential store is unreadable.
143
- }
144
- }
145
- }
146
- if (chunk.type === "finish" && chunk.replayState !== undefined) {
147
- yield { ...chunk, replayState: routePiAiReplayState(chunk.replayState, route) };
148
- } else {
149
- yield chunk;
150
- }
151
- }
152
- }
153
- }
65
+ private readonly replayProviders: ReadonlyMap<string, string> = aliases,
66
+ ) {
67
+ super();
68
+ }
69
+
70
+ private nativeProvider(route: string): string {
71
+ const provider = this.aliases.get(route);
72
+ if (provider === undefined) throw new LlmError(`OAuth adapter does not own provider "${route}"`, "NO_ADAPTER");
73
+ return provider;
74
+ }
75
+
76
+ providerInfo(provider: string): LlmProviderInfo {
77
+ const native = this.nativeProvider(provider);
78
+ const info = this.inner.providerInfo(native);
79
+ const displayName = this.policies.get(provider)?.displayName;
80
+ return { ...info, id: provider, ...(displayName === undefined ? {} : { name: displayName }) };
81
+ }
82
+
83
+ providerRetryPolicy(provider: string): ResolvedRetryPolicy | undefined {
84
+ return this.inner.providerRetryPolicy(this.nativeProvider(provider));
85
+ }
86
+
87
+ async listModels(provider: string): Promise<readonly LlmModelInfo[]> {
88
+ const native = this.nativeProvider(provider);
89
+ const isAuthenticated = this.policies.get(provider)?.isAuthenticated;
90
+ if (isAuthenticated !== undefined) {
91
+ try {
92
+ if (!(await isAuthenticated())) return [];
93
+ } catch {
94
+ // A corrupt/unreadable credential must hide models instead of breaking
95
+ // the entire model picker or presenting a route that cannot be used.
96
+ return [];
97
+ }
98
+ }
99
+ const listed = (await this.inner.listModels(native)).map((model) => ({ ...model, provider }));
100
+ const includeModel = this.policies.get(provider)?.includeModel;
101
+ return includeModel === undefined ? listed : listed.filter((model) => includeModel(model.id));
102
+ }
103
+
104
+ async resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo> {
105
+ const native = this.nativeProvider(provider);
106
+ return { ...(await this.inner.resolveModel(native, model, signal)), provider };
107
+ }
108
+
109
+ async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
110
+ const route = options.provider;
111
+ const native = this.nativeProvider(route);
112
+ const messages = options.messages.map((message) =>
113
+ normalizeReplayForRoute(message, route, this.replayProviders.get(route) ?? native),
114
+ );
115
+ let authFailureNotified = false;
116
+ for await (const raw of this.inner.stream({ ...options, provider: native, messages })) {
117
+ const chunk =
118
+ raw.type === "finish" && raw.reason.kind === "error"
119
+ ? {
120
+ ...raw,
121
+ reason: {
122
+ ...raw.reason,
123
+ failure: remapXaiCapacityFailure(remapAuthFailureIfContextOverflow(raw.reason.failure)),
124
+ },
125
+ }
126
+ : raw;
127
+ if (
128
+ !authFailureNotified &&
129
+ chunk.type === "finish" &&
130
+ chunk.reason.kind === "error" &&
131
+ chunk.reason.failure.code === "AUTH"
132
+ ) {
133
+ authFailureNotified = true;
134
+ const onAuthFailure = this.policies.get(route)?.onAuthFailure;
135
+ if (onAuthFailure !== undefined) {
136
+ try {
137
+ await onAuthFailure();
138
+ } catch {
139
+ // Invalidation is best-effort: the original AUTH failure must
140
+ // surface unchanged even when the credential store is unreadable.
141
+ }
142
+ }
143
+ }
144
+ yield chunk;
145
+ }
146
+ }
147
+ }