@statezero/statezero-tunnel
Version:
Tunnelmole client for StateZero users to create secure tunnels to their local services.
126 lines (107 loc) ⢠4.32 kB
text/typescript
import inquirer from 'inquirer';
import { ProjectManager, ProjectConfig } from './project-manager.js';
import chalk from 'chalk';
interface ProjectSelectionAnswers {
selectedProject: string;
}
interface NewProjectAnswers {
projectName: string;
userName: string;
userEmail: string;
}
export class CliPrompts {
private projectManager: ProjectManager;
constructor() {
this.projectManager = new ProjectManager();
}
public async selectOrCreateProject(): Promise<ProjectConfig> {
const projects = this.projectManager.getProjects();
console.log(chalk.blue.bold('\nš StateZero Project Manager\n'));
if (projects.length === 0) {
console.log(chalk.yellow('No projects found. Let\'s create your first project!\n'));
return await this.createNewProject();
}
const choices = [
...projects.map(p => ({
name: `${chalk.green(p.name)} ${chalk.gray(`(${p.subdomain}.tunnels.statezero.dev)`)}`,
value: p.id,
short: p.name
})),
new inquirer.Separator(),
{
name: chalk.cyan('+ Create new project'),
value: 'new',
short: 'New project'
}
];
const answers: ProjectSelectionAnswers = await inquirer.prompt([
{
type: 'list',
name: 'selectedProject',
message: 'Select a project:',
choices,
pageSize: 10
}
]);
if (answers.selectedProject === 'new') {
return await this.createNewProject();
}
const project = projects.find(p => p.id === answers.selectedProject);
if (!project) {
throw new Error('Selected project not found');
}
this.projectManager.updateLastUsed(project.id);
return project;
}
private async createNewProject(): Promise<ProjectConfig> {
console.log(chalk.yellow('\nš Create New Project\n'));
// Get project name first
const projectNameAnswer = await inquirer.prompt([
{
type: 'input',
name: 'projectName',
message: 'Project name:',
validate: (input: string) => {
if (!input.trim()) return 'Project name is required';
if (input.length < 2) return 'Project name must be at least 2 characters';
if (input.length > 30) return 'Project name must be less than 30 characters';
// Check for duplicate names
const existing = this.projectManager.getProjects();
if (existing.some(p => p.name.toLowerCase() === input.toLowerCase())) {
return 'A project with this name already exists';
}
return true;
}
}
]);
// Get user details
const userDetailsAnswer = await inquirer.prompt([
{
type: 'input',
name: 'userName',
message: 'Your name:',
validate: (input: string) => input.trim() ? true : 'Name is required'
},
{
type: 'input',
name: 'userEmail',
message: 'Your email:',
validate: (input: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(input) ? true : 'Please enter a valid email address';
}
}
]);
const project = this.projectManager.createProject(
projectNameAnswer.projectName,
userDetailsAnswer.userEmail,
userDetailsAnswer.userName
);
console.log(chalk.green(`\nā
Project "${project.name}" created!`));
console.log(chalk.blue(`š Your subdomain: ${project.subdomain}.tunnels.statezero.dev\n`));
return project;
}
public getProjectManager(): ProjectManager {
return this.projectManager;
}
}