Skip to content

Commit 0bc492a

Browse files
author
Prompsit CI
committed
Mirror 457554c (2026-04-11)
1 parent e53891b commit 0bc492a

1 file changed

Lines changed: 24 additions & 3 deletions

File tree

src/commands/device-flow.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ const log = getLogger(import.meta.url);
1919
const BROWSER_TIMEOUT_MS = 3000;
2020
const SLOW_DOWN_INCREMENT = 5; // RFC 8628 §3.5: increase interval by 5s on slow_down
2121

22+
// Adaptive polling: first 30 seconds (while user is actively in browser)
23+
// poll every 2s for snappy UX. After that, fall back to API-provided interval.
24+
// If API returns slow_down, we respect it immediately and disable adaptive mode.
25+
const ADAPTIVE_WINDOW_MS = 30_000;
26+
const ADAPTIVE_INTERVAL_SEC = 2;
27+
2228
/** Result from a completed device flow. */
2329
export interface DeviceFlowResult {
2430
accessToken: string;
@@ -133,8 +139,13 @@ export async function runDeviceFlow(
133139
}
134140

135141
// 4. Poll for authorization
136-
let interval = deviceAuth.interval || DEVICE_FLOW_DEFAULT_INTERVAL;
137-
const deadline = Date.now() + deviceAuth.expires_in * 1000;
142+
// Adaptive interval: fast polling first 30s, fall back to API interval after.
143+
// API-provided interval is the floor once adaptive window ends OR on slow_down.
144+
const apiInterval = deviceAuth.interval || DEVICE_FLOW_DEFAULT_INTERVAL;
145+
let interval = Math.min(apiInterval, ADAPTIVE_INTERVAL_SEC);
146+
let adaptiveMode = true;
147+
const pollStart = Date.now();
148+
const deadline = pollStart + deviceAuth.expires_in * 1000;
138149

139150
// Spinner: ora for CLI, terminal.dim for REPL (stdin is raw)
140151
const isRepl = process.stdin.isRaw;
@@ -147,6 +158,13 @@ export async function runDeviceFlow(
147158

148159
try {
149160
while (Date.now() < deadline) {
161+
// Adaptive window expired → switch to API-provided interval
162+
if (adaptiveMode && Date.now() - pollStart >= ADAPTIVE_WINDOW_MS) {
163+
adaptiveMode = false;
164+
interval = apiInterval;
165+
log.debug("Adaptive polling window ended", { new_interval: String(interval) });
166+
}
167+
150168
// Cancellable sleep (AbortSignal from REPL Ctrl+C or CLI SIGINT)
151169
try {
152170
await sleep(interval * 1000, signal);
@@ -175,7 +193,10 @@ export async function runDeviceFlow(
175193
break;
176194
}
177195
case "slow_down": {
178-
interval += SLOW_DOWN_INCREMENT;
196+
// Server throttling — disable adaptive mode and respect RFC 8628 §3.5:
197+
// "the interval MUST be increased by 5 seconds for all subsequent requests"
198+
adaptiveMode = false;
199+
interval = Math.max(interval, apiInterval) + SLOW_DOWN_INCREMENT;
179200
log.debug("Polling slowed down", { new_interval: String(interval) });
180201
break;
181202
}

0 commit comments

Comments
 (0)