create-alta-app 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.mjs +111 -73
  2. package/package.json +3 -1
package/index.mjs CHANGED
@@ -4,15 +4,15 @@ import { execSync } from 'node:child_process';
4
4
  import fs from 'node:fs';
5
5
  import path from 'node:path';
6
6
  import prompts from 'prompts';
7
+ import ora from 'ora';
8
+ import pc from 'picocolors';
7
9
 
8
10
  const TEMPLATE_REPO = 'adiel-hub/alta-boilerplate';
9
11
  const BRANCH = 'main';
10
-
11
- // ── Alta project provisioning service ──
12
12
  const ALTA_SERVICE_URL = 'https://ikbbbmmzxeemjwzrzsmt.supabase.co/functions/v1/create-project';
13
13
 
14
14
  function run(cmd, cwd) {
15
- execSync(cmd, { cwd, stdio: 'inherit' });
15
+ execSync(cmd, { cwd, stdio: 'ignore' });
16
16
  }
17
17
 
18
18
  function canRun(cmd) {
@@ -45,16 +45,10 @@ async function createProject(name, password) {
45
45
  function removeAuth(targetDir) {
46
46
  const appDir = path.join(targetDir, 'app');
47
47
 
48
- // Remove auth routes
49
48
  fs.rmSync(path.join(appDir, 'routes', 'auth'), { recursive: true, force: true });
50
-
51
- // Remove auth provider
52
49
  fs.unlinkSync(path.join(appDir, 'providers', 'auth-provider.tsx'));
53
-
54
- // Rewrite providers/index.ts — no auth exports
55
50
  fs.writeFileSync(path.join(appDir, 'providers', 'index.ts'), '');
56
51
 
57
- // Rewrite routes.ts — no auth routes
58
52
  fs.writeFileSync(
59
53
  path.join(appDir, 'routes.ts'),
60
54
  `import { type RouteConfig, route, layout } from '@react-router/dev/routes';
@@ -70,7 +64,6 @@ export default [
70
64
  `
71
65
  );
72
66
 
73
- // Rewrite _index.tsx — redirect to dashboard
74
67
  fs.writeFileSync(
75
68
  path.join(appDir, 'routes', '_index.tsx'),
76
69
  `import { useEffect } from 'react';
@@ -88,7 +81,6 @@ export default function IndexRoute() {
88
81
  `
89
82
  );
90
83
 
91
- // Rewrite app/_layout.tsx — no auth guard
92
84
  fs.writeFileSync(
93
85
  path.join(appDir, 'routes', 'app', '_layout.tsx'),
94
86
  `import { Outlet } from 'react-router';
@@ -111,7 +103,6 @@ export default function AppLayoutRoute() {
111
103
  `
112
104
  );
113
105
 
114
- // Rewrite root.tsx — no AuthProvider
115
106
  fs.writeFileSync(
116
107
  path.join(appDir, 'root.tsx'),
117
108
  `import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router';
@@ -150,7 +141,6 @@ export default function Root() {
150
141
  `
151
142
  );
152
143
 
153
- // Rewrite header.tsx — no user/signOut
154
144
  fs.writeFileSync(
155
145
  path.join(appDir, 'components', 'layout', 'header.tsx'),
156
146
  `import { Separator } from '@altahq/design-system/components/ui/separator';
@@ -169,7 +159,6 @@ export function Header() {
169
159
  `
170
160
  );
171
161
 
172
- // Rewrite dashboard — no user reference
173
162
  fs.writeFileSync(
174
163
  path.join(appDir, 'routes', 'app', 'dashboard.tsx'),
175
164
  `import { Card, CardContent, CardHeader, CardTitle } from '@altahq/design-system/components/ui/card';
@@ -221,7 +210,6 @@ export default function DashboardRoute() {
221
210
  `
222
211
  );
223
212
 
224
- // Rewrite settings — no user reference
225
213
  fs.writeFileSync(
226
214
  path.join(appDir, 'routes', 'app', 'settings.tsx'),
227
215
  `import { Card, CardContent, CardHeader, CardTitle } from '@altahq/design-system/components/ui/card';
@@ -250,7 +238,22 @@ export default function SettingsRoute() {
250
238
  }
251
239
 
252
240
  async function main() {
253
- console.log('\n create-alta-app\n');
241
+ console.clear();
242
+ console.log('');
243
+ console.log(pc.magenta(' ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓'));
244
+ console.log(pc.magenta(' ┃ ┃'));
245
+ console.log(pc.magenta(' ┃') + pc.bold(pc.white(' ██████╗ ██╗ ████████╗ ██████╗ ')) + pc.magenta('┃'));
246
+ console.log(pc.magenta(' ┃') + pc.bold(pc.white(' ██╔══██╗██║ ╚══██╔══╝██╔══██╗ ')) + pc.magenta('┃'));
247
+ console.log(pc.magenta(' ┃') + pc.bold(pc.white(' ███████║██║ ██║ ███████║ ')) + pc.magenta('┃'));
248
+ console.log(pc.magenta(' ┃') + pc.bold(pc.white(' ██╔══██║██║ ██║ ██╔══██║ ')) + pc.magenta('┃'));
249
+ console.log(pc.magenta(' ┃') + pc.bold(pc.white(' ██║ ██║███████╗██║ ██║ ██║ ')) + pc.magenta('┃'));
250
+ console.log(pc.magenta(' ┃') + pc.bold(pc.white(' ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ')) + pc.magenta('┃'));
251
+ console.log(pc.magenta(' ┃ ┃'));
252
+ console.log(pc.magenta(' ┃') + pc.dim(' The Full-Stack Project Scaffolding ') + pc.magenta('┃'));
253
+ console.log(pc.magenta(' ┃') + pc.dim(' React · Supabase · Vercel · AI ') + pc.magenta('┃'));
254
+ console.log(pc.magenta(' ┃ ┃'));
255
+ console.log(pc.magenta(' ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛'));
256
+ console.log('');
254
257
 
255
258
  const argName = process.argv[2];
256
259
 
@@ -259,14 +262,14 @@ async function main() {
259
262
  {
260
263
  type: argName ? null : 'text',
261
264
  name: 'projectName',
262
- message: 'Project name:',
265
+ message: 'Project name',
263
266
  initial: 'my-alta-app',
264
267
  validate: (v) => (v.length > 0 ? true : 'Project name is required'),
265
268
  },
266
269
  {
267
270
  type: 'password',
268
271
  name: 'password',
269
- message: 'Alta password:',
272
+ message: 'Alta password',
270
273
  validate: (v) => (v.length > 0 ? true : 'Password is required'),
271
274
  },
272
275
  {
@@ -285,52 +288,63 @@ async function main() {
285
288
  const targetDir = path.resolve(process.cwd(), projectName);
286
289
 
287
290
  if (fs.existsSync(targetDir)) {
288
- console.error(`\n Error: Directory "${projectName}" already exists.\n`);
291
+ console.log(`\n ${pc.red('✗')} Directory ${pc.bold(`"${projectName}"`)} already exists.\n`);
289
292
  process.exit(1);
290
293
  }
291
294
 
292
- // ── Clone template ──
293
- console.log(' Downloading template...\n');
294
- run(`npx --yes degit ${TEMPLATE_REPO}#${BRANCH} "${projectName}"`, process.cwd());
295
+ console.log('');
295
296
 
296
- // Remove the create-alta-app package from the cloned template
297
- const cliDir = path.join(targetDir, 'packages', 'create-alta-app');
298
- if (fs.existsSync(cliDir)) {
299
- fs.rmSync(cliDir, { recursive: true, force: true });
300
- }
297
+ // ── Step 1: Clone template ──
298
+ const spinnerClone = ora({ text: 'Downloading template...', indent: 2 }).start();
299
+ try {
300
+ run(`npx --yes degit ${TEMPLATE_REPO}#${BRANCH} "${projectName}"`, process.cwd());
301
301
 
302
- // Remove the packages dir if empty
303
- const packagesDir = path.join(targetDir, 'packages');
304
- if (fs.existsSync(packagesDir) && fs.readdirSync(packagesDir).length === 0) {
305
- fs.rmSync(packagesDir, { recursive: true, force: true });
306
- }
302
+ const cliDir = path.join(targetDir, 'packages', 'create-alta-app');
303
+ if (fs.existsSync(cliDir)) fs.rmSync(cliDir, { recursive: true, force: true });
304
+ const packagesDir = path.join(targetDir, 'packages');
305
+ if (fs.existsSync(packagesDir) && fs.readdirSync(packagesDir).length === 0) {
306
+ fs.rmSync(packagesDir, { recursive: true, force: true });
307
+ }
307
308
 
308
- // Update package.json name
309
- const rootPkgPath = path.join(targetDir, 'package.json');
310
- const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf-8'));
311
- rootPkg.name = projectName;
312
- fs.writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n');
309
+ const rootPkgPath = path.join(targetDir, 'package.json');
310
+ const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf-8'));
311
+ rootPkg.name = projectName;
312
+ fs.writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n');
313
313
 
314
- // ── Remove auth if not needed ──
315
- if (!response.includeAuth) {
316
- console.log(' Removing auth...\n');
317
- removeAuth(targetDir);
314
+ spinnerClone.succeed(pc.green('Template downloaded'));
315
+ } catch (err) {
316
+ spinnerClone.fail(pc.red('Failed to download template'));
317
+ throw err;
318
318
  }
319
319
 
320
- // ── Create Supabase + Vercel projects ──
321
- console.log(' Creating Supabase & Vercel projects...\n');
320
+ // ── Step 2: Remove auth if not needed ──
321
+ if (!response.includeAuth) {
322
+ const spinnerAuth = ora({ text: 'Removing authentication...', indent: 2 }).start();
323
+ try {
324
+ removeAuth(targetDir);
325
+ spinnerAuth.succeed(pc.green('Authentication removed'));
326
+ } catch (err) {
327
+ spinnerAuth.fail(pc.red('Failed to remove auth'));
328
+ throw err;
329
+ }
330
+ }
322
331
 
332
+ // ── Step 3: Create cloud projects ──
333
+ const spinnerCloud = ora({ text: 'Creating Supabase & Vercel projects...', indent: 2 }).start();
323
334
  let credentials;
324
335
  try {
325
336
  credentials = await createProject(projectName, response.password);
337
+ spinnerCloud.succeed(pc.green('Cloud projects created'));
326
338
  } catch (err) {
327
- console.error(` Error creating projects: ${err.message}`);
328
- console.error(' You can set up manually later.\n');
339
+ spinnerCloud.fail(pc.yellow('Could not create cloud projects'));
340
+ console.log(` ${pc.dim(err.message)}`);
341
+ console.log(` ${pc.dim('You can set up manually later.')}`);
329
342
  credentials = null;
330
343
  }
331
344
 
345
+ // ── Step 4: Write env files ──
332
346
  if (credentials) {
333
- // Write .env at project root used by Vite dev server
347
+ const spinnerEnv = ora({ text: 'Writing environment variables...', indent: 2 }).start();
334
348
  const env = [
335
349
  `VITE_SUPABASE_URL=${credentials.supabaseUrl}`,
336
350
  `VITE_SUPABASE_ANON_KEY=${credentials.supabaseAnonKey}`,
@@ -340,63 +354,87 @@ async function main() {
340
354
  '',
341
355
  ].join('\n');
342
356
  fs.writeFileSync(path.join(targetDir, '.env'), env);
343
-
344
- console.log(' Supabase project created.');
345
- if (credentials.vercelUrl) {
346
- console.log(' Vercel project created.');
347
- }
348
- console.log('');
357
+ spinnerEnv.succeed(pc.green('Environment configured'));
349
358
  }
350
359
 
351
- // ── Install dependencies ──
352
- console.log(' Installing dependencies...\n');
360
+ // ── Step 5: Install dependencies ──
353
361
  if (canRun('pnpm --version')) {
354
- run('pnpm install', targetDir);
362
+ const spinnerInstall = ora({ text: 'Installing dependencies...', indent: 2 }).start();
363
+ try {
364
+ run('pnpm install', targetDir);
365
+ spinnerInstall.succeed(pc.green('Dependencies installed'));
366
+ } catch {
367
+ spinnerInstall.fail(pc.yellow('Failed to install dependencies'));
368
+ console.log(` ${pc.dim(`Run: cd ${projectName} && pnpm install`)}`);
369
+ }
355
370
  } else {
356
- console.log(' pnpm not found. Install it with: npm install -g pnpm');
357
- console.log(` Then run: cd ${projectName} && pnpm install\n`);
371
+ console.log(` ${pc.yellow('⚠')} pnpm not found. Install it: ${pc.bold('npm install -g pnpm')}`);
372
+ console.log(` ${pc.dim(`Then run: cd ${projectName} && pnpm install`)}`);
358
373
  }
359
374
 
360
- // ── Init git + push to GitHub ──
361
- run('git init', targetDir);
362
- run('git add -A', targetDir);
375
+ // ── Step 6: Init git + push ──
376
+ const spinnerGit = ora({ text: 'Initializing git...', indent: 2 }).start();
363
377
  try {
378
+ run('git init', targetDir);
379
+ run('git add -A', targetDir);
364
380
  run('git commit -m "Initial commit from create-alta-app"', targetDir);
381
+ spinnerGit.succeed(pc.green('Git initialized'));
365
382
  } catch {
366
- // git commit can fail if no user is configured
383
+ spinnerGit.warn(pc.yellow('Git init completed (commit may have failed)'));
367
384
  }
368
385
 
369
386
  if (credentials?.githubRepoUrl) {
370
- console.log(' Pushing to GitHub...\n');
387
+ const spinnerPush = ora({ text: 'Pushing to GitHub...', indent: 2 }).start();
371
388
  try {
372
389
  run(`git remote add origin ${credentials.githubRepoUrl}`, targetDir);
373
390
  run('git branch -M main', targetDir);
374
391
  run('git push -u origin main', targetDir);
375
- console.log(' Pushed to GitHub.\n');
392
+ spinnerPush.succeed(pc.green('Pushed to GitHub'));
376
393
  } catch {
377
- console.log(' Could not push to GitHub. Push manually with: git push -u origin main\n');
394
+ spinnerPush.warn(pc.yellow('Could not push to GitHub'));
395
+ console.log(` ${pc.dim('Push manually: git push -u origin main')}`);
378
396
  }
379
397
  }
380
398
 
381
399
  // ── Done ──
382
- console.log(`\n Done! Your project is ready.\n`);
400
+ console.log('');
401
+ console.log(pc.green(' ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓'));
402
+ console.log(pc.green(' ┃ ┃'));
403
+ console.log(pc.green(' ┃') + pc.bold(pc.white(' ✦ Your project is ready! ✦ ')) + pc.green('┃'));
404
+ console.log(pc.green(' ┃ ┃'));
405
+ console.log(pc.green(' ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛'));
406
+ console.log('');
407
+
383
408
  if (credentials) {
384
- console.log(` Supabase: ${credentials.supabaseUrl}`);
409
+ console.log(` ${pc.bold('Project Details:')}`);
410
+ console.log('');
411
+ console.log(` ${pc.magenta('◆')} ${pc.dim('Supabase')} ${credentials.supabaseUrl}`);
385
412
  if (credentials.vercelUrl) {
386
- console.log(` Vercel: ${credentials.vercelUrl}`);
413
+ console.log(` ${pc.magenta('◆')} ${pc.dim('Vercel')} ${credentials.vercelUrl}`);
387
414
  }
388
415
  if (credentials.githubRepoUrl) {
389
- console.log(` GitHub: ${credentials.githubRepoUrl}`);
416
+ console.log(` ${pc.magenta('◆')} ${pc.dim('GitHub')} ${credentials.githubRepoUrl}`);
390
417
  }
391
- console.log(` DB pass: ${credentials.dbPassword} (save this!)`);
418
+ console.log(` ${pc.magenta('◆')} ${pc.dim('DB pass')} Saved in .env`);
392
419
  console.log('');
393
- console.log(' Auto-deploy: every push deploys to Vercel');
420
+ console.log(` ${pc.dim('───────────────────────────────────────────')}`);
421
+ console.log(` ${pc.dim('Auto-deploy: every push to GitHub → Vercel')}`);
422
+ console.log(` ${pc.dim('───────────────────────────────────────────')}`);
394
423
  console.log('');
395
424
  }
396
- console.log(` Next steps:\n`);
397
- console.log(` cd ${projectName}`);
398
- console.log(` pnpm dev`);
425
+
426
+ // ── Step 7: Start dev server ──
427
+ console.log(` ${pc.bold('Starting dev server...')}`);
399
428
  console.log('');
429
+ try {
430
+ execSync('pnpm dev', { cwd: targetDir, stdio: 'inherit' });
431
+ } catch {
432
+ console.log('');
433
+ console.log(` ${pc.dim('To start manually:')}`);
434
+ console.log(` ${pc.cyan(`cd ${projectName}`)}`);
435
+ console.log(` ${pc.cyan('pnpm dev')}`);
436
+ console.log('');
437
+ }
400
438
  }
401
439
 
402
440
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-alta-app",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "description": "Create a new Alta project",
5
5
  "bin": {
6
6
  "create-alta-app": "./index.mjs"
@@ -10,6 +10,8 @@
10
10
  "keywords": ["alta", "boilerplate", "supabase", "react", "vite"],
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
+ "ora": "^8.0.1",
14
+ "picocolors": "^1.1.0",
13
15
  "prompts": "^2.4.2"
14
16
  }
15
17
  }