@jeffreycao/copilot-api 1.3.4 → 1.3.7

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.
@@ -0,0 +1,259 @@
1
+ import { ensurePaths } from "./paths-Cla6y5eD.js";
2
+ import { cacheMacMachineId, cacheModels, cacheVSCodeVersion, cacheVsCodeSessionId, state } from "./utils-DKqD66k9.js";
3
+ import { setupCopilotToken, setupGitHubToken } from "./token-8AyBHdsS.js";
4
+ import { mergeConfigWithDefaults } from "./config-DYOE_-p1.js";
5
+ import { defineCommand } from "citty";
6
+ import consola from "consola";
7
+ import clipboard from "clipboardy";
8
+ import { serve } from "srvx";
9
+ import invariant from "tiny-invariant";
10
+ import { getProxyForUrl } from "proxy-from-env";
11
+ import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
12
+ import { execSync } from "node:child_process";
13
+ import process from "node:process";
14
+
15
+ //#region src/lib/proxy.ts
16
+ function initProxyFromEnv() {
17
+ if (typeof Bun !== "undefined") return;
18
+ try {
19
+ const direct = new Agent();
20
+ const proxies = /* @__PURE__ */ new Map();
21
+ setGlobalDispatcher({
22
+ dispatch(options, handler) {
23
+ try {
24
+ const origin = typeof options.origin === "string" ? new URL(options.origin) : options.origin;
25
+ const raw = getProxyForUrl(origin.toString());
26
+ const proxyUrl = raw && raw.length > 0 ? raw : void 0;
27
+ if (!proxyUrl) {
28
+ consola.debug(`HTTP proxy bypass: ${origin.hostname}`);
29
+ return direct.dispatch(options, handler);
30
+ }
31
+ let agent = proxies.get(proxyUrl);
32
+ if (!agent) {
33
+ agent = new ProxyAgent(proxyUrl);
34
+ proxies.set(proxyUrl, agent);
35
+ }
36
+ let label = proxyUrl;
37
+ try {
38
+ const u = new URL(proxyUrl);
39
+ label = `${u.protocol}//${u.host}`;
40
+ } catch {}
41
+ consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`);
42
+ return agent.dispatch(options, handler);
43
+ } catch {
44
+ return direct.dispatch(options, handler);
45
+ }
46
+ },
47
+ close() {
48
+ return direct.close();
49
+ },
50
+ destroy() {
51
+ return direct.destroy();
52
+ }
53
+ });
54
+ consola.debug("HTTP proxy configured from environment (per-URL)");
55
+ } catch (err) {
56
+ consola.debug("Proxy setup skipped:", err);
57
+ }
58
+ }
59
+
60
+ //#endregion
61
+ //#region src/lib/shell.ts
62
+ function getShell() {
63
+ const { platform, ppid, env } = process;
64
+ if (platform === "win32") {
65
+ try {
66
+ const command = `wmic process get ParentProcessId,Name | findstr "${ppid}"`;
67
+ if (execSync(command, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
68
+ } catch {
69
+ return "cmd";
70
+ }
71
+ return "cmd";
72
+ } else {
73
+ const shellPath = env.SHELL;
74
+ if (shellPath) {
75
+ if (shellPath.endsWith("zsh")) return "zsh";
76
+ if (shellPath.endsWith("fish")) return "fish";
77
+ if (shellPath.endsWith("bash")) return "bash";
78
+ }
79
+ return "sh";
80
+ }
81
+ }
82
+ /**
83
+ * Generates a copy-pasteable script to set multiple environment variables
84
+ * and run a subsequent command.
85
+ * @param {EnvVars} envVars - An object of environment variables to set.
86
+ * @param {string} commandToRun - The command to run after setting the variables.
87
+ * @returns {string} The formatted script string.
88
+ */
89
+ function generateEnvScript(envVars, commandToRun = "") {
90
+ const shell = getShell();
91
+ const filteredEnvVars = Object.entries(envVars).filter(([, value]) => value !== void 0);
92
+ let commandBlock;
93
+ switch (shell) {
94
+ case "powershell":
95
+ commandBlock = filteredEnvVars.map(([key, value]) => `$env:${key} = ${value}`).join("; ");
96
+ break;
97
+ case "cmd":
98
+ commandBlock = filteredEnvVars.map(([key, value]) => `set ${key}=${value}`).join(" & ");
99
+ break;
100
+ case "fish":
101
+ commandBlock = filteredEnvVars.map(([key, value]) => `set -gx ${key} ${value}`).join("; ");
102
+ break;
103
+ default: {
104
+ const assignments = filteredEnvVars.map(([key, value]) => `${key}=${value}`).join(" ");
105
+ commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : "";
106
+ break;
107
+ }
108
+ }
109
+ if (commandBlock && commandToRun) return `${commandBlock}${shell === "cmd" ? " & " : " && "}${commandToRun}`;
110
+ return commandBlock || commandToRun;
111
+ }
112
+
113
+ //#endregion
114
+ //#region src/start.ts
115
+ async function runServer(options) {
116
+ mergeConfigWithDefaults();
117
+ if (options.proxyEnv) initProxyFromEnv();
118
+ state.verbose = options.verbose;
119
+ if (options.verbose) {
120
+ consola.level = 5;
121
+ consola.info("Verbose logging enabled");
122
+ }
123
+ state.accountType = options.accountType;
124
+ if (options.accountType !== "individual") consola.info(`Using ${options.accountType} plan GitHub account`);
125
+ state.manualApprove = options.manual;
126
+ state.rateLimitSeconds = options.rateLimit;
127
+ state.rateLimitWait = options.rateLimitWait;
128
+ state.showToken = options.showToken;
129
+ await ensurePaths();
130
+ await cacheVSCodeVersion();
131
+ cacheMacMachineId();
132
+ cacheVsCodeSessionId();
133
+ if (options.githubToken) {
134
+ state.githubToken = options.githubToken;
135
+ consola.info("Using provided GitHub token");
136
+ } else await setupGitHubToken();
137
+ await setupCopilotToken();
138
+ await cacheModels();
139
+ consola.info(`Available models: \n${state.models?.data.map((model) => `- ${model.id}`).join("\n")}`);
140
+ const serverUrl = `http://localhost:${options.port}`;
141
+ if (options.claudeCode) {
142
+ invariant(state.models, "Models should be loaded by now");
143
+ const selectedModel = await consola.prompt("Select a model to use with Claude Code", {
144
+ type: "select",
145
+ options: state.models.data.map((model) => model.id)
146
+ });
147
+ const selectedSmallModel = await consola.prompt("Select a small model to use with Claude Code", {
148
+ type: "select",
149
+ options: state.models.data.map((model) => model.id)
150
+ });
151
+ const command = generateEnvScript({
152
+ ANTHROPIC_BASE_URL: serverUrl,
153
+ ANTHROPIC_AUTH_TOKEN: "dummy",
154
+ ANTHROPIC_MODEL: selectedModel,
155
+ ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,
156
+ ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,
157
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,
158
+ DISABLE_NON_ESSENTIAL_MODEL_CALLS: "1",
159
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1"
160
+ }, "claude");
161
+ try {
162
+ clipboard.writeSync(command);
163
+ consola.success("Copied Claude Code command to clipboard!");
164
+ } catch {
165
+ consola.warn("Failed to copy to clipboard. Here is the Claude Code command:");
166
+ consola.log(command);
167
+ }
168
+ }
169
+ consola.box(`🌐 Usage Viewer: ${serverUrl}/usage-viewer?endpoint=${serverUrl}/usage`);
170
+ const { server } = await import("./server-BBSm2bHY.js");
171
+ serve({
172
+ fetch: server.fetch,
173
+ port: options.port,
174
+ bun: { idleTimeout: 0 }
175
+ });
176
+ }
177
+ const start = defineCommand({
178
+ meta: {
179
+ name: "start",
180
+ description: "Start the Copilot API server"
181
+ },
182
+ args: {
183
+ port: {
184
+ alias: "p",
185
+ type: "string",
186
+ default: "4141",
187
+ description: "Port to listen on"
188
+ },
189
+ verbose: {
190
+ alias: "v",
191
+ type: "boolean",
192
+ default: false,
193
+ description: "Enable verbose logging"
194
+ },
195
+ "account-type": {
196
+ alias: "a",
197
+ type: "string",
198
+ default: "individual",
199
+ description: "Account type to use (individual, business, enterprise)"
200
+ },
201
+ manual: {
202
+ type: "boolean",
203
+ default: false,
204
+ description: "Enable manual request approval"
205
+ },
206
+ "rate-limit": {
207
+ alias: "r",
208
+ type: "string",
209
+ description: "Rate limit in seconds between requests"
210
+ },
211
+ wait: {
212
+ alias: "w",
213
+ type: "boolean",
214
+ default: false,
215
+ description: "Wait instead of error when rate limit is hit. Has no effect if rate limit is not set"
216
+ },
217
+ "github-token": {
218
+ alias: "g",
219
+ type: "string",
220
+ description: "Provide GitHub token directly (must be generated using the `auth` subcommand)"
221
+ },
222
+ "claude-code": {
223
+ alias: "c",
224
+ type: "boolean",
225
+ default: false,
226
+ description: "Generate a command to launch Claude Code with Copilot API config"
227
+ },
228
+ "show-token": {
229
+ type: "boolean",
230
+ default: false,
231
+ description: "Show GitHub and Copilot tokens on fetch and refresh"
232
+ },
233
+ "proxy-env": {
234
+ type: "boolean",
235
+ default: false,
236
+ description: "Initialize proxy from environment variables"
237
+ }
238
+ },
239
+ run({ args }) {
240
+ const rateLimitRaw = args["rate-limit"];
241
+ const rateLimit = rateLimitRaw === void 0 ? void 0 : Number.parseInt(rateLimitRaw, 10);
242
+ return runServer({
243
+ port: Number.parseInt(args.port, 10),
244
+ verbose: args.verbose,
245
+ accountType: args["account-type"],
246
+ manual: args.manual,
247
+ rateLimit,
248
+ rateLimitWait: args.wait,
249
+ githubToken: args["github-token"],
250
+ claudeCode: args["claude-code"],
251
+ showToken: args["show-token"],
252
+ proxyEnv: args["proxy-env"]
253
+ });
254
+ }
255
+ });
256
+
257
+ //#endregion
258
+ export { start };
259
+ //# sourceMappingURL=start-BaeeWbdc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-BaeeWbdc.js","names":["commandBlock: string"],"sources":["../src/lib/proxy.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\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\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 setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\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 { mergeConfigWithDefaults } from \"./lib/config\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport {\n cacheMacMachineId,\n cacheModels,\n cacheVSCodeVersion,\n cacheVsCodeSessionId,\n} from \"./lib/utils\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n // Ensure config is merged with defaults at startup\n mergeConfigWithDefaults()\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.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n\n await ensurePaths()\n await cacheVSCodeVersion()\n cacheMacMachineId()\n cacheVsCodeSessionId()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\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 const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const selectedModel = await consola.prompt(\n \"Select a model to use with Claude Code\",\n {\n type: \"select\",\n options: state.models.data.map((model) => model.id),\n },\n )\n\n const selectedSmallModel = await consola.prompt(\n \"Select a small model to use with Claude Code\",\n {\n type: \"select\",\n options: state.models.data.map((model) => model.id),\n },\n )\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\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\n consola.box(\n `🌐 Usage Viewer: ${serverUrl}/usage-viewer?endpoint=${serverUrl}/usage`,\n )\n\n const { server } = await import(\"./server\")\n\n serve({\n fetch: server.fetch as ServerHandler,\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 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 \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\",\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\",\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\",\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\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 const rateLimitRaw = args[\"rate-limit\"]\n const rateLimit =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n rateLimitRaw === undefined ? undefined : Number.parseInt(rateLimitRaw, 10)\n\n return runServer({\n port: Number.parseInt(args.port, 10),\n verbose: args.verbose,\n accountType: args[\"account-type\"],\n manual: args.manual,\n rateLimit,\n rateLimitWait: args.wait,\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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"}
@@ -0,0 +1,156 @@
1
+ import { PATHS } from "./paths-Cla6y5eD.js";
2
+ import { HTTPError, getGitHubApiBaseUrl, getOauthAppConfig, getOauthUrls, githubHeaders, isOpencodeOauthApp, sleep, standardHeaders, state } from "./utils-DKqD66k9.js";
3
+ import consola from "consola";
4
+ import fs from "node:fs/promises";
5
+ import { setTimeout } from "node:timers/promises";
6
+
7
+ //#region src/services/github/get-copilot-token.ts
8
+ const getCopilotToken = async () => {
9
+ const response = await fetch(`${getGitHubApiBaseUrl()}/copilot_internal/v2/token`, { headers: githubHeaders(state) });
10
+ if (!response.ok) throw new HTTPError("Failed to get Copilot token", response);
11
+ return await response.json();
12
+ };
13
+
14
+ //#endregion
15
+ //#region src/services/github/get-device-code.ts
16
+ async function getDeviceCode() {
17
+ const { clientId, headers, scope } = getOauthAppConfig();
18
+ const { deviceCodeUrl } = getOauthUrls();
19
+ const response = await fetch(deviceCodeUrl, {
20
+ method: "POST",
21
+ headers,
22
+ body: JSON.stringify({
23
+ client_id: clientId,
24
+ scope
25
+ })
26
+ });
27
+ if (!response.ok) throw new HTTPError("Failed to get device code", response);
28
+ return await response.json();
29
+ }
30
+
31
+ //#endregion
32
+ //#region src/services/github/get-user.ts
33
+ async function getGitHubUser() {
34
+ const response = await fetch(`${getGitHubApiBaseUrl()}/user`, { headers: {
35
+ authorization: `token ${state.githubToken}`,
36
+ ...standardHeaders()
37
+ } });
38
+ if (!response.ok) throw new HTTPError("Failed to get GitHub user", response);
39
+ return await response.json();
40
+ }
41
+
42
+ //#endregion
43
+ //#region src/services/github/poll-access-token.ts
44
+ async function pollAccessToken(deviceCode) {
45
+ const { clientId, headers } = getOauthAppConfig();
46
+ const { accessTokenUrl } = getOauthUrls();
47
+ const sleepDuration = (deviceCode.interval + 1) * 1e3;
48
+ consola.debug(`Polling access token with interval of ${sleepDuration}ms`);
49
+ while (true) {
50
+ const response = await fetch(accessTokenUrl, {
51
+ method: "POST",
52
+ headers,
53
+ body: JSON.stringify({
54
+ client_id: clientId,
55
+ device_code: deviceCode.device_code,
56
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
57
+ })
58
+ });
59
+ if (!response.ok) {
60
+ await sleep(sleepDuration);
61
+ consola.error("Failed to poll access token:", await response.text());
62
+ continue;
63
+ }
64
+ const json = await response.json();
65
+ consola.debug("Polling access token response:", json);
66
+ const { access_token } = json;
67
+ if (access_token) return access_token;
68
+ else await sleep(sleepDuration);
69
+ }
70
+ }
71
+
72
+ //#endregion
73
+ //#region src/lib/token.ts
74
+ let copilotRefreshLoopController = null;
75
+ const stopCopilotRefreshLoop = () => {
76
+ if (!copilotRefreshLoopController) return;
77
+ copilotRefreshLoopController.abort();
78
+ copilotRefreshLoopController = null;
79
+ };
80
+ const readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8");
81
+ const writeGithubToken = (token) => fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token);
82
+ const setupCopilotToken = async () => {
83
+ if (isOpencodeOauthApp()) {
84
+ if (!state.githubToken) throw new Error(`opencode token not found`);
85
+ state.copilotToken = state.githubToken;
86
+ consola.debug("GitHub Copilot token set from opencode auth token");
87
+ if (state.showToken) consola.info("Copilot token:", state.copilotToken);
88
+ stopCopilotRefreshLoop();
89
+ return;
90
+ }
91
+ const { token, refresh_in } = await getCopilotToken();
92
+ state.copilotToken = token;
93
+ consola.debug("GitHub Copilot Token fetched successfully!");
94
+ if (state.showToken) consola.info("Copilot token:", token);
95
+ stopCopilotRefreshLoop();
96
+ const controller = new AbortController();
97
+ copilotRefreshLoopController = controller;
98
+ runCopilotRefreshLoop(refresh_in, controller.signal).catch(() => {
99
+ consola.warn("Copilot token refresh loop stopped");
100
+ }).finally(() => {
101
+ if (copilotRefreshLoopController === controller) copilotRefreshLoopController = null;
102
+ });
103
+ };
104
+ const runCopilotRefreshLoop = async (refreshIn, signal) => {
105
+ let nextRefreshDelayMs = (refreshIn - 60) * 1e3;
106
+ while (!signal.aborted) {
107
+ await setTimeout(nextRefreshDelayMs, void 0, { signal });
108
+ consola.debug("Refreshing Copilot token");
109
+ try {
110
+ const { token, refresh_in } = await getCopilotToken();
111
+ state.copilotToken = token;
112
+ consola.debug("Copilot token refreshed");
113
+ if (state.showToken) consola.info("Refreshed Copilot token:", token);
114
+ nextRefreshDelayMs = (refresh_in - 60) * 1e3;
115
+ } catch (error) {
116
+ consola.error("Failed to refresh Copilot token:", error);
117
+ nextRefreshDelayMs = 15e3;
118
+ consola.warn(`Retrying Copilot token refresh in ${nextRefreshDelayMs}ms`);
119
+ }
120
+ }
121
+ };
122
+ async function setupGitHubToken(options) {
123
+ try {
124
+ const githubToken = await readGithubToken();
125
+ if (githubToken && !options?.force) {
126
+ state.githubToken = githubToken;
127
+ if (state.showToken) consola.info("GitHub token:", githubToken);
128
+ await logUser();
129
+ return;
130
+ }
131
+ consola.info("Not logged in, getting new access token");
132
+ const response = await getDeviceCode();
133
+ consola.debug("Device code response:", response);
134
+ consola.info(`Please enter the code "${response.user_code}" in ${response.verification_uri}`);
135
+ const token = await pollAccessToken(response);
136
+ await writeGithubToken(token);
137
+ state.githubToken = token;
138
+ if (state.showToken) consola.info("GitHub token:", token);
139
+ await logUser();
140
+ } catch (error) {
141
+ if (error instanceof HTTPError) {
142
+ consola.error("Failed to get GitHub token:", await error.response.json());
143
+ throw error;
144
+ }
145
+ consola.error("Failed to get GitHub token:", error);
146
+ throw error;
147
+ }
148
+ }
149
+ async function logUser() {
150
+ const user = await getGitHubUser();
151
+ consola.info(`Logged in as ${user.login}`);
152
+ }
153
+
154
+ //#endregion
155
+ export { setupCopilotToken, setupGitHubToken };
156
+ //# sourceMappingURL=token-8AyBHdsS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-8AyBHdsS.js","names":["copilotRefreshLoopController: AbortController | null","delay"],"sources":["../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts"],"sourcesContent":["import { getGitHubApiBaseUrl, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n const response = await fetch(\n `${getGitHubApiBaseUrl()}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n return (await response.json()) as GetCopilotTokenResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import { getOauthAppConfig, getOauthUrls } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n const { clientId, headers, scope } = getOauthAppConfig()\n const { deviceCodeUrl } = getOauthUrls()\n\n const response = await fetch(deviceCodeUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n client_id: clientId,\n scope,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { getGitHubApiBaseUrl, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${getGitHubApiBaseUrl()}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import consola from \"consola\"\n\nimport { getOauthAppConfig, getOauthUrls } from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n const { clientId, headers } = getOauthAppConfig()\n const { accessTokenUrl } = getOauthUrls()\n\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n\n while (true) {\n const response = await fetch(accessTokenUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n client_id: clientId,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n })\n\n if (!response.ok) {\n await sleep(sleepDuration)\n consola.error(\"Failed to poll access token:\", await response.text())\n\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n } else {\n await sleep(sleepDuration)\n }\n }\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport { setTimeout as delay } from \"node:timers/promises\"\n\nimport { isOpencodeOauthApp } from \"~/lib/api-config\"\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nlet copilotRefreshLoopController: AbortController | null = null\n\nexport const stopCopilotRefreshLoop = () => {\n if (!copilotRefreshLoopController) {\n return\n }\n\n copilotRefreshLoopController.abort()\n copilotRefreshLoopController = null\n}\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n if (isOpencodeOauthApp()) {\n if (!state.githubToken) throw new Error(`opencode token not found`)\n\n state.copilotToken = state.githubToken\n\n consola.debug(\"GitHub Copilot token set from opencode auth token\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", state.copilotToken)\n }\n\n stopCopilotRefreshLoop()\n return\n }\n\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n stopCopilotRefreshLoop()\n\n const controller = new AbortController()\n copilotRefreshLoopController = controller\n\n runCopilotRefreshLoop(refresh_in, controller.signal)\n .catch(() => {\n consola.warn(\"Copilot token refresh loop stopped\")\n })\n .finally(() => {\n if (copilotRefreshLoopController === controller) {\n copilotRefreshLoopController = null\n }\n })\n}\n\nconst runCopilotRefreshLoop = async (\n refreshIn: number,\n signal: AbortSignal,\n) => {\n let nextRefreshDelayMs = (refreshIn - 60) * 1000\n\n while (!signal.aborted) {\n await delay(nextRefreshDelayMs, undefined, { signal })\n\n consola.debug(\"Refreshing Copilot token\")\n\n try {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n\n nextRefreshDelayMs = (refresh_in - 60) * 1000\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n nextRefreshDelayMs = 15_000\n consola.warn(`Retrying Copilot token refresh in ${nextRefreshDelayMs}ms`)\n }\n }\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n"],"mappings":"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"}