@jeffreycao/copilot-api 2.6.26 → 2.6.29
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/auth-B4LfP6nc.js +2 -0
- package/dist/{auth-BUdtezdW.js → auth-CmKD_Gmp.js} +2 -2
- package/dist/{auth-BUdtezdW.js.map → auth-CmKD_Gmp.js.map} +1 -1
- package/dist/copilot-runtime-B4x9RzsD.js +384 -0
- package/dist/copilot-runtime-B4x9RzsD.js.map +1 -0
- package/dist/main.js +2 -2
- package/dist/{server-JC3AQpcl.js → server-VjfrS2Aw.js} +113 -24
- package/dist/server-VjfrS2Aw.js.map +1 -0
- package/dist/{start-bv97pvAG.js → start-DX3Q5lol.js} +8 -284
- package/dist/start-DX3Q5lol.js.map +1 -0
- package/dist/{token-DgVri1k7.js → token-0pmwyQAu.js} +93 -33
- package/dist/token-0pmwyQAu.js.map +1 -0
- package/package.json +1 -1
- package/dist/auth-BYKwBiQx.js +0 -2
- package/dist/models-CHdnmX1S.js +0 -90
- package/dist/models-CHdnmX1S.js.map +0 -1
- package/dist/server-JC3AQpcl.js.map +0 -1
- package/dist/start-bv97pvAG.js.map +0 -1
- package/dist/token-DgVri1k7.js.map +0 -1
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { S as ensurePaths, g as mergeConfigWithDefaults } from "./config-store-CARrUljo.js";
|
|
2
2
|
import { i as listEnabledProviders, p as startModelsDevCache } from "./config-B2OaAnpL.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { a as runProviderSetup } from "./auth-
|
|
6
|
-
import {
|
|
3
|
+
import { r as isGitHubCopilotEnabled } from "./github-copilot-provider-DlQZgaCT.js";
|
|
4
|
+
import { $ as state, L as getConfiguredApiKeys, R as getMissingApiKeysMessage, b as readGitHubToken, k as initOpencodeVersion, x as readGitHubTokenFromEnv, y as GITHUB_TOKEN_ENV } from "./token-0pmwyQAu.js";
|
|
5
|
+
import { a as runProviderSetup } from "./auth-CmKD_Gmp.js";
|
|
6
|
+
import { i as getLatestModelForFamily, t as setupCopilotRuntime } from "./copilot-runtime-B4x9RzsD.js";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
import consola from "consola";
|
|
9
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import { networkInterfaces } from "node:os";
|
|
12
9
|
import { getProxyForUrl } from "proxy-from-env";
|
|
13
10
|
import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
|
|
14
11
|
import { execSync } from "node:child_process";
|
|
@@ -178,273 +175,6 @@ function generateEnvScript(envVars, commandToRun = "") {
|
|
|
178
175
|
return commandBlock || commandToRun;
|
|
179
176
|
}
|
|
180
177
|
//#endregion
|
|
181
|
-
//#region src/services/copilot/get-models.ts
|
|
182
|
-
const getModels = async () => {
|
|
183
|
-
consola.info(`Fetching models from ${copilotBaseUrl(state)}/models`);
|
|
184
|
-
const response = await fetch(`${copilotBaseUrl(state)}/models`, { headers: copilotModelsHeaders(state) });
|
|
185
|
-
if (!response.ok) {
|
|
186
|
-
const errorText = await response.clone().text();
|
|
187
|
-
consola.error("Failed to get models response body", errorText);
|
|
188
|
-
throw new HTTPError("Failed to get models", response);
|
|
189
|
-
}
|
|
190
|
-
return await response.json();
|
|
191
|
-
};
|
|
192
|
-
//#endregion
|
|
193
|
-
//#region src/services/copilot/models-cache.ts
|
|
194
|
-
const MODELS_REFRESH_BASE_MS = 18e5;
|
|
195
|
-
let modelsRefreshTimer = null;
|
|
196
|
-
const stopModelsRefreshLoop = () => {
|
|
197
|
-
if (modelsRefreshTimer) {
|
|
198
|
-
clearTimeout(modelsRefreshTimer);
|
|
199
|
-
modelsRefreshTimer = null;
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
const refreshModels = async (fetcher) => {
|
|
203
|
-
const prevIds = new Set(state.models?.data.map((m) => m.id) ?? []);
|
|
204
|
-
const models = await fetcher();
|
|
205
|
-
state.models = {
|
|
206
|
-
...models,
|
|
207
|
-
data: models.data.filter((model) => model.policy?.state !== "disabled" && (model.model_picker_enabled || model.capabilities.type === "embeddings"))
|
|
208
|
-
};
|
|
209
|
-
const nextIds = state.models.data.map((m) => m.id);
|
|
210
|
-
const added = nextIds.filter((id) => !prevIds.has(id));
|
|
211
|
-
if (added.length > 0) consola.info(`Models refresh: ${added.length} new`);
|
|
212
|
-
else consola.debug(`Models refresh: no changes (${nextIds.length} total)`);
|
|
213
|
-
};
|
|
214
|
-
const scheduleModelsRefresh = (fetcher, intervalMs) => {
|
|
215
|
-
const delay = intervalMs + Math.floor(Math.random() * (intervalMs / 6));
|
|
216
|
-
consola.debug(`Scheduling next models refresh in ${Math.round(delay / 1e3)} seconds`);
|
|
217
|
-
stopModelsRefreshLoop();
|
|
218
|
-
modelsRefreshTimer = setTimeout(async () => {
|
|
219
|
-
try {
|
|
220
|
-
await refreshModels(fetcher);
|
|
221
|
-
} catch (error) {
|
|
222
|
-
consola.warn("Failed to refresh models, keeping previous cache.", error);
|
|
223
|
-
} finally {
|
|
224
|
-
scheduleModelsRefresh(fetcher, intervalMs);
|
|
225
|
-
}
|
|
226
|
-
}, delay);
|
|
227
|
-
};
|
|
228
|
-
async function cacheModels(fetcher = getModels, intervalMs = MODELS_REFRESH_BASE_MS) {
|
|
229
|
-
await refreshModels(fetcher);
|
|
230
|
-
scheduleModelsRefresh(fetcher, intervalMs);
|
|
231
|
-
}
|
|
232
|
-
//#endregion
|
|
233
|
-
//#region src/lib/deviceid.ts
|
|
234
|
-
const WINDOWS_DEVICE_ID_KEY = String.raw`\SOFTWARE\Microsoft\DeveloperTools`;
|
|
235
|
-
const WINDOWS_DEVICE_ID_NAME = "deviceid";
|
|
236
|
-
const windows64Architectures = /* @__PURE__ */ new Set([
|
|
237
|
-
"AMD64",
|
|
238
|
-
"ARM64",
|
|
239
|
-
"IA64"
|
|
240
|
-
]);
|
|
241
|
-
const getPosixHomeDir = () => {
|
|
242
|
-
if (!process.env.HOME) throw new Error("Home directory not found");
|
|
243
|
-
return process.env.HOME;
|
|
244
|
-
};
|
|
245
|
-
const getDeviceIdFilePath = () => {
|
|
246
|
-
let folder;
|
|
247
|
-
switch (process.platform) {
|
|
248
|
-
case "darwin":
|
|
249
|
-
folder = path.posix.join(getPosixHomeDir(), "Library", "Application Support");
|
|
250
|
-
break;
|
|
251
|
-
case "linux":
|
|
252
|
-
folder = process.env.XDG_CACHE_HOME ?? path.posix.join(getPosixHomeDir(), ".cache");
|
|
253
|
-
break;
|
|
254
|
-
default: throw new Error("Unsupported platform");
|
|
255
|
-
}
|
|
256
|
-
return path.posix.join(folder, "Microsoft", "DeveloperTools", "deviceid");
|
|
257
|
-
};
|
|
258
|
-
const isMissingFileError = (error) => {
|
|
259
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
260
|
-
};
|
|
261
|
-
const readStoredDeviceIdFile = async (filePath) => {
|
|
262
|
-
const { readFile } = await import("node:fs/promises");
|
|
263
|
-
try {
|
|
264
|
-
return await readFile(filePath, "utf8");
|
|
265
|
-
} catch (error) {
|
|
266
|
-
if (isMissingFileError(error)) return;
|
|
267
|
-
throw error;
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
const writeStoredDeviceIdFile = async (filePath, deviceId) => {
|
|
271
|
-
const { mkdir, writeFile } = await import("node:fs/promises");
|
|
272
|
-
await mkdir(path.posix.dirname(filePath), { recursive: true });
|
|
273
|
-
await writeFile(filePath, deviceId, "utf8");
|
|
274
|
-
};
|
|
275
|
-
const getWindowsRegistryArch = () => {
|
|
276
|
-
const architecture = (process.env.PROCESSOR_ARCHITEW6432 ?? process.env.PROCESSOR_ARCHITECTURE)?.toUpperCase();
|
|
277
|
-
return architecture && windows64Architectures.has(architecture) ? "x64" : void 0;
|
|
278
|
-
};
|
|
279
|
-
const loadWinreg = async () => {
|
|
280
|
-
const module = await import("winreg");
|
|
281
|
-
return "default" in module ? module.default : module;
|
|
282
|
-
};
|
|
283
|
-
const isMissingRegistryError = (error) => {
|
|
284
|
-
if (!error) return false;
|
|
285
|
-
const errorCode = Number(error.code);
|
|
286
|
-
return Number.isFinite(errorCode) && errorCode === 1;
|
|
287
|
-
};
|
|
288
|
-
const createWindowsRegistry = async () => {
|
|
289
|
-
const Winreg = await loadWinreg();
|
|
290
|
-
return {
|
|
291
|
-
registry: new Winreg({
|
|
292
|
-
hive: Winreg.HKCU,
|
|
293
|
-
key: WINDOWS_DEVICE_ID_KEY,
|
|
294
|
-
arch: getWindowsRegistryArch()
|
|
295
|
-
}),
|
|
296
|
-
regSz: Winreg.REG_SZ
|
|
297
|
-
};
|
|
298
|
-
};
|
|
299
|
-
const readRegistryString = async (registry, name) => {
|
|
300
|
-
return new Promise((resolve, reject) => {
|
|
301
|
-
registry.get(name, (error, item) => {
|
|
302
|
-
if (isMissingRegistryError(error)) {
|
|
303
|
-
resolve(void 0);
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
if (error) {
|
|
307
|
-
reject(error instanceof Error ? error : /* @__PURE__ */ new Error("Unknown registry error"));
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
resolve(item?.value);
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
};
|
|
314
|
-
const writeRegistryString = async ({ registry, regSz, name, value }) => {
|
|
315
|
-
return new Promise((resolve, reject) => {
|
|
316
|
-
registry.set(name, regSz, value, (error) => {
|
|
317
|
-
if (error) {
|
|
318
|
-
reject(error instanceof Error ? error : /* @__PURE__ */ new Error("Unknown registry error"));
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
resolve();
|
|
322
|
-
});
|
|
323
|
-
});
|
|
324
|
-
};
|
|
325
|
-
const getStoredVSCodeDeviceId = async () => {
|
|
326
|
-
switch (process.platform) {
|
|
327
|
-
case "win32": {
|
|
328
|
-
const { registry } = await createWindowsRegistry();
|
|
329
|
-
return readRegistryString(registry, WINDOWS_DEVICE_ID_NAME);
|
|
330
|
-
}
|
|
331
|
-
case "darwin":
|
|
332
|
-
case "linux": return readStoredDeviceIdFile(getDeviceIdFilePath());
|
|
333
|
-
default: throw new Error("Unsupported platform");
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
const setStoredVSCodeDeviceId = async (deviceId) => {
|
|
337
|
-
switch (process.platform) {
|
|
338
|
-
case "win32": {
|
|
339
|
-
const { registry, regSz } = await createWindowsRegistry();
|
|
340
|
-
await writeRegistryString({
|
|
341
|
-
registry,
|
|
342
|
-
regSz,
|
|
343
|
-
name: WINDOWS_DEVICE_ID_NAME,
|
|
344
|
-
value: deviceId
|
|
345
|
-
});
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
case "darwin":
|
|
349
|
-
case "linux":
|
|
350
|
-
await writeStoredDeviceIdFile(getDeviceIdFilePath(), deviceId);
|
|
351
|
-
return;
|
|
352
|
-
default: throw new Error("Unsupported platform");
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
const createVSCodeDeviceId = () => randomUUID().toLowerCase();
|
|
356
|
-
async function getVSCodeDeviceId() {
|
|
357
|
-
let deviceId;
|
|
358
|
-
try {
|
|
359
|
-
deviceId = await getStoredVSCodeDeviceId();
|
|
360
|
-
} catch (error) {
|
|
361
|
-
consola.debug("Failed to read VSCode device id", error);
|
|
362
|
-
}
|
|
363
|
-
if (deviceId) return deviceId;
|
|
364
|
-
const newDeviceId = createVSCodeDeviceId();
|
|
365
|
-
try {
|
|
366
|
-
await setStoredVSCodeDeviceId(newDeviceId);
|
|
367
|
-
} catch (error) {
|
|
368
|
-
consola.warn("Failed to persist VSCode device id, using ephemeral id", error);
|
|
369
|
-
}
|
|
370
|
-
return newDeviceId;
|
|
371
|
-
}
|
|
372
|
-
//#endregion
|
|
373
|
-
//#region src/services/get-vscode-version.ts
|
|
374
|
-
const FALLBACK = "1.139.1";
|
|
375
|
-
async function getVSCodeVersion() {
|
|
376
|
-
await Promise.resolve();
|
|
377
|
-
return FALLBACK;
|
|
378
|
-
}
|
|
379
|
-
//#endregion
|
|
380
|
-
//#region src/services/vscode-env.ts
|
|
381
|
-
const cacheVSCodeVersion = async () => {
|
|
382
|
-
const response = await getVSCodeVersion();
|
|
383
|
-
state.vsCodeVersion = response;
|
|
384
|
-
consola.info(`Using VSCode version: ${response}`);
|
|
385
|
-
};
|
|
386
|
-
const invalidMacAddresses = /* @__PURE__ */ new Set([
|
|
387
|
-
"00:00:00:00:00:00",
|
|
388
|
-
"ff:ff:ff:ff:ff:ff",
|
|
389
|
-
"ac:de:48:00:11:22"
|
|
390
|
-
]);
|
|
391
|
-
function validateMacAddress(candidate) {
|
|
392
|
-
const tempCandidate = candidate.replaceAll("-", ":").toLowerCase();
|
|
393
|
-
return !invalidMacAddresses.has(tempCandidate);
|
|
394
|
-
}
|
|
395
|
-
function getMac() {
|
|
396
|
-
const ifaces = networkInterfaces();
|
|
397
|
-
for (const name in ifaces) {
|
|
398
|
-
const networkInterface = ifaces[name];
|
|
399
|
-
if (networkInterface) {
|
|
400
|
-
for (const { mac } of networkInterface) if (validateMacAddress(mac)) return mac;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
return null;
|
|
404
|
-
}
|
|
405
|
-
const cacheMacMachineId = () => {
|
|
406
|
-
const macAddress = getMac() ?? randomUUID();
|
|
407
|
-
state.macMachineId = createHash("sha256").update(macAddress, "utf8").digest("hex");
|
|
408
|
-
consola.debug(`Using machine ID: ${state.macMachineId}`);
|
|
409
|
-
};
|
|
410
|
-
const cacheVsCodeDeviceId = async () => {
|
|
411
|
-
state.vsCodeDeviceId = await getVSCodeDeviceId();
|
|
412
|
-
consola.debug(`Using VSCode device ID: ${state.vsCodeDeviceId}`);
|
|
413
|
-
};
|
|
414
|
-
const SESSION_REFRESH_BASE_MS = 36e5;
|
|
415
|
-
const SESSION_REFRESH_JITTER_MS = 12e5;
|
|
416
|
-
let vsCodeSessionRefreshTimer = null;
|
|
417
|
-
const generateSessionId = () => {
|
|
418
|
-
state.vsCodeSessionId = randomUUID() + Date.now().toString();
|
|
419
|
-
consola.debug(`Generated VSCode session ID: ${state.vsCodeSessionId}`);
|
|
420
|
-
};
|
|
421
|
-
const stopVsCodeSessionRefreshLoop = () => {
|
|
422
|
-
if (vsCodeSessionRefreshTimer) {
|
|
423
|
-
clearTimeout(vsCodeSessionRefreshTimer);
|
|
424
|
-
vsCodeSessionRefreshTimer = null;
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
const scheduleSessionIdRefresh = () => {
|
|
428
|
-
const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS);
|
|
429
|
-
const delay = SESSION_REFRESH_BASE_MS + randomDelay;
|
|
430
|
-
consola.debug(`Scheduling next VSCode session ID refresh in ${Math.round(delay / 1e3)} seconds`);
|
|
431
|
-
stopVsCodeSessionRefreshLoop();
|
|
432
|
-
vsCodeSessionRefreshTimer = setTimeout(() => {
|
|
433
|
-
try {
|
|
434
|
-
generateSessionId();
|
|
435
|
-
} catch (error) {
|
|
436
|
-
consola.error("Failed to refresh session ID, rescheduling...", error);
|
|
437
|
-
} finally {
|
|
438
|
-
scheduleSessionIdRefresh();
|
|
439
|
-
}
|
|
440
|
-
}, delay);
|
|
441
|
-
};
|
|
442
|
-
const cacheVsCodeSessionId = () => {
|
|
443
|
-
stopVsCodeSessionRefreshLoop();
|
|
444
|
-
generateSessionId();
|
|
445
|
-
scheduleSessionIdRefresh();
|
|
446
|
-
};
|
|
447
|
-
//#endregion
|
|
448
178
|
//#region src/start.ts
|
|
449
179
|
async function resolveGitHubToken(cliToken) {
|
|
450
180
|
if (cliToken) return {
|
|
@@ -464,15 +194,9 @@ async function resolveGitHubToken(cliToken) {
|
|
|
464
194
|
return null;
|
|
465
195
|
}
|
|
466
196
|
async function setupCopilotMode(githubToken, source, serverUrl, claudeCode) {
|
|
467
|
-
state.
|
|
197
|
+
state.githubTokenSource = source;
|
|
468
198
|
consola.info(source === "cli" ? "Using provided GitHub token" : source === "env" ? `Using GitHub token from the ${GITHUB_TOKEN_ENV} environment variable` : "Using GitHub token from local file");
|
|
469
|
-
await
|
|
470
|
-
await cacheVSCodeVersion();
|
|
471
|
-
cacheMacMachineId();
|
|
472
|
-
cacheVsCodeSessionId();
|
|
473
|
-
await cacheVsCodeDeviceId();
|
|
474
|
-
await setupCopilotToken();
|
|
475
|
-
await cacheModels();
|
|
199
|
+
await setupCopilotRuntime(githubToken);
|
|
476
200
|
if (claudeCode) runClaudeCode(serverUrl);
|
|
477
201
|
}
|
|
478
202
|
function runClaudeCode(serverUrl) {
|
|
@@ -549,7 +273,7 @@ async function runServer(options) {
|
|
|
549
273
|
if (resolvedGitHubToken && isGitHubCopilotEnabled()) await setupCopilotMode(resolvedGitHubToken.token, resolvedGitHubToken.source, serverUrl, options.claudeCode);
|
|
550
274
|
else await setupProviderMode(serverUrl, options.claudeCode);
|
|
551
275
|
consola.box(`🌐 Dashboard Viewer: ${serverUrl}/usage-viewer?endpoint=${serverUrl}/usage`);
|
|
552
|
-
const { createServer } = await import("./server-
|
|
276
|
+
const { createServer } = await import("./server-VjfrS2Aw.js");
|
|
553
277
|
const server = createServer({ networkExposed: binding.networkExposed });
|
|
554
278
|
serve({
|
|
555
279
|
fetch: server.fetch,
|
|
@@ -618,4 +342,4 @@ const start = defineCommand({
|
|
|
618
342
|
//#endregion
|
|
619
343
|
export { start };
|
|
620
344
|
|
|
621
|
-
//# sourceMappingURL=start-
|
|
345
|
+
//# sourceMappingURL=start-DX3Q5lol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-DX3Q5lol.js","names":["get","process"],"sources":["../src/lib/proxy.ts","../src/lib/server-host-shared.ts","../src/lib/server-host.ts","../src/lib/shell.ts","../src/start.ts"],"sourcesContent":["import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nlet proxyEnvDispatcher: Dispatcher | undefined\n\nexport function getProxyEnvDispatcher(): Dispatcher | undefined {\n return proxyEnvDispatcher\n}\n\nexport function initProxyFromEnv(): void {\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n proxyEnvDispatcher = dispatcher as unknown as Dispatcher\n\n if (typeof Bun !== \"undefined\") {\n consola.debug(\"WebSocket proxy configured from environment (per-URL)\")\n return\n }\n\n setGlobalDispatcher(proxyEnvDispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","// Pure hostname helpers shared by the gateway server (Node) and the desktop\n// app (including the renderer bundle). This module must stay free of\n// `node:*` imports because the renderer cannot use `node:net`; all\n// address-family checks live in `server-host.ts`.\nexport const INVALID_HOST_CHARACTERS = /[\\s/?#]/\n\n// Bind hosts that listen on every interface, in normalized form (no\n// brackets, so \"[::]\" is covered via `stripIpv6Brackets`).\nexport const NORMALIZED_WILDCARD_HOSTS = new Set([\"0.0.0.0\", \"::\"])\n\nexport function stripIpv6Brackets(hostname: string): string {\n if (hostname.startsWith(\"[\") && hostname.endsWith(\"]\")) {\n return hostname.slice(1, -1)\n }\n return hostname\n}\n\nexport function normalizeHostnameBase(hostname: string): string {\n const normalized = stripIpv6Brackets(hostname.trim())\n if (!normalized || INVALID_HOST_CHARACTERS.test(normalized)) {\n throw new Error(`Invalid server host: ${JSON.stringify(hostname)}`)\n }\n return normalized\n}\n\nexport function isWildcardHostname(hostname: string): boolean {\n return NORMALIZED_WILDCARD_HOSTS.has(stripIpv6Brackets(hostname.trim()))\n}\n","import { isIP } from \"node:net\"\n\nimport { isWildcardHostname, normalizeHostnameBase } from \"./server-host-shared\"\n\nexport const DEFAULT_SERVER_HOST = \"127.0.0.1\"\n\n// Listen failures that mean the hostname itself cannot be bound, as opposed\n// to the port being occupied (EADDRINUSE) or forbidden (EACCES). ENOTFOUND\n// covers unresolvable names such as typos, EADDRNOTAVAIL covers valid IPs\n// that are not assigned to this machine.\nconst INVALID_BIND_ERROR_CODES = new Set([\n \"ENOTFOUND\",\n \"EADDRNOTAVAIL\",\n \"EINVAL\",\n \"EAFNOSUPPORT\",\n \"ENXIO\",\n])\n\nexport function isInvalidBindErrorCode(code?: string): boolean {\n return !!code && INVALID_BIND_ERROR_CODES.has(code)\n}\n\nexport interface ServerBinding {\n hostname: string\n clientHostname: string\n networkExposed: boolean\n}\n\nfunction isLoopbackIpv4(hostname: string): boolean {\n return isIP(hostname) === 4 && hostname.split(\".\", 1)[0] === \"127\"\n}\n\nfunction isLoopbackMappedIpv4(hostname: string): boolean {\n try {\n const canonicalHostname = new URL(`http://[${hostname}]/`).hostname.slice(\n 1,\n -1,\n )\n const mappedIpv4 = canonicalHostname.match(\n /^::ffff:([\\da-f]{1,4}):[\\da-f]{1,4}$/,\n )\n if (!mappedIpv4) {\n return false\n }\n\n return (Number.parseInt(mappedIpv4[1], 16) & 0xff00) === 0x7f00\n } catch {\n return false\n }\n}\n\nexport function normalizeServerHostname(hostname: string): string {\n return normalizeHostnameBase(hostname)\n}\n\nexport function isLoopbackHostname(hostname: string): boolean {\n const normalized = normalizeServerHostname(hostname).toLowerCase()\n if (normalized === \"localhost\" || normalized === \"localhost.\") {\n return true\n }\n if (isLoopbackIpv4(normalized)) {\n return true\n }\n if (isIP(normalized) !== 6) {\n return false\n }\n\n if (normalized === \"::1\" || normalized === \"0:0:0:0:0:0:0:1\") {\n return true\n }\n\n return isLoopbackMappedIpv4(normalized)\n}\n\nexport function resolveServerBinding(\n hostname: string,\n hasApiKeys: boolean,\n): ServerBinding {\n const normalizedHostname = normalizeServerHostname(hostname)\n const networkExposed = !isLoopbackHostname(normalizedHostname)\n\n if (networkExposed && !hasApiKeys) {\n throw new Error(\n `Refusing to listen on non-loopback host ${JSON.stringify(normalizedHostname)} without gateway API keys. Run \\`npx @jeffreycao/copilot-api@latest auth keys --add <key>\\` first, or use \\`--host ${DEFAULT_SERVER_HOST}\\`.`,\n )\n }\n\n return {\n hostname: normalizedHostname,\n clientHostname: resolveClientHostname(normalizedHostname),\n networkExposed,\n }\n}\n\nexport function resolveClientHostname(hostname: string): string {\n const normalizedHostname = normalizeServerHostname(hostname)\n // Wildcard binds listen on every interface, which clients cannot dial\n // directly (0.0.0.0 is not a routable destination).\n return isWildcardHostname(normalizedHostname) ? DEFAULT_SERVER_HOST : (\n normalizedHostname.toLowerCase()\n )\n}\n\nexport function resolveClientHostnameOrDefault(\n hostname: string | null | undefined,\n): string {\n const normalizedHostname = hostname?.trim()\n return normalizedHostname ?\n resolveClientHostname(normalizedHostname)\n : DEFAULT_SERVER_HOST\n}\n\nexport function formatServerUrl(hostname: string, port: number): string {\n const urlHostname =\n isIP(hostname) === 6 ? `[${hostname.replace(\"%\", \"%25\")}]` : hostname\n return `http://${urlHostname}:${port}`\n}\n","import { execSync } from \"node:child_process\"\nimport process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, ppid, env } = process\n\n if (platform === \"win32\") {\n try {\n const command = `wmic process get ParentProcessId,Name | findstr \"${ppid}\"`\n const parentProcess = execSync(command, { stdio: \"pipe\" }).toString()\n\n if (parentProcess.toLowerCase().includes(\"powershell.exe\")) {\n return \"powershell\"\n }\n } catch {\n return \"cmd\"\n }\n\n return \"cmd\"\n } else {\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n }\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${value}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set ${key}=${value}`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${value}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${value}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator = shell === \"cmd\" ? \" & \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { runProviderSetup } from \"./auth\"\nimport { isGitHubCopilotEnabled } from \"./lib/github-copilot-provider\"\nimport { listEnabledProviders, mergeConfigWithDefaults } from \"./lib/config\"\nimport { setupCopilotRuntime } from \"~/lib/copilot-runtime\"\nimport {\n GITHUB_TOKEN_ENV,\n readGitHubToken,\n readGitHubTokenFromEnv,\n} from \"./lib/credential-store\"\nimport { getLatestModelForFamily } from \"./lib/models\"\nimport { startModelsDevCache } from \"./lib/models-dev-cache\"\nimport { initOpencodeVersion } from \"./lib/opencode\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport {\n getConfiguredApiKeys,\n getMissingApiKeysMessage,\n} from \"./lib/request-auth\"\nimport {\n DEFAULT_SERVER_HOST,\n formatServerUrl,\n resolveServerBinding,\n} from \"./lib/server-host\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\n\ninterface RunServerOptions {\n host: string\n port: number\n verbose: boolean\n githubToken?: string\n claudeCode: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\ntype GitHubTokenSource = \"cli\" | \"env\" | \"file\"\n\n// The environment is preferred over the token file so the token never has to\n// travel through the process list; --github-token stays first for callers that\n// opt in explicitly.\nasync function resolveGitHubToken(\n cliToken: string | undefined,\n): Promise<{ token: string; source: GitHubTokenSource } | null> {\n if (cliToken) return { token: cliToken, source: \"cli\" }\n\n const envToken = readGitHubTokenFromEnv()\n if (envToken) return { token: envToken, source: \"env\" }\n\n const fileToken = await readGitHubToken()\n if (fileToken) return { token: fileToken, source: \"file\" }\n\n return null\n}\n\nasync function setupCopilotMode(\n githubToken: string,\n source: GitHubTokenSource,\n serverUrl: string,\n claudeCode: boolean,\n): Promise<void> {\n state.githubTokenSource = source\n consola.info(\n source === \"cli\" ? \"Using provided GitHub token\"\n : source === \"env\" ?\n `Using GitHub token from the ${GITHUB_TOKEN_ENV} environment variable`\n : \"Using GitHub token from local file\",\n )\n\n await setupCopilotRuntime(githubToken)\n\n if (claudeCode) {\n runClaudeCode(serverUrl)\n }\n}\n\nfunction runClaudeCode(serverUrl: string): void {\n consola.log(\n \"\\n💡 Tip: The --claude-code flag simply generates a clipboard command for launching Claude Code. \\n\"\n + \"All models remain fully accessible without this flag, just configure the model ID directly in your settings.json file.\",\n )\n\n invariant(state.models, \"Models should be loaded by now\")\n\n // Default to the latest available model for each Claude Code size tier so\n // opus maps to opus, sonnet maps to sonnet, and haiku maps to haiku.\n const opusModel = getLatestModelForFamily(\"opus\")?.id\n const sonnetModel = getLatestModelForFamily(\"sonnet\")?.id\n const haikuModel = getLatestModelForFamily(\"haiku\")?.id\n\n consola.info(\n \"Selected default Claude Code models:\\n\"\n + `- Opus: ${opusModel ?? \"(none available)\"}\\n`\n + `- Sonnet: ${sonnetModel ?? \"(none available)\"}\\n`\n + `- Haiku: ${haikuModel ?? \"(none available)\"}`,\n )\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: sonnetModel ?? opusModel,\n ANTHROPIC_DEFAULT_OPUS_MODEL: opusModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: sonnetModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: haikuModel,\n CLAUDE_CODE_USE_VERTEX: \"0\",\n CLAUDE_CODE_USE_BEDROCK: \"0\",\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n CLAUDE_CODE_ATTRIBUTION_HEADER: \"0\",\n CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION: \"false\",\n CLAUDE_CODE_DISABLE_TERMINAL_TITLE: \"true\",\n CLAUDE_CODE_ENABLE_AWAY_SUMMARY: \"0\",\n CLAUDE_CODE_TOTAL_TOKENS_REMINDER: \"off\",\n MCP_CONNECT_TIMEOUT_MS: \"20000\",\n },\n \"claude\",\n )\n\n try {\n clipboard.writeSync(command)\n consola.success(\"Copied Claude Code command to clipboard!\")\n } catch {\n consola.warn(\n \"Failed to copy to clipboard. Here is the Claude Code command:\",\n )\n consola.log(command)\n }\n}\n\nasync function setupProviderMode(\n serverUrl: string,\n claudeCode: boolean,\n): Promise<void> {\n const enabledProviders = listEnabledProviders()\n\n if (enabledProviders.length > 0) {\n consola.info(`Using enabled providers: ${enabledProviders.join(\", \")}`)\n return\n }\n\n if (!isGitHubCopilotEnabled()) {\n throw new Error(\n \"No enabled providers found. Enable GitHub Copilot with `copilot-api provider enable github-copilot`, or enable another configured provider.\",\n )\n }\n\n consola.info(\"No enabled providers found. Setting one up...\")\n await runProviderSetup()\n\n if (state.githubToken && isGitHubCopilotEnabled()) {\n // The setup flow persisted the token with the credential store.\n await setupCopilotMode(state.githubToken, \"file\", serverUrl, claudeCode)\n return\n }\n\n const providersAfterSetup = listEnabledProviders()\n if (providersAfterSetup.length === 0) {\n throw new Error(\n \"Failed to configure any provider. Run `copilot-api auth login` to set one up.\",\n )\n }\n consola.info(`Configured providers: ${providersAfterSetup.join(\", \")}`)\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n const tlsModule = await import(\"./lib/tls\")\n tlsModule.enableSystemCACompat()\n\n consola.options.throttle = 0\n\n mergeConfigWithDefaults()\n\n const configuredApiKeys = getConfiguredApiKeys()\n const binding = resolveServerBinding(\n options.host,\n configuredApiKeys.length > 0,\n )\n\n const missingApiKeysMessage = getMissingApiKeysMessage()\n if (missingApiKeysMessage) {\n consola.info(missingApiKeysMessage)\n }\n\n await initOpencodeVersion()\n\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n state.verbose = options.verbose\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await startModelsDevCache()\n\n const serverUrl = formatServerUrl(binding.clientHostname, options.port)\n\n const resolvedGitHubToken =\n isGitHubCopilotEnabled() ?\n await resolveGitHubToken(options.githubToken)\n : null\n if (resolvedGitHubToken && isGitHubCopilotEnabled()) {\n await setupCopilotMode(\n resolvedGitHubToken.token,\n resolvedGitHubToken.source,\n serverUrl,\n options.claudeCode,\n )\n } else {\n await setupProviderMode(serverUrl, options.claudeCode)\n }\n\n consola.box(\n `🌐 Dashboard Viewer: ${serverUrl}/usage-viewer?endpoint=${serverUrl}/usage`,\n )\n\n const { createServer } = await import(\"./server\")\n const server = createServer({ networkExposed: binding.networkExposed })\n\n serve({\n fetch: server.fetch as ServerHandler,\n hostname: binding.hostname,\n port: options.port,\n bun: {\n idleTimeout: 0,\n },\n })\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the Copilot API server\",\n },\n args: {\n host: {\n type: \"string\",\n default: process.env.HOST?.trim() || DEFAULT_SERVER_HOST,\n description: \"Host to listen on\",\n },\n port: {\n alias: \"p\",\n type: \"string\",\n default: \"4141\",\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\",\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"claude-code\": {\n alias: \"c\",\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\",\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n },\n run({ args }) {\n return runServer({\n host: args.host,\n port: Number.parseInt(args.port, 10),\n verbose: args.verbose,\n githubToken: args[\"github-token\"],\n claudeCode: args[\"claude-code\"],\n showToken: args[\"show-token\"],\n proxyEnv: args[\"proxy-env\"],\n })\n },\n})\n"],"mappings":"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"}
|
|
@@ -762,8 +762,9 @@ function buildCodexRequestHeaders(requestHeaders) {
|
|
|
762
762
|
applyOpencodeCodexHeaders(headers);
|
|
763
763
|
return headers;
|
|
764
764
|
}
|
|
765
|
+
const codexResponsesDependencies = { isResponsesApiWebSocketEnabled: () => isResponsesApiWebSocketEnabled() };
|
|
765
766
|
function resolveCodexResponsesTransport(transport) {
|
|
766
|
-
return transport ?? (isResponsesApiWebSocketEnabled() ? "websocket" : "http");
|
|
767
|
+
return transport ?? (codexResponsesDependencies.isResponsesApiWebSocketEnabled() ? "websocket" : "http");
|
|
767
768
|
}
|
|
768
769
|
function buildCodexResponsesWebSocketHeaders(requestHeaders, options = {}) {
|
|
769
770
|
const headers = buildCodexResponsesHeaders(requestHeaders, options);
|
|
@@ -1836,6 +1837,8 @@ async function writeCodexCredentials(credentials, options = {}) {
|
|
|
1836
1837
|
const accountIdSelector = normalizeCodexAccountSelector(normalizedCredentials.accountId);
|
|
1837
1838
|
const existingIndex = store.accounts.findIndex((account) => account.accountId === normalizedCredentials.accountId);
|
|
1838
1839
|
if (existingIndex < 0 && options.insertIfMissing === false) return;
|
|
1840
|
+
const existingRefreshToken = store.accounts[existingIndex]?.refreshToken;
|
|
1841
|
+
if (options.expectedRefreshToken !== void 0 && existingRefreshToken !== options.expectedRefreshToken && existingRefreshToken !== normalizedCredentials.refreshToken) return;
|
|
1839
1842
|
if (existingIndex < 0 && store.accounts.some((account) => normalizeCodexAccountSelector(account.accountId) === accountIdSelector)) throw new Error(`Codex account id '${normalizedCredentials.accountId}' is already in use`);
|
|
1840
1843
|
if (existingIndex < 0 && store.accounts.length >= 3) throw new Error(`Codex supports at most 3 accounts`);
|
|
1841
1844
|
if (store.accounts.some((account, index) => index !== existingIndex && account.alias && normalizeCodexAccountSelector(account.alias) === accountIdSelector)) throw new Error(`Codex account id '${normalizedCredentials.accountId}' conflicts with another account alias`);
|
|
@@ -1996,13 +1999,15 @@ const defaultPollAccessTokenDependencies = {
|
|
|
1996
1999
|
sleep
|
|
1997
2000
|
};
|
|
1998
2001
|
const toSleepDuration = (intervalSeconds) => (intervalSeconds + 1) * 1e3;
|
|
1999
|
-
async function pollAccessToken(deviceCode, dependencies = defaultPollAccessTokenDependencies) {
|
|
2002
|
+
async function pollAccessToken(deviceCode, dependencies = defaultPollAccessTokenDependencies, options = {}) {
|
|
2003
|
+
const { signal } = options;
|
|
2000
2004
|
const { clientId, headers } = getOauthAppConfig();
|
|
2001
2005
|
const { accessTokenUrl } = getOauthUrls();
|
|
2002
2006
|
const expiresAt = dependencies.now() + deviceCode.expires_in * 1e3;
|
|
2003
2007
|
let intervalSeconds = deviceCode.interval;
|
|
2004
2008
|
consola.debug(`Polling access token with interval of ${toSleepDuration(intervalSeconds)}ms`);
|
|
2005
2009
|
while (true) {
|
|
2010
|
+
signal?.throwIfAborted();
|
|
2006
2011
|
if (dependencies.now() >= expiresAt) throw new Error("GitHub device code expired before authorization completed. Please log in again.");
|
|
2007
2012
|
const json = await requestAccessToken(accessTokenUrl, {
|
|
2008
2013
|
method: "POST",
|
|
@@ -2011,7 +2016,8 @@ async function pollAccessToken(deviceCode, dependencies = defaultPollAccessToken
|
|
|
2011
2016
|
client_id: clientId,
|
|
2012
2017
|
device_code: deviceCode.device_code,
|
|
2013
2018
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
2014
|
-
})
|
|
2019
|
+
}),
|
|
2020
|
+
signal
|
|
2015
2021
|
});
|
|
2016
2022
|
if (json) {
|
|
2017
2023
|
consola.debug("Polling access token response received");
|
|
@@ -2022,13 +2028,31 @@ async function pollAccessToken(deviceCode, dependencies = defaultPollAccessToken
|
|
|
2022
2028
|
consola.debug(`GitHub asked to slow down, polling interval is now ${intervalSeconds}s`);
|
|
2023
2029
|
} else if (json.error && json.error !== "authorization_pending") throw new Error(`GitHub device authorization failed: ${json.error_description ?? json.error}`);
|
|
2024
2030
|
}
|
|
2025
|
-
await dependencies.sleep
|
|
2031
|
+
await sleepUnlessAborted(dependencies.sleep, toSleepDuration(intervalSeconds), signal);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
async function sleepUnlessAborted(sleepFor, ms, signal) {
|
|
2035
|
+
if (!signal) {
|
|
2036
|
+
await sleepFor(ms);
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
signal.throwIfAborted();
|
|
2040
|
+
let onAbort;
|
|
2041
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
2042
|
+
onAbort = () => reject(signal.reason);
|
|
2043
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2044
|
+
});
|
|
2045
|
+
try {
|
|
2046
|
+
await Promise.race([aborted, sleepFor(ms)]);
|
|
2047
|
+
} finally {
|
|
2048
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
2026
2049
|
}
|
|
2027
2050
|
}
|
|
2028
2051
|
/**
|
|
2029
2052
|
* Resolves to `undefined` when the poll should simply be retried. The device
|
|
2030
2053
|
* code stays valid until it expires, so a dropped connection (for example a
|
|
2031
2054
|
* proxy closing the socket) or a non-2xx response must not abort the login.
|
|
2055
|
+
* A request aborted through `init.signal` rejects instead.
|
|
2032
2056
|
*/
|
|
2033
2057
|
async function requestAccessToken(url, init) {
|
|
2034
2058
|
try {
|
|
@@ -2039,6 +2063,7 @@ async function requestAccessToken(url, init) {
|
|
|
2039
2063
|
}
|
|
2040
2064
|
return await response.json();
|
|
2041
2065
|
} catch (error) {
|
|
2066
|
+
if (init.signal?.aborted) throw error;
|
|
2042
2067
|
consola.warn(`Failed to poll access token, will retry: ${describeError(error)}`);
|
|
2043
2068
|
return;
|
|
2044
2069
|
}
|
|
@@ -2054,8 +2079,9 @@ function describeError(error) {
|
|
|
2054
2079
|
//#region src/lib/token.ts
|
|
2055
2080
|
let copilotRefreshLoopController = null;
|
|
2056
2081
|
let codexRefreshLoopController = null;
|
|
2057
|
-
let
|
|
2058
|
-
|
|
2082
|
+
let codexRuntimeGeneration = 0;
|
|
2083
|
+
const codexRefreshInFlight = /* @__PURE__ */ new Map();
|
|
2084
|
+
const codexCredentialsPendingPersistence = /* @__PURE__ */ new Map();
|
|
2059
2085
|
const defaultCopilotTokenDependencies = {
|
|
2060
2086
|
getCopilotToken,
|
|
2061
2087
|
getCopilotUsage
|
|
@@ -2070,6 +2096,14 @@ const stopCodexRefreshLoop = () => {
|
|
|
2070
2096
|
codexRefreshLoopController.abort();
|
|
2071
2097
|
codexRefreshLoopController = null;
|
|
2072
2098
|
};
|
|
2099
|
+
const invalidateCodexRuntime = () => {
|
|
2100
|
+
codexRuntimeGeneration++;
|
|
2101
|
+
stopCodexRefreshLoop();
|
|
2102
|
+
state.codexAccessToken = void 0;
|
|
2103
|
+
state.codexRefreshToken = void 0;
|
|
2104
|
+
state.codexExpiresAt = void 0;
|
|
2105
|
+
state.codexAccountId = void 0;
|
|
2106
|
+
};
|
|
2073
2107
|
function applyCodexCredentials(credentials) {
|
|
2074
2108
|
state.codexAccessToken = credentials.accessToken;
|
|
2075
2109
|
state.codexRefreshToken = credentials.refreshToken;
|
|
@@ -2150,17 +2184,21 @@ async function removeCodexAccount(selector) {
|
|
|
2150
2184
|
});
|
|
2151
2185
|
}
|
|
2152
2186
|
async function persistCodexCredentials(credentials, options = {}) {
|
|
2187
|
+
const generation = options.runtimeGeneration ?? codexRuntimeGeneration;
|
|
2153
2188
|
const persist = async () => {
|
|
2154
2189
|
await writeCodexCredentials(credentials, {
|
|
2155
2190
|
alias: options.alias,
|
|
2156
|
-
insertIfMissing: options.insertIfMissing
|
|
2191
|
+
insertIfMissing: options.insertIfMissing,
|
|
2192
|
+
expectedRefreshToken: options.expectedRefreshToken
|
|
2157
2193
|
});
|
|
2158
2194
|
if (options.syncProvider !== false) syncCodexProviderConfig({
|
|
2159
2195
|
accountId: options.activateAccount ? credentials.accountId : void 0,
|
|
2160
2196
|
enabled: options.enableProvider ? true : void 0
|
|
2161
2197
|
});
|
|
2162
|
-
applyCodexCredentials(credentials);
|
|
2163
|
-
|
|
2198
|
+
if (generation === codexRuntimeGeneration && (options.syncProvider !== false || getConfiguredCodexAccountId() === credentials.accountId)) applyCodexCredentials(credentials);
|
|
2199
|
+
if (options.syncProvider !== false) {
|
|
2200
|
+
for (const [key, pending] of codexCredentialsPendingPersistence) if (pending.accountId === credentials.accountId) codexCredentialsPendingPersistence.delete(key);
|
|
2201
|
+
}
|
|
2164
2202
|
};
|
|
2165
2203
|
if (options.syncProvider === false) {
|
|
2166
2204
|
await persist();
|
|
@@ -2168,14 +2206,19 @@ async function persistCodexCredentials(credentials, options = {}) {
|
|
|
2168
2206
|
}
|
|
2169
2207
|
await withCodexAccountMutationLock(persist);
|
|
2170
2208
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2209
|
+
function createCodexRefreshDependencies(credentials) {
|
|
2210
|
+
const generation = codexRuntimeGeneration;
|
|
2211
|
+
return {
|
|
2212
|
+
getCurrentCredentials: getLoadedCodexCredentials,
|
|
2213
|
+
persistCodexCredentials: (refreshed) => persistCodexCredentials(refreshed, {
|
|
2214
|
+
insertIfMissing: false,
|
|
2215
|
+
syncProvider: false,
|
|
2216
|
+
expectedRefreshToken: credentials.refreshToken,
|
|
2217
|
+
runtimeGeneration: generation
|
|
2218
|
+
}),
|
|
2219
|
+
refreshCodexCredentials
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2179
2222
|
/**
|
|
2180
2223
|
* Refreshes and persists Codex credentials through one module level
|
|
2181
2224
|
* single-flight guard.
|
|
@@ -2186,29 +2229,31 @@ const defaultCodexRefreshDependencies = {
|
|
|
2186
2229
|
* Codex request, so a burst of requests (or the background loop waking at the
|
|
2187
2230
|
* same moment) must share a single attempt instead of burning the token.
|
|
2188
2231
|
*/
|
|
2189
|
-
function refreshCodexCredentialsOnce(credentials, dependencies
|
|
2190
|
-
const
|
|
2232
|
+
function refreshCodexCredentialsOnce(credentials, dependencies) {
|
|
2233
|
+
const current = dependencies ? dependencies.getCurrentCredentials() : getLoadedCodexCredentials();
|
|
2234
|
+
const rotated = current && current.accountId === credentials.accountId && current.refreshToken !== credentials.refreshToken ? current : null;
|
|
2235
|
+
const base = rotated ?? credentials;
|
|
2236
|
+
const refreshDependencies = dependencies ?? createCodexRefreshDependencies(base);
|
|
2237
|
+
const refreshKey = JSON.stringify([base.accountId, base.refreshToken]);
|
|
2238
|
+
const inFlight = codexRefreshInFlight.get(refreshKey);
|
|
2191
2239
|
if (inFlight) return inFlight;
|
|
2192
2240
|
const attempt = (async () => {
|
|
2193
|
-
const pendingPersistence = codexCredentialsPendingPersistence;
|
|
2241
|
+
const pendingPersistence = codexCredentialsPendingPersistence.get(refreshKey);
|
|
2194
2242
|
if (pendingPersistence) {
|
|
2195
|
-
await
|
|
2196
|
-
if (codexCredentialsPendingPersistence === pendingPersistence) codexCredentialsPendingPersistence
|
|
2243
|
+
await refreshDependencies.persistCodexCredentials(pendingPersistence);
|
|
2244
|
+
if (codexCredentialsPendingPersistence.get(refreshKey) === pendingPersistence) codexCredentialsPendingPersistence.delete(refreshKey);
|
|
2197
2245
|
return pendingPersistence;
|
|
2198
2246
|
}
|
|
2199
|
-
const current = dependencies.getCurrentCredentials();
|
|
2200
|
-
const rotated = current && current.refreshToken !== credentials.refreshToken ? current : null;
|
|
2201
2247
|
if (rotated && !isCodexCredentialsExpired(rotated)) return rotated;
|
|
2202
|
-
const
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
if (codexCredentialsPendingPersistence === refreshed) codexCredentialsPendingPersistence = null;
|
|
2248
|
+
const refreshed = await refreshDependencies.refreshCodexCredentials(base);
|
|
2249
|
+
codexCredentialsPendingPersistence.set(refreshKey, refreshed);
|
|
2250
|
+
await refreshDependencies.persistCodexCredentials(refreshed);
|
|
2251
|
+
if (codexCredentialsPendingPersistence.get(refreshKey) === refreshed) codexCredentialsPendingPersistence.delete(refreshKey);
|
|
2207
2252
|
return refreshed;
|
|
2208
2253
|
})();
|
|
2209
|
-
codexRefreshInFlight
|
|
2254
|
+
codexRefreshInFlight.set(refreshKey, attempt);
|
|
2210
2255
|
const clearAttempt = () => {
|
|
2211
|
-
if (codexRefreshInFlight === attempt) codexRefreshInFlight
|
|
2256
|
+
if (codexRefreshInFlight.get(refreshKey) === attempt) codexRefreshInFlight.delete(refreshKey);
|
|
2212
2257
|
};
|
|
2213
2258
|
attempt.then(clearAttempt, clearAttempt);
|
|
2214
2259
|
return attempt;
|
|
@@ -2241,6 +2286,17 @@ const setupCopilotToken = async (dependencies = defaultCopilotTokenDependencies)
|
|
|
2241
2286
|
});
|
|
2242
2287
|
};
|
|
2243
2288
|
const setupCodexToken = async () => {
|
|
2289
|
+
while (getRawProviderConfig("codex")?.enabled !== false) {
|
|
2290
|
+
const generation = codexRuntimeGeneration;
|
|
2291
|
+
try {
|
|
2292
|
+
await setupCodexTokenForGeneration(generation);
|
|
2293
|
+
} catch (error) {
|
|
2294
|
+
if (generation === codexRuntimeGeneration) throw error;
|
|
2295
|
+
}
|
|
2296
|
+
if (generation === codexRuntimeGeneration) return;
|
|
2297
|
+
}
|
|
2298
|
+
};
|
|
2299
|
+
const setupCodexTokenForGeneration = async (generation) => {
|
|
2244
2300
|
const configuredAccountId = getConfiguredCodexAccountId();
|
|
2245
2301
|
const loadedCredentials = getLoadedCodexCredentials();
|
|
2246
2302
|
if (configuredAccountId && loadedCredentials?.accountId === configuredAccountId && !isCodexCredentialsExpired(loadedCredentials) && codexRefreshLoopController) return;
|
|
@@ -2248,6 +2304,7 @@ const setupCodexToken = async () => {
|
|
|
2248
2304
|
let selectedAccountId = configuredAccountId;
|
|
2249
2305
|
if (!selectedAccountId) {
|
|
2250
2306
|
store = await readCodexCredentialStore();
|
|
2307
|
+
if (generation !== codexRuntimeGeneration) return;
|
|
2251
2308
|
if (!store || store.accounts.length === 0) throw new Error(`Codex credentials not found. Run \`copilot-api auth login --provider codex\` first.`);
|
|
2252
2309
|
if (store.accounts.length > 1) throw new Error("Multiple Codex accounts found but no account is selected. Run `copilot-api auth codex --use <alias-or-accountId>` first.");
|
|
2253
2310
|
selectedAccountId = store.accounts[0].accountId;
|
|
@@ -2261,6 +2318,7 @@ const setupCodexToken = async () => {
|
|
|
2261
2318
|
if (loadedCredentials && !selectedLoadedCredentials) stopCodexRefreshLoop();
|
|
2262
2319
|
if (!selectedLoadedCredentials) {
|
|
2263
2320
|
store ??= await readCodexCredentialStore();
|
|
2321
|
+
if (generation !== codexRuntimeGeneration) return;
|
|
2264
2322
|
if (!store || store.accounts.length === 0) throw new Error(`Codex credentials not found. Run \`copilot-api auth login --provider codex\` first.`);
|
|
2265
2323
|
}
|
|
2266
2324
|
const credentials = selectedLoadedCredentials ?? store?.accounts.find((account) => account.accountId === selectedAccountId);
|
|
@@ -2270,6 +2328,7 @@ const setupCodexToken = async () => {
|
|
|
2270
2328
|
consola.debug("Refreshing expired Codex credentials");
|
|
2271
2329
|
nextCredentials = await refreshCodexCredentialsOnce(credentials);
|
|
2272
2330
|
}
|
|
2331
|
+
if (generation !== codexRuntimeGeneration) return;
|
|
2273
2332
|
applyCodexCredentials(nextCredentials);
|
|
2274
2333
|
stopCodexRefreshLoop();
|
|
2275
2334
|
const controller = new AbortController();
|
|
@@ -2300,6 +2359,7 @@ const runCopilotRefreshLoop = async (refreshIn, signal, dependencies) => {
|
|
|
2300
2359
|
consola.debug("Refreshing Copilot token");
|
|
2301
2360
|
try {
|
|
2302
2361
|
const response = await dependencies.getCopilotToken();
|
|
2362
|
+
if (signal.aborted) return;
|
|
2303
2363
|
applyCopilotTokenResponse(response);
|
|
2304
2364
|
refreshAtMs = getRefreshDeadlineMs(response.refresh_in);
|
|
2305
2365
|
retryDelayMs = RETRY_REFRESH_DELAY_MS;
|
|
@@ -2378,6 +2438,6 @@ async function logUser(dependencies = defaultCopilotTokenDependencies) {
|
|
|
2378
2438
|
state.tokenBasedBilling = copilotUser.token_based_billing;
|
|
2379
2439
|
}
|
|
2380
2440
|
//#endregion
|
|
2381
|
-
export {
|
|
2441
|
+
export { state as $, compactAutoContinuePromptStarts as A, CODEX_API_BASE_URL as B, copilotHeaders as C, prepareInteractionHeaders as D, prepareForCompact as E, createAuthMiddleware as F, resolveTraceId as G, forwardCodexResponses as H, getConfiguredAdminApiKeys as I, createResponsesSafeStream as J, fetchUpstreamWithLifecycle as K, getConfiguredApiKeys as L, compactSummaryPromptStart as M, compactSystemPromptStarts as N, prepareMessageProxyHeaders as O, compactTextOnlyGuard as P, createWebSocketUrl as Q, getMissingApiKeysMessage as R, copilotBaseUrl as S, copilotWebSocketHeaders as T, generateTraceId as U, buildCodexRequestHeaders as V, requestContext as W, getResponsesStreamTerminalDisposition as X, encodePoolKeyPart as Y, createPooledWebSocketStream as Z, parseUserIdMetadata as _, removeCodexAccount as a, readGitHubToken as b, setupCopilotToken as c, generateRequestIdFromPayload as d, FULL_MODEL_CATALOG_HEADER as et, getRootSessionId as f, isResponsesStream as g, isNullish as h, persistCodexCredentials as i, compactMessageSections as j, initOpencodeVersion as k, setupGitHubToken as l, isAsyncIterable as m, invalidateCodexRuntime as n, selectCodexAccount as o, getUUID as p, createResponsesHttpEventStream as q, logUser as r, setupCodexToken as s, getCodexAccounts as t, stripInternalRequestHeaders as tt, stopCopilotRefreshLoop as u, getCopilotUsage as v, copilotModelsHeaders as w, readGitHubTokenFromEnv as x, GITHUB_TOKEN_ENV as y, loginCodex as z };
|
|
2382
2442
|
|
|
2383
|
-
//# sourceMappingURL=token-
|
|
2443
|
+
//# sourceMappingURL=token-0pmwyQAu.js.map
|