@jeffreycao/copilot-api 2.6.28 → 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-CgMFSux_.js → auth-CmKD_Gmp.js} +2 -2
- package/dist/{auth-CgMFSux_.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-sTarDtg3.js → server-VjfrS2Aw.js} +79 -4
- package/dist/server-VjfrS2Aw.js.map +1 -0
- package/dist/{start-DPRCrNJa.js → start-DX3Q5lol.js} +8 -284
- package/dist/start-DX3Q5lol.js.map +1 -0
- package/dist/{token-CZr63uyO.js → token-0pmwyQAu.js} +66 -29
- package/dist/token-0pmwyQAu.js.map +1 -0
- package/package.json +1 -1
- package/dist/auth-C5B75e7U.js +0 -2
- package/dist/models-C_0HbW3K.js +0 -90
- package/dist/models-C_0HbW3K.js.map +0 -1
- package/dist/server-sTarDtg3.js.map +0 -1
- package/dist/start-DPRCrNJa.js.map +0 -1
- package/dist/token-CZr63uyO.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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"}
|
|
@@ -1837,6 +1837,8 @@ async function writeCodexCredentials(credentials, options = {}) {
|
|
|
1837
1837
|
const accountIdSelector = normalizeCodexAccountSelector(normalizedCredentials.accountId);
|
|
1838
1838
|
const existingIndex = store.accounts.findIndex((account) => account.accountId === normalizedCredentials.accountId);
|
|
1839
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;
|
|
1840
1842
|
if (existingIndex < 0 && store.accounts.some((account) => normalizeCodexAccountSelector(account.accountId) === accountIdSelector)) throw new Error(`Codex account id '${normalizedCredentials.accountId}' is already in use`);
|
|
1841
1843
|
if (existingIndex < 0 && store.accounts.length >= 3) throw new Error(`Codex supports at most 3 accounts`);
|
|
1842
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`);
|
|
@@ -2077,8 +2079,9 @@ function describeError(error) {
|
|
|
2077
2079
|
//#region src/lib/token.ts
|
|
2078
2080
|
let copilotRefreshLoopController = null;
|
|
2079
2081
|
let codexRefreshLoopController = null;
|
|
2080
|
-
let
|
|
2081
|
-
|
|
2082
|
+
let codexRuntimeGeneration = 0;
|
|
2083
|
+
const codexRefreshInFlight = /* @__PURE__ */ new Map();
|
|
2084
|
+
const codexCredentialsPendingPersistence = /* @__PURE__ */ new Map();
|
|
2082
2085
|
const defaultCopilotTokenDependencies = {
|
|
2083
2086
|
getCopilotToken,
|
|
2084
2087
|
getCopilotUsage
|
|
@@ -2093,6 +2096,14 @@ const stopCodexRefreshLoop = () => {
|
|
|
2093
2096
|
codexRefreshLoopController.abort();
|
|
2094
2097
|
codexRefreshLoopController = null;
|
|
2095
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
|
+
};
|
|
2096
2107
|
function applyCodexCredentials(credentials) {
|
|
2097
2108
|
state.codexAccessToken = credentials.accessToken;
|
|
2098
2109
|
state.codexRefreshToken = credentials.refreshToken;
|
|
@@ -2173,17 +2184,21 @@ async function removeCodexAccount(selector) {
|
|
|
2173
2184
|
});
|
|
2174
2185
|
}
|
|
2175
2186
|
async function persistCodexCredentials(credentials, options = {}) {
|
|
2187
|
+
const generation = options.runtimeGeneration ?? codexRuntimeGeneration;
|
|
2176
2188
|
const persist = async () => {
|
|
2177
2189
|
await writeCodexCredentials(credentials, {
|
|
2178
2190
|
alias: options.alias,
|
|
2179
|
-
insertIfMissing: options.insertIfMissing
|
|
2191
|
+
insertIfMissing: options.insertIfMissing,
|
|
2192
|
+
expectedRefreshToken: options.expectedRefreshToken
|
|
2180
2193
|
});
|
|
2181
2194
|
if (options.syncProvider !== false) syncCodexProviderConfig({
|
|
2182
2195
|
accountId: options.activateAccount ? credentials.accountId : void 0,
|
|
2183
2196
|
enabled: options.enableProvider ? true : void 0
|
|
2184
2197
|
});
|
|
2185
|
-
applyCodexCredentials(credentials);
|
|
2186
|
-
|
|
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
|
+
}
|
|
2187
2202
|
};
|
|
2188
2203
|
if (options.syncProvider === false) {
|
|
2189
2204
|
await persist();
|
|
@@ -2191,14 +2206,19 @@ async function persistCodexCredentials(credentials, options = {}) {
|
|
|
2191
2206
|
}
|
|
2192
2207
|
await withCodexAccountMutationLock(persist);
|
|
2193
2208
|
}
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
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
|
+
}
|
|
2202
2222
|
/**
|
|
2203
2223
|
* Refreshes and persists Codex credentials through one module level
|
|
2204
2224
|
* single-flight guard.
|
|
@@ -2209,29 +2229,31 @@ const defaultCodexRefreshDependencies = {
|
|
|
2209
2229
|
* Codex request, so a burst of requests (or the background loop waking at the
|
|
2210
2230
|
* same moment) must share a single attempt instead of burning the token.
|
|
2211
2231
|
*/
|
|
2212
|
-
function refreshCodexCredentialsOnce(credentials, dependencies
|
|
2213
|
-
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);
|
|
2214
2239
|
if (inFlight) return inFlight;
|
|
2215
2240
|
const attempt = (async () => {
|
|
2216
|
-
const pendingPersistence = codexCredentialsPendingPersistence;
|
|
2241
|
+
const pendingPersistence = codexCredentialsPendingPersistence.get(refreshKey);
|
|
2217
2242
|
if (pendingPersistence) {
|
|
2218
|
-
await
|
|
2219
|
-
if (codexCredentialsPendingPersistence === pendingPersistence) codexCredentialsPendingPersistence
|
|
2243
|
+
await refreshDependencies.persistCodexCredentials(pendingPersistence);
|
|
2244
|
+
if (codexCredentialsPendingPersistence.get(refreshKey) === pendingPersistence) codexCredentialsPendingPersistence.delete(refreshKey);
|
|
2220
2245
|
return pendingPersistence;
|
|
2221
2246
|
}
|
|
2222
|
-
const current = dependencies.getCurrentCredentials();
|
|
2223
|
-
const rotated = current && current.refreshToken !== credentials.refreshToken ? current : null;
|
|
2224
2247
|
if (rotated && !isCodexCredentialsExpired(rotated)) return rotated;
|
|
2225
|
-
const
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
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);
|
|
2230
2252
|
return refreshed;
|
|
2231
2253
|
})();
|
|
2232
|
-
codexRefreshInFlight
|
|
2254
|
+
codexRefreshInFlight.set(refreshKey, attempt);
|
|
2233
2255
|
const clearAttempt = () => {
|
|
2234
|
-
if (codexRefreshInFlight === attempt) codexRefreshInFlight
|
|
2256
|
+
if (codexRefreshInFlight.get(refreshKey) === attempt) codexRefreshInFlight.delete(refreshKey);
|
|
2235
2257
|
};
|
|
2236
2258
|
attempt.then(clearAttempt, clearAttempt);
|
|
2237
2259
|
return attempt;
|
|
@@ -2264,6 +2286,17 @@ const setupCopilotToken = async (dependencies = defaultCopilotTokenDependencies)
|
|
|
2264
2286
|
});
|
|
2265
2287
|
};
|
|
2266
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) => {
|
|
2267
2300
|
const configuredAccountId = getConfiguredCodexAccountId();
|
|
2268
2301
|
const loadedCredentials = getLoadedCodexCredentials();
|
|
2269
2302
|
if (configuredAccountId && loadedCredentials?.accountId === configuredAccountId && !isCodexCredentialsExpired(loadedCredentials) && codexRefreshLoopController) return;
|
|
@@ -2271,6 +2304,7 @@ const setupCodexToken = async () => {
|
|
|
2271
2304
|
let selectedAccountId = configuredAccountId;
|
|
2272
2305
|
if (!selectedAccountId) {
|
|
2273
2306
|
store = await readCodexCredentialStore();
|
|
2307
|
+
if (generation !== codexRuntimeGeneration) return;
|
|
2274
2308
|
if (!store || store.accounts.length === 0) throw new Error(`Codex credentials not found. Run \`copilot-api auth login --provider codex\` first.`);
|
|
2275
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.");
|
|
2276
2310
|
selectedAccountId = store.accounts[0].accountId;
|
|
@@ -2284,6 +2318,7 @@ const setupCodexToken = async () => {
|
|
|
2284
2318
|
if (loadedCredentials && !selectedLoadedCredentials) stopCodexRefreshLoop();
|
|
2285
2319
|
if (!selectedLoadedCredentials) {
|
|
2286
2320
|
store ??= await readCodexCredentialStore();
|
|
2321
|
+
if (generation !== codexRuntimeGeneration) return;
|
|
2287
2322
|
if (!store || store.accounts.length === 0) throw new Error(`Codex credentials not found. Run \`copilot-api auth login --provider codex\` first.`);
|
|
2288
2323
|
}
|
|
2289
2324
|
const credentials = selectedLoadedCredentials ?? store?.accounts.find((account) => account.accountId === selectedAccountId);
|
|
@@ -2293,6 +2328,7 @@ const setupCodexToken = async () => {
|
|
|
2293
2328
|
consola.debug("Refreshing expired Codex credentials");
|
|
2294
2329
|
nextCredentials = await refreshCodexCredentialsOnce(credentials);
|
|
2295
2330
|
}
|
|
2331
|
+
if (generation !== codexRuntimeGeneration) return;
|
|
2296
2332
|
applyCodexCredentials(nextCredentials);
|
|
2297
2333
|
stopCodexRefreshLoop();
|
|
2298
2334
|
const controller = new AbortController();
|
|
@@ -2323,6 +2359,7 @@ const runCopilotRefreshLoop = async (refreshIn, signal, dependencies) => {
|
|
|
2323
2359
|
consola.debug("Refreshing Copilot token");
|
|
2324
2360
|
try {
|
|
2325
2361
|
const response = await dependencies.getCopilotToken();
|
|
2362
|
+
if (signal.aborted) return;
|
|
2326
2363
|
applyCopilotTokenResponse(response);
|
|
2327
2364
|
refreshAtMs = getRefreshDeadlineMs(response.refresh_in);
|
|
2328
2365
|
retryDelayMs = RETRY_REFRESH_DELAY_MS;
|
|
@@ -2401,6 +2438,6 @@ async function logUser(dependencies = defaultCopilotTokenDependencies) {
|
|
|
2401
2438
|
state.tokenBasedBilling = copilotUser.token_based_billing;
|
|
2402
2439
|
}
|
|
2403
2440
|
//#endregion
|
|
2404
|
-
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 };
|
|
2405
2442
|
|
|
2406
|
-
//# sourceMappingURL=token-
|
|
2443
|
+
//# sourceMappingURL=token-0pmwyQAu.js.map
|