Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 11 additions & 26 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions src/commands/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ export default (cmd: Command): Command => {
.command('login')
.description(t('cmdAuthLoginDescription'))
.option('-e, --email', 'Login via email verification (no browser required)')
.option('--auth-url <url>', 'Override auth service URL (e.g., http://localhost:3001)')
.option(
'--auth-url <url>',
'Override auth service URL (e.g., http://localhost:3001)',
)
.action((options) => {
// If --email flag is provided, use email-based login (no browser needed)
if (options.email) {
const authApiUrl = options.authUrl || getDefined('AUTH__API_URL') || 'https://auth.alternatefutures.ai';
const authApiUrl =
options.authUrl ||
getDefined('AUTH__API_URL') ||
'https://auth.alternatefutures.ai';
return emailLoginActionHandler({ authApiUrl });
}

Expand All @@ -39,7 +45,8 @@ export default (cmd: Command): Command => {
.command('signup')
.description('Create a new account using email verification')
.action(() => {
const authApiUrl = getDefined('AUTH__API_URL') || 'https://auth.alternatefutures.ai';
const authApiUrl =
getDefined('AUTH__API_URL') || 'https://auth.alternatefutures.ai';

return signupActionHandler({
authApiUrl,
Expand Down
38 changes: 28 additions & 10 deletions src/commands/auth/loginEmail.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as readline from 'readline';
import * as readline from 'node:readline';
import { output } from '../../cli';
import { config } from '../../config';

Expand Down Expand Up @@ -30,15 +30,20 @@ const createPrompt = (): readline.Interface => {
});
};

const askQuestion = (rl: readline.Interface, question: string): Promise<string> => {
const askQuestion = (
rl: readline.Interface,
question: string,
): Promise<string> => {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer.trim());
});
});
};

export const emailLoginActionHandler = async ({ authApiUrl }: EmailLoginActionHandlerArgs) => {
export const emailLoginActionHandler = async ({
authApiUrl,
}: EmailLoginActionHandlerArgs) => {
const rl = createPrompt();

try {
Expand Down Expand Up @@ -78,11 +83,16 @@ export const emailLoginActionHandler = async ({ authApiUrl }: EmailLoginActionHa

output.success('Verification code sent to your email');
output.log('');
output.log(`📬 Check your inbox for a 6-digit code (expires in ${Math.floor((requestData.expiresIn || 300) / 60)} minutes)`);
output.log(
`📬 Check your inbox for a 6-digit code (expires in ${Math.floor((requestData.expiresIn || 300) / 60)} minutes)`,
);
output.log('');

// Step 3: Get verification code
const code = await askQuestion(rl, '🔐 Enter the 6-digit verification code: ');
const code = await askQuestion(
rl,
'🔐 Enter the 6-digit verification code: ',
);

if (!code || code.length !== 6) {
output.error('Invalid verification code. Please enter a 6-digit code.');
Expand Down Expand Up @@ -117,7 +127,7 @@ export const emailLoginActionHandler = async ({ authApiUrl }: EmailLoginActionHa
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
name: `CLI Token - ${new Date().toISOString().split('T')[0]}`,
Expand All @@ -143,7 +153,9 @@ export const emailLoginActionHandler = async ({ authApiUrl }: EmailLoginActionHa
output.log('');
output.log(`✅ Logged in as: ${email}`);
output.log('');
output.log('You can now use the AlternateFutures CLI to deploy your projects.');
output.log(
'You can now use the AlternateFutures CLI to deploy your projects.',
);
output.printNewLine();

rl.close();
Expand All @@ -163,14 +175,20 @@ export const emailLoginActionHandler = async ({ authApiUrl }: EmailLoginActionHa
output.log('');

if (fetchError.cause) {
output.log(`Technical details: ${fetchError.cause.message || fetchError.cause}`);
output.log(
`Technical details: ${fetchError.cause.message || fetchError.cause}`,
);
}

output.log('');
output.log('Troubleshooting:');
output.log(` 1. Verify the auth service is running: curl -k ${authApiUrl}/health`);
output.log(
` 1. Verify the auth service is running: curl -k ${authApiUrl}/health`,
);
output.log(' 2. Check your network connection');
output.log(' 3. Try setting NODE_TLS_REJECT_UNAUTHORIZED=0 if using self-signed certs');
output.log(
' 3. Try setting NODE_TLS_REJECT_UNAUTHORIZED=0 if using self-signed certs',
);
} else {
output.error(error.message);
if (fetchError.cause) {
Expand Down
38 changes: 28 additions & 10 deletions src/commands/auth/signup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as readline from 'readline';
import * as readline from 'node:readline';
import { output } from '../../cli';
import { config } from '../../config';

Expand Down Expand Up @@ -30,15 +30,20 @@ const createPrompt = (): readline.Interface => {
});
};

const askQuestion = (rl: readline.Interface, question: string): Promise<string> => {
const askQuestion = (
rl: readline.Interface,
question: string,
): Promise<string> => {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer.trim());
});
});
};

export const signupActionHandler = async ({ authApiUrl }: SignupActionHandlerArgs) => {
export const signupActionHandler = async ({
authApiUrl,
}: SignupActionHandlerArgs) => {
const rl = createPrompt();

try {
Expand Down Expand Up @@ -76,11 +81,16 @@ export const signupActionHandler = async ({ authApiUrl }: SignupActionHandlerArg

output.success('Verification code sent to your email');
output.log('');
output.log(`📬 Check your inbox for a 6-digit code (expires in ${Math.floor((requestData.expiresIn || 300) / 60)} minutes)`);
output.log(
`📬 Check your inbox for a 6-digit code (expires in ${Math.floor((requestData.expiresIn || 300) / 60)} minutes)`,
);
output.log('');

// Step 3: Get verification code
const code = await askQuestion(rl, '🔐 Enter the 6-digit verification code: ');
const code = await askQuestion(
rl,
'🔐 Enter the 6-digit verification code: ',
);

if (!code || code.length !== 6) {
output.error('Invalid verification code. Please enter a 6-digit code.');
Expand Down Expand Up @@ -115,7 +125,7 @@ export const signupActionHandler = async ({ authApiUrl }: SignupActionHandlerArg
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
name: `CLI Token - ${new Date().toISOString().split('T')[0]}`,
Expand All @@ -141,7 +151,9 @@ export const signupActionHandler = async ({ authApiUrl }: SignupActionHandlerArg
output.log('');
output.log(`✅ Logged in as: ${email}`);
output.log('');
output.log('You can now use the AlternateFutures CLI to deploy your projects.');
output.log(
'You can now use the AlternateFutures CLI to deploy your projects.',
);
output.printNewLine();

rl.close();
Expand All @@ -161,14 +173,20 @@ export const signupActionHandler = async ({ authApiUrl }: SignupActionHandlerArg
output.log('');

if (fetchError.cause) {
output.log(`Technical details: ${fetchError.cause.message || fetchError.cause}`);
output.log(
`Technical details: ${fetchError.cause.message || fetchError.cause}`,
);
}

output.log('');
output.log('Troubleshooting:');
output.log(` 1. Verify the auth service is running: curl -k ${authApiUrl}/health`);
output.log(
` 1. Verify the auth service is running: curl -k ${authApiUrl}/health`,
);
output.log(' 2. Check your network connection');
output.log(' 3. Try setting NODE_TLS_REJECT_UNAUTHORIZED=0 if using self-signed certs');
output.log(
' 3. Try setting NODE_TLS_REJECT_UNAUTHORIZED=0 if using self-signed certs',
);
} else {
output.error(error.message);
if (fetchError.cause) {
Expand Down
Loading