(
origin: string,
options: DeviceLoginHttpOptions = {},
)
| 186 | }; |
| 187 | |
| 188 | export const discoverCliLogin = async ( |
| 189 | origin: string, |
| 190 | options: DeviceLoginHttpOptions = {}, |
| 191 | ): Promise<CliLoginDiscovery> => { |
| 192 | let response: Response; |
| 193 | const url = cliLoginUrl(origin); |
| 194 | try { |
| 195 | response = await fetch(url, { |
| 196 | headers: headersForUrl(url, { accept: "application/json" }, options), |
| 197 | }); |
| 198 | } catch (cause) { |
| 199 | throw new DeviceLoginError( |
| 200 | `Could not reach ${origin} to start login: ${cause instanceof Error ? cause.message : String(cause)}`, |
| 201 | ); |
| 202 | } |
| 203 | if (!response.ok) { |
| 204 | throw new DeviceLoginError( |
| 205 | `${origin} does not support CLI login (GET /api/auth/cli-login returned ${response.status}). ` + |
| 206 | "It may be an older server, or a local/unauthenticated server that needs no login.", |
| 207 | ); |
| 208 | } |
| 209 | const body = await readJson(response); |
| 210 | const deviceAuthorizationEndpoint = asString(body.deviceAuthorizationEndpoint); |
| 211 | const tokenEndpoint = asString(body.tokenEndpoint); |
| 212 | const clientId = asString(body.clientId); |
| 213 | if (!deviceAuthorizationEndpoint || !tokenEndpoint || !clientId) { |
| 214 | throw new DeviceLoginError(`${origin} returned an incomplete CLI-login configuration.`); |
| 215 | } |
| 216 | return { |
| 217 | provider: asString(body.provider) ?? "unknown", |
| 218 | deviceAuthorizationEndpoint, |
| 219 | tokenEndpoint, |
| 220 | clientId, |
| 221 | scope: asString(body.scope), |
| 222 | requestFormat: asString(body.requestFormat) === "json" ? "json" : "form", |
| 223 | }; |
| 224 | }; |
| 225 | |
| 226 | export const requestDeviceCode = async ( |
| 227 | discovery: CliLoginDiscovery, |
no test coverage detected