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.
- package/index.mjs +111 -73
- 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: '
|
|
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.
|
|
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.
|
|
291
|
+
console.log(`\n ${pc.red('✗')} Directory ${pc.bold(`"${projectName}"`)} already exists.\n`);
|
|
289
292
|
process.exit(1);
|
|
290
293
|
}
|
|
291
294
|
|
|
292
|
-
|
|
293
|
-
console.log(' Downloading template...\n');
|
|
294
|
-
run(`npx --yes degit ${TEMPLATE_REPO}#${BRANCH} "${projectName}"`, process.cwd());
|
|
295
|
+
console.log('');
|
|
295
296
|
|
|
296
|
-
//
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
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
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
fs.
|
|
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
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
// ──
|
|
321
|
-
|
|
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
|
-
|
|
328
|
-
console.
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
357
|
-
console.log(` Then run: cd ${projectName} && pnpm install
|
|
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
|
|
361
|
-
|
|
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
|
-
|
|
383
|
+
spinnerGit.warn(pc.yellow('Git init completed (commit may have failed)'));
|
|
367
384
|
}
|
|
368
385
|
|
|
369
386
|
if (credentials?.githubRepoUrl) {
|
|
370
|
-
|
|
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
|
-
|
|
392
|
+
spinnerPush.succeed(pc.green('Pushed to GitHub'));
|
|
376
393
|
} catch {
|
|
377
|
-
|
|
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(
|
|
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(`
|
|
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(`
|
|
413
|
+
console.log(` ${pc.magenta('◆')} ${pc.dim('Vercel')} ${credentials.vercelUrl}`);
|
|
387
414
|
}
|
|
388
415
|
if (credentials.githubRepoUrl) {
|
|
389
|
-
console.log(`
|
|
416
|
+
console.log(` ${pc.magenta('◆')} ${pc.dim('GitHub')} ${credentials.githubRepoUrl}`);
|
|
390
417
|
}
|
|
391
|
-
console.log(`
|
|
418
|
+
console.log(` ${pc.magenta('◆')} ${pc.dim('DB pass')} Saved in .env`);
|
|
392
419
|
console.log('');
|
|
393
|
-
console.log(
|
|
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
|
-
|
|
397
|
-
|
|
398
|
-
console.log(`
|
|
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.
|
|
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
|
}
|