Skip to content

Commit 08ef97b

Browse files
fix(opencode): add oauth polling safety margin in copilot device authentication (#8986)
1 parent 1aedb26 commit 08ef97b

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

packages/opencode/src/plugin/copilot.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { Installation } from "@/installation"
33
import { iife } from "@/util/iife"
44

55
const CLIENT_ID = "Ov23li8tweQw6odWQebz"
6+
// Add a small safety buffer when polling to avoid hitting the server
7+
// slightly too early due to clock skew / timer drift.
8+
const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000 // 3 seconds
69

710
function normalizeDomain(url: string) {
811
return url.replace(/^https?:\/\//, "").replace(/\/$/, "")
@@ -204,6 +207,7 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> {
204207
const data = (await response.json()) as {
205208
access_token?: string
206209
error?: string
210+
interval?: number
207211
}
208212

209213
if (data.access_token) {
@@ -230,13 +234,29 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> {
230234
}
231235

232236
if (data.error === "authorization_pending") {
233-
await new Promise((resolve) => setTimeout(resolve, deviceData.interval * 1000))
237+
await Bun.sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS)
238+
continue
239+
}
240+
241+
if (data.error === "slow_down") {
242+
// Based on the RFC spec, we must add 5 seconds to our current polling interval.
243+
// (See https://www.rfc-editor.org/rfc/rfc8628#section-3.5)
244+
let newInterval = (deviceData.interval + 5) * 1000
245+
246+
// GitHub OAuth API may return the new interval in seconds in the response.
247+
// We should try to use that if provided with safety margin.
248+
const serverInterval = data.interval
249+
if (serverInterval && typeof serverInterval === 'number' && serverInterval > 0) {
250+
newInterval = serverInterval * 1000
251+
}
252+
253+
await Bun.sleep(newInterval + OAUTH_POLLING_SAFETY_MARGIN_MS)
234254
continue
235255
}
236256

237257
if (data.error) return { type: "failed" as const }
238258

239-
await new Promise((resolve) => setTimeout(resolve, deviceData.interval * 1000))
259+
await Bun.sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS)
240260
continue
241261
}
242262
},

0 commit comments

Comments
 (0)