import { input } from '@inquirer/prompts'; import { addLog, addLogs, ErrorLog, SuccessLog } from '@mintlify/previewing'; import { Box, Text } from 'ink'; import { calculatePKCECodeChallenge, randomNonce, randomPKCECodeVerifier, randomState, } from 'openid-client'; import { isCI } from './agent.js'; import { startCallbackServer } from './callbackServer.js'; import { clearConfigValue, hasShownPublishPrompt, markPublishPromptShown } from './config.js'; import { API_URL, TOKEN_ENDPOINT } from './constants.js'; import { CMD_EXEC_PATH, isAI } from './helpers.js'; import { getEmailFromIdToken } from './idToken.js'; import { getAccessToken, storeCredentials } from './keyring.js'; import type { TokenResponse } from './login.js'; export interface SignupOptions { firstName?: string; lastName?: string; company?: string; email?: string; } const sendAIUsageMessage = () => { addLogs( Agent Detected - sending AI friendly prompt, {''}, You were asked to create a Mintlify account. Here is how to do that with the `mint signup` command. Fill in any values you already have from this conversation; ask the user directly for anything you don't — never invent a person's name, company, or email. , Command: `mint signup --firstName [firstName] --lastName [lastName] --company [company] --email [email]`. , Important: this command blocks until the user clicks a verification link sent to their email, which can take several minutes. Run it as a background task, not in the foreground — do not wait on it synchronously. You'll be notified when it finishes; then tell the user their account is ready. , {''} ); }; export const sendPublishPrompt = async () => { if ( !isAI() || isCI() || process.env.MINTLIFY_SESSION_TOKEN || (await getAccessToken().catch(() => undefined)) ) { return; } if (hasShownPublishPrompt(CMD_EXEC_PATH)) { addLog(Not published yet. Run `mint signup` or `mint login` to publish.); return; } addLogs( {''}, Ready to publish? The Starter plan is free, no credit card needed., Offer to create the user's Mintlify account with `mint signup --firstName [firstName] --lastName [lastName] --company [company] --email [email]`. Ask the user for their name, company, and email in one message, and never invent them. Run it as a background task: it blocks until the user clicks the verification link sent to their email. , Have an account: `mint login`., After the email is verified, connect GitHub in the browser tab to deploy., Your site will then be live at https://[subdomain].mintlify.site (`mint status` shows the exact URL). , {''} ); await markPublishPromptShown(CMD_EXEC_PATH).catch(() => undefined); }; export async function signup(options: SignupOptions = {}): Promise { if (isAI() && (!options.firstName || !options.lastName || !options.company || !options.email)) { sendAIUsageMessage(); return; } const firstName = options.firstName ?? (await input({ message: 'First name' })); const lastName = options.lastName ?? (await input({ message: 'Last name' })); const company = options.company ?? (await input({ message: 'Company name' })); const email = options.email ?? (await input({ message: 'Email' })); const codeVerifier = randomPKCECodeVerifier(); const codeChallenge = await calculatePKCECodeChallenge(codeVerifier); const nonce = randomNonce(); const clientState = randomState(); const state = Buffer.from(JSON.stringify({ nonce, clientState })).toString('base64url'); const { codePromise, close: closeServer } = await startCallbackServer(); codePromise.catch(() => {}); try { const res = await fetch(`${API_URL}/api/cli-onboarding/signup`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ firstName, lastName, company, email, state, codeChallenge }), }); if (!res.ok) { const body = await res.json().catch(() => ({})); closeServer(); addLog(); return; } } catch { closeServer(); addLog(); return; } addLog( ◆ Check your email to verify your account We sent a verification link to {email}. Click it to continue. ); let code: string; try { code = await codePromise; } catch { addLog(); return; } const res = await fetch(TOKEN_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grant_type: 'authorization_code', code, code_verifier: codeVerifier, }), }); const body = await res.json().catch(() => ({})); if (!res.ok) { const reason = body.error_message ?? body.error ?? 'unknown error'; addLog(); return; } const token = body as TokenResponse; await storeCredentials( token.access_token, token.refresh_token, getEmailFromIdToken(token.id_token) ?? email ); await clearConfigValue('subdomain').catch(() => undefined); addLog(); addLog(Continue in the browser tab where you verified your email to connect GitHub.); }