github-copilot-oauth 1.0.0 → 1.0.1
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/dist/index.js +541 -26
- package/dist/index.js.map +1 -1
- package/dist/proxy.js +181 -13
- package/dist/proxy.js.map +1 -1
- package/package.json +1 -2
- package/dist/chunk-CUD4IYWR.js +0 -511
- package/dist/chunk-CUD4IYWR.js.map +0 -1
package/dist/chunk-CUD4IYWR.js
DELETED
|
@@ -1,511 +0,0 @@
|
|
|
1
|
-
// src/types.ts
|
|
2
|
-
var GitHubCopilotOAuthError = class extends Error {
|
|
3
|
-
code;
|
|
4
|
-
constructor(code, message, options) {
|
|
5
|
-
super(message, options);
|
|
6
|
-
this.name = "GitHubCopilotOAuthError";
|
|
7
|
-
this.code = code;
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
// src/enterprise.ts
|
|
12
|
-
function normalizeEnterpriseDomain(enterpriseUrl, options = {}) {
|
|
13
|
-
const value = enterpriseUrl?.trim();
|
|
14
|
-
if (!value) {
|
|
15
|
-
return void 0;
|
|
16
|
-
}
|
|
17
|
-
let parsed;
|
|
18
|
-
try {
|
|
19
|
-
parsed = new URL(/^https?:\/\//i.test(value) ? value : `https://${value}`);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
throw new GitHubCopilotOAuthError("unsupported", "Invalid GitHub Enterprise URL.", { cause: error });
|
|
22
|
-
}
|
|
23
|
-
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
24
|
-
throw new GitHubCopilotOAuthError("unsupported", "Invalid GitHub Enterprise URL protocol.");
|
|
25
|
-
}
|
|
26
|
-
if (parsed.username || parsed.password || parsed.port || parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
27
|
-
throw new GitHubCopilotOAuthError("unsupported", "GitHub Enterprise URL must be a hostname only.");
|
|
28
|
-
}
|
|
29
|
-
const hostname = parsed.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
30
|
-
if (!hostname || isUnsafeEnterpriseHostname(hostname)) {
|
|
31
|
-
throw new GitHubCopilotOAuthError("unsupported", "Unsafe GitHub Enterprise hostname.");
|
|
32
|
-
}
|
|
33
|
-
if (hostname === "github.com") {
|
|
34
|
-
return void 0;
|
|
35
|
-
}
|
|
36
|
-
if (!options.allowEnterprise) {
|
|
37
|
-
throw new GitHubCopilotOAuthError("unsupported", "Custom GitHub Enterprise hosts are not enabled.");
|
|
38
|
-
}
|
|
39
|
-
return hostname;
|
|
40
|
-
}
|
|
41
|
-
function isUnsafeEnterpriseHostname(hostname) {
|
|
42
|
-
return hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname.includes(":") || /^\d+(?:\.\d+){3}$/.test(hostname);
|
|
43
|
-
}
|
|
44
|
-
function copilotBase(enterpriseUrl, options = {}) {
|
|
45
|
-
const domain = normalizeEnterpriseDomain(enterpriseUrl, options);
|
|
46
|
-
if (!domain) {
|
|
47
|
-
return "https://api.githubcopilot.com";
|
|
48
|
-
}
|
|
49
|
-
return `https://copilot-api.${domain}`;
|
|
50
|
-
}
|
|
51
|
-
function copilotTokenExchangeUrl(enterpriseUrl, options = {}) {
|
|
52
|
-
const domain = normalizeEnterpriseDomain(enterpriseUrl, options);
|
|
53
|
-
if (!domain) {
|
|
54
|
-
return "https://api.github.com/copilot_internal/v2/token";
|
|
55
|
-
}
|
|
56
|
-
return `https://api.${domain}/copilot_internal/v2/token`;
|
|
57
|
-
}
|
|
58
|
-
function githubOAuthUrls(enterpriseUrl, options = {}) {
|
|
59
|
-
const domain = normalizeEnterpriseDomain(enterpriseUrl, options) ?? "github.com";
|
|
60
|
-
return {
|
|
61
|
-
domain,
|
|
62
|
-
code: `https://${domain}/login/device/code`,
|
|
63
|
-
token: `https://${domain}/login/oauth/access_token`
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// src/headers.ts
|
|
68
|
-
var COPILOT_HEADERS = {
|
|
69
|
-
"User-Agent": "GitHubCopilotChat/0.35.0",
|
|
70
|
-
"Editor-Version": "vscode/1.107.0",
|
|
71
|
-
"Editor-Plugin-Version": "copilot-chat/0.35.0",
|
|
72
|
-
"Copilot-Integration-Id": "vscode-chat"
|
|
73
|
-
};
|
|
74
|
-
function copilotHeaders(accessToken, options) {
|
|
75
|
-
return {
|
|
76
|
-
...COPILOT_HEADERS,
|
|
77
|
-
Authorization: `Bearer ${accessToken}`,
|
|
78
|
-
"Openai-Intent": "conversation-edits",
|
|
79
|
-
"X-Initiator": options?.initiator ?? "user",
|
|
80
|
-
...options?.vision ? { "Copilot-Vision-Request": "true" } : {}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
function copilotModelHeaders(accessToken) {
|
|
84
|
-
return {
|
|
85
|
-
...COPILOT_HEADERS,
|
|
86
|
-
Authorization: `Bearer ${accessToken}`
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function copilotTokenExchangeHeaders(githubToken) {
|
|
90
|
-
return {
|
|
91
|
-
Accept: "application/json",
|
|
92
|
-
Authorization: `Bearer ${githubToken}`,
|
|
93
|
-
...COPILOT_HEADERS
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// src/memory-token-store.ts
|
|
98
|
-
function createMemoryTokenStore(initial) {
|
|
99
|
-
let current = initial;
|
|
100
|
-
return {
|
|
101
|
-
async load() {
|
|
102
|
-
return current;
|
|
103
|
-
},
|
|
104
|
-
async save(tokens) {
|
|
105
|
-
current = tokens;
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// src/token-exchange.ts
|
|
111
|
-
async function exchangeGitHubCopilotToken({
|
|
112
|
-
fetch,
|
|
113
|
-
githubToken,
|
|
114
|
-
enterpriseUrl,
|
|
115
|
-
allowEnterprise
|
|
116
|
-
}) {
|
|
117
|
-
const response = await fetch(copilotTokenExchangeUrl(enterpriseUrl, { allowEnterprise }), {
|
|
118
|
-
headers: copilotTokenExchangeHeaders(githubToken)
|
|
119
|
-
});
|
|
120
|
-
if (!response.ok) {
|
|
121
|
-
throw new GitHubCopilotOAuthError(
|
|
122
|
-
"auth_failed",
|
|
123
|
-
`GitHub Copilot token exchange failed (${response.status}).`
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
const payload = await response.json();
|
|
127
|
-
if (typeof payload.token !== "string" || !payload.token.trim()) {
|
|
128
|
-
throw new GitHubCopilotOAuthError("auth_failed", "GitHub Copilot token exchange did not return a token.");
|
|
129
|
-
}
|
|
130
|
-
if (typeof payload.expires_at !== "number" || !Number.isFinite(payload.expires_at) || payload.expires_at <= 0) {
|
|
131
|
-
throw new GitHubCopilotOAuthError(
|
|
132
|
-
"auth_failed",
|
|
133
|
-
"GitHub Copilot token exchange did not return a valid expiration."
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
return {
|
|
137
|
-
token: payload.token,
|
|
138
|
-
expiresAt: payload.expires_at * 1e3
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// src/copilot-fetch.ts
|
|
143
|
-
var DEFAULT_REFRESH_MARGIN_MS = 60 * 1e3;
|
|
144
|
-
var DEFAULT_BROWSER_PROXY_BASE_URL = "/api/proxy/github-copilot";
|
|
145
|
-
function pickFetch(customFetch) {
|
|
146
|
-
if (typeof customFetch === "function") {
|
|
147
|
-
return customFetch;
|
|
148
|
-
}
|
|
149
|
-
if (typeof globalThis.fetch === "function") {
|
|
150
|
-
return globalThis.fetch.bind(globalThis);
|
|
151
|
-
}
|
|
152
|
-
throw new GitHubCopilotOAuthError("fetch_required", "A fetch implementation is required for GitHub Copilot OAuth.");
|
|
153
|
-
}
|
|
154
|
-
function withoutTrailingSlash(value) {
|
|
155
|
-
return value.replace(/\/$/, "");
|
|
156
|
-
}
|
|
157
|
-
function createStore(settings) {
|
|
158
|
-
if (settings.tokenStore) {
|
|
159
|
-
return settings.tokenStore;
|
|
160
|
-
}
|
|
161
|
-
if (settings.tokens) {
|
|
162
|
-
return createMemoryTokenStore(settings.tokens);
|
|
163
|
-
}
|
|
164
|
-
throw new GitHubCopilotOAuthError(
|
|
165
|
-
"tokens_required",
|
|
166
|
-
"GitHub Copilot OAuth tokens are required. Pass `tokens` or `tokenStore`."
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
var TokenManager = class {
|
|
170
|
-
constructor(settings, store, fetch) {
|
|
171
|
-
this.settings = settings;
|
|
172
|
-
this.store = store;
|
|
173
|
-
this.fetch = fetch;
|
|
174
|
-
}
|
|
175
|
-
settings;
|
|
176
|
-
store;
|
|
177
|
-
fetch;
|
|
178
|
-
inflight;
|
|
179
|
-
current;
|
|
180
|
-
async token() {
|
|
181
|
-
if (this.inflight) {
|
|
182
|
-
return this.inflight;
|
|
183
|
-
}
|
|
184
|
-
this.inflight = this.loadToken().finally(() => {
|
|
185
|
-
this.inflight = void 0;
|
|
186
|
-
});
|
|
187
|
-
return this.inflight;
|
|
188
|
-
}
|
|
189
|
-
async githubToken() {
|
|
190
|
-
const tokens = this.current ?? await this.store.load();
|
|
191
|
-
if (!tokens?.githubToken) {
|
|
192
|
-
throw new GitHubCopilotOAuthError("auth_failed", "GitHub Copilot OAuth token is missing.");
|
|
193
|
-
}
|
|
194
|
-
this.current = tokens;
|
|
195
|
-
return tokens.githubToken;
|
|
196
|
-
}
|
|
197
|
-
async loadToken() {
|
|
198
|
-
let tokens = this.current ?? await this.store.load();
|
|
199
|
-
if (!tokens?.githubToken) {
|
|
200
|
-
throw new GitHubCopilotOAuthError("auth_failed", "GitHub Copilot OAuth token is missing.");
|
|
201
|
-
}
|
|
202
|
-
this.current = tokens;
|
|
203
|
-
const margin = this.settings.tokenRefreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS;
|
|
204
|
-
const expiresAt = tokens.copilotTokenExpiresAt ?? 0;
|
|
205
|
-
if (tokens.copilotToken && (expiresAt <= 0 || expiresAt > Date.now() + margin)) {
|
|
206
|
-
return { token: tokens.copilotToken, fromExchange: true };
|
|
207
|
-
}
|
|
208
|
-
try {
|
|
209
|
-
const exchanged = await exchangeGitHubCopilotToken({
|
|
210
|
-
fetch: this.fetch,
|
|
211
|
-
githubToken: tokens.githubToken,
|
|
212
|
-
enterpriseUrl: this.settings.enterpriseUrl ?? tokens.enterpriseUrl,
|
|
213
|
-
allowEnterprise: this.settings.allowEnterprise
|
|
214
|
-
});
|
|
215
|
-
tokens = {
|
|
216
|
-
...tokens,
|
|
217
|
-
copilotToken: exchanged.token,
|
|
218
|
-
copilotTokenExpiresAt: exchanged.expiresAt
|
|
219
|
-
};
|
|
220
|
-
this.current = tokens;
|
|
221
|
-
await this.store.save(tokens);
|
|
222
|
-
await this.settings.onTokens?.(tokens);
|
|
223
|
-
return { token: exchanged.token, fromExchange: true };
|
|
224
|
-
} catch (error) {
|
|
225
|
-
if (this.settings.fallbackToGitHubToken === false) {
|
|
226
|
-
throw error;
|
|
227
|
-
}
|
|
228
|
-
return { token: tokens.githubToken, fromExchange: false };
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
async function readStoredTokens(settings) {
|
|
233
|
-
if (settings.tokens) {
|
|
234
|
-
return settings.tokens;
|
|
235
|
-
}
|
|
236
|
-
const tokenStore = settings.tokenStore;
|
|
237
|
-
if (typeof tokenStore?.getTokens === "function") {
|
|
238
|
-
return tokenStore.getTokens();
|
|
239
|
-
}
|
|
240
|
-
return void 0;
|
|
241
|
-
}
|
|
242
|
-
async function resolveBaseURL(settings) {
|
|
243
|
-
if (settings.baseURL) {
|
|
244
|
-
return withoutTrailingSlash(settings.baseURL);
|
|
245
|
-
}
|
|
246
|
-
const storedTokens = await readStoredTokens(settings);
|
|
247
|
-
const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl ?? storedTokens?.enterpriseUrl;
|
|
248
|
-
return withoutTrailingSlash(copilotBase(enterpriseUrl, settings));
|
|
249
|
-
}
|
|
250
|
-
function resolveTargetUrl(input, baseURL) {
|
|
251
|
-
const base = new URL(baseURL);
|
|
252
|
-
const parsed = /^https?:\/\//.test(input) ? new URL(input) : new URL(input, "https://copilot.invalid");
|
|
253
|
-
let pathname = parsed.pathname;
|
|
254
|
-
const basePath = withoutTrailingSlash(base.pathname);
|
|
255
|
-
if (basePath && pathname.startsWith(`${basePath}/`)) {
|
|
256
|
-
pathname = pathname.slice(basePath.length);
|
|
257
|
-
}
|
|
258
|
-
if (pathname === "/v1") {
|
|
259
|
-
pathname = "/";
|
|
260
|
-
} else if (pathname.startsWith("/v1/")) {
|
|
261
|
-
pathname = pathname.slice(3);
|
|
262
|
-
}
|
|
263
|
-
if (!pathname.startsWith("/")) {
|
|
264
|
-
pathname = `/${pathname}`;
|
|
265
|
-
}
|
|
266
|
-
return `${base.origin}${basePath}${pathname}${parsed.search}`;
|
|
267
|
-
}
|
|
268
|
-
function browserOrigin() {
|
|
269
|
-
const maybeWindow = globalThis.window;
|
|
270
|
-
return typeof maybeWindow?.location?.origin === "string" ? maybeWindow.location.origin.replace(/\/$/, "") : void 0;
|
|
271
|
-
}
|
|
272
|
-
function resolveBrowserProxyUrl(target, baseURL, settings) {
|
|
273
|
-
const origin = browserOrigin();
|
|
274
|
-
if (!origin || settings.browserProxyBaseUrl === false) {
|
|
275
|
-
return void 0;
|
|
276
|
-
}
|
|
277
|
-
const proxyBase = settings.browserProxyBaseUrl ?? DEFAULT_BROWSER_PROXY_BASE_URL;
|
|
278
|
-
const absoluteProxyBase = /^https?:\/\//.test(proxyBase) ? proxyBase.replace(/\/$/, "") : `${origin}${proxyBase.startsWith("/") ? "" : "/"}${proxyBase}`.replace(/\/$/, "");
|
|
279
|
-
const upstreamBasePath = withoutTrailingSlash(new URL(baseURL).pathname);
|
|
280
|
-
let pathname = target.pathname;
|
|
281
|
-
if (upstreamBasePath && pathname.startsWith(`${upstreamBasePath}/`)) {
|
|
282
|
-
pathname = pathname.slice(upstreamBasePath.length);
|
|
283
|
-
}
|
|
284
|
-
return `${absoluteProxyBase}${pathname}${target.search}`;
|
|
285
|
-
}
|
|
286
|
-
async function readRequestParts(input, init) {
|
|
287
|
-
if (input instanceof Request) {
|
|
288
|
-
const headers = new Headers(input.headers);
|
|
289
|
-
if (init?.headers) {
|
|
290
|
-
new Headers(init.headers).forEach((value, key) => headers.set(key, value));
|
|
291
|
-
}
|
|
292
|
-
return {
|
|
293
|
-
url: input.url,
|
|
294
|
-
method: init?.method ?? input.method,
|
|
295
|
-
headers,
|
|
296
|
-
body: init?.body ?? (input.body == null ? void 0 : await input.clone().text()),
|
|
297
|
-
signal: init?.signal ?? input.signal
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
return {
|
|
301
|
-
url: String(input),
|
|
302
|
-
method: init?.method,
|
|
303
|
-
headers: new Headers(init?.headers),
|
|
304
|
-
body: init?.body,
|
|
305
|
-
signal: init?.signal
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
async function bodyToText(body) {
|
|
309
|
-
if (body == null) return void 0;
|
|
310
|
-
if (typeof body === "string") return body;
|
|
311
|
-
if (body instanceof URLSearchParams) return body.toString();
|
|
312
|
-
if (body instanceof FormData || body instanceof ReadableStream) return void 0;
|
|
313
|
-
if (body instanceof Blob) return body.text();
|
|
314
|
-
if (body instanceof ArrayBuffer) return new TextDecoder().decode(body);
|
|
315
|
-
if (ArrayBuffer.isView(body)) return new TextDecoder().decode(body);
|
|
316
|
-
return void 0;
|
|
317
|
-
}
|
|
318
|
-
function hasVisionInput(body) {
|
|
319
|
-
if (!body.trim()) {
|
|
320
|
-
return false;
|
|
321
|
-
}
|
|
322
|
-
try {
|
|
323
|
-
const payload = JSON.parse(body);
|
|
324
|
-
const chatVision = payload.messages?.some(
|
|
325
|
-
(item) => Array.isArray(item.content) && item.content.some((part) => part?.type === "image_url")
|
|
326
|
-
);
|
|
327
|
-
if (chatVision) {
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
|
-
return Boolean(
|
|
331
|
-
payload.input?.some((item) => Array.isArray(item.content) && item.content.some((part) => part?.type === "input_image"))
|
|
332
|
-
);
|
|
333
|
-
} catch {
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
function applyHeaders(headers, authToken, pathname, bodyText, settings) {
|
|
338
|
-
const vision = settings.vision ?? (typeof bodyText === "string" && hasVisionInput(bodyText));
|
|
339
|
-
const authHeaders = pathname.endsWith("/models") ? copilotModelHeaders(authToken) : copilotHeaders(authToken, { vision, initiator: settings.initiator });
|
|
340
|
-
headers.delete("authorization");
|
|
341
|
-
for (const [key, value] of Object.entries(authHeaders)) {
|
|
342
|
-
headers.set(key, value);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
function createGitHubCopilotOAuthFetch(settings = {}) {
|
|
346
|
-
const fetch = pickFetch(settings.fetch);
|
|
347
|
-
const store = createStore(settings);
|
|
348
|
-
const manager = new TokenManager(settings, store, fetch);
|
|
349
|
-
return async (input, init) => {
|
|
350
|
-
const baseURL = await resolveBaseURL(settings);
|
|
351
|
-
const request = await readRequestParts(input, init);
|
|
352
|
-
const targetUrl = resolveTargetUrl(request.url, baseURL);
|
|
353
|
-
const target = new URL(targetUrl);
|
|
354
|
-
const bodyText = await bodyToText(request.body);
|
|
355
|
-
const body = bodyText ?? request.body;
|
|
356
|
-
const headers = new Headers(settings.headers);
|
|
357
|
-
request.headers.forEach((value, key) => headers.set(key, value));
|
|
358
|
-
const proxyUrl = resolveBrowserProxyUrl(target, baseURL, settings);
|
|
359
|
-
if (proxyUrl) {
|
|
360
|
-
headers.delete("authorization");
|
|
361
|
-
headers.set("Authorization", `Bearer ${await manager.githubToken()}`);
|
|
362
|
-
const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl;
|
|
363
|
-
if (enterpriseUrl) headers.set("x-copilot-enterprise-url", enterpriseUrl);
|
|
364
|
-
return fetch(proxyUrl, {
|
|
365
|
-
method: request.method ?? init?.method,
|
|
366
|
-
headers,
|
|
367
|
-
body,
|
|
368
|
-
signal: request.signal ?? void 0
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
const token = await manager.token();
|
|
372
|
-
applyHeaders(headers, token.token, target.pathname, bodyText, settings);
|
|
373
|
-
const response = await fetch(target.toString(), {
|
|
374
|
-
method: request.method ?? init?.method,
|
|
375
|
-
headers,
|
|
376
|
-
body,
|
|
377
|
-
signal: request.signal ?? void 0
|
|
378
|
-
});
|
|
379
|
-
if (token.fromExchange && settings.fallbackToGitHubToken !== false && (response.status === 401 || response.status === 403)) {
|
|
380
|
-
const fallbackHeaders = new Headers(headers);
|
|
381
|
-
applyHeaders(fallbackHeaders, await manager.githubToken(), target.pathname, bodyText, settings);
|
|
382
|
-
return fetch(target.toString(), {
|
|
383
|
-
method: request.method ?? init?.method,
|
|
384
|
-
headers: fallbackHeaders,
|
|
385
|
-
body,
|
|
386
|
-
signal: request.signal ?? void 0
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
return response;
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
async function createGitHubCopilotClient(settings = {}) {
|
|
393
|
-
const baseURL = await resolveBaseURL(settings);
|
|
394
|
-
const fetch = createGitHubCopilotOAuthFetch(settings);
|
|
395
|
-
return {
|
|
396
|
-
baseURL,
|
|
397
|
-
fetch,
|
|
398
|
-
request: (path, init) => fetch(resolveTargetUrl(path, baseURL), init)
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
function isCopilotResponsesModel(modelId) {
|
|
402
|
-
const normalized = modelId.toLowerCase();
|
|
403
|
-
const match = /^gpt-(\d+)/.exec(normalized);
|
|
404
|
-
if (!match) {
|
|
405
|
-
return false;
|
|
406
|
-
}
|
|
407
|
-
const generation = Number(match[1]);
|
|
408
|
-
return generation >= 5 && !normalized.startsWith("gpt-5-mini");
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// src/device-flow.ts
|
|
412
|
-
var DEFAULT_GITHUB_COPILOT_CLIENT_ID = "Ov23li8tweQw6odWQebz";
|
|
413
|
-
var POLL_BUFFER_MS = 3e3;
|
|
414
|
-
function pickFetch2(customFetch) {
|
|
415
|
-
if (typeof customFetch === "function") {
|
|
416
|
-
return customFetch;
|
|
417
|
-
}
|
|
418
|
-
if (typeof globalThis.fetch === "function") {
|
|
419
|
-
return globalThis.fetch.bind(globalThis);
|
|
420
|
-
}
|
|
421
|
-
throw new GitHubCopilotOAuthError("fetch_required", "A fetch implementation is required for GitHub Copilot OAuth.");
|
|
422
|
-
}
|
|
423
|
-
async function startGitHubCopilotDeviceFlow(options = {}) {
|
|
424
|
-
const fetch = pickFetch2(options.fetch);
|
|
425
|
-
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
426
|
-
const clientId = options.clientId ?? DEFAULT_GITHUB_COPILOT_CLIENT_ID;
|
|
427
|
-
const urls = githubOAuthUrls(options.enterpriseUrl, { allowEnterprise: options.allowEnterprise });
|
|
428
|
-
const codeResponse = await fetch(urls.code, {
|
|
429
|
-
method: "POST",
|
|
430
|
-
headers: {
|
|
431
|
-
Accept: "application/json",
|
|
432
|
-
"Content-Type": "application/json"
|
|
433
|
-
},
|
|
434
|
-
body: JSON.stringify({
|
|
435
|
-
client_id: clientId,
|
|
436
|
-
scope: "read:user"
|
|
437
|
-
})
|
|
438
|
-
});
|
|
439
|
-
if (!codeResponse.ok) {
|
|
440
|
-
throw new GitHubCopilotOAuthError("auth_failed", "Failed to initiate GitHub Copilot authorization.");
|
|
441
|
-
}
|
|
442
|
-
const code = await codeResponse.json();
|
|
443
|
-
if (!code.verification_uri || !code.user_code || !code.device_code) {
|
|
444
|
-
throw new GitHubCopilotOAuthError("auth_failed", "GitHub Copilot authorization response did not include a device code.");
|
|
445
|
-
}
|
|
446
|
-
return {
|
|
447
|
-
providerId: "github-copilot",
|
|
448
|
-
url: code.verification_uri,
|
|
449
|
-
code: code.user_code,
|
|
450
|
-
instructions: `Enter code: ${code.user_code}`,
|
|
451
|
-
async complete() {
|
|
452
|
-
while (true) {
|
|
453
|
-
const tokenResponse = await fetch(urls.token, {
|
|
454
|
-
method: "POST",
|
|
455
|
-
headers: {
|
|
456
|
-
Accept: "application/json",
|
|
457
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
458
|
-
},
|
|
459
|
-
body: new URLSearchParams({
|
|
460
|
-
client_id: clientId,
|
|
461
|
-
device_code: code.device_code ?? "",
|
|
462
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
463
|
-
}).toString()
|
|
464
|
-
});
|
|
465
|
-
if (!tokenResponse.ok) {
|
|
466
|
-
throw new GitHubCopilotOAuthError("auth_failed", "GitHub Copilot OAuth authorization failed.");
|
|
467
|
-
}
|
|
468
|
-
const token = await tokenResponse.json();
|
|
469
|
-
if (token.access_token) {
|
|
470
|
-
const result = {
|
|
471
|
-
githubToken: token.access_token,
|
|
472
|
-
...urls.domain === "github.com" ? {} : { enterpriseUrl: urls.domain }
|
|
473
|
-
};
|
|
474
|
-
await options.tokenStore?.save(result);
|
|
475
|
-
return result;
|
|
476
|
-
}
|
|
477
|
-
if (token.error === "authorization_pending") {
|
|
478
|
-
await sleep((code.interval ?? 5) * 1e3 + POLL_BUFFER_MS);
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
if (token.error === "slow_down") {
|
|
482
|
-
const nextInterval = token.interval && token.interval > 0 ? token.interval : (code.interval ?? 5) + 5;
|
|
483
|
-
await sleep(nextInterval * 1e3 + POLL_BUFFER_MS);
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
throw new GitHubCopilotOAuthError("auth_failed", "GitHub Copilot OAuth authorization failed.");
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
export {
|
|
493
|
-
GitHubCopilotOAuthError,
|
|
494
|
-
normalizeEnterpriseDomain,
|
|
495
|
-
copilotBase,
|
|
496
|
-
copilotTokenExchangeUrl,
|
|
497
|
-
githubOAuthUrls,
|
|
498
|
-
COPILOT_HEADERS,
|
|
499
|
-
copilotHeaders,
|
|
500
|
-
copilotModelHeaders,
|
|
501
|
-
copilotTokenExchangeHeaders,
|
|
502
|
-
createMemoryTokenStore,
|
|
503
|
-
exchangeGitHubCopilotToken,
|
|
504
|
-
hasVisionInput,
|
|
505
|
-
createGitHubCopilotOAuthFetch,
|
|
506
|
-
createGitHubCopilotClient,
|
|
507
|
-
isCopilotResponsesModel,
|
|
508
|
-
DEFAULT_GITHUB_COPILOT_CLIENT_ID,
|
|
509
|
-
startGitHubCopilotDeviceFlow
|
|
510
|
-
};
|
|
511
|
-
//# sourceMappingURL=chunk-CUD4IYWR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/enterprise.ts","../src/headers.ts","../src/memory-token-store.ts","../src/token-exchange.ts","../src/copilot-fetch.ts","../src/device-flow.ts"],"sourcesContent":["export type FetchLike = typeof globalThis.fetch;\r\n\r\n/** GitHub OAuth credentials plus optional short-lived Copilot API token. Treat these as account credentials. */\r\nexport type GitHubCopilotOAuthTokens = {\r\n /** GitHub OAuth access token returned by the device flow. Used to mint Copilot API tokens. */\r\n githubToken: string;\r\n /** Short-lived token returned by GitHub's Copilot token exchange endpoint. */\r\n copilotToken?: string;\r\n /** Copilot API token expiry as epoch milliseconds. */\r\n copilotTokenExpiresAt?: number;\r\n /** Optional validated GitHub Enterprise hostname. Omitted for github.com. */\r\n enterpriseUrl?: string;\r\n};\r\n\r\n/** Async storage interface for loading and persisting GitHub Copilot OAuth credentials. */\r\nexport type TokenStore = {\r\n /** Load the latest credentials. Return `undefined` when the user is not signed in. */\r\n load(): Promise<GitHubCopilotOAuthTokens | undefined>;\r\n /** Persist credentials after sign-in or Copilot token exchange. */\r\n save(tokens: GitHubCopilotOAuthTokens): Promise<void>;\r\n};\r\n\r\n/** In-progress GitHub Copilot device authorization flow. */\r\nexport type GitHubCopilotDeviceFlow = {\r\n providerId: 'github-copilot';\r\n /** URL the user should open to authorize the device flow. */\r\n url: string;\r\n /** User code to enter on the authorization page. */\r\n code: string;\r\n /** Human-readable instruction string for command-line or app UI. */\r\n instructions: string;\r\n /** Poll until authorization completes and return GitHub OAuth credentials. */\r\n complete(): Promise<GitHubCopilotOAuthTokens>;\r\n};\r\n\r\n/** Options for starting GitHub Copilot's device OAuth flow. */\r\nexport type GitHubCopilotDeviceFlowOptions = {\r\n /** Custom fetch implementation, useful for tests and non-standard runtimes. */\r\n fetch?: FetchLike;\r\n /** Sleep override used between polling attempts. */\r\n sleep?: (ms: number) => Promise<void>;\r\n /** OAuth client id. Defaults to the GitHub Copilot Chat client id. */\r\n clientId?: string;\r\n /** Optional GitHub Enterprise hostname. Custom hosts require `allowEnterprise: true`. */\r\n enterpriseUrl?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n /** Optional store that receives credentials after successful authorization. */\r\n tokenStore?: TokenStore;\r\n};\r\n\r\n/** Shared settings for Copilot fetch and AI SDK provider creation. */\r\nexport type GitHubCopilotOAuthSettings = {\r\n /** Custom fetch implementation for both token exchange and Copilot API requests. */\r\n fetch?: FetchLike;\r\n /** Secure token storage used to load and save exchanged Copilot tokens. */\r\n tokenStore?: TokenStore;\r\n /** Inline tokens for scripts/tests. Prefer `tokenStore` for production apps. */\r\n tokens?: GitHubCopilotOAuthTokens;\r\n /** Optional GitHub Enterprise hostname. Custom hosts require `allowEnterprise: true`. */\r\n enterpriseUrl?: string;\r\n /** Allow validated custom GitHub Enterprise hostnames. Defaults to false. */\r\n allowEnterprise?: boolean;\r\n /** Copilot API base URL override. Defaults to GitHub's public Copilot API. */\r\n baseURL?: string;\r\n /** Browser proxy base URL for Copilot API requests. Defaults to `/api/proxy/github-copilot` in browsers. Pass `false` to disable. */\r\n browserProxyBaseUrl?: string | false;\r\n /** Additional headers sent to the Copilot API before Copilot auth headers are applied. */\r\n headers?: Record<string, string>;\r\n /** `X-Initiator` header. Defaults to `user`. */\r\n initiator?: CopilotInitiator;\r\n /** Force `Copilot-Vision-Request` on or off. When omitted, image inputs are detected from JSON bodies. */\r\n vision?: boolean;\r\n /** Refresh Copilot API token this many milliseconds before expiry. */\r\n tokenRefreshMarginMs?: number;\r\n /** Allow fallback to the GitHub OAuth token if Copilot token exchange fails or gets 401/403. Defaults to true. */\r\n fallbackToGitHubToken?: boolean;\r\n /** Called after a successful Copilot token exchange. */\r\n onTokens?: (tokens: GitHubCopilotOAuthTokens) => void | Promise<void>;\r\n};\r\n\r\n/** Settings for the AI SDK provider factory. */\r\nexport type GitHubCopilotProviderSettings = GitHubCopilotOAuthSettings & {\r\n /** Provider name exposed to AI SDK telemetry and metadata. */\r\n name?: string;\r\n};\r\n\r\nexport type CopilotInitiator = 'user' | 'agent';\r\n\r\n/** Error class used for OAuth, token, and credential setup failures. */\r\nexport class GitHubCopilotOAuthError extends Error {\r\n readonly code: string;\r\n\r\n constructor(code: string, message: string, options?: ErrorOptions) {\r\n super(message, options);\r\n this.name = 'GitHubCopilotOAuthError';\r\n this.code = code;\r\n }\r\n}\r\n","import { GitHubCopilotOAuthError } from './types';\r\n\r\n/** Normalize and validate a GitHub Enterprise hostname. Returns undefined for github.com. */\r\nexport function normalizeEnterpriseDomain(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string | undefined {\r\n const value = enterpriseUrl?.trim();\r\n if (!value) {\r\n return undefined;\r\n }\r\n\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(/^https?:\\/\\//i.test(value) ? value : `https://${value}`);\r\n } catch (error) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Invalid GitHub Enterprise URL.', { cause: error });\r\n }\r\n\r\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Invalid GitHub Enterprise URL protocol.');\r\n }\r\n\r\n if (parsed.username || parsed.password || parsed.port || parsed.pathname !== '/' || parsed.search || parsed.hash) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'GitHub Enterprise URL must be a hostname only.');\r\n }\r\n\r\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\r\n if (!hostname || isUnsafeEnterpriseHostname(hostname)) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Unsafe GitHub Enterprise hostname.');\r\n }\r\n\r\n if (hostname === 'github.com') {\r\n return undefined;\r\n }\r\n\r\n if (!options.allowEnterprise) {\r\n throw new GitHubCopilotOAuthError('unsupported', 'Custom GitHub Enterprise hosts are not enabled.');\r\n }\r\n\r\n return hostname;\r\n}\r\n\r\n// Blocks hostnames that could resolve to local development environments or be confused\r\n// with loopback addresses. Prevents SSRF and local network access attacks.\r\nfunction isUnsafeEnterpriseHostname(hostname: string): boolean {\r\n return (\r\n hostname === 'localhost' ||\r\n hostname.endsWith('.localhost') ||\r\n hostname.endsWith('.local') ||\r\n hostname.includes(':') ||\r\n /^\\d+(?:\\.\\d+){3}$/.test(hostname)\r\n );\r\n}\r\n\r\n/** Resolve the Copilot API base URL for github.com or a validated Enterprise hostname. */\r\nexport function copilotBase(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options);\r\n if (!domain) {\r\n return 'https://api.githubcopilot.com';\r\n }\r\n\r\n return `https://copilot-api.${domain}`;\r\n}\r\n\r\n/** Resolve the GitHub endpoint used to exchange OAuth tokens for Copilot API tokens. */\r\nexport function copilotTokenExchangeUrl(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}): string {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options);\r\n if (!domain) {\r\n return 'https://api.github.com/copilot_internal/v2/token';\r\n }\r\n\r\n return `https://api.${domain}/copilot_internal/v2/token`;\r\n}\r\n\r\n/** Resolve the GitHub device OAuth endpoints for github.com or Enterprise. */\r\nexport function githubOAuthUrls(enterpriseUrl?: string, options: { allowEnterprise?: boolean } = {}) {\r\n const domain = normalizeEnterpriseDomain(enterpriseUrl, options) ?? 'github.com';\r\n return {\r\n domain,\r\n code: `https://${domain}/login/device/code`,\r\n token: `https://${domain}/login/oauth/access_token`,\r\n };\r\n}\r\n","import type { CopilotInitiator } from './types';\r\n\r\nexport const COPILOT_HEADERS = {\r\n 'User-Agent': 'GitHubCopilotChat/0.35.0',\r\n 'Editor-Version': 'vscode/1.107.0',\r\n 'Editor-Plugin-Version': 'copilot-chat/0.35.0',\r\n 'Copilot-Integration-Id': 'vscode-chat',\r\n} as const;\r\n\r\n/** Build headers for Copilot chat/completions and responses requests. */\r\nexport function copilotHeaders(accessToken: string, options?: { vision?: boolean; initiator?: CopilotInitiator }) {\r\n return {\r\n ...COPILOT_HEADERS,\r\n Authorization: `Bearer ${accessToken}`,\r\n 'Openai-Intent': 'conversation-edits',\r\n 'X-Initiator': options?.initiator ?? 'user',\r\n ...(options?.vision ? { 'Copilot-Vision-Request': 'true' } : {}),\r\n };\r\n}\r\n\r\n/** Build headers for Copilot model-list requests. */\r\nexport function copilotModelHeaders(accessToken: string) {\r\n return {\r\n ...COPILOT_HEADERS,\r\n Authorization: `Bearer ${accessToken}`,\r\n };\r\n}\r\n\r\n/** Build headers for GitHub's Copilot token exchange endpoint. */\r\nexport function copilotTokenExchangeHeaders(githubToken: string) {\r\n return {\r\n Accept: 'application/json',\r\n Authorization: `Bearer ${githubToken}`,\r\n ...COPILOT_HEADERS,\r\n };\r\n}\r\n","import type { GitHubCopilotOAuthTokens, TokenStore } from './types';\r\n\r\n/**\r\n * Create an in-memory token store.\r\n *\r\n * This is useful for tests and short-lived scripts. It does not persist tokens\r\n * across process restarts.\r\n */\r\nexport function createMemoryTokenStore(initial?: GitHubCopilotOAuthTokens): TokenStore {\r\n let current = initial;\r\n\r\n return {\r\n async load() {\r\n return current;\r\n },\r\n async save(tokens) {\r\n current = tokens;\r\n },\r\n };\r\n}\r\n","import { copilotTokenExchangeUrl } from './enterprise';\r\nimport { copilotTokenExchangeHeaders } from './headers';\r\nimport type { FetchLike } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\n/** Exchange a GitHub OAuth token for a short-lived GitHub Copilot API token. */\r\nexport async function exchangeGitHubCopilotToken({\r\n fetch,\r\n githubToken,\r\n enterpriseUrl,\r\n allowEnterprise,\r\n}: {\r\n fetch: FetchLike;\r\n githubToken: string;\r\n enterpriseUrl?: string;\r\n allowEnterprise?: boolean;\r\n}): Promise<{ token: string; expiresAt: number }> {\r\n const response = await fetch(copilotTokenExchangeUrl(enterpriseUrl, { allowEnterprise }), {\r\n headers: copilotTokenExchangeHeaders(githubToken),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new GitHubCopilotOAuthError(\r\n 'auth_failed',\r\n `GitHub Copilot token exchange failed (${response.status}).`,\r\n );\r\n }\r\n\r\n const payload = (await response.json()) as {\r\n token?: number | string;\r\n expires_at?: number;\r\n };\r\n\r\n if (typeof payload.token !== 'string' || !payload.token.trim()) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot token exchange did not return a token.');\r\n }\r\n\r\n if (typeof payload.expires_at !== 'number' || !Number.isFinite(payload.expires_at) || payload.expires_at <= 0) {\r\n throw new GitHubCopilotOAuthError(\r\n 'auth_failed',\r\n 'GitHub Copilot token exchange did not return a valid expiration.',\r\n );\r\n }\r\n\r\n return {\r\n token: payload.token,\r\n expiresAt: payload.expires_at * 1000,\r\n };\r\n}\r\n","import { copilotBase } from './enterprise';\r\nimport { copilotHeaders, copilotModelHeaders } from './headers';\r\nimport { createMemoryTokenStore } from './memory-token-store';\r\nimport { exchangeGitHubCopilotToken } from './token-exchange';\r\nimport type { FetchLike, GitHubCopilotOAuthSettings, GitHubCopilotOAuthTokens, TokenStore } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\nconst DEFAULT_REFRESH_MARGIN_MS = 60 * 1000;\r\nconst DEFAULT_BROWSER_PROXY_BASE_URL = '/api/proxy/github-copilot';\r\n\r\ntype RequestParts = {\r\n url: string;\r\n method?: string;\r\n headers: Headers;\r\n body?: BodyInit | null;\r\n signal?: AbortSignal | null;\r\n};\r\n\r\n// Resolves fetch with fallback: custom override > globalThis.fetch > error.\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') {\r\n return customFetch;\r\n }\r\n\r\n if (typeof globalThis.fetch === 'function') {\r\n return globalThis.fetch.bind(globalThis);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot OAuth.');\r\n}\r\n\r\nfunction withoutTrailingSlash(value: string): string {\r\n return value.replace(/\\/$/, '');\r\n}\r\n\r\nfunction createStore(settings: GitHubCopilotOAuthSettings): TokenStore {\r\n if (settings.tokenStore) {\r\n return settings.tokenStore;\r\n }\r\n\r\n if (settings.tokens) {\r\n return createMemoryTokenStore(settings.tokens);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError(\r\n 'tokens_required',\r\n 'GitHub Copilot OAuth tokens are required. Pass `tokens` or `tokenStore`.',\r\n );\r\n}\r\n\r\nclass TokenManager {\r\n private inflight?: Promise<{ token: string; fromExchange: boolean }>;\r\n private current?: GitHubCopilotOAuthTokens;\r\n\r\n constructor(\r\n private readonly settings: GitHubCopilotOAuthSettings,\r\n private readonly store: TokenStore,\r\n private readonly fetch: FetchLike,\r\n ) {}\r\n\r\n async token(): Promise<{ token: string; fromExchange: boolean }> {\r\n if (this.inflight) {\r\n return this.inflight;\r\n }\r\n\r\n this.inflight = this.loadToken()\r\n .finally(() => {\r\n this.inflight = undefined;\r\n });\r\n return this.inflight;\r\n }\r\n\r\n async githubToken(): Promise<string> {\r\n const tokens = this.current ?? (await this.store.load());\r\n if (!tokens?.githubToken) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth token is missing.');\r\n }\r\n\r\n this.current = tokens;\r\n return tokens.githubToken;\r\n }\r\n\r\n private async loadToken(): Promise<{ token: string; fromExchange: boolean }> {\r\n let tokens = this.current ?? (await this.store.load());\r\n if (!tokens?.githubToken) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth token is missing.');\r\n }\r\n\r\n this.current = tokens;\r\n const margin = this.settings.tokenRefreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS;\r\n const expiresAt = tokens.copilotTokenExpiresAt ?? 0;\r\n if (tokens.copilotToken && (expiresAt <= 0 || expiresAt > Date.now() + margin)) {\r\n return { token: tokens.copilotToken, fromExchange: true };\r\n }\r\n\r\n try {\r\n const exchanged = await exchangeGitHubCopilotToken({\r\n fetch: this.fetch,\r\n githubToken: tokens.githubToken,\r\n enterpriseUrl: this.settings.enterpriseUrl ?? tokens.enterpriseUrl,\r\n allowEnterprise: this.settings.allowEnterprise,\r\n });\r\n tokens = {\r\n ...tokens,\r\n copilotToken: exchanged.token,\r\n copilotTokenExpiresAt: exchanged.expiresAt,\r\n };\r\n this.current = tokens;\r\n await this.store.save(tokens);\r\n await this.settings.onTokens?.(tokens);\r\n return { token: exchanged.token, fromExchange: true };\r\n } catch (error) {\r\n if (this.settings.fallbackToGitHubToken === false) {\r\n throw error;\r\n }\r\n\r\n return { token: tokens.githubToken, fromExchange: false };\r\n }\r\n }\r\n}\r\n\r\nasync function readStoredTokens(settings: GitHubCopilotOAuthSettings): Promise<GitHubCopilotOAuthTokens | undefined> {\r\n if (settings.tokens) {\r\n return settings.tokens;\r\n }\r\n\r\n const tokenStore = settings.tokenStore as (TokenStore & {\r\n getTokens?: () => Promise<GitHubCopilotOAuthTokens | undefined>;\r\n }) | undefined;\r\n\r\n if (typeof tokenStore?.getTokens === 'function') {\r\n return tokenStore.getTokens();\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nasync function resolveBaseURL(settings: GitHubCopilotOAuthSettings): Promise<string> {\r\n if (settings.baseURL) {\r\n return withoutTrailingSlash(settings.baseURL);\r\n }\r\n\r\n const storedTokens = await readStoredTokens(settings);\r\n const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl ?? storedTokens?.enterpriseUrl;\r\n\r\n return withoutTrailingSlash(copilotBase(enterpriseUrl, settings));\r\n}\r\n\r\n// Normalizes an incoming OpenAI-compatible URL against a base URL.\r\n// Strips /v1 prefix to map to Copilot API paths while preserving query strings.\r\nfunction resolveTargetUrl(input: string, baseURL: string): string {\r\n const base = new URL(baseURL);\r\n const parsed = /^https?:\\/\\//.test(input) ? new URL(input) : new URL(input, 'https://copilot.invalid');\r\n let pathname = parsed.pathname;\r\n const basePath = withoutTrailingSlash(base.pathname);\r\n\r\n if (basePath && pathname.startsWith(`${basePath}/`)) {\r\n pathname = pathname.slice(basePath.length);\r\n }\r\n\r\n if (pathname === '/v1') {\r\n pathname = '/';\r\n } else if (pathname.startsWith('/v1/')) {\r\n pathname = pathname.slice(3);\r\n }\r\n\r\n if (!pathname.startsWith('/')) {\r\n pathname = `/${pathname}`;\r\n }\r\n\r\n return `${base.origin}${basePath}${pathname}${parsed.search}`;\r\n}\r\n\r\nfunction browserOrigin(): string | undefined {\r\n const maybeWindow = (globalThis as { window?: { location?: { origin?: string } } }).window;\r\n return typeof maybeWindow?.location?.origin === 'string' ? maybeWindow.location.origin.replace(/\\/$/, '') : undefined;\r\n}\r\n\r\n// Resolves a browser proxy URL for Copilot API requests. Returns undefined in Node.js\r\n// or when browser proxy is disabled. Strips the upstream base path so proxy can route correctly.\r\nfunction resolveBrowserProxyUrl(target: URL, baseURL: string, settings: GitHubCopilotOAuthSettings): string | undefined {\r\n const origin = browserOrigin();\r\n if (!origin || settings.browserProxyBaseUrl === false) {\r\n return undefined;\r\n }\r\n\r\n const proxyBase = settings.browserProxyBaseUrl ?? DEFAULT_BROWSER_PROXY_BASE_URL;\r\n const absoluteProxyBase = /^https?:\\/\\//.test(proxyBase) ? proxyBase.replace(/\\/$/, '') : `${origin}${proxyBase.startsWith('/') ? '' : '/'}${proxyBase}`.replace(/\\/$/, '');\r\n const upstreamBasePath = withoutTrailingSlash(new URL(baseURL).pathname);\r\n let pathname = target.pathname;\r\n\r\n if (upstreamBasePath && pathname.startsWith(`${upstreamBasePath}/`)) {\r\n pathname = pathname.slice(upstreamBasePath.length);\r\n }\r\n\r\n return `${absoluteProxyBase}${pathname}${target.search}`;\r\n}\r\n\r\nasync function readRequestParts(input: Parameters<FetchLike>[0], init?: Parameters<FetchLike>[1]): Promise<RequestParts> {\r\n if (input instanceof Request) {\r\n const headers = new Headers(input.headers);\r\n if (init?.headers) {\r\n new Headers(init.headers).forEach((value, key) => headers.set(key, value));\r\n }\r\n\r\n return {\r\n url: input.url,\r\n method: init?.method ?? input.method,\r\n headers,\r\n body: init?.body ?? (input.body == null ? undefined : await input.clone().text()),\r\n signal: init?.signal ?? input.signal,\r\n };\r\n }\r\n\r\n return {\r\n url: String(input),\r\n method: init?.method,\r\n headers: new Headers(init?.headers),\r\n body: init?.body,\r\n signal: init?.signal,\r\n };\r\n}\r\n\r\nasync function bodyToText(body: BodyInit | null | undefined): Promise<string | undefined> {\r\n if (body == null) return undefined;\r\n if (typeof body === 'string') return body;\r\n if (body instanceof URLSearchParams) return body.toString();\r\n if (body instanceof FormData || body instanceof ReadableStream) return undefined;\r\n if (body instanceof Blob) return body.text();\r\n if (body instanceof ArrayBuffer) return new TextDecoder().decode(body);\r\n if (ArrayBuffer.isView(body)) return new TextDecoder().decode(body);\r\n return undefined;\r\n}\r\n\r\n/** Return true when a chat/completions or responses JSON body contains image input. */\r\nexport function hasVisionInput(body: string): boolean {\r\n if (!body.trim()) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload = JSON.parse(body) as {\r\n messages?: { content?: { type?: string }[] }[];\r\n input?: { content?: { type?: string }[] }[];\r\n };\r\n\r\n const chatVision = payload.messages?.some(\r\n (item) => Array.isArray(item.content) && item.content.some((part) => part?.type === 'image_url'),\r\n );\r\n if (chatVision) {\r\n return true;\r\n }\r\n\r\n return Boolean(\r\n payload.input?.some((item) => Array.isArray(item.content) && item.content.some((part) => part?.type === 'input_image')),\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Applies Copilot-specific headers. Detects vision capability from request body\r\n// unless explicitly configured. Uses model headers for /models, chat headers otherwise.\r\nfunction applyHeaders(headers: Headers, authToken: string, pathname: string, bodyText: string | undefined, settings: GitHubCopilotOAuthSettings) {\r\n const vision = settings.vision ?? (typeof bodyText === 'string' && hasVisionInput(bodyText));\r\n const authHeaders = pathname.endsWith('/models')\r\n ? copilotModelHeaders(authToken)\r\n : copilotHeaders(authToken, { vision, initiator: settings.initiator });\r\n\r\n headers.delete('authorization');\r\n for (const [key, value] of Object.entries(authHeaders)) {\r\n headers.set(key, value);\r\n }\r\n}\r\n\r\n/**\r\n * Create a fetch implementation that authenticates OpenAI-compatible requests\r\n * with GitHub Copilot OAuth credentials.\r\n */\r\nexport function createGitHubCopilotOAuthFetch(settings: GitHubCopilotOAuthSettings = {}): FetchLike {\r\n const fetch = pickFetch(settings.fetch);\r\n const store = createStore(settings);\r\n const manager = new TokenManager(settings, store, fetch);\r\n\r\n return async (input, init) => {\r\n const baseURL = await resolveBaseURL(settings);\r\n const request = await readRequestParts(input, init);\r\n const targetUrl = resolveTargetUrl(request.url, baseURL);\r\n const target = new URL(targetUrl);\r\n const bodyText = await bodyToText(request.body);\r\n const body = bodyText ?? request.body;\r\n const headers = new Headers(settings.headers);\r\n\r\n request.headers.forEach((value, key) => headers.set(key, value));\r\n const proxyUrl = resolveBrowserProxyUrl(target, baseURL, settings);\r\n if (proxyUrl) {\r\n headers.delete('authorization');\r\n headers.set('Authorization', `Bearer ${await manager.githubToken()}`);\r\n const enterpriseUrl = settings.enterpriseUrl ?? settings.tokens?.enterpriseUrl;\r\n if (enterpriseUrl) headers.set('x-copilot-enterprise-url', enterpriseUrl);\r\n return fetch(proxyUrl, {\r\n method: request.method ?? init?.method,\r\n headers,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n }\r\n\r\n const token = await manager.token();\r\n applyHeaders(headers, token.token, target.pathname, bodyText, settings);\r\n\r\n const response = await fetch(target.toString(), {\r\n method: request.method ?? init?.method,\r\n headers,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n\r\n if (token.fromExchange && settings.fallbackToGitHubToken !== false && (response.status === 401 || response.status === 403)) {\r\n const fallbackHeaders = new Headers(headers);\r\n applyHeaders(fallbackHeaders, await manager.githubToken(), target.pathname, bodyText, settings);\r\n return fetch(target.toString(), {\r\n method: request.method ?? init?.method,\r\n headers: fallbackHeaders,\r\n body,\r\n signal: request.signal ?? undefined,\r\n });\r\n }\r\n\r\n return response;\r\n };\r\n}\r\n\r\n/** Create a small Copilot client around `createGitHubCopilotOAuthFetch`. */\r\nexport async function createGitHubCopilotClient(settings: GitHubCopilotOAuthSettings = {}) {\r\n const baseURL = await resolveBaseURL(settings);\r\n const fetch = createGitHubCopilotOAuthFetch(settings);\r\n\r\n return {\r\n baseURL,\r\n fetch,\r\n request: (path: string, init?: RequestInit) => fetch(resolveTargetUrl(path, baseURL), init),\r\n };\r\n}\r\n\r\n/** Route GPT-5 non-mini models to Copilot's Responses endpoint. */\r\nexport function isCopilotResponsesModel(modelId: string): boolean {\r\n const normalized = modelId.toLowerCase();\r\n const match = /^gpt-(\\d+)/.exec(normalized);\r\n if (!match) {\r\n return false;\r\n }\r\n\r\n const generation = Number(match[1]);\r\n return generation >= 5 && !normalized.startsWith('gpt-5-mini');\r\n}\r\n","import { githubOAuthUrls } from './enterprise';\r\nimport type { FetchLike, GitHubCopilotDeviceFlow, GitHubCopilotDeviceFlowOptions, GitHubCopilotOAuthTokens } from './types';\r\nimport { GitHubCopilotOAuthError } from './types';\r\n\r\nexport const DEFAULT_GITHUB_COPILOT_CLIENT_ID = 'Ov23li8tweQw6odWQebz';\r\n// Adds buffer to server-provided interval to avoid race condition on slow responses.\r\nconst POLL_BUFFER_MS = 3000;\r\n\r\nfunction pickFetch(customFetch?: FetchLike): FetchLike {\r\n if (typeof customFetch === 'function') {\r\n return customFetch;\r\n }\r\n\r\n if (typeof globalThis.fetch === 'function') {\r\n return globalThis.fetch.bind(globalThis);\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('fetch_required', 'A fetch implementation is required for GitHub Copilot OAuth.');\r\n}\r\n\r\n/**\r\n * Start GitHub Copilot's device OAuth flow.\r\n *\r\n * The returned flow contains a URL and user code for authorization. Call\r\n * `flow.complete()` after showing those values to poll for authorization and\r\n * return the GitHub OAuth token used to mint Copilot API tokens.\r\n */\r\nexport async function startGitHubCopilotDeviceFlow(\r\n options: GitHubCopilotDeviceFlowOptions = {},\r\n): Promise<GitHubCopilotDeviceFlow> {\r\n const fetch = pickFetch(options.fetch);\r\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\r\n const clientId = options.clientId ?? DEFAULT_GITHUB_COPILOT_CLIENT_ID;\r\n const urls = githubOAuthUrls(options.enterpriseUrl, { allowEnterprise: options.allowEnterprise });\r\n\r\n const codeResponse = await fetch(urls.code, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n client_id: clientId,\r\n scope: 'read:user',\r\n }),\r\n });\r\n\r\n if (!codeResponse.ok) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'Failed to initiate GitHub Copilot authorization.');\r\n }\r\n\r\n const code = (await codeResponse.json()) as {\r\n verification_uri?: string;\r\n user_code?: string;\r\n device_code?: string;\r\n interval?: number;\r\n };\r\n\r\n if (!code.verification_uri || !code.user_code || !code.device_code) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot authorization response did not include a device code.');\r\n }\r\n\r\n return {\r\n providerId: 'github-copilot',\r\n url: code.verification_uri,\r\n code: code.user_code,\r\n instructions: `Enter code: ${code.user_code}`,\r\n async complete() {\r\n while (true) {\r\n const tokenResponse = await fetch(urls.token, {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n },\r\n body: new URLSearchParams({\r\n client_id: clientId,\r\n device_code: code.device_code ?? '',\r\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\r\n }).toString(),\r\n });\r\n\r\n if (!tokenResponse.ok) {\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth authorization failed.');\r\n }\r\n\r\n const token = (await tokenResponse.json()) as {\r\n access_token?: string;\r\n error?: string;\r\n interval?: number;\r\n };\r\n\r\n if (token.access_token) {\r\n const result: GitHubCopilotOAuthTokens = {\r\n githubToken: token.access_token,\r\n ...(urls.domain === 'github.com' ? {} : { enterpriseUrl: urls.domain }),\r\n };\r\n await options.tokenStore?.save(result);\r\n return result;\r\n }\r\n\r\n if (token.error === 'authorization_pending') {\r\n await sleep((code.interval ?? 5) * 1000 + POLL_BUFFER_MS);\r\n continue;\r\n }\r\n\r\n if (token.error === 'slow_down') {\r\n const nextInterval = token.interval && token.interval > 0 ? token.interval : (code.interval ?? 5) + 5;\r\n await sleep(nextInterval * 1000 + POLL_BUFFER_MS);\r\n continue;\r\n }\r\n\r\n throw new GitHubCopilotOAuthError('auth_failed', 'GitHub Copilot OAuth authorization failed.');\r\n }\r\n },\r\n };\r\n}\r\n"],"mappings":"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","names":["pickFetch"]}
|