UNPKG

@embeddable.com/sdk-core

Version:

Core Embeddable SDK module responsible for web-components bundling and publishing.

128 lines (109 loc) 3.62 kB
import * as fs from "node:fs/promises"; import axios from "axios"; import provideConfig from "./provideConfig"; import { initLogger, logError } from "./logger"; // @ts-ignore import reportErrorToRollbar from "./rollbar.mjs"; import { CREDENTIALS_DIR, CREDENTIALS_FILE } from "./credentials"; const oraP = import("ora"); const openP = import("open"); export default async () => { await initLogger("login"); const breadcrumbs: string[] = []; const ora = (await oraP).default; const authenticationSpinner = ora("Waiting for code verification...").start(); try { const open = (await openP).default; const config = await provideConfig(); breadcrumbs.push("provideConfig"); await resolveFiles(); breadcrumbs.push("resolveFiles"); const deviceCodePayload = { client_id: config.authClientId, audience: config.audienceUrl, }; const deviceCodeResponse = await axios.post( `https://${config.authDomain}/oauth/device/code`, deviceCodePayload, ); ora( "Confirm this code on your browser: " + deviceCodeResponse.data["user_code"], ).info(); const tokenPayload = { grant_type: "urn:ietf:params:oauth:grant-type:device_code", device_code: deviceCodeResponse.data["device_code"], client_id: config.authClientId, }; await open(deviceCodeResponse.data["verification_uri_complete"]); let isTerminated = false; const signalHandler = () => { isTerminated = true; authenticationSpinner.fail("Authentication process interrupted"); process.exit(0); }; process.on("SIGTERM", signalHandler); process.on("SIGINT", signalHandler); /** * This is a recommended way to poll, since it take some time for a user to enter a `user_code` in a browser. * deviceCodeResponse.data['interval'] is a recommended/calculated polling interval specified in seconds. */ while (!isTerminated) { try { const tokenResponse = await axios.post( `https://${config.authDomain}/oauth/token`, tokenPayload, ); await fs.writeFile( CREDENTIALS_FILE, JSON.stringify(tokenResponse.data), ); authenticationSpinner.succeed( "You are successfully authenticated now!", ); break; } catch (e: any) { if (e.response.data?.error !== "authorization_pending") { authenticationSpinner.fail( "Authentication failed. Please try again.", ); process.exit(1); } await sleep(deviceCodeResponse.data["interval"] * 1000); } } // Clean up signal handlers process.off("SIGTERM", signalHandler); process.off("SIGINT", signalHandler); } catch (error: unknown) { authenticationSpinner.fail("Authentication failed. Please try again."); await logError({ command: "login", breadcrumbs, error }); await reportErrorToRollbar(error); console.log(error); process.exit(1); } }; export async function getToken() { try { const rawCredentials = await fs.readFile(CREDENTIALS_FILE, "utf-8"); const credentials = JSON.parse(rawCredentials.toString()); return credentials?.access_token ?? ""; } catch (_e) { return ""; } } function sleep(ms: number) { return new Promise((res) => setTimeout(res, ms)); } export async function resolveFiles() { try { await fs.access(CREDENTIALS_DIR); } catch (_e) { await fs.mkdir(CREDENTIALS_DIR); } try { await fs.access(CREDENTIALS_FILE); } catch (e) { await fs.writeFile(CREDENTIALS_FILE, ""); } }