(
flowId: string,
opts?: { timeoutMs?: number }
)
| 105 | } |
| 106 | |
| 107 | async waitForDeviceFlow( |
| 108 | flowId: string, |
| 109 | opts?: { timeoutMs?: number } |
| 110 | ): Promise<Result<void, string>> { |
| 111 | const flow = this.flows.get(flowId); |
| 112 | if (!flow) { |
| 113 | return Err("Device flow not found"); |
| 114 | } |
| 115 | |
| 116 | // Start polling in background (guard against re-entrant calls, e.g. React StrictMode re-mount) |
| 117 | if (!flow.pollingStarted) { |
| 118 | flow.pollingStarted = true; |
| 119 | void this.pollForToken(flow); |
| 120 | } |
| 121 | |
| 122 | const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS; |
| 123 | let timeoutHandle: ReturnType<typeof setTimeout> | null = null; |
| 124 | const timeoutPromise = new Promise<Result<void, string>>((resolve) => { |
| 125 | timeoutHandle = setTimeout(() => { |
| 126 | resolve(Err("Timed out waiting for GitHub authorization")); |
| 127 | }, timeoutMs); |
| 128 | }); |
| 129 | |
| 130 | const result = await Promise.race([flow.resultPromise, timeoutPromise]); |
| 131 | |
| 132 | if (timeoutHandle !== null) { |
| 133 | clearTimeout(timeoutHandle); |
| 134 | } |
| 135 | |
| 136 | if (!result.success) { |
| 137 | void this.finishFlow(flowId, result); |
| 138 | } |
| 139 | |
| 140 | return result; |
| 141 | } |
| 142 | |
| 143 | cancelDeviceFlow(flowId: string): void { |
| 144 | const flow = this.flows.get(flowId); |
nothing calls this directly
no test coverage detected