import { getResocketConfig } from "../config"; import { getFormattedError } from "../utils/errror"; import { Clerk } from "@clerk/clerk-js/headless"; import type { UserConfig } from "../types"; export const requireAuth = () => { if (process.env.RESOCKET_CF_ACCOUNT_ID && process.env.RESOCKET_CF_API_TOKEN) return { accountId: process.env.RESOCKET_CF_ACCOUNT_ID, token: process.env.RESOCKET_CF_API_TOKEN, }; const { envs } = getResocketConfig(); let missing: string[] = []; if (!process.env.RESOCKET_CF_ACCOUNT_ID) { if (!envs.CLOUDFLARE_ACCOUNT_ID) missing.push("CLOUDFLARE_ACCOUNT_ID"); process.env.RESOCKET_CF_ACCOUNT_ID = envs.CLOUDFLARE_ACCOUNT_ID; } if (!process.env.RESOCKET_CF_API_TOKEN) { if (!envs.CLOUDFLARE_API_TOKEN) missing.push("CLOUDFLARE_API_TOKEN"); process.env.RESOCKET_CF_API_TOKEN = envs.CLOUDFLARE_API_TOKEN; } if (missing.length > 0) throw new Error( getFormattedError({ coreMessage: "env 'CLOUDFLARE_ACCOUNT_ID' & 'CLOUDFLARE_API_TOKEN' are required!", highlightAffected: { title: "missing env", value: missing }, humanMessage: "You are not providing the correct environment variables necessary to run this command, plz note that we do not store any of your environment variables", proTip: "you can provide the variables in a .env file at root, or you can also pass the variables to the cli with --vars command", }) ); return { accountId: process.env.RESOCKET_CF_ACCOUNT_ID, token: process.env.RESOCKET_CF_API_TOKEN, }; }; const pubkey = "pk_test_dXB3YXJkLWdyaXp6bHktMTguY2xlcmsuYWNjb3VudHMuZGV2JA"; interface ClerkSetupOptions { headers?: Record; } export const tokenStore = (initToken?: string) => { let _token: string | undefined = initToken; return { getToken() { return _token; }, setToken(token: string) { _token = token; return _token; }, }; }; type TokenStore = ReturnType; const configureClerkInstance = ( clerk: Clerk, store: TokenStore, headers: Record = {} ) => { //* we need to get the auth headers by hijacking into this. & also passing custom headers //* ref - https://github.com/clerk/javascript/blob/main/packages/chrome-extension/src/singleton.ts#L67-L89 clerk.__unstable__onBeforeRequest(async (requestInit) => { requestInit.credentials = "omit"; requestInit.url?.searchParams.append("_is_native", "1"); //* we set custom headers here for authentication const requestHeaders = requestInit.headers as Headers; requestHeaders.set("authorization", store.getToken() || ""); requestHeaders.set("user-agent", "resocket-cli"); Object.entries(headers).forEach(([key, value]) => requestHeaders.set(key, value) ); }); clerk.__unstable__onAfterResponse(async (_, response) => { const authHeader = response?.headers.get("authorization"); if (authHeader) { store.setToken(authHeader); } }); }; export const initializeClerk = async ( options: ClerkSetupOptions, store: TokenStore ): Promise => { const clerk = new Clerk(pubkey); configureClerkInstance(clerk, store, options.headers); await clerk.load({ standardBrowser: false }); return clerk; }; export const authenticateClerk = async ( signInToken: string, headers: Record = {} ): Promise => { let store = tokenStore(); const clerk = await initializeClerk({ headers }, store); const signInResponse = await clerk.client?.signIn.create({ strategy: "ticket", ticket: signInToken, }); if (signInResponse?.status !== "complete") { throw new Error( `Login process did not complete: ${JSON.stringify(signInResponse)}` ); } if (!store.getToken()) { throw new Error("No authentication token received"); } const activeSession = clerk.client?.activeSessions?.[0]; if (!activeSession?.user) { throw new Error("No active session found"); } return { version: "0", accessToken: store.getToken()!, username: activeSession.user.username!, }; }; export const logoutClerk = async (authToken: string) => { const clerk = await initializeClerk({}, tokenStore(authToken)); await clerk.signOut(); };