@jeffreycao/copilot-api 2.4.2 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- import { P as ensurePaths, i as listEnabledProviders, j as mergeConfigWithDefaults } from "./config-DVWu2hKk.js";
2
- import { K as state, S as initOpencodeVersion, _ as copilotModelsHeaders, h as copilotBaseUrl, i as setupCopilotToken, j as getMissingApiKeysMessage, m as readGitHubToken, q as HTTPError, t as logUser } from "./token-D0GGk3E8.js";
3
- import { i as runProviderSetup } from "./auth-DvqwYkJr.js";
4
- import { n as getLatestModelForFamily } from "./models-DKNAPa_j.js";
1
+ import { P as ensurePaths, i as listEnabledProviders, j as mergeConfigWithDefaults } from "./config-Dj2ZvQuL.js";
2
+ import { J as state, M as getConfiguredApiKeys, N as getMissingApiKeysMessage, Y as HTTPError, _ as copilotBaseUrl, g as readGitHubTokenFromEnv, h as readGitHubToken, i as setupCopilotToken, m as GITHUB_TOKEN_ENV, t as logUser, w as initOpencodeVersion, y as copilotModelsHeaders } from "./token-CaFzyRJX.js";
3
+ import { i as runProviderSetup } from "./auth-DQZ-A7MU.js";
4
+ import { n as getLatestModelForFamily } from "./models-12Y1nB8k.js";
5
5
  import { defineCommand } from "citty";
6
6
  import consola from "consola";
7
7
  import { createHash, randomUUID } from "node:crypto";
@@ -13,6 +13,7 @@ import { execSync } from "node:child_process";
13
13
  import clipboard from "clipboardy";
14
14
  import { serve } from "srvx";
15
15
  import invariant from "tiny-invariant";
16
+ import { isIP } from "node:net";
16
17
  import process$1 from "node:process";
17
18
  //#region src/lib/proxy.ts
18
19
  let proxyEnvDispatcher;
@@ -64,6 +65,65 @@ function initProxyFromEnv() {
64
65
  }
65
66
  }
66
67
  //#endregion
68
+ //#region src/lib/server-host-shared.ts
69
+ const INVALID_HOST_CHARACTERS = /[\s/?#]/;
70
+ const NORMALIZED_WILDCARD_HOSTS = new Set(["0.0.0.0", "::"]);
71
+ function stripIpv6Brackets(hostname) {
72
+ if (hostname.startsWith("[") && hostname.endsWith("]")) return hostname.slice(1, -1);
73
+ return hostname;
74
+ }
75
+ function normalizeHostnameBase(hostname) {
76
+ const normalized = stripIpv6Brackets(hostname.trim());
77
+ if (!normalized || INVALID_HOST_CHARACTERS.test(normalized)) throw new Error(`Invalid server host: ${JSON.stringify(hostname)}`);
78
+ return normalized;
79
+ }
80
+ function isWildcardHostname(hostname) {
81
+ return NORMALIZED_WILDCARD_HOSTS.has(stripIpv6Brackets(hostname.trim()));
82
+ }
83
+ //#endregion
84
+ //#region src/lib/server-host.ts
85
+ const DEFAULT_SERVER_HOST = "127.0.0.1";
86
+ function isLoopbackIpv4(hostname) {
87
+ return isIP(hostname) === 4 && hostname.split(".", 1)[0] === "127";
88
+ }
89
+ function isLoopbackMappedIpv4(hostname) {
90
+ try {
91
+ const mappedIpv4 = new URL(`http://[${hostname}]/`).hostname.slice(1, -1).match(/^::ffff:([\da-f]{1,4}):[\da-f]{1,4}$/);
92
+ if (!mappedIpv4) return false;
93
+ return (Number.parseInt(mappedIpv4[1], 16) & 65280) === 32512;
94
+ } catch {
95
+ return false;
96
+ }
97
+ }
98
+ function normalizeServerHostname(hostname) {
99
+ return normalizeHostnameBase(hostname);
100
+ }
101
+ function isLoopbackHostname(hostname) {
102
+ const normalized = normalizeServerHostname(hostname).toLowerCase();
103
+ if (normalized === "localhost" || normalized === "localhost.") return true;
104
+ if (isLoopbackIpv4(normalized)) return true;
105
+ if (isIP(normalized) !== 6) return false;
106
+ if (normalized === "::1" || normalized === "0:0:0:0:0:0:0:1") return true;
107
+ return isLoopbackMappedIpv4(normalized);
108
+ }
109
+ function resolveServerBinding(hostname, hasApiKeys) {
110
+ const normalizedHostname = normalizeServerHostname(hostname);
111
+ const networkExposed = !isLoopbackHostname(normalizedHostname);
112
+ if (networkExposed && !hasApiKeys) throw new Error(`Refusing to listen on non-loopback host ${JSON.stringify(normalizedHostname)} without gateway API keys. Run \`npx copilot-api auth keys --add <key>\` first, or use \`--host ${DEFAULT_SERVER_HOST}\`.`);
113
+ return {
114
+ hostname: normalizedHostname,
115
+ clientHostname: resolveClientHostname(normalizedHostname),
116
+ networkExposed
117
+ };
118
+ }
119
+ function resolveClientHostname(hostname) {
120
+ const normalizedHostname = normalizeServerHostname(hostname);
121
+ return isWildcardHostname(normalizedHostname) ? DEFAULT_SERVER_HOST : normalizedHostname.toLowerCase();
122
+ }
123
+ function formatServerUrl(hostname, port) {
124
+ return `http://${isIP(hostname) === 6 ? `[${hostname.replace("%", "%25")}]` : hostname}:${port}`;
125
+ }
126
+ //#endregion
67
127
  //#region src/lib/shell.ts
68
128
  function getShell() {
69
129
  const { platform, ppid, env } = process$1;
@@ -382,9 +442,26 @@ const cacheVsCodeSessionId = () => {
382
442
  };
383
443
  //#endregion
384
444
  //#region src/start.ts
385
- async function setupCopilotMode(githubToken, fromCli, serverUrl, claudeCode) {
445
+ async function resolveGitHubToken(cliToken) {
446
+ if (cliToken) return {
447
+ token: cliToken,
448
+ source: "cli"
449
+ };
450
+ const envToken = readGitHubTokenFromEnv();
451
+ if (envToken) return {
452
+ token: envToken,
453
+ source: "env"
454
+ };
455
+ const fileToken = await readGitHubToken();
456
+ if (fileToken) return {
457
+ token: fileToken,
458
+ source: "file"
459
+ };
460
+ return null;
461
+ }
462
+ async function setupCopilotMode(githubToken, source, serverUrl, claudeCode) {
386
463
  state.githubToken = githubToken;
387
- consola.info(fromCli ? "Using provided GitHub token" : "Using GitHub token from local file");
464
+ 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");
388
465
  await logUser();
389
466
  await cacheVSCodeVersion();
390
467
  cacheMacMachineId();
@@ -439,7 +516,7 @@ async function setupProviderMode(serverUrl, claudeCode) {
439
516
  consola.info("No enabled providers found. Setting one up...");
440
517
  await runProviderSetup();
441
518
  if (state.githubToken) {
442
- await setupCopilotMode(state.githubToken, false, serverUrl, claudeCode);
519
+ await setupCopilotMode(state.githubToken, "file", serverUrl, claudeCode);
443
520
  return;
444
521
  }
445
522
  const providersAfterSetup = listEnabledProviders();
@@ -450,6 +527,8 @@ async function runServer(options) {
450
527
  (await import("./tls-Aq1Dd8E2.js")).enableSystemCACompat();
451
528
  consola.options.throttle = 0;
452
529
  mergeConfigWithDefaults();
530
+ const configuredApiKeys = getConfiguredApiKeys();
531
+ const binding = resolveServerBinding(options.host, configuredApiKeys.length > 0);
453
532
  const missingApiKeysMessage = getMissingApiKeysMessage();
454
533
  if (missingApiKeysMessage) consola.info(missingApiKeysMessage);
455
534
  await initOpencodeVersion();
@@ -461,14 +540,15 @@ async function runServer(options) {
461
540
  }
462
541
  state.showToken = options.showToken;
463
542
  await ensurePaths();
464
- const serverUrl = `http://localhost:${options.port}`;
465
- const githubToken = options.githubToken || await readGitHubToken();
466
- if (githubToken) await setupCopilotMode(githubToken, Boolean(options.githubToken), serverUrl, options.claudeCode);
543
+ const serverUrl = formatServerUrl(binding.clientHostname, options.port);
544
+ const resolvedGitHubToken = await resolveGitHubToken(options.githubToken);
545
+ if (resolvedGitHubToken) await setupCopilotMode(resolvedGitHubToken.token, resolvedGitHubToken.source, serverUrl, options.claudeCode);
467
546
  else await setupProviderMode(serverUrl, options.claudeCode);
468
547
  consola.box(`🌐 Usage Viewer: ${serverUrl}/usage-viewer?endpoint=${serverUrl}/usage`);
469
- const { server } = await import("./server-BvDQf9Nd.js");
548
+ const { createServer } = await import("./server-B4-mT5EU.js");
470
549
  serve({
471
- fetch: server.fetch,
550
+ fetch: createServer({ networkExposed: binding.networkExposed }).fetch,
551
+ hostname: binding.hostname,
472
552
  port: options.port,
473
553
  bun: { idleTimeout: 0 }
474
554
  });
@@ -479,6 +559,11 @@ const start = defineCommand({
479
559
  description: "Start the Copilot API server"
480
560
  },
481
561
  args: {
562
+ host: {
563
+ type: "string",
564
+ default: process.env.HOST?.trim() || "127.0.0.1",
565
+ description: "Host to listen on"
566
+ },
482
567
  port: {
483
568
  alias: "p",
484
569
  type: "string",
@@ -515,6 +600,7 @@ const start = defineCommand({
515
600
  },
516
601
  run({ args }) {
517
602
  return runServer({
603
+ host: args.host,
518
604
  port: Number.parseInt(args.port, 10),
519
605
  verbose: args.verbose,
520
606
  githubToken: args["github-token"],
@@ -527,4 +613,4 @@ const start = defineCommand({
527
613
  //#endregion
528
614
  export { start };
529
615
 
530
- //# sourceMappingURL=start-BGY-GA8y.js.map
616
+ //# sourceMappingURL=start-BcGt4v2F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-BcGt4v2F.js","names":["get","process","getCopilotModels"],"sources":["../src/lib/proxy.ts","../src/lib/server-host-shared.ts","../src/lib/server-host.ts","../src/lib/shell.ts","../src/services/copilot/get-models.ts","../src/services/copilot/models-cache.ts","../src/lib/deviceid.ts","../src/services/get-vscode-version.ts","../src/services/vscode-env.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 copilot-api 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","import consola from \"consola\"\n\nimport { copilotBaseUrl, copilotModelsHeaders } from \"~/lib/api-config\"\n\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport type { ModelsResponse } from \"~/lib/types/models\"\n\nexport const getModels = async () => {\n consola.info(`Fetching models from ${copilotBaseUrl(state)}/models`)\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotModelsHeaders(state),\n })\n\n if (!response.ok) {\n const errorText = await response.clone().text()\n\n consola.error(\"Failed to get models response body\", errorText)\n\n throw new HTTPError(\"Failed to get models\", response)\n }\n\n return (await response.json()) as ModelsResponse\n}\n","import consola from \"consola\"\n\nimport { state } from \"~/lib/state\"\nimport { getModels as getCopilotModels } from \"~/services/copilot/get-models\"\n\n// Periodically refresh models so long-running daemons pick up new SKUs.\nconst MODELS_REFRESH_BASE_MS = 30 * 60 * 1000\nlet modelsRefreshTimer: ReturnType<typeof setTimeout> | null = null\n\nexport const stopModelsRefreshLoop = () => {\n if (modelsRefreshTimer) {\n clearTimeout(modelsRefreshTimer)\n modelsRefreshTimer = null\n }\n}\n\ntype ModelsFetcher = typeof getCopilotModels\n\nconst refreshModels = async (fetcher: ModelsFetcher) => {\n const prevIds = new Set(state.models?.data.map((m) => m.id) ?? [])\n const models = await fetcher()\n state.models = {\n ...models,\n data: models.data.filter(\n (model) =>\n model.policy?.state !== \"disabled\"\n && (model.model_picker_enabled\n || model.capabilities.type === \"embeddings\"),\n ),\n }\n const nextIds = state.models.data.map((m) => m.id)\n const added = nextIds.filter((id) => !prevIds.has(id))\n if (added.length > 0) {\n consola.info(`Models refresh: ${added.length} new`)\n } else {\n consola.debug(`Models refresh: no changes (${nextIds.length} total)`)\n }\n}\n\nconst scheduleModelsRefresh = (fetcher: ModelsFetcher, intervalMs: number) => {\n const jitter = Math.floor(Math.random() * (intervalMs / 6))\n const delay = intervalMs + jitter\n consola.debug(\n `Scheduling next models refresh in ${Math.round(delay / 1000)} seconds`,\n )\n\n stopModelsRefreshLoop()\n modelsRefreshTimer = setTimeout(async () => {\n try {\n await refreshModels(fetcher)\n } catch (error) {\n consola.warn(\"Failed to refresh models, keeping previous cache.\", error)\n } finally {\n scheduleModelsRefresh(fetcher, intervalMs)\n }\n }, delay)\n}\n\nexport async function cacheModels(\n fetcher: ModelsFetcher = getCopilotModels,\n intervalMs: number = MODELS_REFRESH_BASE_MS,\n): Promise<void> {\n await refreshModels(fetcher)\n scheduleModelsRefresh(fetcher, intervalMs)\n}\n","import consola from \"consola\"\nimport { randomUUID } from \"node:crypto\"\nimport path from \"node:path\"\n\nconst WINDOWS_DEVICE_ID_KEY = String.raw`\\SOFTWARE\\Microsoft\\DeveloperTools`\nconst WINDOWS_DEVICE_ID_NAME = \"deviceid\"\n\ntype RegistryArch = \"x86\" | \"x64\"\n\ninterface WinregConstructor {\n new (options: {\n hive: string\n key: string\n arch?: RegistryArch\n }): WinregRegistry\n HKCU: string\n REG_SZ: string\n}\n\ninterface WinregRegistry {\n get(\n name: string,\n callback: (error: RegistryError | null, item: RegistryItem | null) => void,\n ): void\n set(\n name: string,\n type: string,\n value: string,\n callback: (error: RegistryError | null) => void,\n ): void\n}\n\ninterface RegistryItem {\n value?: string\n}\n\ninterface RegistryError extends Error {\n code?: number | string\n}\n\nconst windows64Architectures = new Set([\"AMD64\", \"ARM64\", \"IA64\"])\n\nconst getPosixHomeDir = (): string => {\n if (!process.env.HOME) {\n throw new Error(\"Home directory not found\")\n }\n\n return process.env.HOME\n}\n\nconst getDeviceIdFilePath = (): string => {\n let folder: string\n\n switch (process.platform) {\n case \"darwin\": {\n folder = path.posix.join(\n getPosixHomeDir(),\n \"Library\",\n \"Application Support\",\n )\n break\n }\n case \"linux\": {\n folder =\n process.env.XDG_CACHE_HOME\n ?? path.posix.join(getPosixHomeDir(), \".cache\")\n break\n }\n default: {\n throw new Error(\"Unsupported platform\")\n }\n }\n\n return path.posix.join(folder, \"Microsoft\", \"DeveloperTools\", \"deviceid\")\n}\n\nconst isMissingFileError = (error: unknown): error is NodeJS.ErrnoException => {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\"\n}\n\nconst readStoredDeviceIdFile = async (\n filePath: string,\n): Promise<string | undefined> => {\n const { readFile } = await import(\"node:fs/promises\")\n\n try {\n return await readFile(filePath, \"utf8\")\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined\n }\n\n throw error\n }\n}\n\nconst writeStoredDeviceIdFile = async (\n filePath: string,\n deviceId: string,\n): Promise<void> => {\n const { mkdir, writeFile } = await import(\"node:fs/promises\")\n\n await mkdir(path.posix.dirname(filePath), { recursive: true })\n await writeFile(filePath, deviceId, \"utf8\")\n}\n\nconst getWindowsRegistryArch = (): RegistryArch | undefined => {\n const architecture = (\n process.env.PROCESSOR_ARCHITEW6432 ?? process.env.PROCESSOR_ARCHITECTURE\n )?.toUpperCase()\n\n return architecture && windows64Architectures.has(architecture) ?\n \"x64\"\n : undefined\n}\n\nconst loadWinreg = async (): Promise<WinregConstructor> => {\n const module = await import(\"winreg\")\n const winreg =\n \"default\" in module ? (module.default as unknown) : (module as unknown)\n\n return winreg as WinregConstructor\n}\n\nconst isMissingRegistryError = (error: RegistryError | null): boolean => {\n if (!error) {\n return false\n }\n\n const errorCode = Number(error.code)\n\n return Number.isFinite(errorCode) && errorCode === 1\n}\n\nconst createWindowsRegistry = async (): Promise<{\n registry: WinregRegistry\n regSz: string\n}> => {\n const Winreg = await loadWinreg()\n\n return {\n registry: new Winreg({\n hive: Winreg.HKCU,\n key: WINDOWS_DEVICE_ID_KEY,\n arch: getWindowsRegistryArch(),\n }),\n regSz: Winreg.REG_SZ,\n }\n}\n\nconst readRegistryString = async (\n registry: WinregRegistry,\n name: string,\n): Promise<string | undefined> => {\n return new Promise((resolve, reject) => {\n registry.get(name, (error, item) => {\n if (isMissingRegistryError(error)) {\n resolve(undefined)\n return\n }\n\n if (error) {\n reject(\n error instanceof Error ? error : new Error(\"Unknown registry error\"),\n )\n return\n }\n\n resolve(item?.value)\n })\n })\n}\n\nconst writeRegistryString = async ({\n registry,\n regSz,\n name,\n value,\n}: {\n registry: WinregRegistry\n regSz: string\n name: string\n value: string\n}): Promise<void> => {\n return new Promise((resolve, reject) => {\n registry.set(name, regSz, value, (error) => {\n if (error) {\n reject(\n error instanceof Error ? error : new Error(\"Unknown registry error\"),\n )\n return\n }\n\n resolve()\n })\n })\n}\n\nexport const getStoredVSCodeDeviceId = async (): Promise<\n string | undefined\n> => {\n switch (process.platform) {\n case \"win32\": {\n const { registry } = await createWindowsRegistry()\n\n return readRegistryString(registry, WINDOWS_DEVICE_ID_NAME)\n }\n case \"darwin\":\n case \"linux\": {\n return readStoredDeviceIdFile(getDeviceIdFilePath())\n }\n default: {\n throw new Error(\"Unsupported platform\")\n }\n }\n}\n\nconst setStoredVSCodeDeviceId = async (deviceId: string): Promise<void> => {\n switch (process.platform) {\n case \"win32\": {\n const { registry, regSz } = await createWindowsRegistry()\n\n await writeRegistryString({\n registry,\n regSz,\n name: WINDOWS_DEVICE_ID_NAME,\n value: deviceId,\n })\n return\n }\n case \"darwin\":\n case \"linux\": {\n await writeStoredDeviceIdFile(getDeviceIdFilePath(), deviceId)\n return\n }\n default: {\n throw new Error(\"Unsupported platform\")\n }\n }\n}\n\nconst createVSCodeDeviceId = (): string => randomUUID().toLowerCase()\n\nexport async function getVSCodeDeviceId(): Promise<string> {\n let deviceId: string | undefined\n\n try {\n deviceId = await getStoredVSCodeDeviceId()\n } catch (error) {\n consola.debug(\"Failed to read VSCode device id\", error)\n }\n\n if (deviceId) {\n return deviceId\n }\n\n const newDeviceId = createVSCodeDeviceId()\n\n try {\n await setStoredVSCodeDeviceId(newDeviceId)\n } catch (error) {\n consola.warn(\n \"Failed to persist VSCode device id, using ephemeral id\",\n error,\n )\n }\n\n return newDeviceId\n}\n","const FALLBACK = \"1.130.0\"\n\nexport async function getVSCodeVersion() {\n await Promise.resolve()\n return FALLBACK\n}\n","import consola from \"consola\"\nimport { createHash, randomUUID } from \"node:crypto\"\nimport { networkInterfaces } from \"node:os\"\n\nimport { getVSCodeDeviceId } from \"~/lib/deviceid\"\nimport { state } from \"~/lib/state\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n\nconst invalidMacAddresses = new Set([\n \"00:00:00:00:00:00\",\n \"ff:ff:ff:ff:ff:ff\",\n \"ac:de:48:00:11:22\",\n])\n\nfunction validateMacAddress(candidate: string): boolean {\n const tempCandidate = candidate.replaceAll(\"-\", \":\").toLowerCase()\n return !invalidMacAddresses.has(tempCandidate)\n}\n\nexport function getMac(): string | null {\n const ifaces = networkInterfaces()\n // eslint-disable-next-line guard-for-in\n for (const name in ifaces) {\n const networkInterface = ifaces[name]\n if (networkInterface) {\n for (const { mac } of networkInterface) {\n if (validateMacAddress(mac)) {\n return mac\n }\n }\n }\n }\n return null\n}\n\nexport const cacheMacMachineId = () => {\n const macAddress = getMac() ?? randomUUID()\n state.macMachineId = createHash(\"sha256\")\n .update(macAddress, \"utf8\")\n .digest(\"hex\")\n consola.debug(`Using machine ID: ${state.macMachineId}`)\n}\n\nexport const cacheVsCodeDeviceId = async () => {\n state.vsCodeDeviceId = await getVSCodeDeviceId()\n consola.debug(`Using VSCode device ID: ${state.vsCodeDeviceId}`)\n}\n\nconst SESSION_REFRESH_BASE_MS = 60 * 60 * 1000\nconst SESSION_REFRESH_JITTER_MS = 20 * 60 * 1000\nlet vsCodeSessionRefreshTimer: ReturnType<typeof setTimeout> | null = null\n\nconst generateSessionId = () => {\n state.vsCodeSessionId = randomUUID() + Date.now().toString()\n consola.debug(`Generated VSCode session ID: ${state.vsCodeSessionId}`)\n}\n\nexport const stopVsCodeSessionRefreshLoop = () => {\n if (vsCodeSessionRefreshTimer) {\n clearTimeout(vsCodeSessionRefreshTimer)\n vsCodeSessionRefreshTimer = null\n }\n}\n\nconst scheduleSessionIdRefresh = () => {\n const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS)\n const delay = SESSION_REFRESH_BASE_MS + randomDelay\n consola.debug(\n `Scheduling next VSCode session ID refresh in ${Math.round(\n delay / 1000,\n )} seconds`,\n )\n\n stopVsCodeSessionRefreshLoop()\n vsCodeSessionRefreshTimer = setTimeout(() => {\n try {\n generateSessionId()\n } catch (error) {\n consola.error(\"Failed to refresh session ID, rescheduling...\", error)\n } finally {\n scheduleSessionIdRefresh()\n }\n }, delay)\n}\n\nexport const cacheVsCodeSessionId = () => {\n stopVsCodeSessionRefreshLoop()\n generateSessionId()\n scheduleSessionIdRefresh()\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 { listEnabledProviders, mergeConfigWithDefaults } from \"./lib/config\"\nimport {\n GITHUB_TOKEN_ENV,\n readGitHubToken,\n readGitHubTokenFromEnv,\n} from \"./lib/credential-store\"\nimport { getLatestModelForFamily } from \"./lib/models\"\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\"\nimport { logUser, setupCopilotToken } from \"./lib/token\"\nimport { cacheModels } from \"./services/copilot/models-cache\"\nimport {\n cacheMacMachineId,\n cacheVSCodeVersion,\n cacheVsCodeSessionId,\n cacheVsCodeDeviceId,\n} from \"./services/vscode-env\"\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.githubToken = githubToken\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 logUser()\n\n await cacheVSCodeVersion()\n cacheMacMachineId()\n cacheVsCodeSessionId()\n await cacheVsCodeDeviceId()\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.info(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\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 CLAUDE_CODE_EFFORT_LEVEL: \"max\",\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 consola.info(\"No enabled providers found. Setting one up...\")\n await runProviderSetup()\n\n if (state.githubToken) {\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\n const serverUrl = formatServerUrl(binding.clientHostname, options.port)\n\n const resolvedGitHubToken = await resolveGitHubToken(options.githubToken)\n if (resolvedGitHubToken) {\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 `🌐 Usage 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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"}
@@ -1,4 +1,4 @@
1
- import { A as isResponsesApiWebSocketEnabled, E as getResponsesTransportConfig, N as PATHS, c as setProviderConfig, n as getRawProviderConfig, w as getConfig } from "./config-DVWu2hKk.js";
1
+ import { A as isResponsesApiWebSocketEnabled, E as getUpstreamTransportConfig, F as writeFileAtomically, N as PATHS, c as setProviderConfig, n as getRawProviderConfig, w as getConfig } from "./config-Dj2ZvQuL.js";
2
2
  import consola from "consola";
3
3
  import { createHash, randomBytes, randomUUID } from "node:crypto";
4
4
  import path from "node:path";
@@ -18,7 +18,30 @@ var HTTPError = class extends Error {
18
18
  this.response = response;
19
19
  }
20
20
  };
21
+ var UpstreamHeadersTimeoutError = class extends Error {
22
+ timeoutMs;
23
+ constructor(timeoutMs) {
24
+ super(`Upstream did not return headers within ${timeoutMs}ms`);
25
+ this.name = "UpstreamHeadersTimeoutError";
26
+ this.timeoutMs = timeoutMs;
27
+ }
28
+ };
29
+ var UpstreamStreamInactivityTimeoutError = class extends Error {
30
+ timeoutMs;
31
+ constructor(timeoutMs) {
32
+ super(`Upstream stream was inactive for ${timeoutMs}ms`);
33
+ this.name = "UpstreamStreamInactivityTimeoutError";
34
+ this.timeoutMs = timeoutMs;
35
+ }
36
+ };
21
37
  async function forwardError(c, error) {
38
+ if (error instanceof UpstreamHeadersTimeoutError || error instanceof UpstreamStreamInactivityTimeoutError) {
39
+ consola.error("Error occurred:", error);
40
+ return c.json({ error: {
41
+ message: error.message,
42
+ type: "upstream_timeout"
43
+ } }, 504);
44
+ }
22
45
  if (c.req.raw.signal.aborted || isAbortError$1(error)) return new Response(null, {
23
46
  status: 499,
24
47
  statusText: "Client Closed Request"
@@ -510,19 +533,37 @@ const createResponsesSafeStream = async function* (source, options = {}) {
510
533
  const isAbortError = (error) => error instanceof Error && error.name === "AbortError";
511
534
  //#endregion
512
535
  //#region src/services/responses-http.ts
513
- var ResponsesHeadersTimeoutError = class extends Error {
514
- constructor(timeoutMs) {
515
- super(`Responses upstream did not return headers within ${timeoutMs}ms`);
516
- this.name = "ResponsesHeadersTimeoutError";
517
- }
518
- };
519
- var ResponsesStreamInactivityTimeoutError = class extends Error {
520
- constructor(timeoutMs) {
521
- super(`Responses upstream stream was inactive for ${timeoutMs}ms`);
522
- this.name = "ResponsesStreamInactivityTimeoutError";
536
+ const createResponsesHttpEventStream = async function* (response) {
537
+ const responseBody = response.body;
538
+ if (!responseBody) return;
539
+ const reader = responseBody.getReader();
540
+ const readerBackedBody = new ReadableStream({
541
+ async pull(controller) {
542
+ const result = await reader.read();
543
+ if (result.done) {
544
+ controller.close();
545
+ return;
546
+ }
547
+ controller.enqueue(result.value);
548
+ },
549
+ async cancel(reason) {
550
+ await reader.cancel(reason);
551
+ }
552
+ });
553
+ try {
554
+ yield* events(new Response(readerBackedBody));
555
+ } finally {
556
+ try {
557
+ await reader.cancel();
558
+ } catch {} finally {
559
+ reader.releaseLock();
560
+ }
523
561
  }
524
562
  };
525
- async function fetchResponsesWithLifecycle(input, init, options) {
563
+ //#endregion
564
+ //#region src/services/upstream-http.ts
565
+ async function fetchUpstreamWithLifecycle(input, init, options) {
566
+ options.clientSignal?.throwIfAborted();
526
567
  const lifecycle = createRequestLifecycle(options);
527
568
  try {
528
569
  const response = await fetch(input, {
@@ -537,16 +578,9 @@ async function fetchResponsesWithLifecycle(input, init, options) {
537
578
  }
538
579
  const createRequestLifecycle = (options) => {
539
580
  const controller = new AbortController();
540
- const downstreamSignal = options.signal;
541
581
  let finished = false;
542
- let headersTimer = null;
543
- const abortFromDownstream = () => {
544
- controller.abort(toAbortReason(downstreamSignal?.reason));
545
- };
546
- if (downstreamSignal?.aborted) abortFromDownstream();
547
- else downstreamSignal?.addEventListener("abort", abortFromDownstream, { once: true });
548
- if (!controller.signal.aborted) headersTimer = setTimeout(() => {
549
- controller.abort(new ResponsesHeadersTimeoutError(options.headersTimeoutMs));
582
+ let headersTimer = setTimeout(() => {
583
+ controller.abort(new UpstreamHeadersTimeoutError(options.headersTimeoutMs));
550
584
  }, options.headersTimeoutMs);
551
585
  const clearHeadersTimer = () => {
552
586
  if (headersTimer === null) return;
@@ -557,7 +591,6 @@ const createRequestLifecycle = (options) => {
557
591
  if (finished) return;
558
592
  finished = true;
559
593
  clearHeadersTimer();
560
- downstreamSignal?.removeEventListener("abort", abortFromDownstream);
561
594
  };
562
595
  return {
563
596
  abort: (reason) => {
@@ -565,7 +598,6 @@ const createRequestLifecycle = (options) => {
565
598
  },
566
599
  finish,
567
600
  finishWithError: (error) => {
568
- clearHeadersTimer();
569
601
  const reason = controller.signal.reason;
570
602
  finish();
571
603
  return reason instanceof Error ? reason : toError(error);
@@ -628,38 +660,11 @@ const createManagedResponseBody = (body, lifecycle, options) => {
628
660
  }
629
661
  });
630
662
  };
631
- const createResponsesHttpEventStream = async function* (response, signal) {
632
- const responseBody = response.body;
633
- if (!responseBody) return;
634
- const reader = responseBody.getReader();
635
- const readerBackedBody = new ReadableStream({
636
- async pull(controller) {
637
- const result = await reader.read();
638
- if (result.done) {
639
- controller.close();
640
- return;
641
- }
642
- controller.enqueue(result.value);
643
- },
644
- async cancel(reason) {
645
- await reader.cancel(reason);
646
- }
647
- });
648
- try {
649
- yield* events(new Response(readerBackedBody), signal);
650
- } finally {
651
- try {
652
- await reader.cancel();
653
- } catch {} finally {
654
- reader.releaseLock();
655
- }
656
- }
657
- };
658
663
  const readWithLifecycle = async (reader, lifecycle, options) => await new Promise((resolve, reject) => {
659
664
  let settled = false;
660
665
  const signal = lifecycle.signal;
661
666
  const timer = setTimeout(() => {
662
- const error = new ResponsesStreamInactivityTimeoutError(options.streamInactivityTimeoutMs);
667
+ const error = new UpstreamStreamInactivityTimeoutError(options.streamInactivityTimeoutMs);
663
668
  lifecycle.abort(error);
664
669
  settle(() => reject(error));
665
670
  }, options.streamInactivityTimeoutMs);
@@ -804,33 +809,33 @@ function buildCodexResponsesWebSocketPayload(payload) {
804
809
  function buildCodexResponsesWebSocketUrl(baseUrl = CODEX_API_BASE_URL) {
805
810
  return createWebSocketUrl(resolveCodexResponsesUrl(baseUrl));
806
811
  }
807
- function prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl = CODEX_API_BASE_URL, signal) {
812
+ function prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl = CODEX_API_BASE_URL) {
808
813
  const headers = buildCodexResponsesWebSocketHeaders(requestHeaders);
809
814
  return {
810
815
  headers,
811
816
  payload: buildCodexResponsesWebSocketPayload(payload),
812
817
  poolKey: buildCodexResponsesWebSocketPoolKey(payload, headers, baseUrl),
813
- signal,
814
818
  url: buildCodexResponsesWebSocketUrl(baseUrl)
815
819
  };
816
820
  }
817
821
  async function forwardCodexResponses(payload, requestHeaders, baseUrl = CODEX_API_BASE_URL, options = {}) {
818
822
  consola.log(`<-- model: ${payload.model}`);
823
+ options.clientSignal?.throwIfAborted();
819
824
  const transport = resolveCodexResponsesTransport(options.transport);
820
- if (payload.stream && transport === "websocket") return forwardCodexResponsesOverWebSocket(payload, requestHeaders, baseUrl, options.signal);
825
+ if (payload.stream && transport === "websocket") return forwardCodexResponsesOverWebSocket(payload, requestHeaders, baseUrl, options.clientSignal);
821
826
  const normalizedPayload = normalizeCodexResponsesPayload(payload);
822
- const transportConfig = getResponsesTransportConfig();
823
- const response = await fetchResponsesWithLifecycle(resolveCodexResponsesUrl(baseUrl), {
827
+ const transportConfig = getUpstreamTransportConfig();
828
+ const response = await fetchUpstreamWithLifecycle(resolveCodexResponsesUrl(baseUrl), {
824
829
  method: "POST",
825
830
  headers: buildCodexResponsesHeaders(requestHeaders, { stream: normalizedPayload.stream }),
826
831
  body: JSON.stringify(normalizedPayload)
827
832
  }, {
833
+ clientSignal: options.clientSignal,
828
834
  headersTimeoutMs: transportConfig.headersTimeoutMs,
829
- signal: options.signal,
830
835
  streamInactivityTimeoutMs: transportConfig.streamInactivityTimeoutMs
831
836
  });
832
837
  if (!response.ok) throw new HTTPError("Failed to create codex responses", response);
833
- if (normalizedPayload.stream) return createResponsesSafeStream(createResponsesHttpEventStream(response, options.signal), { signal: options.signal });
838
+ if (normalizedPayload.stream) return createResponsesSafeStream(createResponsesHttpEventStream(response));
834
839
  return await response.json();
835
840
  }
836
841
  const normalizeCodexResponsesPayload = (payload) => {
@@ -896,12 +901,12 @@ const buildCodexResponsesWebSocketPoolKey = (payload, headers, baseUrl) => {
896
901
  headerFingerprint
897
902
  ].map(encodePoolKeyPart).join("|");
898
903
  };
899
- const forwardCodexResponsesOverWebSocket = (payload, requestHeaders, baseUrl, signal) => {
900
- return createCodexResponsesWebSocketStream(prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl, signal));
904
+ const forwardCodexResponsesOverWebSocket = (payload, requestHeaders, baseUrl, clientSignal) => {
905
+ return createCodexResponsesWebSocketStream(prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl), clientSignal);
901
906
  };
902
- const createCodexResponsesWebSocketStream = (request) => {
903
- const transportConfig = getResponsesTransportConfig();
904
- return createResponsesSafeStream(createPooledWebSocketStream(request, {
907
+ const createCodexResponsesWebSocketStream = (request, clientSignal) => {
908
+ const transportConfig = getUpstreamTransportConfig();
909
+ return createResponsesSafeStream(createClientPreflightStream(createPooledWebSocketStream(request, {
905
910
  createChunk: createCodexResponsesWebSocketStreamChunk,
906
911
  maxBufferedBytes: transportConfig.websocketMaxBufferedBytes,
907
912
  maxBufferedMessages: transportConfig.websocketMaxBufferedMessages,
@@ -912,7 +917,11 @@ const createCodexResponsesWebSocketStream = (request) => {
912
917
  streamInactivityTimeoutMs: transportConfig.streamInactivityTimeoutMs,
913
918
  streamErrorMessage: "Upstream connection lost, Codex responses websocket stream error",
914
919
  terminalChunkMissingMessage: "Codex responses websocket ended without a terminal response, retry your request."
915
- }), { signal: request.signal });
920
+ }), clientSignal));
921
+ };
922
+ const createClientPreflightStream = async function* (source, clientSignal) {
923
+ if (clientSignal?.aborted) return;
924
+ yield* source;
916
925
  };
917
926
  const createCodexResponsesWebSocketStreamChunk = (data) => {
918
927
  if (data === "[DONE]") return { data };
@@ -1080,7 +1089,7 @@ async function exchangeAuthorizationCode(code, verifier) {
1080
1089
  throw new Error(`Codex token exchange failed (${response.status}): ${details || response.statusText}`);
1081
1090
  }
1082
1091
  const payload = await response.json();
1083
- if (typeof payload.access_token !== "string" || typeof payload.refresh_token !== "string" || typeof payload.expires_in !== "number") throw new TypeError(`Codex token exchange response missing fields: ${JSON.stringify(payload)}`);
1092
+ if (typeof payload.access_token !== "string" || typeof payload.refresh_token !== "string" || typeof payload.expires_in !== "number") throw new TypeError("Codex token exchange response missing required fields");
1084
1093
  return {
1085
1094
  accessToken: payload.access_token,
1086
1095
  refreshToken: payload.refresh_token,
@@ -1102,7 +1111,7 @@ async function refreshAccessToken(refreshToken) {
1102
1111
  throw new Error(`Codex token refresh failed (${response.status}): ${details || response.statusText}`);
1103
1112
  }
1104
1113
  const payload = await response.json();
1105
- if (typeof payload.access_token !== "string" || typeof payload.refresh_token !== "string" || typeof payload.expires_in !== "number") throw new TypeError(`Codex token refresh response missing fields: ${JSON.stringify(payload)}`);
1114
+ if (typeof payload.access_token !== "string" || typeof payload.refresh_token !== "string" || typeof payload.expires_in !== "number") throw new TypeError("Codex token refresh response missing required fields");
1106
1115
  return {
1107
1116
  accessToken: payload.access_token,
1108
1117
  refreshToken: payload.refresh_token,
@@ -1565,14 +1574,8 @@ async function readOptionalFile(filePath) {
1565
1574
  throw error;
1566
1575
  }
1567
1576
  }
1568
- async function writeProtectedFile(filePath, content) {
1569
- await fs.mkdir(path.dirname(filePath), { recursive: true });
1570
- await fs.writeFile(filePath, content, "utf8");
1571
- try {
1572
- await fs.chmod(filePath, 384);
1573
- } catch {
1574
- return;
1575
- }
1577
+ function writeProtectedFile(filePath, content) {
1578
+ return Promise.resolve().then(() => writeFileAtomically(filePath, content));
1576
1579
  }
1577
1580
  function normalizeCodexCredentials(credentials) {
1578
1581
  if (!credentials || typeof credentials !== "object") return null;
@@ -1588,6 +1591,10 @@ function normalizeCodexCredentials(credentials) {
1588
1591
  async function readGitHubToken() {
1589
1592
  return (await readOptionalFile(PATHS.GITHUB_TOKEN_PATH))?.trim() || null;
1590
1593
  }
1594
+ const GITHUB_TOKEN_ENV = "COPILOT_API_GITHUB_TOKEN";
1595
+ function readGitHubTokenFromEnv() {
1596
+ return process.env["COPILOT_API_GITHUB_TOKEN"]?.trim() || void 0;
1597
+ }
1591
1598
  async function writeGitHubToken(token) {
1592
1599
  await writeProtectedFile(PATHS.GITHUB_TOKEN_PATH, token.trim());
1593
1600
  }
@@ -1744,7 +1751,7 @@ async function pollAccessToken(deviceCode) {
1744
1751
  continue;
1745
1752
  }
1746
1753
  const json = await response.json();
1747
- consola.debug("Polling access token response:", json);
1754
+ consola.debug("Polling access token response received");
1748
1755
  const { access_token } = json;
1749
1756
  if (access_token) return access_token;
1750
1757
  else await sleep(sleepDuration);
@@ -1951,6 +1958,6 @@ async function logUser(dependencies = defaultCopilotTokenDependencies) {
1951
1958
  state.tokenBasedBilling = copilotUser.token_based_billing;
1952
1959
  }
1953
1960
  //#endregion
1954
- export { getConfiguredApiKeys as A, fetchResponsesWithLifecycle as B, compactAutoContinuePromptStarts as C, compactTextOnlyGuard as D, compactSystemPromptStarts as E, forwardCodexResponses as F, createWebSocketUrl as G, encodePoolKeyPart as H, generateTraceId as I, forwardError as J, state as K, requestContext as L, loginCodex as M, CODEX_API_BASE_URL as N, createAuthMiddleware as O, buildCodexRequestHeaders as P, resolveTraceId as R, initOpencodeVersion as S, compactSummaryPromptStart as T, isTerminalResponsesStreamChunk as U, createResponsesSafeStream as V, createPooledWebSocketStream as W, copilotModelsHeaders as _, setupGitHubToken as a, prepareInteractionHeaders as b, getUUID as c, isResponsesStream as d, parseUserIdMetadata as f, copilotHeaders as g, copilotBaseUrl as h, setupCopilotToken as i, getMissingApiKeysMessage as j, getConfiguredAdminApiKeys as k, isAsyncIterable as l, readGitHubToken as m, persistCodexCredentials as n, generateRequestIdFromPayload as o, getCopilotUsage as p, HTTPError as q, setupCodexToken as r, getRootSessionId as s, logUser as t, isNullish as u, copilotWebSocketHeaders as v, compactMessageSections as w, prepareMessageProxyHeaders as x, prepareForCompact as y, createResponsesHttpEventStream as z };
1961
+ export { createAuthMiddleware as A, resolveTraceId as B, prepareMessageProxyHeaders as C, compactSummaryPromptStart as D, compactMessageSections as E, CODEX_API_BASE_URL as F, isTerminalResponsesStreamChunk as G, createResponsesHttpEventStream as H, buildCodexRequestHeaders as I, state as J, createPooledWebSocketStream as K, forwardCodexResponses as L, getConfiguredApiKeys as M, getMissingApiKeysMessage as N, compactSystemPromptStarts as O, loginCodex as P, generateTraceId as R, prepareInteractionHeaders as S, compactAutoContinuePromptStarts as T, createResponsesSafeStream as U, fetchUpstreamWithLifecycle as V, encodePoolKeyPart as W, forwardError as X, HTTPError as Y, copilotBaseUrl as _, setupGitHubToken as a, copilotWebSocketHeaders as b, getUUID as c, isResponsesStream as d, parseUserIdMetadata as f, readGitHubTokenFromEnv as g, readGitHubToken as h, setupCopilotToken as i, getConfiguredAdminApiKeys as j, compactTextOnlyGuard as k, isAsyncIterable as l, GITHUB_TOKEN_ENV as m, persistCodexCredentials as n, generateRequestIdFromPayload as o, getCopilotUsage as p, createWebSocketUrl as q, setupCodexToken as r, getRootSessionId as s, logUser as t, isNullish as u, copilotHeaders as v, initOpencodeVersion as w, prepareForCompact as x, copilotModelsHeaders as y, requestContext as z };
1955
1962
 
1956
- //# sourceMappingURL=token-D0GGk3E8.js.map
1963
+ //# sourceMappingURL=token-CaFzyRJX.js.map