(openBrowser = true)
| 109 | } |
| 110 | |
| 111 | export async function performLogin(openBrowser = true): Promise<string | null> { |
| 112 | const spinner = ora("Preparing login...").start(); |
| 113 | |
| 114 | let authorization; |
| 115 | try { |
| 116 | authorization = await startDeviceAuthorization(baseUrl, CLI_CLIENT_ID); |
| 117 | } catch (error) { |
| 118 | spinner.fail(pc.red("Login failed")); |
| 119 | if (error instanceof Error) console.error(pc.red(error.message)); |
| 120 | return null; |
| 121 | } |
| 122 | |
| 123 | spinner.stop(); |
| 124 | |
| 125 | console.log( |
| 126 | renderDeviceCodeBox( |
| 127 | authorization.user_code, |
| 128 | authorization.verification_uri, |
| 129 | authorization.verification_uri_complete |
| 130 | ) |
| 131 | ); |
| 132 | |
| 133 | const target = authorization.verification_uri_complete ?? authorization.verification_uri; |
| 134 | if (openBrowser) { |
| 135 | await waitForEnter("Press Enter to open the browser, or Ctrl-C to quit..."); |
| 136 | try { |
| 137 | await open(target); |
| 138 | } catch { |
| 139 | console.log(pc.dim(` Couldn't open a browser — visit the link above manually.`)); |
| 140 | } |
| 141 | } else { |
| 142 | console.log(pc.dim(" Open the link above in any browser to continue.")); |
| 143 | console.log(""); |
| 144 | } |
| 145 | |
| 146 | const waitingSpinner = ora({ text: "Waiting for authorization...", indent: 2 }).start(); |
| 147 | |
| 148 | const deadline = Date.now() + authorization.expires_in * 1000; |
| 149 | let intervalMs = (authorization.interval ?? DEFAULT_DEVICE_POLL_INTERVAL_SECONDS) * 1000; |
| 150 | |
| 151 | while (Date.now() < deadline) { |
| 152 | await new Promise((resolve) => setTimeout(resolve, intervalMs)); |
| 153 | try { |
| 154 | const result = await pollDeviceToken(baseUrl, CLI_CLIENT_ID, authorization.device_code); |
| 155 | if (result.status === "approved" && result.tokens) { |
| 156 | saveTokens(result.tokens); |
| 157 | const successText = await announceIdentity(result.tokens.access_token); |
| 158 | waitingSpinner.succeed(pc.green(successText)); |
| 159 | return result.tokens.access_token; |
| 160 | } |
| 161 | if (result.status === "slow_down") { |
| 162 | intervalMs += 5000; |
| 163 | continue; |
| 164 | } |
| 165 | if (result.status === "denied") { |
| 166 | waitingSpinner.fail(pc.red("Authorization denied.")); |
| 167 | return null; |
| 168 | } |
no test coverage detected