@code-yeongyu/senpi-ai 2026.8.12 → 2026.8.13
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.md +26 -8
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/azure-openai-responses.js +5 -1
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/bedrock-converse-stream.lazy.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js +2 -2
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-shared.d.ts +15 -1
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js +103 -4
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js +2 -2
- package/dist/api/google-vertex.js.map +1 -1
- package/dist/api/lazy.d.ts +5 -1
- package/dist/api/lazy.d.ts.map +1 -1
- package/dist/api/lazy.js +19 -7
- package/dist/api/lazy.js.map +1 -1
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-completions.d.ts +3 -1
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +47 -7
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +22 -9
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.js +5 -1
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/pi-messages.d.ts.map +1 -1
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/api/simple-options.d.ts +2 -0
- package/dist/api/simple-options.d.ts.map +1 -1
- package/dist/api/simple-options.js +8 -2
- package/dist/api/simple-options.js.map +1 -1
- package/dist/api/transform-messages.js.map +1 -1
- package/dist/api/warm-prompt-cache.js.map +1 -1
- package/dist/auth/credential-store.d.ts +6 -6
- package/dist/auth/credential-store.d.ts.map +1 -1
- package/dist/auth/credential-store.js +22 -11
- package/dist/auth/credential-store.js.map +1 -1
- package/dist/auth/helpers.d.ts +1 -0
- package/dist/auth/helpers.d.ts.map +1 -1
- package/dist/auth/helpers.js +7 -2
- package/dist/auth/helpers.js.map +1 -1
- package/dist/auth/oauth/anthropic.d.ts.map +1 -1
- package/dist/auth/oauth/anthropic.js +14 -8
- package/dist/auth/oauth/anthropic.js.map +1 -1
- package/dist/auth/oauth/device-code.d.ts +1 -1
- package/dist/auth/oauth/device-code.d.ts.map +1 -1
- package/dist/auth/oauth/device-code.js +4 -4
- package/dist/auth/oauth/device-code.js.map +1 -1
- package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
- package/dist/auth/oauth/github-copilot.js +43 -30
- package/dist/auth/oauth/github-copilot.js.map +1 -1
- package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
- package/dist/auth/oauth/kimi-coding.js +17 -5
- package/dist/auth/oauth/kimi-coding.js.map +1 -1
- package/dist/auth/oauth/load.d.ts.map +1 -1
- package/dist/auth/oauth/load.js.map +1 -1
- package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
- package/dist/auth/oauth/openai-codex.js +12 -5
- package/dist/auth/oauth/openai-codex.js.map +1 -1
- package/dist/auth/oauth/openrouter.d.ts.map +1 -1
- package/dist/auth/oauth/openrouter.js +10 -10
- package/dist/auth/oauth/openrouter.js.map +1 -1
- package/dist/auth/oauth/radius.d.ts.map +1 -1
- package/dist/auth/oauth/radius.js +8 -7
- package/dist/auth/oauth/radius.js.map +1 -1
- package/dist/auth/oauth/xai.d.ts.map +1 -1
- package/dist/auth/oauth/xai.js +3 -2
- package/dist/auth/oauth/xai.js.map +1 -1
- package/dist/auth/resolve.d.ts +1 -0
- package/dist/auth/resolve.d.ts.map +1 -1
- package/dist/auth/resolve.js +24 -13
- package/dist/auth/resolve.js.map +1 -1
- package/dist/auth/types.d.ts +21 -8
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/compat.js.map +1 -1
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js +3 -0
- package/dist/env-api-keys.js.map +1 -1
- package/dist/image-models.generated.d.ts +69 -54
- package/dist/image-models.generated.d.ts.map +1 -1
- package/dist/image-models.generated.js +15 -0
- package/dist/image-models.generated.js.map +1 -1
- package/dist/images-models.d.ts.map +1 -1
- package/dist/images-models.js +1 -0
- package/dist/images-models.js.map +1 -1
- package/dist/model.d.ts +2 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js.map +1 -1
- package/dist/models-store.d.ts +9 -12
- package/dist/models-store.d.ts.map +1 -1
- package/dist/models-store.js +6 -3
- package/dist/models-store.js.map +1 -1
- package/dist/models.d.ts +40 -18
- package/dist/models.d.ts.map +1 -1
- package/dist/models.generated.d.ts +6 -0
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +6 -0
- package/dist/models.generated.js.map +1 -1
- package/dist/models.js +247 -91
- package/dist/models.js.map +1 -1
- package/dist/node/provider-scope.d.ts.map +1 -1
- package/dist/providers/all.d.ts.map +1 -1
- package/dist/providers/all.js +6 -0
- package/dist/providers/all.js.map +1 -1
- package/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.js +15 -7
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +15 -6
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/baseten.d.ts +3 -0
- package/dist/providers/baseten.d.ts.map +1 -0
- package/dist/providers/baseten.js +15 -0
- package/dist/providers/baseten.js.map +1 -0
- package/dist/providers/baseten.models.d.ts +4 -0
- package/dist/providers/baseten.models.d.ts.map +1 -0
- package/dist/providers/baseten.models.js +6 -0
- package/dist/providers/baseten.models.js.map +1 -0
- package/dist/providers/cloudflare-auth.d.ts.map +1 -1
- package/dist/providers/cloudflare-auth.js +15 -10
- package/dist/providers/cloudflare-auth.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/baseten.json +1 -0
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/opengateway.json +1 -0
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan-individual.json +1 -0
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/xai.json +1 -1
- package/dist/providers/faux.d.ts +18 -13
- package/dist/providers/faux.d.ts.map +1 -1
- package/dist/providers/faux.js +95 -5
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/github-copilot.js +1 -1
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/google-vertex.d.ts.map +1 -1
- package/dist/providers/google-vertex.js +15 -7
- package/dist/providers/google-vertex.js.map +1 -1
- package/dist/providers/kimi-coding.d.ts.map +1 -1
- package/dist/providers/kimi-coding.js +1 -0
- package/dist/providers/kimi-coding.js.map +1 -1
- package/dist/providers/ollama.d.ts.map +1 -1
- package/dist/providers/ollama.js +1 -2
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai-codex.d.ts.map +1 -1
- package/dist/providers/openai-codex.js +5 -1
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/opengateway.d.ts +3 -0
- package/dist/providers/opengateway.d.ts.map +1 -0
- package/dist/providers/opengateway.js +15 -0
- package/dist/providers/opengateway.js.map +1 -0
- package/dist/providers/opengateway.models.d.ts +4 -0
- package/dist/providers/opengateway.models.d.ts.map +1 -0
- package/dist/providers/opengateway.models.js +6 -0
- package/dist/providers/opengateway.models.js.map +1 -0
- package/dist/providers/qwen-token-plan-individual.d.ts +3 -0
- package/dist/providers/qwen-token-plan-individual.d.ts.map +1 -0
- package/dist/providers/qwen-token-plan-individual.js +15 -0
- package/dist/providers/qwen-token-plan-individual.js.map +1 -0
- package/dist/providers/qwen-token-plan-individual.models.d.ts +4 -0
- package/dist/providers/qwen-token-plan-individual.models.d.ts.map +1 -0
- package/dist/providers/qwen-token-plan-individual.models.js +6 -0
- package/dist/providers/qwen-token-plan-individual.models.js.map +1 -0
- package/dist/providers/radius.d.ts.map +1 -1
- package/dist/providers/radius.js +36 -26
- package/dist/providers/radius.js.map +1 -1
- package/dist/providers/xai.d.ts.map +1 -1
- package/dist/providers/xai.js +1 -0
- package/dist/providers/xai.js.map +1 -1
- package/dist/tool-call-middleware/context-transformer.js.map +1 -1
- package/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.d.ts.map +1 -1
- package/dist/tool-call-middleware/protocols/kimi-xtml/parse.js.map +1 -1
- package/dist/tool-call-middleware/recovery-content-lifecycle.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-event-stream.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-native-projection.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-native-projection.js.map +1 -1
- package/dist/tool-call-middleware/recovery-stream-terminal.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-stream-wrapper.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-stream-wrapper.js +5 -0
- package/dist/tool-call-middleware/recovery-stream-wrapper.js.map +1 -1
- package/dist/tool-call-middleware/recovery-text-projection.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-text-projection.js.map +1 -1
- package/dist/tool-call-middleware/stream-thinking-projection.d.ts.map +1 -1
- package/dist/tool-call-middleware/stream-wrapper-shared.d.ts.map +1 -1
- package/dist/tool-call-middleware/stream-wrapper-shared.js.map +1 -1
- package/dist/tool-call-middleware/stream-wrapper.js.map +1 -1
- package/dist/types.d.ts +94 -87
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/abort.d.ts +8 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +49 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/deferred-tools.js.map +1 -1
- package/dist/utils/event-stream.d.ts.map +1 -1
- package/dist/utils/overflow.d.ts +14 -1
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js +18 -1
- package/dist/utils/overflow.js.map +1 -1
- package/dist/utils/prompt-cache-ttl.d.ts +3 -1
- package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
- package/dist/utils/prompt-cache-ttl.js +2 -0
- package/dist/utils/prompt-cache-ttl.js.map +1 -1
- package/dist/utils/provider-retry.js.map +1 -1
- package/dist/utils/retry.d.ts +25 -0
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js +64 -0
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/tool-schema-compat.d.ts.map +1 -1
- package/dist/utils/tool-schema-compat.js +1 -0
- package/dist/utils/tool-schema-compat.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +6 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-copilot.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"github-copilot.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AA0YvF,eAAO,MAAM,kBAAkB,EAAE,SAchC,CAAC"}
|
|
@@ -60,29 +60,35 @@ function getGitHubCopilotBaseUrl(token, enterpriseDomain) {
|
|
|
60
60
|
function asRecord(value) {
|
|
61
61
|
return value && typeof value === "object" ? value : undefined;
|
|
62
62
|
}
|
|
63
|
-
function
|
|
64
|
-
const policy = asRecord(item.policy);
|
|
65
|
-
const capabilities = asRecord(item.capabilities);
|
|
66
|
-
const supports = asRecord(capabilities?.supports);
|
|
67
|
-
return item.model_picker_enabled === true && policy?.state !== "disabled" && supports?.tool_calls !== false;
|
|
68
|
-
}
|
|
69
|
-
function parseAvailableCopilotModelIds(raw) {
|
|
63
|
+
function parseAvailableCopilotModelIds(raw, allowPolicyFallback) {
|
|
70
64
|
const data = asRecord(raw)?.data;
|
|
71
65
|
if (!Array.isArray(data)) {
|
|
72
66
|
throw new Error("Invalid Copilot models response");
|
|
73
67
|
}
|
|
74
|
-
const
|
|
68
|
+
const pickerIds = [];
|
|
69
|
+
const policyEnabledIds = [];
|
|
75
70
|
for (const rawItem of data) {
|
|
76
71
|
const item = asRecord(rawItem);
|
|
77
72
|
const id = item?.id;
|
|
78
|
-
if (typeof id
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
if (!item || typeof id !== "string")
|
|
74
|
+
continue;
|
|
75
|
+
const capabilities = asRecord(item.capabilities);
|
|
76
|
+
const supports = asRecord(capabilities?.supports);
|
|
77
|
+
if (supports?.tool_calls === false)
|
|
78
|
+
continue;
|
|
79
|
+
const policy = asRecord(item.policy);
|
|
80
|
+
if (item.model_picker_enabled === true && policy?.state !== "disabled")
|
|
81
|
+
pickerIds.push(id);
|
|
82
|
+
if (policy?.state === "enabled")
|
|
83
|
+
policyEnabledIds.push(id);
|
|
81
84
|
}
|
|
82
|
-
return
|
|
85
|
+
return pickerIds.length > 0 || !allowPolicyFallback ? pickerIds : policyEnabledIds;
|
|
83
86
|
}
|
|
84
|
-
async function fetchAvailableGitHubCopilotModelIds(copilotToken, enterpriseDomain) {
|
|
87
|
+
async function fetchAvailableGitHubCopilotModelIds(copilotToken, enterpriseDomain, signal) {
|
|
85
88
|
const baseUrl = getGitHubCopilotBaseUrl(copilotToken, enterpriseDomain);
|
|
89
|
+
// Some Individual accounts return false for every picker flag despite explicit enabled policies.
|
|
90
|
+
// Limit the fallback to that endpoint so other account types keep strict picker semantics.
|
|
91
|
+
const allowPolicyFallback = baseUrl === "https://api.individual.githubcopilot.com";
|
|
86
92
|
const raw = await fetchJson(`${baseUrl}/models`, {
|
|
87
93
|
headers: {
|
|
88
94
|
Accept: "application/json",
|
|
@@ -90,9 +96,9 @@ async function fetchAvailableGitHubCopilotModelIds(copilotToken, enterpriseDomai
|
|
|
90
96
|
...COPILOT_HEADERS,
|
|
91
97
|
"X-GitHub-Api-Version": COPILOT_API_VERSION,
|
|
92
98
|
},
|
|
93
|
-
signal: AbortSignal.timeout(5000),
|
|
99
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(5000)]),
|
|
94
100
|
});
|
|
95
|
-
return parseAvailableCopilotModelIds(raw);
|
|
101
|
+
return parseAvailableCopilotModelIds(raw, allowPolicyFallback);
|
|
96
102
|
}
|
|
97
103
|
async function fetchJson(url, init) {
|
|
98
104
|
const response = await fetch(url, init);
|
|
@@ -102,7 +108,7 @@ async function fetchJson(url, init) {
|
|
|
102
108
|
}
|
|
103
109
|
return response.json();
|
|
104
110
|
}
|
|
105
|
-
async function startDeviceFlow(domain) {
|
|
111
|
+
async function startDeviceFlow(domain, signal) {
|
|
106
112
|
const urls = getUrls(domain);
|
|
107
113
|
const data = await fetchJson(urls.deviceCodeUrl, {
|
|
108
114
|
method: "POST",
|
|
@@ -115,6 +121,7 @@ async function startDeviceFlow(domain) {
|
|
|
115
121
|
client_id: CLIENT_ID,
|
|
116
122
|
scope: "read:user",
|
|
117
123
|
}),
|
|
124
|
+
signal,
|
|
118
125
|
});
|
|
119
126
|
if (!data || typeof data !== "object") {
|
|
120
127
|
throw new Error("Invalid device code response");
|
|
@@ -171,6 +178,7 @@ async function pollForGitHubAccessToken(domain, device, signal) {
|
|
|
171
178
|
device_code: device.device_code,
|
|
172
179
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
173
180
|
}),
|
|
181
|
+
signal,
|
|
174
182
|
});
|
|
175
183
|
if (raw && typeof raw === "object" && typeof raw.access_token === "string") {
|
|
176
184
|
return { status: "complete", value: raw.access_token };
|
|
@@ -190,7 +198,7 @@ async function pollForGitHubAccessToken(domain, device, signal) {
|
|
|
190
198
|
},
|
|
191
199
|
});
|
|
192
200
|
}
|
|
193
|
-
async function refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain) {
|
|
201
|
+
async function refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain, signal) {
|
|
194
202
|
const domain = enterpriseDomain || "github.com";
|
|
195
203
|
const urls = getUrls(domain);
|
|
196
204
|
const raw = await fetchJson(urls.copilotTokenUrl, {
|
|
@@ -199,6 +207,7 @@ async function refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain) {
|
|
|
199
207
|
Authorization: `Bearer ${refreshToken}`,
|
|
200
208
|
...COPILOT_HEADERS,
|
|
201
209
|
},
|
|
210
|
+
signal,
|
|
202
211
|
});
|
|
203
212
|
if (!raw || typeof raw !== "object") {
|
|
204
213
|
throw new Error("Invalid Copilot token response");
|
|
@@ -219,18 +228,18 @@ async function refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain) {
|
|
|
219
228
|
/**
|
|
220
229
|
* Refresh GitHub Copilot token
|
|
221
230
|
*/
|
|
222
|
-
async function refreshGitHubCopilotToken(refreshToken, enterpriseDomain) {
|
|
223
|
-
const credentials = await refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain);
|
|
231
|
+
async function refreshGitHubCopilotToken(refreshToken, enterpriseDomain, signal) {
|
|
232
|
+
const credentials = await refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain, signal);
|
|
224
233
|
return {
|
|
225
234
|
...credentials,
|
|
226
|
-
availableModelIds: await fetchAvailableGitHubCopilotModelIds(credentials.access, enterpriseDomain),
|
|
235
|
+
availableModelIds: await fetchAvailableGitHubCopilotModelIds(credentials.access, enterpriseDomain, signal),
|
|
227
236
|
};
|
|
228
237
|
}
|
|
229
238
|
/**
|
|
230
239
|
* Enable a model for the user's GitHub Copilot account.
|
|
231
240
|
* This is required for some models (like Claude, Grok) before they can be used.
|
|
232
241
|
*/
|
|
233
|
-
async function enableGitHubCopilotModel(token, modelId, enterpriseDomain) {
|
|
242
|
+
async function enableGitHubCopilotModel(token, modelId, enterpriseDomain, signal) {
|
|
234
243
|
const baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);
|
|
235
244
|
const url = `${baseUrl}/models/${modelId}/policy`;
|
|
236
245
|
try {
|
|
@@ -244,10 +253,13 @@ async function enableGitHubCopilotModel(token, modelId, enterpriseDomain) {
|
|
|
244
253
|
"x-interaction-type": "chat-policy",
|
|
245
254
|
},
|
|
246
255
|
body: JSON.stringify({ state: "enabled" }),
|
|
256
|
+
signal,
|
|
247
257
|
});
|
|
248
258
|
return response.ok;
|
|
249
259
|
}
|
|
250
|
-
catch {
|
|
260
|
+
catch (error) {
|
|
261
|
+
if (signal.aborted)
|
|
262
|
+
throw error;
|
|
251
263
|
return false;
|
|
252
264
|
}
|
|
253
265
|
}
|
|
@@ -255,10 +267,10 @@ async function enableGitHubCopilotModel(token, modelId, enterpriseDomain) {
|
|
|
255
267
|
* Enable all known GitHub Copilot models that may require policy acceptance.
|
|
256
268
|
* Called after successful login to ensure all models are available.
|
|
257
269
|
*/
|
|
258
|
-
async function enableAllGitHubCopilotModels(token, enterpriseDomain) {
|
|
270
|
+
async function enableAllGitHubCopilotModels(token, enterpriseDomain, signal) {
|
|
259
271
|
const models = Object.values(GITHUB_COPILOT_MODELS);
|
|
260
272
|
await Promise.all(models.map(async (model) => {
|
|
261
|
-
await enableGitHubCopilotModel(token, model.id, enterpriseDomain);
|
|
273
|
+
await enableGitHubCopilotModel(token, model.id, enterpriseDomain, signal);
|
|
262
274
|
}));
|
|
263
275
|
}
|
|
264
276
|
async function loginGitHubCopilot(interaction) {
|
|
@@ -267,14 +279,14 @@ async function loginGitHubCopilot(interaction) {
|
|
|
267
279
|
message: "GitHub Enterprise URL/domain (blank for github.com)",
|
|
268
280
|
placeholder: "company.ghe.com",
|
|
269
281
|
});
|
|
270
|
-
if (interaction.signal
|
|
282
|
+
if (interaction.signal.aborted)
|
|
271
283
|
throw new Error("Login cancelled");
|
|
272
284
|
const trimmed = input.trim();
|
|
273
285
|
const enterpriseDomain = normalizeDomain(input);
|
|
274
286
|
if (trimmed && !enterpriseDomain)
|
|
275
287
|
throw new Error("Invalid GitHub Enterprise URL/domain");
|
|
276
288
|
const domain = enterpriseDomain || "github.com";
|
|
277
|
-
const device = await startDeviceFlow(domain);
|
|
289
|
+
const device = await startDeviceFlow(domain, interaction.signal);
|
|
278
290
|
interaction.notify({
|
|
279
291
|
type: "device_code",
|
|
280
292
|
userCode: device.user_code,
|
|
@@ -283,12 +295,12 @@ async function loginGitHubCopilot(interaction) {
|
|
|
283
295
|
expiresInSeconds: device.expires_in,
|
|
284
296
|
});
|
|
285
297
|
const githubAccessToken = await pollForGitHubAccessToken(domain, device, interaction.signal);
|
|
286
|
-
const credentials = await refreshGitHubCopilotAccessToken(githubAccessToken, enterpriseDomain ?? undefined);
|
|
298
|
+
const credentials = await refreshGitHubCopilotAccessToken(githubAccessToken, enterpriseDomain ?? undefined, interaction.signal);
|
|
287
299
|
interaction.notify({ type: "progress", message: "Enabling models..." });
|
|
288
|
-
await enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? undefined);
|
|
300
|
+
await enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? undefined, interaction.signal);
|
|
289
301
|
return {
|
|
290
302
|
...credentials,
|
|
291
|
-
availableModelIds: await fetchAvailableGitHubCopilotModelIds(credentials.access, enterpriseDomain ?? undefined),
|
|
303
|
+
availableModelIds: await fetchAvailableGitHubCopilotModelIds(credentials.access, enterpriseDomain ?? undefined, interaction.signal),
|
|
292
304
|
};
|
|
293
305
|
}
|
|
294
306
|
function copilotEnterpriseDomain(credential) {
|
|
@@ -299,8 +311,9 @@ function copilotEnterpriseDomain(credential) {
|
|
|
299
311
|
}
|
|
300
312
|
export const githubCopilotOAuth = {
|
|
301
313
|
name: "GitHub Copilot",
|
|
314
|
+
isSubscription: true,
|
|
302
315
|
login: loginGitHubCopilot,
|
|
303
|
-
refresh: (credential) => refreshGitHubCopilotToken(credential.refresh, copilotEnterpriseDomain(credential)),
|
|
316
|
+
refresh: (credential, signal) => refreshGitHubCopilotToken(credential.refresh, copilotEnterpriseDomain(credential), signal),
|
|
304
317
|
/** Derive the credential-specific proxy endpoint for each request. */
|
|
305
318
|
async toAuth(credential) {
|
|
306
319
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-copilot.js","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot OAuth flow\n */\n\nimport { GITHUB_COPILOT_MODELS } from \"../../providers/github-copilot.models.ts\";\nimport type { AuthInteraction, OAuthAuth, OAuthCredential } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"SXYxLmI1MDdhMDhjODdlY2ZlOTg=\");\n\nconst COPILOT_HEADERS = {\n\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\"Editor-Version\": \"vscode/1.107.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.35.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n} as const;\nconst COPILOT_API_VERSION = \"2026-06-01\";\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval?: number;\n\texpires_in: number;\n};\n\ntype DeviceTokenSuccessResponse = {\n\taccess_token: string;\n\ttoken_type?: string;\n\tscope?: string;\n};\n\ntype DeviceTokenErrorResponse = {\n\terror: string;\n\terror_description?: string;\n\tinterval?: number;\n};\n\nfunction normalizeDomain(input: string): string | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\ttry {\n\t\tconst url = trimmed.includes(\"://\") ? new URL(trimmed) : new URL(`https://${trimmed}`);\n\t\treturn url.hostname;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction getUrls(domain: string): {\n\tdeviceCodeUrl: string;\n\taccessTokenUrl: string;\n\tcopilotTokenUrl: string;\n} {\n\treturn {\n\t\tdeviceCodeUrl: `https://${domain}/login/device/code`,\n\t\taccessTokenUrl: `https://${domain}/login/oauth/access_token`,\n\t\tcopilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`,\n\t};\n}\n\n/**\n * Parse the proxy-ep from a Copilot token and convert to API base URL.\n * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...\n * Returns API URL like https://api.individual.githubcopilot.com\n */\nfunction getBaseUrlFromToken(token: string): string | null {\n\tconst match = token.match(/proxy-ep=([^;]+)/);\n\tif (!match) return null;\n\tconst proxyHost = match[1];\n\t// Convert proxy.xxx to api.xxx\n\tconst apiHost = proxyHost.replace(/^proxy\\./, \"api.\");\n\treturn `https://${apiHost}`;\n}\n\nfunction getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {\n\t// If we have a token, extract the base URL from proxy-ep\n\tif (token) {\n\t\tconst urlFromToken = getBaseUrlFromToken(token);\n\t\tif (urlFromToken) return urlFromToken;\n\t}\n\t// Fallback for enterprise or if token parsing fails\n\tif (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;\n\treturn \"https://api.individual.githubcopilot.com\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn value && typeof value === \"object\" ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction isSelectableCopilotModel(item: Record<string, unknown>): boolean {\n\tconst policy = asRecord(item.policy);\n\tconst capabilities = asRecord(item.capabilities);\n\tconst supports = asRecord(capabilities?.supports);\n\treturn item.model_picker_enabled === true && policy?.state !== \"disabled\" && supports?.tool_calls !== false;\n}\n\nfunction parseAvailableCopilotModelIds(raw: unknown): string[] {\n\tconst data = asRecord(raw)?.data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid Copilot models response\");\n\t}\n\n\tconst ids: string[] = [];\n\tfor (const rawItem of data) {\n\t\tconst item = asRecord(rawItem);\n\t\tconst id = item?.id;\n\t\tif (typeof id === \"string\" && item && isSelectableCopilotModel(item)) {\n\t\t\tids.push(id);\n\t\t}\n\t}\n\treturn ids;\n}\n\nasync function fetchAvailableGitHubCopilotModelIds(copilotToken: string, enterpriseDomain?: string): Promise<string[]> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(copilotToken, enterpriseDomain);\n\tconst raw = await fetchJson(`${baseUrl}/models`, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${copilotToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t\t\"X-GitHub-Api-Version\": COPILOT_API_VERSION,\n\t\t},\n\t\tsignal: AbortSignal.timeout(5000),\n\t});\n\treturn parseAvailableCopilotModelIds(raw);\n}\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\nasync function startDeviceFlow(domain: string): Promise<DeviceCodeResponse> {\n\tconst urls = getUrls(domain);\n\tconst data = await fetchJson(urls.deviceCodeUrl, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tscope: \"read:user\",\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst deviceCode = (data as Record<string, unknown>).device_code;\n\tconst userCode = (data as Record<string, unknown>).user_code;\n\tconst verificationUri = (data as Record<string, unknown>).verification_uri;\n\tconst interval = (data as Record<string, unknown>).interval;\n\tconst expiresIn = (data as Record<string, unknown>).expires_in;\n\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\t(interval !== undefined && typeof interval !== \"number\") ||\n\t\ttypeof expiresIn !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\t// The verification URI is opened in the user's browser and to prevent `open` from\n\t// opening an executable or similar, we force it to be a URL.\n\tlet parsedUri: URL;\n\ttry {\n\t\tparsedUri = new URL(verificationUri);\n\t} catch {\n\t\tthrow new Error(\"Untrusted verification_uri in device code response\");\n\t}\n\tif (parsedUri.protocol !== \"https:\" && parsedUri.protocol !== \"http:\") {\n\t\tthrow new Error(\"Untrusted verification_uri in device code response\");\n\t}\n\n\treturn {\n\t\tdevice_code: deviceCode,\n\t\tuser_code: userCode,\n\t\tverification_uri: parsedUri.href,\n\t\tinterval,\n\t\texpires_in: expiresIn,\n\t};\n}\n\nasync function pollForGitHubAccessToken(\n\tdomain: string,\n\tdevice: DeviceCodeResponse,\n\tsignal?: AbortSignal,\n): Promise<string> {\n\tconst urls = getUrls(domain);\n\treturn pollOAuthDeviceCodeFlow<string>({\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst raw = await fetchJson(urls.accessTokenUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.device_code,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenSuccessResponse).access_token === \"string\") {\n\t\t\t\treturn { status: \"complete\", value: (raw as DeviceTokenSuccessResponse).access_token };\n\t\t\t}\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenErrorResponse).error === \"string\") {\n\t\t\t\tconst { error, error_description: description, interval } = raw as DeviceTokenErrorResponse;\n\t\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\t}\n\n\t\t\t\tif (error === \"slow_down\") {\n\t\t\t\t\treturn { status: \"slow_down\", intervalSeconds: typeof interval === \"number\" ? interval : undefined };\n\t\t\t\t}\n\n\t\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\t\treturn { status: \"failed\", message: `Device flow failed: ${error}${descriptionSuffix}` };\n\t\t\t}\n\n\t\t\treturn { status: \"failed\", message: \"Invalid device token response\" };\n\t\t},\n\t});\n}\n\nasync function refreshGitHubCopilotAccessToken(\n\trefreshToken: string,\n\tenterpriseDomain?: string,\n): Promise<OAuthCredential> {\n\tconst domain = enterpriseDomain || \"github.com\";\n\tconst urls = getUrls(domain);\n\n\tconst raw = await fetchJson(urls.copilotTokenUrl, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${refreshToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid Copilot token response\");\n\t}\n\n\tconst token = (raw as Record<string, unknown>).token;\n\tconst expiresAt = (raw as Record<string, unknown>).expires_at;\n\n\tif (typeof token !== \"string\" || typeof expiresAt !== \"number\") {\n\t\tthrow new Error(\"Invalid Copilot token response fields\");\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: refreshToken,\n\t\taccess: token,\n\t\texpires: expiresAt * 1000 - 5 * 60 * 1000,\n\t\tenterpriseUrl: enterpriseDomain,\n\t};\n}\n\n/**\n * Refresh GitHub Copilot token\n */\nasync function refreshGitHubCopilotToken(refreshToken: string, enterpriseDomain?: string): Promise<OAuthCredential> {\n\tconst credentials = await refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain);\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds: await fetchAvailableGitHubCopilotModelIds(credentials.access, enterpriseDomain),\n\t};\n}\n\n/**\n * Enable a model for the user's GitHub Copilot account.\n * This is required for some models (like Claude, Grok) before they can be used.\n */\nasync function enableGitHubCopilotModel(token: string, modelId: string, enterpriseDomain?: string): Promise<boolean> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\tconst url = `${baseUrl}/models/${modelId}/policy`;\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\"openai-intent\": \"chat-policy\",\n\t\t\t\t\"x-interaction-type\": \"chat-policy\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({ state: \"enabled\" }),\n\t\t});\n\t\treturn response.ok;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Enable all known GitHub Copilot models that may require policy acceptance.\n * Called after successful login to ensure all models are available.\n */\nasync function enableAllGitHubCopilotModels(token: string, enterpriseDomain?: string): Promise<void> {\n\tconst models = Object.values(GITHUB_COPILOT_MODELS);\n\tawait Promise.all(\n\t\tmodels.map(async (model) => {\n\t\t\tawait enableGitHubCopilotModel(token, model.id, enterpriseDomain);\n\t\t}),\n\t);\n}\n\nasync function loginGitHubCopilot(interaction: AuthInteraction): Promise<OAuthCredential> {\n\tconst input = await interaction.prompt({\n\t\ttype: \"text\",\n\t\tmessage: \"GitHub Enterprise URL/domain (blank for github.com)\",\n\t\tplaceholder: \"company.ghe.com\",\n\t});\n\tif (interaction.signal?.aborted) throw new Error(\"Login cancelled\");\n\n\tconst trimmed = input.trim();\n\tconst enterpriseDomain = normalizeDomain(input);\n\tif (trimmed && !enterpriseDomain) throw new Error(\"Invalid GitHub Enterprise URL/domain\");\n\tconst domain = enterpriseDomain || \"github.com\";\n\n\tconst device = await startDeviceFlow(domain);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.user_code,\n\t\tverificationUri: device.verification_uri,\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t});\n\n\tconst githubAccessToken = await pollForGitHubAccessToken(domain, device, interaction.signal);\n\tconst credentials = await refreshGitHubCopilotAccessToken(githubAccessToken, enterpriseDomain ?? undefined);\n\tinteraction.notify({ type: \"progress\", message: \"Enabling models...\" });\n\tawait enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? undefined);\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds: await fetchAvailableGitHubCopilotModelIds(credentials.access, enterpriseDomain ?? undefined),\n\t};\n}\n\nfunction copilotEnterpriseDomain(credential: OAuthCredential): string | undefined {\n\tconst enterpriseUrl = credential.enterpriseUrl;\n\tif (typeof enterpriseUrl !== \"string\" || !enterpriseUrl) return undefined;\n\treturn normalizeDomain(enterpriseUrl) ?? undefined;\n}\n\nexport const githubCopilotOAuth: OAuthAuth = {\n\tname: \"GitHub Copilot\",\n\tlogin: loginGitHubCopilot,\n\trefresh: (credential) => refreshGitHubCopilotToken(credential.refresh, copilotEnterpriseDomain(credential)),\n\n\t/** Derive the credential-specific proxy endpoint for each request. */\n\tasync toAuth(credential) {\n\t\treturn {\n\t\t\tapiKey: credential.access,\n\t\t\tbaseUrl: getGitHubCopilotBaseUrl(credential.access, copilotEnterpriseDomain(credential)),\n\t\t};\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"github-copilot.js","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot OAuth flow\n */\n\nimport { GITHUB_COPILOT_MODELS } from \"../../providers/github-copilot.models.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"SXYxLmI1MDdhMDhjODdlY2ZlOTg=\");\n\nconst COPILOT_HEADERS = {\n\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\"Editor-Version\": \"vscode/1.107.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.35.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n} as const;\nconst COPILOT_API_VERSION = \"2026-06-01\";\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval?: number;\n\texpires_in: number;\n};\n\ntype DeviceTokenSuccessResponse = {\n\taccess_token: string;\n\ttoken_type?: string;\n\tscope?: string;\n};\n\ntype DeviceTokenErrorResponse = {\n\terror: string;\n\terror_description?: string;\n\tinterval?: number;\n};\n\nfunction normalizeDomain(input: string): string | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\ttry {\n\t\tconst url = trimmed.includes(\"://\") ? new URL(trimmed) : new URL(`https://${trimmed}`);\n\t\treturn url.hostname;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction getUrls(domain: string): {\n\tdeviceCodeUrl: string;\n\taccessTokenUrl: string;\n\tcopilotTokenUrl: string;\n} {\n\treturn {\n\t\tdeviceCodeUrl: `https://${domain}/login/device/code`,\n\t\taccessTokenUrl: `https://${domain}/login/oauth/access_token`,\n\t\tcopilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`,\n\t};\n}\n\n/**\n * Parse the proxy-ep from a Copilot token and convert to API base URL.\n * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...\n * Returns API URL like https://api.individual.githubcopilot.com\n */\nfunction getBaseUrlFromToken(token: string): string | null {\n\tconst match = token.match(/proxy-ep=([^;]+)/);\n\tif (!match) return null;\n\tconst proxyHost = match[1];\n\t// Convert proxy.xxx to api.xxx\n\tconst apiHost = proxyHost.replace(/^proxy\\./, \"api.\");\n\treturn `https://${apiHost}`;\n}\n\nfunction getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {\n\t// If we have a token, extract the base URL from proxy-ep\n\tif (token) {\n\t\tconst urlFromToken = getBaseUrlFromToken(token);\n\t\tif (urlFromToken) return urlFromToken;\n\t}\n\t// Fallback for enterprise or if token parsing fails\n\tif (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;\n\treturn \"https://api.individual.githubcopilot.com\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn value && typeof value === \"object\" ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction parseAvailableCopilotModelIds(raw: unknown, allowPolicyFallback: boolean): string[] {\n\tconst data = asRecord(raw)?.data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid Copilot models response\");\n\t}\n\n\tconst pickerIds: string[] = [];\n\tconst policyEnabledIds: string[] = [];\n\tfor (const rawItem of data) {\n\t\tconst item = asRecord(rawItem);\n\t\tconst id = item?.id;\n\t\tif (!item || typeof id !== \"string\") continue;\n\n\t\tconst capabilities = asRecord(item.capabilities);\n\t\tconst supports = asRecord(capabilities?.supports);\n\t\tif (supports?.tool_calls === false) continue;\n\t\tconst policy = asRecord(item.policy);\n\t\tif (item.model_picker_enabled === true && policy?.state !== \"disabled\") pickerIds.push(id);\n\t\tif (policy?.state === \"enabled\") policyEnabledIds.push(id);\n\t}\n\treturn pickerIds.length > 0 || !allowPolicyFallback ? pickerIds : policyEnabledIds;\n}\n\nasync function fetchAvailableGitHubCopilotModelIds(\n\tcopilotToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<string[]> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(copilotToken, enterpriseDomain);\n\t// Some Individual accounts return false for every picker flag despite explicit enabled policies.\n\t// Limit the fallback to that endpoint so other account types keep strict picker semantics.\n\tconst allowPolicyFallback = baseUrl === \"https://api.individual.githubcopilot.com\";\n\tconst raw = await fetchJson(`${baseUrl}/models`, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${copilotToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t\t\"X-GitHub-Api-Version\": COPILOT_API_VERSION,\n\t\t},\n\t\tsignal: AbortSignal.any([signal, AbortSignal.timeout(5000)]),\n\t});\n\treturn parseAvailableCopilotModelIds(raw, allowPolicyFallback);\n}\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\nasync function startDeviceFlow(domain: string, signal: AbortSignal): Promise<DeviceCodeResponse> {\n\tconst urls = getUrls(domain);\n\tconst data = await fetchJson(urls.deviceCodeUrl, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tscope: \"read:user\",\n\t\t}),\n\t\tsignal,\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst deviceCode = (data as Record<string, unknown>).device_code;\n\tconst userCode = (data as Record<string, unknown>).user_code;\n\tconst verificationUri = (data as Record<string, unknown>).verification_uri;\n\tconst interval = (data as Record<string, unknown>).interval;\n\tconst expiresIn = (data as Record<string, unknown>).expires_in;\n\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\t(interval !== undefined && typeof interval !== \"number\") ||\n\t\ttypeof expiresIn !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\t// The verification URI is opened in the user's browser and to prevent `open` from\n\t// opening an executable or similar, we force it to be a URL.\n\tlet parsedUri: URL;\n\ttry {\n\t\tparsedUri = new URL(verificationUri);\n\t} catch {\n\t\tthrow new Error(\"Untrusted verification_uri in device code response\");\n\t}\n\tif (parsedUri.protocol !== \"https:\" && parsedUri.protocol !== \"http:\") {\n\t\tthrow new Error(\"Untrusted verification_uri in device code response\");\n\t}\n\n\treturn {\n\t\tdevice_code: deviceCode,\n\t\tuser_code: userCode,\n\t\tverification_uri: parsedUri.href,\n\t\tinterval,\n\t\texpires_in: expiresIn,\n\t};\n}\n\nasync function pollForGitHubAccessToken(\n\tdomain: string,\n\tdevice: DeviceCodeResponse,\n\tsignal: AbortSignal,\n): Promise<string> {\n\tconst urls = getUrls(domain);\n\treturn pollOAuthDeviceCodeFlow<string>({\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst raw = await fetchJson(urls.accessTokenUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.device_code,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenSuccessResponse).access_token === \"string\") {\n\t\t\t\treturn { status: \"complete\", value: (raw as DeviceTokenSuccessResponse).access_token };\n\t\t\t}\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenErrorResponse).error === \"string\") {\n\t\t\t\tconst { error, error_description: description, interval } = raw as DeviceTokenErrorResponse;\n\t\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\t}\n\n\t\t\t\tif (error === \"slow_down\") {\n\t\t\t\t\treturn { status: \"slow_down\", intervalSeconds: typeof interval === \"number\" ? interval : undefined };\n\t\t\t\t}\n\n\t\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\t\treturn { status: \"failed\", message: `Device flow failed: ${error}${descriptionSuffix}` };\n\t\t\t}\n\n\t\t\treturn { status: \"failed\", message: \"Invalid device token response\" };\n\t\t},\n\t});\n}\n\nasync function refreshGitHubCopilotAccessToken(\n\trefreshToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tconst domain = enterpriseDomain || \"github.com\";\n\tconst urls = getUrls(domain);\n\n\tconst raw = await fetchJson(urls.copilotTokenUrl, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${refreshToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t},\n\t\tsignal,\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid Copilot token response\");\n\t}\n\n\tconst token = (raw as Record<string, unknown>).token;\n\tconst expiresAt = (raw as Record<string, unknown>).expires_at;\n\n\tif (typeof token !== \"string\" || typeof expiresAt !== \"number\") {\n\t\tthrow new Error(\"Invalid Copilot token response fields\");\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: refreshToken,\n\t\taccess: token,\n\t\texpires: expiresAt * 1000 - 5 * 60 * 1000,\n\t\tenterpriseUrl: enterpriseDomain,\n\t};\n}\n\n/**\n * Refresh GitHub Copilot token\n */\nasync function refreshGitHubCopilotToken(\n\trefreshToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tconst credentials = await refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain, signal);\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds: await fetchAvailableGitHubCopilotModelIds(credentials.access, enterpriseDomain, signal),\n\t};\n}\n\n/**\n * Enable a model for the user's GitHub Copilot account.\n * This is required for some models (like Claude, Grok) before they can be used.\n */\nasync function enableGitHubCopilotModel(\n\ttoken: string,\n\tmodelId: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<boolean> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\tconst url = `${baseUrl}/models/${modelId}/policy`;\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\"openai-intent\": \"chat-policy\",\n\t\t\t\t\"x-interaction-type\": \"chat-policy\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({ state: \"enabled\" }),\n\t\t\tsignal,\n\t\t});\n\t\treturn response.ok;\n\t} catch (error) {\n\t\tif (signal.aborted) throw error;\n\t\treturn false;\n\t}\n}\n\n/**\n * Enable all known GitHub Copilot models that may require policy acceptance.\n * Called after successful login to ensure all models are available.\n */\nasync function enableAllGitHubCopilotModels(\n\ttoken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<void> {\n\tconst models = Object.values(GITHUB_COPILOT_MODELS);\n\tawait Promise.all(\n\t\tmodels.map(async (model) => {\n\t\t\tawait enableGitHubCopilotModel(token, model.id, enterpriseDomain, signal);\n\t\t}),\n\t);\n}\n\nasync function loginGitHubCopilot(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst input = await interaction.prompt({\n\t\ttype: \"text\",\n\t\tmessage: \"GitHub Enterprise URL/domain (blank for github.com)\",\n\t\tplaceholder: \"company.ghe.com\",\n\t});\n\tif (interaction.signal.aborted) throw new Error(\"Login cancelled\");\n\n\tconst trimmed = input.trim();\n\tconst enterpriseDomain = normalizeDomain(input);\n\tif (trimmed && !enterpriseDomain) throw new Error(\"Invalid GitHub Enterprise URL/domain\");\n\tconst domain = enterpriseDomain || \"github.com\";\n\n\tconst device = await startDeviceFlow(domain, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.user_code,\n\t\tverificationUri: device.verification_uri,\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t});\n\n\tconst githubAccessToken = await pollForGitHubAccessToken(domain, device, interaction.signal);\n\tconst credentials = await refreshGitHubCopilotAccessToken(\n\t\tgithubAccessToken,\n\t\tenterpriseDomain ?? undefined,\n\t\tinteraction.signal,\n\t);\n\tinteraction.notify({ type: \"progress\", message: \"Enabling models...\" });\n\tawait enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? undefined, interaction.signal);\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds: await fetchAvailableGitHubCopilotModelIds(\n\t\t\tcredentials.access,\n\t\t\tenterpriseDomain ?? undefined,\n\t\t\tinteraction.signal,\n\t\t),\n\t};\n}\n\nfunction copilotEnterpriseDomain(credential: OAuthCredential): string | undefined {\n\tconst enterpriseUrl = credential.enterpriseUrl;\n\tif (typeof enterpriseUrl !== \"string\" || !enterpriseUrl) return undefined;\n\treturn normalizeDomain(enterpriseUrl) ?? undefined;\n}\n\nexport const githubCopilotOAuth: OAuthAuth = {\n\tname: \"GitHub Copilot\",\n\tisSubscription: true,\n\tlogin: loginGitHubCopilot,\n\trefresh: (credential, signal) =>\n\t\trefreshGitHubCopilotToken(credential.refresh, copilotEnterpriseDomain(credential), signal),\n\n\t/** Derive the credential-specific proxy endpoint for each request. */\n\tasync toAuth(credential) {\n\t\treturn {\n\t\t\tapiKey: credential.access,\n\t\t\tbaseUrl: getGitHubCopilotBaseUrl(credential.access, copilotEnterpriseDomain(credential)),\n\t\t};\n\t},\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kimi-coding.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"kimi-coding.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AA6RvF,eAAO,MAAM,eAAe,EAAE,SAe7B,CAAC"}
|
|
@@ -18,7 +18,7 @@ function getOauthHost() {
|
|
|
18
18
|
return (override || DEFAULT_OAUTH_HOST).replace(/\/+$/, "");
|
|
19
19
|
}
|
|
20
20
|
function requestSignal(signal) {
|
|
21
|
-
return AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
21
|
+
return AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);
|
|
22
22
|
}
|
|
23
23
|
function formUrlEncode(fields) {
|
|
24
24
|
return new URLSearchParams(fields).toString();
|
|
@@ -168,8 +168,19 @@ async function pollForToken(oauthHost, device, signal) {
|
|
|
168
168
|
},
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
|
-
function sleep(ms) {
|
|
172
|
-
return new Promise((resolve) =>
|
|
171
|
+
function sleep(ms, signal) {
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
signal.throwIfAborted();
|
|
174
|
+
const onAbort = () => {
|
|
175
|
+
clearTimeout(timeout);
|
|
176
|
+
reject(signal.reason);
|
|
177
|
+
};
|
|
178
|
+
const timeout = setTimeout(() => {
|
|
179
|
+
signal.removeEventListener("abort", onAbort);
|
|
180
|
+
resolve();
|
|
181
|
+
}, ms);
|
|
182
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
183
|
+
});
|
|
173
184
|
}
|
|
174
185
|
function isRetryableRefreshFailure(response) {
|
|
175
186
|
return response.status === 429 || response.status >= 500;
|
|
@@ -178,9 +189,9 @@ async function refreshToken(oauthHost, refreshTokenValue, signal) {
|
|
|
178
189
|
let lastError;
|
|
179
190
|
for (let attempt = 0; attempt <= REFRESH_MAX_RETRIES; attempt++) {
|
|
180
191
|
if (attempt > 0) {
|
|
181
|
-
await sleep(1000 * 2 ** (attempt - 1));
|
|
192
|
+
await sleep(1000 * 2 ** (attempt - 1), signal);
|
|
182
193
|
}
|
|
183
|
-
if (signal
|
|
194
|
+
if (signal.aborted) {
|
|
184
195
|
throw new Error("Kimi Code token refresh aborted");
|
|
185
196
|
}
|
|
186
197
|
let response;
|
|
@@ -236,6 +247,7 @@ async function loginKimiCoding(interaction) {
|
|
|
236
247
|
}
|
|
237
248
|
export const kimiCodingOAuth = {
|
|
238
249
|
name: "Kimi Code (subscription)",
|
|
250
|
+
isSubscription: true,
|
|
239
251
|
loginLabel: "Sign in with Kimi Code",
|
|
240
252
|
login: loginKimiCoding,
|
|
241
253
|
refresh: async (credential, signal) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi Code (subscription) OAuth flow\n *\n * RFC 8628 device authorization grant against https://auth.kimi.com with JSON\n * responses. The access token authenticates requests to\n * https://api.kimi.com/coding as an `Authorization: Bearer` header.\n */\n\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport type { AuthInteraction, OAuthAuth, OAuthCredential } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst DEFAULT_OAUTH_HOST = \"https://auth.kimi.com\";\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nconst DEFAULT_POLL_INTERVAL_SECONDS = 5;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\nconst REFRESH_MAX_RETRIES = 3;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete: string;\n\tintervalSeconds: number;\n\texpiresInSeconds: number;\n};\n\ntype TokenResponse = {\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n};\n\nfunction getOauthHost(): string {\n\tconst override = getProviderEnvValue(\"KIMI_CODE_OAUTH_HOST\") || getProviderEnvValue(\"KIMI_OAUTH_HOST\");\n\treturn (override || DEFAULT_OAUTH_HOST).replace(/\\/+$/, \"\");\n}\n\nfunction requestSignal(signal?: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), ...(signal ? [signal] : [])]);\n}\n\nfunction formUrlEncode(fields: Record<string, string>): string {\n\treturn new URLSearchParams(fields).toString();\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */\nfunction trustedHttpUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\" || !value) return null;\n\ttry {\n\t\tconst url = new URL(value);\n\t\tif (url.protocol !== \"https:\" && url.protocol !== \"http:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function startDeviceAuthorization(oauthHost: string, signal?: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(`${oauthHost}/api/oauth/device_authorization`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: formUrlEncode({ client_id: CLIENT_ID }),\n\t\tsignal: requestSignal(signal),\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`Kimi Code device authorization failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tconst json = await readJson(response);\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = json?.verification_uri;\n\tconst verificationUriComplete = json?.verification_uri_complete;\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof verificationUriComplete !== \"string\" ||\n\t\t!trustedHttpUrl(verificationUriComplete) ||\n\t\t!trustedHttpUrl(verificationUri)\n\t) {\n\t\tthrow new Error(`Invalid Kimi Code device authorization response: ${JSON.stringify(json)}`);\n\t}\n\n\tconst interval = json?.interval;\n\tconst expiresIn = json?.expires_in;\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tverificationUriComplete,\n\t\tintervalSeconds:\n\t\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0\n\t\t\t\t? interval\n\t\t\t\t: DEFAULT_POLL_INTERVAL_SECONDS,\n\t\texpiresInSeconds:\n\t\t\ttypeof expiresIn === \"number\" && Number.isFinite(expiresIn) && expiresIn > 0\n\t\t\t\t? expiresIn\n\t\t\t\t: DEVICE_CODE_TIMEOUT_SECONDS,\n\t};\n}\n\nfunction parseTokenResponse(json: Record<string, unknown> | null, operation: string): TokenResponse {\n\tconst accessToken = json?.access_token;\n\tconst refreshToken = json?.refresh_token;\n\tconst expiresIn = json?.expires_in;\n\tif (\n\t\ttypeof accessToken !== \"string\" ||\n\t\t!accessToken ||\n\t\ttypeof refreshToken !== \"string\" ||\n\t\t!refreshToken ||\n\t\ttypeof expiresIn !== \"number\" ||\n\t\t!Number.isFinite(expiresIn) ||\n\t\texpiresIn <= 0\n\t) {\n\t\tthrow new Error(`Kimi Code token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresIn * 1000,\n\t};\n}\n\nasync function pollForToken(\n\toauthHost: string,\n\tdevice: DeviceAuthorization,\n\tsignal?: AbortSignal,\n): Promise<TokenResponse> {\n\treturn pollOAuthDeviceCodeFlow<TokenResponse>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\n\t\t\tif (response.status >= 500) {\n\t\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\tmessage: `Kimi Code device token request failed with status ${response.status}${text ? `: ${text}` : \"\"}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn { status: \"complete\", value: parseTokenResponse(json, \"poll\") };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { status: \"failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst error = json?.error;\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tconst interval = json?.interval;\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"slow_down\",\n\t\t\t\t\tintervalSeconds: typeof interval === \"number\" && interval > 0 ? interval : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code device authorization expired. Please restart login.\" };\n\t\t\t}\n\t\t\tif (error === \"access_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code login was denied.\" };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `Kimi Code device token request failed (status ${response.status})${typeof error === \"string\" ? `: ${error}${description}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryableRefreshFailure(response: Response): boolean {\n\treturn response.status === 429 || response.status >= 500;\n}\n\nasync function refreshToken(\n\toauthHost: string,\n\trefreshTokenValue: string,\n\tsignal?: AbortSignal,\n): Promise<TokenResponse> {\n\tlet lastError: Error | undefined;\n\tfor (let attempt = 0; attempt <= REFRESH_MAX_RETRIES; attempt++) {\n\t\tif (attempt > 0) {\n\t\t\tawait sleep(1000 * 2 ** (attempt - 1));\n\t\t}\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Kimi Code token refresh aborted\");\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\trefresh_token: refreshTokenValue,\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst json = await readJson(response);\n\t\tif (response.ok) {\n\t\t\treturn parseTokenResponse(json, \"refresh\");\n\t\t}\n\n\t\t// Unauthorized: the stored credential is dead; Models clears it and prompts re-login.\n\t\tif (response.status === 401 || response.status === 403 || json?.error === \"invalid_grant\") {\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tthrow new Error(`Kimi Code token refresh unauthorized (status ${response.status})${description}`);\n\t\t}\n\n\t\tif (isRetryableRefreshFailure(response) && attempt < REFRESH_MAX_RETRIES) {\n\t\t\tlastError = new Error(`Kimi Code token refresh failed with status ${response.status}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst text = JSON.stringify(json);\n\t\tthrow new Error(`Kimi Code token refresh failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tthrow lastError ?? new Error(\"Kimi Code token refresh failed\");\n}\n\nasync function loginKimiCoding(interaction: AuthInteraction): Promise<OAuthCredential> {\n\tconst oauthHost = getOauthHost();\n\tconst device = await startDeviceAuthorization(oauthHost, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\tconst token = await pollForToken(oauthHost, device, interaction.signal);\n\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n}\n\nexport const kimiCodingOAuth: OAuthAuth = {\n\tname: \"Kimi Code (subscription)\",\n\tloginLabel: \"Sign in with Kimi Code\",\n\n\tlogin: loginKimiCoding,\n\n\trefresh: async (credential, signal) => {\n\t\tconst token = await refreshToken(getOauthHost(), credential.refresh, signal);\n\t\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n\t},\n\n\tasync toAuth(credential) {\n\t\treturn { headers: { Authorization: `Bearer ${credential.access}` } };\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi Code (subscription) OAuth flow\n *\n * RFC 8628 device authorization grant against https://auth.kimi.com with JSON\n * responses. The access token authenticates requests to\n * https://api.kimi.com/coding as an `Authorization: Bearer` header.\n */\n\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst DEFAULT_OAUTH_HOST = \"https://auth.kimi.com\";\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nconst DEFAULT_POLL_INTERVAL_SECONDS = 5;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\nconst REFRESH_MAX_RETRIES = 3;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete: string;\n\tintervalSeconds: number;\n\texpiresInSeconds: number;\n};\n\ntype TokenResponse = {\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n};\n\nfunction getOauthHost(): string {\n\tconst override = getProviderEnvValue(\"KIMI_CODE_OAUTH_HOST\") || getProviderEnvValue(\"KIMI_OAUTH_HOST\");\n\treturn (override || DEFAULT_OAUTH_HOST).replace(/\\/+$/, \"\");\n}\n\nfunction requestSignal(signal: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);\n}\n\nfunction formUrlEncode(fields: Record<string, string>): string {\n\treturn new URLSearchParams(fields).toString();\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */\nfunction trustedHttpUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\" || !value) return null;\n\ttry {\n\t\tconst url = new URL(value);\n\t\tif (url.protocol !== \"https:\" && url.protocol !== \"http:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function startDeviceAuthorization(oauthHost: string, signal: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(`${oauthHost}/api/oauth/device_authorization`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: formUrlEncode({ client_id: CLIENT_ID }),\n\t\tsignal: requestSignal(signal),\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`Kimi Code device authorization failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tconst json = await readJson(response);\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = json?.verification_uri;\n\tconst verificationUriComplete = json?.verification_uri_complete;\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof verificationUriComplete !== \"string\" ||\n\t\t!trustedHttpUrl(verificationUriComplete) ||\n\t\t!trustedHttpUrl(verificationUri)\n\t) {\n\t\tthrow new Error(`Invalid Kimi Code device authorization response: ${JSON.stringify(json)}`);\n\t}\n\n\tconst interval = json?.interval;\n\tconst expiresIn = json?.expires_in;\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tverificationUriComplete,\n\t\tintervalSeconds:\n\t\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0\n\t\t\t\t? interval\n\t\t\t\t: DEFAULT_POLL_INTERVAL_SECONDS,\n\t\texpiresInSeconds:\n\t\t\ttypeof expiresIn === \"number\" && Number.isFinite(expiresIn) && expiresIn > 0\n\t\t\t\t? expiresIn\n\t\t\t\t: DEVICE_CODE_TIMEOUT_SECONDS,\n\t};\n}\n\nfunction parseTokenResponse(json: Record<string, unknown> | null, operation: string): TokenResponse {\n\tconst accessToken = json?.access_token;\n\tconst refreshToken = json?.refresh_token;\n\tconst expiresIn = json?.expires_in;\n\tif (\n\t\ttypeof accessToken !== \"string\" ||\n\t\t!accessToken ||\n\t\ttypeof refreshToken !== \"string\" ||\n\t\t!refreshToken ||\n\t\ttypeof expiresIn !== \"number\" ||\n\t\t!Number.isFinite(expiresIn) ||\n\t\texpiresIn <= 0\n\t) {\n\t\tthrow new Error(`Kimi Code token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresIn * 1000,\n\t};\n}\n\nasync function pollForToken(\n\toauthHost: string,\n\tdevice: DeviceAuthorization,\n\tsignal: AbortSignal,\n): Promise<TokenResponse> {\n\treturn pollOAuthDeviceCodeFlow<TokenResponse>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\n\t\t\tif (response.status >= 500) {\n\t\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\tmessage: `Kimi Code device token request failed with status ${response.status}${text ? `: ${text}` : \"\"}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn { status: \"complete\", value: parseTokenResponse(json, \"poll\") };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { status: \"failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst error = json?.error;\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tconst interval = json?.interval;\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"slow_down\",\n\t\t\t\t\tintervalSeconds: typeof interval === \"number\" && interval > 0 ? interval : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code device authorization expired. Please restart login.\" };\n\t\t\t}\n\t\t\tif (error === \"access_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code login was denied.\" };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `Kimi Code device token request failed (status ${response.status})${typeof error === \"string\" ? `: ${error}${description}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tsignal.throwIfAborted();\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(signal.reason);\n\t\t};\n\t\tconst timeout = setTimeout(() => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}, ms);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\nfunction isRetryableRefreshFailure(response: Response): boolean {\n\treturn response.status === 429 || response.status >= 500;\n}\n\nasync function refreshToken(oauthHost: string, refreshTokenValue: string, signal: AbortSignal): Promise<TokenResponse> {\n\tlet lastError: Error | undefined;\n\tfor (let attempt = 0; attempt <= REFRESH_MAX_RETRIES; attempt++) {\n\t\tif (attempt > 0) {\n\t\t\tawait sleep(1000 * 2 ** (attempt - 1), signal);\n\t\t}\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Kimi Code token refresh aborted\");\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\trefresh_token: refreshTokenValue,\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst json = await readJson(response);\n\t\tif (response.ok) {\n\t\t\treturn parseTokenResponse(json, \"refresh\");\n\t\t}\n\n\t\t// Unauthorized: the stored credential is dead; Models clears it and prompts re-login.\n\t\tif (response.status === 401 || response.status === 403 || json?.error === \"invalid_grant\") {\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tthrow new Error(`Kimi Code token refresh unauthorized (status ${response.status})${description}`);\n\t\t}\n\n\t\tif (isRetryableRefreshFailure(response) && attempt < REFRESH_MAX_RETRIES) {\n\t\t\tlastError = new Error(`Kimi Code token refresh failed with status ${response.status}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst text = JSON.stringify(json);\n\t\tthrow new Error(`Kimi Code token refresh failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tthrow lastError ?? new Error(\"Kimi Code token refresh failed\");\n}\n\nasync function loginKimiCoding(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst oauthHost = getOauthHost();\n\tconst device = await startDeviceAuthorization(oauthHost, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\tconst token = await pollForToken(oauthHost, device, interaction.signal);\n\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n}\n\nexport const kimiCodingOAuth: OAuthAuth = {\n\tname: \"Kimi Code (subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with Kimi Code\",\n\n\tlogin: loginKimiCoding,\n\n\trefresh: async (credential, signal) => {\n\t\tconst token = await refreshToken(getOauthHost(), credential.refresh, signal);\n\t\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n\t},\n\n\tasync toAuth(credential) {\n\t\treturn { headers: { Authorization: `Bearer ${credential.access}` } };\n\t},\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/load.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAa7C,KAAK,gBAAgB,GAAG;IACvB,SAAS,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAChD,WAAW,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAClD,aAAa,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACpD,UAAU,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,UAAU,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,GAAG,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACvF,CAAC;AAIF,4EAA4E;AAC5E,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAE/E;AAED,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,SAAS,CAG5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,QAAa,OAAO,CAAC,SAAS,CAG9D,CAAC;AAEF,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,SAAS,CAGhE,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAa,OAAO,CAAC,SAAS,CAG7D,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAa,OAAO,CAAC,SAAS,CAG7D,CAAC;AAEF,eAAO,MAAM,YAAY,QAAa,OAAO,CAAC,SAAS,CAGtD,CAAC;AAEF,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/load.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAa7C,KAAK,gBAAgB,GAAG;IACvB,SAAS,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAChD,WAAW,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAClD,aAAa,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACpD,UAAU,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,UAAU,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,GAAG,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACvF,CAAC;AAIF,4EAA4E;AAC5E,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAE/E;AAED,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,SAAS,CAG5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,QAAa,OAAO,CAAC,SAAS,CAG9D,CAAC;AAEF,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,SAAS,CAGhE,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAa,OAAO,CAAC,SAAS,CAG7D,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAa,OAAO,CAAC,SAAS,CAG7D,CAAC;AAEF,eAAO,MAAM,YAAY,QAAa,OAAO,CAAC,SAAS,CAGtD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,SAAS,CAOnG,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/auth/oauth/load.ts"],"names":[],"mappings":";;;;;;;;AAEA;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAoB,EAAE;IACjE,MAAM,gBAAgB,GAAG,
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/auth/oauth/load.ts"],"names":[],"mappings":";;;;;;;;AAEA;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAoB,EAAE;IACjE,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzG,OAAO,MAAM,kCAAC,gBAAgB,EAAC,CAAC;AACjC,CAAC,CAAC;AAYF,IAAI,cAA4C,CAAC;AAEjD,4EAA4E;AAC5E,MAAM,UAAU,+BAA+B,CAAC,OAAyB;IACxE,cAAc,GAAG,OAAO,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,IAAwB,EAAE;IAChE,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC,SAAS,EAAE,CAAC;IACtD,OAAQ,CAAC,MAAM,iBAAiB,CAAC,gBAAgB,CAAC,CAAmC,CAAC,cAAc,CAAC;AACtG,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,IAAwB,EAAE;IAClE,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC,WAAW,EAAE,CAAC;IACxD,OAAQ,CAAC,MAAM,iBAAiB,CAAC,mBAAmB,CAAC,CAAqC,CAAC,gBAAgB,CAAC;AAC7G,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,IAAwB,EAAE;IACpE,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC,aAAa,EAAE,CAAC;IAC1D,OAAQ,CAAC,MAAM,iBAAiB,CAAC,qBAAqB,CAAC,CAAuC,CAAC,kBAAkB,CAAC;AACnH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,IAAwB,EAAE;IACjE,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC,UAAU,EAAE,CAAC;IACvD,OAAQ,CAAC,MAAM,iBAAiB,CAAC,iBAAiB,CAAC,CAAoC,CAAC,eAAe,CAAC;AACzG,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,IAAwB,EAAE;IACjE,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC,UAAU,EAAE,CAAC;IACvD,OAAQ,CAAC,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAoC,CAAC,eAAe,CAAC;AAC1G,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,IAAwB,EAAE;IAC1D,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC,GAAG,EAAE,CAAC;IAChD,OAAQ,CAAC,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAA6B,CAAC,QAAQ,CAAC;AACpF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,OAA0C,EAAsB,EAAE;IACvG,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1D,OACC,CAAC,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAGvC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC,CAAC","sourcesContent":["import type { OAuthAuth } from \"../types.ts\";\n\n/**\n * Loads an OAuth flow module through a variable specifier so bundlers cannot\n * follow the import into Node-only flow code (`node:http` callback servers,\n * `node:crypto` PKCE). The `.ts`/`.js` rewrite keeps the trick working from\n * both source and built output.\n */\nconst importOAuthModule = (specifier: string): Promise<unknown> => {\n\tconst runtimeSpecifier = import.meta.url.endsWith(\".js\") ? specifier.replace(/\\.ts$/, \".js\") : specifier;\n\treturn import(runtimeSpecifier);\n};\n\ntype OAuthFlowLoaders = {\n\tanthropic: () => OAuthAuth | Promise<OAuthAuth>;\n\topenaiCodex: () => OAuthAuth | Promise<OAuthAuth>;\n\tgithubCopilot: () => OAuthAuth | Promise<OAuthAuth>;\n\topenrouter: () => OAuthAuth | Promise<OAuthAuth>;\n\tkimiCoding: () => OAuthAuth | Promise<OAuthAuth>;\n\txai: () => OAuthAuth | Promise<OAuthAuth>;\n\tradius: (options: { name: string; gateway: string }) => OAuthAuth | Promise<OAuthAuth>;\n};\n\nlet bundledLoaders: OAuthFlowLoaders | undefined;\n\n/** Registers statically bundled OAuth flows for standalone Bun binaries. */\nexport function registerBundledOAuthFlowLoaders(loaders: OAuthFlowLoaders): void {\n\tbundledLoaders = loaders;\n}\n\nexport const loadAnthropicOAuth = async (): Promise<OAuthAuth> => {\n\tif (bundledLoaders) return bundledLoaders.anthropic();\n\treturn ((await importOAuthModule(\"./anthropic.ts\")) as { anthropicOAuth: OAuthAuth }).anthropicOAuth;\n};\n\nexport const loadOpenAICodexOAuth = async (): Promise<OAuthAuth> => {\n\tif (bundledLoaders) return bundledLoaders.openaiCodex();\n\treturn ((await importOAuthModule(\"./openai-codex.ts\")) as { openaiCodexOAuth: OAuthAuth }).openaiCodexOAuth;\n};\n\nexport const loadGitHubCopilotOAuth = async (): Promise<OAuthAuth> => {\n\tif (bundledLoaders) return bundledLoaders.githubCopilot();\n\treturn ((await importOAuthModule(\"./github-copilot.ts\")) as { githubCopilotOAuth: OAuthAuth }).githubCopilotOAuth;\n};\n\nexport const loadOpenRouterOAuth = async (): Promise<OAuthAuth> => {\n\tif (bundledLoaders) return bundledLoaders.openrouter();\n\treturn ((await importOAuthModule(\"./openrouter.ts\")) as { openRouterOAuth: OAuthAuth }).openRouterOAuth;\n};\n\nexport const loadKimiCodingOAuth = async (): Promise<OAuthAuth> => {\n\tif (bundledLoaders) return bundledLoaders.kimiCoding();\n\treturn ((await importOAuthModule(\"./kimi-coding.ts\")) as { kimiCodingOAuth: OAuthAuth }).kimiCodingOAuth;\n};\n\nexport const loadXaiOAuth = async (): Promise<OAuthAuth> => {\n\tif (bundledLoaders) return bundledLoaders.xai();\n\treturn ((await importOAuthModule(\"./xai.ts\")) as { xaiOAuth: OAuthAuth }).xaiOAuth;\n};\n\nexport const loadRadiusOAuth = async (options: { name: string; gateway: string }): Promise<OAuthAuth> => {\n\tif (bundledLoaders) return bundledLoaders.radius(options);\n\treturn (\n\t\t(await importOAuthModule(\"./radius.ts\")) as {\n\t\t\tcreateRadiusOAuth: (input: { name: string; gateway: string }) => OAuthAuth;\n\t\t}\n\t).createRadiusOAuth(options);\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-codex.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/openai-codex.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"openai-codex.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/openai-codex.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAudvF,eAAO,MAAM,gBAAgB,EAAE,SA6B9B,CAAC"}
|
|
@@ -97,7 +97,7 @@ async function readTokenResponse(response, operation) {
|
|
|
97
97
|
expires: Date.now() + json.expires_in * 1000,
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
|
-
async function exchangeAuthorizationCode(code, verifier, redirectUri
|
|
100
|
+
async function exchangeAuthorizationCode(code, verifier, redirectUri, signal) {
|
|
101
101
|
const response = await fetchWithLoginCancellation(TOKEN_URL, {
|
|
102
102
|
method: "POST",
|
|
103
103
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
@@ -112,7 +112,7 @@ async function exchangeAuthorizationCode(code, verifier, redirectUri = REDIRECT_
|
|
|
112
112
|
});
|
|
113
113
|
return readTokenResponse(response, "exchange");
|
|
114
114
|
}
|
|
115
|
-
async function refreshAccessToken(refreshToken) {
|
|
115
|
+
async function refreshAccessToken(refreshToken, signal) {
|
|
116
116
|
let response;
|
|
117
117
|
try {
|
|
118
118
|
response = await fetch(TOKEN_URL, {
|
|
@@ -123,6 +123,7 @@ async function refreshAccessToken(refreshToken) {
|
|
|
123
123
|
refresh_token: refreshToken,
|
|
124
124
|
client_id: CLIENT_ID,
|
|
125
125
|
}),
|
|
126
|
+
signal,
|
|
126
127
|
});
|
|
127
128
|
}
|
|
128
129
|
catch (error) {
|
|
@@ -339,6 +340,10 @@ async function loginOpenAICodex(interaction) {
|
|
|
339
340
|
const { verifier, state, url } = await createAuthorizationFlow();
|
|
340
341
|
const server = await startLocalOAuthServer(state);
|
|
341
342
|
const manualAbort = new AbortController();
|
|
343
|
+
const onAbort = () => server.cancelWait();
|
|
344
|
+
interaction.signal.addEventListener("abort", onAbort, { once: true });
|
|
345
|
+
if (interaction.signal.aborted)
|
|
346
|
+
onAbort();
|
|
342
347
|
let code;
|
|
343
348
|
let manualCode;
|
|
344
349
|
let manualError;
|
|
@@ -391,6 +396,7 @@ async function loginOpenAICodex(interaction) {
|
|
|
391
396
|
return exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI, interaction.signal);
|
|
392
397
|
}
|
|
393
398
|
finally {
|
|
399
|
+
interaction.signal.removeEventListener("abort", onAbort);
|
|
394
400
|
manualAbort.abort();
|
|
395
401
|
server.close();
|
|
396
402
|
}
|
|
@@ -398,11 +404,12 @@ async function loginOpenAICodex(interaction) {
|
|
|
398
404
|
/**
|
|
399
405
|
* Refresh OpenAI Codex OAuth token
|
|
400
406
|
*/
|
|
401
|
-
async function refreshOpenAICodexToken(refreshToken) {
|
|
402
|
-
return credentialsFromToken(await refreshAccessToken(refreshToken));
|
|
407
|
+
async function refreshOpenAICodexToken(refreshToken, signal) {
|
|
408
|
+
return credentialsFromToken(await refreshAccessToken(refreshToken, signal));
|
|
403
409
|
}
|
|
404
410
|
export const openaiCodexOAuth = {
|
|
405
411
|
name: "OpenAI (ChatGPT Plus/Pro)",
|
|
412
|
+
isSubscription: true,
|
|
406
413
|
async login(interaction) {
|
|
407
414
|
const method = await interaction.prompt({
|
|
408
415
|
type: "select",
|
|
@@ -420,7 +427,7 @@ export const openaiCodexOAuth = {
|
|
|
420
427
|
}
|
|
421
428
|
return loginOpenAICodex(interaction);
|
|
422
429
|
},
|
|
423
|
-
refresh: (credential) => refreshOpenAICodexToken(credential.refresh),
|
|
430
|
+
refresh: (credential, signal) => refreshOpenAICodexToken(credential.refresh, signal),
|
|
424
431
|
async toAuth(credential) {
|
|
425
432
|
return { apiKey: credential.access };
|
|
426
433
|
},
|