Skip to content

Commit 943ddb0

Browse files
committed
feat: token handling
1 parent a5c14e8 commit 943ddb0

File tree

8 files changed

+72
-281
lines changed

8 files changed

+72
-281
lines changed

docs/api/completions.txt

Lines changed: 0 additions & 213 deletions
This file was deleted.

docs/api/models.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/lib/tokens.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
interface Tokens {
2+
GITHUB_TOKEN: string | undefined
3+
COPILOT_TOKEN: string | undefined
4+
}
5+
6+
export const TOKENS: Tokens = {
7+
GITHUB_TOKEN: undefined,
8+
COPILOT_TOKEN: undefined,
9+
}

src/main.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
import { chatCompletions } from "./services/copilot-vscode/chat-completions/service"
1+
import consola from "consola"
22

3-
const gen = chatCompletions({
4-
messages: [
5-
{
6-
content:
7-
"Hey how do write a factorial function in typescript in functional programming style",
8-
role: "user",
9-
},
10-
],
11-
model: "gpt-4o-mini",
12-
})
3+
import { TOKENS } from "./lib/tokens"
4+
import { getCopilotToken } from "./services/copilot-vscode/get-token/copilot-token"
5+
import { getGitHubToken } from "./services/copilot-vscode/get-token/github-token"
136

14-
for await (const chunk of gen) {
15-
console.log(chunk)
16-
}
7+
const githubToken = await getGitHubToken()
8+
TOKENS.GITHUB_TOKEN = githubToken
9+
10+
const { token: copilotToken, refresh_in } = await getCopilotToken()
11+
TOKENS.COPILOT_TOKEN = copilotToken
12+
13+
// refresh_in is in minutes
14+
// we're refreshing 100 minutes early
15+
const refreshInterval = (refresh_in - 100) * 60 * 1000
16+
17+
setInterval(async () => {
18+
consola.start("Refreshing copilot token")
19+
const { token: copilotToken } = await getCopilotToken()
20+
TOKENS.COPILOT_TOKEN = copilotToken
21+
}, refreshInterval)
Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
import { ofetch } from "ofetch"
22

3-
import { getToken } from "./get-token/service"
3+
import { TOKENS } from "~/lib/tokens"
44

5-
const result = await getToken()
5+
export const copilotVSCode = ofetch.create({
6+
baseURL: "https://api.individual.githubcopilot.com",
7+
headers: {
8+
"copilot-integration-id": "vscode-chat",
9+
},
10+
11+
onRequest({ options }) {
12+
options.headers.set("authorization", `Bearer ${TOKENS.COPILOT_TOKEN}`)
13+
},
14+
})
615

7-
export const COPILOT_VSCODE_BASE_URL =
8-
"https://api.individual.githubcopilot.com"
9-
export const COPILOT_VSCODE_TOKEN = result.token
10-
export const COPILOT_VSCODE_HEADERS = {
11-
authorization: `Bearer ${COPILOT_VSCODE_TOKEN}`,
12-
"copilot-integration-id": "vscode-chat",
13-
}
16+
export const github = ofetch.create({
17+
baseURL: "https://api.github.com",
18+
headers: {
19+
// "editor-plugin-version": "copilot-chat/0.23.2",
20+
// "editor-version": "vscode/1.96.2",
21+
// "user-agent": "GitHubCopilotChat/0.23.2",
22+
// "x-github-api-version": "2024-12-15",
23+
},
1424

15-
export const copilotVSCode = ofetch.create({
16-
baseURL: COPILOT_VSCODE_BASE_URL,
17-
headers: COPILOT_VSCODE_HEADERS,
25+
onRequest({ options }) {
26+
options.headers.set("authorization", `token ${TOKENS.GITHUB_TOKEN}`)
27+
},
1828
})
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { GetCopilotTokenResponse } from "./types"
2+
3+
import { github } from "../api-instance"
4+
5+
export const getCopilotToken = async () =>
6+
github<GetCopilotTokenResponse>("/copilot_internal/v2/token", {
7+
method: "GET",
8+
})
Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,7 @@
1-
import consola from "consola"
21
import { execa } from "execa"
32

4-
import { PATHS } from "~/lib/paths"
5-
6-
import type { GetTokenResponse } from "./types"
7-
8-
const TEN_MINUTES = 10 * 60 * 1000
9-
103
// @ts-expect-error TypeScript can't analyze timeout
11-
export async function getToken(): Promise<GetTokenResponse> {
12-
try {
13-
const cachedToken = await readCachedToken()
14-
15-
if (Date.now() - cachedToken.expires_at > ONE_DAY) {
16-
return cachedToken
17-
}
18-
} catch (e) {
19-
if (!(e instanceof Error)) throw e
20-
if (e.message === "No such file or directory")
21-
consola.info(`No cached token found in ${PATHS.PATH_TOKEN_CACHE}`)
22-
}
23-
4+
export async function getGitHubToken(): Promise<string> {
245
// Kill any existing vscode processes
256
// otherwise, no token call will be made
267
await killVSCodeProcesses()
@@ -34,20 +15,24 @@ export async function getToken(): Promise<GetTokenResponse> {
3415

3516
for await (const line of mitmdump.stdout) {
3617
if (typeof line !== "string") continue
37-
if (!line.includes("tid=")) continue
38-
39-
consola.debug(`Found token output line: ${line}`)
18+
if (!line.includes("authorization: token")) continue
19+
20+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
21+
const token = line
22+
.split("\n")
23+
.map((line) => line.trim())
24+
.filter(Boolean)
25+
.find((line) => line.includes("authorization: token"))!
26+
.split("authorization: token ")
27+
.at(1)!
28+
.trim()
4029

4130
clearTimeout(timeout)
4231

4332
await killVSCodeProcesses()
4433
mitmdump.kill()
4534

46-
const parsed = JSON.parse(line) as GetTokenResponse
47-
parsed.expires_at = Date.now() + t
48-
49-
await writeCachedToken(line)
50-
return JSON.parse(line) as GetTokenResponse
35+
return token
5136
}
5237
}
5338

@@ -73,11 +58,3 @@ const createVSCodeProcess = () =>
7358
])
7459

7560
const killVSCodeProcesses = () => execa({ reject: false })("pkill", ["code"])
76-
77-
const readCachedToken = async () => {
78-
const content = await Bun.file(PATHS.PATH_TOKEN_CACHE).text()
79-
return JSON.parse(content) as GetTokenResponse
80-
}
81-
82-
const writeCachedToken = async (token: string) =>
83-
Bun.write(PATHS.PATH_TOKEN_CACHE, token)

src/services/copilot-vscode/get-token/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export interface GetTokenResponse {
1+
export interface GetCopilotTokenResponse {
22
annotations_enabled: boolean
33
chat_enabled: boolean
44
chat_jetbrains_enabled: boolean

0 commit comments

Comments
 (0)