create-solostack 1.2.1 → 1.2.3
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/package.json +1 -1
- package/src/generators/base.js +188 -174
- package/src/generators/setup.js +38 -21
- package/src/index.js +1 -1
package/package.json
CHANGED
package/src/generators/base.js
CHANGED
|
@@ -316,206 +316,220 @@ export default function RootLayout({
|
|
|
316
316
|
|
|
317
317
|
import { useState, useEffect } from 'react';
|
|
318
318
|
import Link from 'next/link';
|
|
319
|
-
import {
|
|
319
|
+
import {
|
|
320
|
+
CheckCircle2,
|
|
321
|
+
AlertCircle,
|
|
322
|
+
Terminal,
|
|
323
|
+
Database,
|
|
324
|
+
Shield,
|
|
325
|
+
CreditCard,
|
|
326
|
+
Mail,
|
|
327
|
+
Loader2,
|
|
328
|
+
ChevronRight,
|
|
329
|
+
ExternalLink,
|
|
330
|
+
Book
|
|
331
|
+
} from 'lucide-react';
|
|
320
332
|
|
|
321
333
|
export default function Home() {
|
|
322
|
-
const [
|
|
323
|
-
const [
|
|
324
|
-
mrr: 0,
|
|
325
|
-
users: 0,
|
|
326
|
-
shipped: 0
|
|
327
|
-
});
|
|
334
|
+
const [status, setStatus] = useState<any>(null);
|
|
335
|
+
const [loading, setLoading] = useState(true);
|
|
328
336
|
|
|
329
337
|
useEffect(() => {
|
|
330
|
-
|
|
338
|
+
fetch('/api/setup')
|
|
339
|
+
.then(res => res.json())
|
|
340
|
+
.then(data => {
|
|
341
|
+
setStatus(data);
|
|
342
|
+
setLoading(false);
|
|
343
|
+
})
|
|
344
|
+
.catch(() => setLoading(false));
|
|
331
345
|
}, []);
|
|
332
346
|
|
|
333
|
-
const incrementStats = () => {
|
|
334
|
-
setStats(prev => ({
|
|
335
|
-
mrr: prev.mrr + 100,
|
|
336
|
-
users: prev.users + 5,
|
|
337
|
-
shipped: prev.shipped + 1
|
|
338
|
-
}));
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
if (!mounted) return null;
|
|
342
|
-
|
|
343
347
|
return (
|
|
344
348
|
<div className="min-h-screen bg-zinc-950 text-zinc-50 font-sans selection:bg-indigo-500/30">
|
|
345
349
|
|
|
346
|
-
{/*
|
|
347
|
-
<
|
|
348
|
-
<div className="max-w-
|
|
349
|
-
<div className="
|
|
350
|
-
<div className="
|
|
351
|
-
|
|
352
|
-
<Rocket className="h-5 w-5 text-white" />
|
|
353
|
-
</div>
|
|
354
|
-
<span className="text-xl font-bold tracking-tight">${projectName}</span>
|
|
355
|
-
</div>
|
|
356
|
-
<div className="flex items-center gap-4">
|
|
357
|
-
{process.env.NODE_ENV === 'development' && (
|
|
358
|
-
<Link
|
|
359
|
-
href="/setup"
|
|
360
|
-
className="text-sm font-medium text-zinc-400 hover:text-white transition-colors flex items-center gap-2"
|
|
361
|
-
>
|
|
362
|
-
<CheckCircle2 className="h-4 w-4" />
|
|
363
|
-
Diagnostics
|
|
364
|
-
</Link>
|
|
365
|
-
)}
|
|
366
|
-
<Link
|
|
367
|
-
href="/login"
|
|
368
|
-
className="text-sm font-medium text-zinc-400 hover:text-white transition-colors"
|
|
369
|
-
>
|
|
370
|
-
Sign In
|
|
371
|
-
</Link>
|
|
372
|
-
<Link
|
|
373
|
-
href="/signup"
|
|
374
|
-
className="inline-flex items-center justify-center rounded-md bg-white px-4 py-2 text-sm font-medium text-zinc-950 shadow-sm hover:bg-zinc-200 transition-colors"
|
|
375
|
-
>
|
|
376
|
-
Get Started
|
|
377
|
-
</Link>
|
|
378
|
-
</div>
|
|
350
|
+
{/* Header */}
|
|
351
|
+
<header className="border-b border-zinc-900 bg-zinc-950/50 backdrop-blur-xl sticky top-0 z-10">
|
|
352
|
+
<div className="max-w-5xl mx-auto px-6 h-16 flex items-center justify-between">
|
|
353
|
+
<div className="font-bold text-lg tracking-tight flex items-center gap-2">
|
|
354
|
+
<div className="w-3 h-3 rounded-full bg-indigo-500 shadow-[0_0_10px_rgba(99,102,241,0.5)]" />
|
|
355
|
+
<span className="text-zinc-100">${projectName}</span>
|
|
379
356
|
</div>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
357
|
+
<div className="flex items-center gap-4">
|
|
358
|
+
<span className="text-xs font-mono text-zinc-500 bg-zinc-900 px-2 py-1 rounded border border-zinc-800">
|
|
359
|
+
v0.1.0 (Dev Mode)
|
|
360
|
+
</span>
|
|
361
|
+
<a
|
|
362
|
+
href="https://github.com/danish296/create-solostack"
|
|
363
|
+
target="_blank"
|
|
364
|
+
rel="noreferrer"
|
|
365
|
+
className="text-zinc-400 hover:text-white transition-colors"
|
|
366
|
+
>
|
|
367
|
+
<ExternalLink className="w-4 h-4" />
|
|
368
|
+
</a>
|
|
390
369
|
</div>
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
370
|
+
</div>
|
|
371
|
+
</header>
|
|
372
|
+
|
|
373
|
+
<main className="max-w-5xl mx-auto px-6 py-12">
|
|
374
|
+
{/* Welcome Section */}
|
|
375
|
+
<div className="mb-12 border-b border-zinc-900 pb-12">
|
|
376
|
+
<h1 className="text-4xl font-bold tracking-tight mb-4 text-white">
|
|
377
|
+
Your Stack is Ready.
|
|
395
378
|
</h1>
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
379
|
+
<p className="text-zinc-400 text-lg max-w-2xl leading-relaxed">
|
|
380
|
+
Welcome to your new SaaS application. This page is your
|
|
381
|
+
<span className="text-zinc-200 font-medium"> local development hub</span>.
|
|
382
|
+
Check your integrations, review the tech stack, and start building.
|
|
399
383
|
</p>
|
|
400
|
-
|
|
401
|
-
<div className="
|
|
402
|
-
<
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
>
|
|
406
|
-
|
|
407
|
-
</Link>
|
|
408
|
-
<a
|
|
409
|
-
href="https://github.com/yourusername/create-solostack"
|
|
410
|
-
target="_blank"
|
|
411
|
-
rel="noopener noreferrer"
|
|
412
|
-
className="w-full sm:w-auto inline-flex items-center justify-center gap-2 rounded-lg border border-zinc-800 bg-zinc-900/50 px-8 py-3.5 text-sm font-medium text-zinc-300 hover:bg-zinc-800 hover:text-white transition-all backdrop-blur-sm"
|
|
413
|
-
>
|
|
414
|
-
Star on GitHub
|
|
415
|
-
</a>
|
|
384
|
+
|
|
385
|
+
<div className="mt-8 flex items-center gap-4">
|
|
386
|
+
<div className="flex items-center gap-2 text-sm text-zinc-500 bg-zinc-900/50 px-3 py-2 rounded-md border border-zinc-800 font-mono">
|
|
387
|
+
<Terminal className="w-4 h-4 text-indigo-400" />
|
|
388
|
+
<span>src/app/page.tsx</span>
|
|
389
|
+
</div>
|
|
390
|
+
<span className="text-zinc-600 text-sm">← Edit this file to build your landing page</span>
|
|
416
391
|
</div>
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
{/* System Status Grid */}
|
|
395
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-12">
|
|
396
|
+
<StatusCard
|
|
397
|
+
title="Database"
|
|
398
|
+
icon={<Database className="w-5 h-5 text-emerald-400" />}
|
|
399
|
+
status={status?.database?.connected}
|
|
400
|
+
loading={loading}
|
|
401
|
+
description="${config?.database === 'Supabase' ? 'Supabase' : 'PostgreSQL + Prisma'}"
|
|
402
|
+
details={status?.database?.connected ? \`User count: \${status.database.userCount}\` : status?.database?.error || "Not connected"}
|
|
403
|
+
actionLabel="${config?.database === 'Supabase' ? 'Dashboard' : 'Open Studio'}"
|
|
404
|
+
actionCommand="${config?.database === 'Supabase' ? '' : 'npm run db:studio'}"
|
|
405
|
+
actionUrl="${config?.database === 'Supabase' ? 'https://supabase.com/dashboard' : ''}"
|
|
406
|
+
/>
|
|
407
|
+
<StatusCard
|
|
408
|
+
title="Authentication"
|
|
409
|
+
icon={<Shield className="w-5 h-5 text-blue-400" />}
|
|
410
|
+
status={status?.auth?.configured}
|
|
411
|
+
loading={loading}
|
|
412
|
+
description={status?.auth?.type || status?.auth?.providers?.map((p: any) => p.name).join(', ') || "Not configured"}
|
|
413
|
+
details={status?.auth?.configured ? "Ready to authenticate users" : "Missing secrets"}
|
|
414
|
+
actionLabel="Read Docs"
|
|
415
|
+
actionUrl="${config?.auth === 'Supabase Auth' ? 'https://supabase.com/docs/guides/auth' : 'https://next-auth.js.org'}"
|
|
416
|
+
/>
|
|
417
|
+
<StatusCard
|
|
418
|
+
title="Payments"
|
|
419
|
+
icon={<CreditCard className="w-5 h-5 text-purple-400" />}
|
|
420
|
+
status={status?.stripe?.configured}
|
|
421
|
+
loading={loading}
|
|
422
|
+
description="Stripe"
|
|
423
|
+
details={status?.stripe?.configured ? "API Keys present" : "Missing API Keys"}
|
|
424
|
+
actionLabel="Dashboard"
|
|
425
|
+
actionUrl="https://dashboard.stripe.com/test/apikeys"
|
|
426
|
+
/>
|
|
427
|
+
<StatusCard
|
|
428
|
+
title="Email"
|
|
429
|
+
icon={<Mail className="w-5 h-5 text-pink-400" />}
|
|
430
|
+
status={status?.email?.configured}
|
|
431
|
+
loading={loading}
|
|
432
|
+
description="Resend"
|
|
433
|
+
details={status?.email?.configured ? "Ready to send" : "Missing API Key"}
|
|
434
|
+
actionLabel="Send Test"
|
|
435
|
+
actionUrl="/setup"
|
|
436
|
+
/>
|
|
437
|
+
</div>
|
|
417
438
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
<div className="p-4 rounded-lg bg-zinc-900/50 border border-zinc-800">
|
|
441
|
-
<div className="flex items-center gap-2 text-zinc-400 mb-2">
|
|
442
|
-
<Box className="h-4 w-4 text-purple-500" /> Shipped
|
|
443
|
-
</div>
|
|
444
|
-
<div className="text-3xl font-mono font-bold text-white">
|
|
445
|
-
{stats.shipped}
|
|
446
|
-
</div>
|
|
447
|
-
</div>
|
|
448
|
-
</div>
|
|
449
|
-
|
|
450
|
-
<div className="text-center">
|
|
451
|
-
<p className="text-zinc-500 mb-6 font-mono text-sm">
|
|
452
|
-
> CLICK_BELOW_TO_SIMULATE_GROWTH.exe
|
|
453
|
-
</p>
|
|
454
|
-
<button
|
|
455
|
-
onClick={incrementStats}
|
|
456
|
-
className="group relative inline-flex items-center justify-center rounded-full bg-zinc-100 px-8 py-4 font-bold text-zinc-950 transition-all hover:scale-105 active:scale-95 shadow-lg hover:shadow-indigo-500/20"
|
|
457
|
-
>
|
|
458
|
-
<Play className="mr-2 h-5 w-5 fill-zinc-950 transition-transform group-hover:translate-x-1" />
|
|
459
|
-
SHIP FEATURE
|
|
460
|
-
</button>
|
|
461
|
-
<p className="mt-4 text-xs text-zinc-600">
|
|
462
|
-
* Results may vary. Consistency is key.
|
|
463
|
-
</p>
|
|
464
|
-
</div>
|
|
465
|
-
</div>
|
|
466
|
-
</div>
|
|
439
|
+
{/* Resources Section */}
|
|
440
|
+
<div>
|
|
441
|
+
<h2 className="text-xl font-semibold mb-6 flex items-center gap-2">
|
|
442
|
+
<Book className="w-5 h-5 text-zinc-400" />
|
|
443
|
+
Documentation & Resources
|
|
444
|
+
</h2>
|
|
445
|
+
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
446
|
+
<ResourceLink
|
|
447
|
+
href="https://nextjs.org/docs"
|
|
448
|
+
title="Next.js 15"
|
|
449
|
+
desc="App Router, Server Actions"
|
|
450
|
+
/>
|
|
451
|
+
<ResourceLink
|
|
452
|
+
href="https://ui.shadcn.com"
|
|
453
|
+
title="shadcn/ui"
|
|
454
|
+
desc="Component Library"
|
|
455
|
+
/>
|
|
456
|
+
<ResourceLink
|
|
457
|
+
href="https://www.prisma.io/docs"
|
|
458
|
+
title="Prisma"
|
|
459
|
+
desc="Database ORM"
|
|
460
|
+
/>
|
|
467
461
|
</div>
|
|
468
462
|
</div>
|
|
469
463
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
464
|
+
</main>
|
|
465
|
+
</div>
|
|
466
|
+
);
|
|
467
|
+
}
|
|
473
468
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
title="Authentication"
|
|
481
|
-
description="Secure user management with NextAuth or Supabase. Login, signup, and protected routes."
|
|
482
|
-
/>
|
|
483
|
-
<FeatureCard
|
|
484
|
-
icon={<Database className="h-6 w-6 text-emerald-400" />}
|
|
485
|
-
title="Database"
|
|
486
|
-
description="Type-safe data access with Prisma and PostgreSQL. Seeding scripts included."
|
|
487
|
-
/>
|
|
488
|
-
<FeatureCard
|
|
489
|
-
icon={<CreditCard className="h-6 w-6 text-purple-400" />}
|
|
490
|
-
title="Payments"
|
|
491
|
-
description="Stripe integration with checkout sessions, webhooks, and subscription management."
|
|
492
|
-
/>
|
|
493
|
-
<FeatureCard
|
|
494
|
-
icon={<Mail className="h-6 w-6 text-pink-400" />}
|
|
495
|
-
title="Emails"
|
|
496
|
-
description="Transactional emails with Resend and React Email. Beautiful templates out of the box."
|
|
497
|
-
/>
|
|
498
|
-
</div>
|
|
469
|
+
function StatusCard({ title, icon, status, loading, description, details, actionLabel, actionCommand, actionUrl }: any) {
|
|
470
|
+
return (
|
|
471
|
+
<div className="border border-zinc-800 bg-zinc-900/30 rounded-xl p-6 hover:bg-zinc-900/50 transition-colors">
|
|
472
|
+
<div className="flex justify-between items-start mb-4">
|
|
473
|
+
<div className="p-2 bg-zinc-950 rounded-lg border border-zinc-800">
|
|
474
|
+
{icon}
|
|
499
475
|
</div>
|
|
476
|
+
{loading ? (
|
|
477
|
+
<Loader2 className="w-5 h-5 animate-spin text-zinc-600" />
|
|
478
|
+
) : status ? (
|
|
479
|
+
<CheckCircle2 className="w-5 h-5 text-emerald-500" />
|
|
480
|
+
) : (
|
|
481
|
+
<AlertCircle className="w-5 h-5 text-amber-500" />
|
|
482
|
+
)}
|
|
483
|
+
</div>
|
|
484
|
+
|
|
485
|
+
<h3 className="text-lg font-medium text-white mb-1">{title}</h3>
|
|
486
|
+
<p className="text-sm font-medium text-zinc-300 mb-2">{description}</p>
|
|
487
|
+
|
|
488
|
+
<div className="min-h-[20px] mb-6">
|
|
489
|
+
<p className={\`text-xs \${status ? 'text-zinc-500' : 'text-amber-500/80'}\`}>
|
|
490
|
+
{details}
|
|
491
|
+
</p>
|
|
500
492
|
</div>
|
|
501
493
|
|
|
502
|
-
{
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
494
|
+
{actionCommand ? (
|
|
495
|
+
<div className="flex items-center justify-between pt-4 border-t border-zinc-800/50">
|
|
496
|
+
<code className="text-xs bg-black px-2 py-1 rounded text-zinc-400 font-mono">
|
|
497
|
+
{actionCommand}
|
|
498
|
+
</code>
|
|
499
|
+
</div>
|
|
500
|
+
) : actionUrl ? (
|
|
501
|
+
<div className="pt-4 border-t border-zinc-800/50">
|
|
502
|
+
{actionUrl.startsWith('http') ? (
|
|
503
|
+
<a href={actionUrl} target="_blank" rel="noreferrer" className="text-xs font-medium text-indigo-400 hover:text-indigo-300 flex items-center gap-1">
|
|
504
|
+
{actionLabel} <ExternalLink className="w-3 h-3" />
|
|
505
|
+
</a>
|
|
506
|
+
) : (
|
|
507
|
+
<Link href={actionUrl} className="text-xs font-medium text-indigo-400 hover:text-indigo-300 flex items-center gap-1">
|
|
508
|
+
{actionLabel} <ChevronRight className="w-3 h-3" />
|
|
509
|
+
</Link>
|
|
510
|
+
)}
|
|
514
511
|
</div>
|
|
515
|
-
|
|
512
|
+
) : null}
|
|
516
513
|
</div>
|
|
517
514
|
);
|
|
518
515
|
}
|
|
516
|
+
|
|
517
|
+
function ResourceLink({ href, title, desc }: any) {
|
|
518
|
+
return (
|
|
519
|
+
<a
|
|
520
|
+
href={href}
|
|
521
|
+
target="_blank"
|
|
522
|
+
rel="noreferrer"
|
|
523
|
+
className="group block p-4 rounded-lg border border-zinc-800 bg-zinc-900/20 hover:bg-zinc-800/50 transition-all"
|
|
524
|
+
>
|
|
525
|
+
<div className="flex items-center justify-between mb-1">
|
|
526
|
+
<span className="font-medium text-zinc-200 group-hover:text-white transition-colors">{title}</span>
|
|
527
|
+
<ExternalLink className="w-3 h-3 text-zinc-600 group-hover:text-zinc-400" />
|
|
528
|
+
</div>
|
|
529
|
+
<p className="text-xs text-zinc-500">{desc}</p>
|
|
530
|
+
</a>
|
|
531
|
+
);
|
|
532
|
+
}
|
|
519
533
|
`;
|
|
520
534
|
|
|
521
535
|
await writeFile(path.join(projectPath, 'src/app/page.tsx'), pageTsx);
|
package/src/generators/setup.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { writeFile, ensureDir } from '../utils/files.js';
|
|
3
3
|
|
|
4
|
-
export async function generateSetup(projectPath) {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export async function generateSetup(projectPath, config) {
|
|
5
|
+
const isSupabaseAuth = config?.auth === 'Supabase Auth';
|
|
6
|
+
// Create setup page directory
|
|
7
|
+
await ensureDir(path.join(projectPath, 'src/app/setup'));
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
// Generate setup page UI
|
|
10
|
+
const setupPage = `'use client';
|
|
10
11
|
|
|
11
12
|
import { useState, useEffect } from 'react';
|
|
12
|
-
import
|
|
13
|
+
import Link from 'next/link';
|
|
14
|
+
import { CheckCircle, XCircle, Loader2, AlertCircle, RefreshCw, Mail, ArrowLeft } from 'lucide-react';
|
|
13
15
|
|
|
14
16
|
export default function SetupPage() {
|
|
15
17
|
const [data, setData] = useState<any>(null);
|
|
@@ -70,6 +72,15 @@ export default function SetupPage() {
|
|
|
70
72
|
return (
|
|
71
73
|
<div className="min-h-screen bg-gray-50 p-8">
|
|
72
74
|
<div className="mx-auto max-w-4xl space-y-8">
|
|
75
|
+
{/* Back to Home */}
|
|
76
|
+
<Link
|
|
77
|
+
href="/"
|
|
78
|
+
className="inline-flex items-center gap-2 text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors"
|
|
79
|
+
>
|
|
80
|
+
<ArrowLeft className="h-4 w-4" />
|
|
81
|
+
Back to Home
|
|
82
|
+
</Link>
|
|
83
|
+
|
|
73
84
|
<div className="flex items-center justify-between">
|
|
74
85
|
<div>
|
|
75
86
|
<h1 className="text-3xl font-bold tracking-tight">Setup & Diagnostics</h1>
|
|
@@ -240,14 +251,13 @@ function StatusIcon({ status }: { status: boolean }) {
|
|
|
240
251
|
}
|
|
241
252
|
`;
|
|
242
253
|
|
|
243
|
-
|
|
254
|
+
await writeFile(path.join(projectPath, 'src/app/setup/page.tsx'), setupPage);
|
|
244
255
|
|
|
245
|
-
|
|
246
|
-
|
|
256
|
+
// Create API routes directory
|
|
257
|
+
await ensureDir(path.join(projectPath, 'src/app/api/setup'));
|
|
247
258
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
import { db } from '@/lib/db';
|
|
259
|
+
// Generate Setup API route
|
|
260
|
+
const setupApi = `import { NextResponse } from 'next/server';
|
|
251
261
|
|
|
252
262
|
export async function GET() {
|
|
253
263
|
if (process.env.NODE_ENV !== 'development') {
|
|
@@ -259,12 +269,15 @@ export async function GET() {
|
|
|
259
269
|
connected: false,
|
|
260
270
|
userCount: 0,
|
|
261
271
|
error: null as string | null,
|
|
262
|
-
provider: 'PostgreSQL'
|
|
272
|
+
provider: '${isSupabaseAuth ? 'Supabase' : 'PostgreSQL'}'
|
|
263
273
|
},
|
|
264
274
|
auth: {
|
|
265
275
|
configured: false,
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
type: '${isSupabaseAuth ? 'Supabase Auth' : 'NextAuth.js'}',
|
|
277
|
+
hasSecret: ${isSupabaseAuth ? '!!(process.env.NEXT_PUBLIC_SUPABASE_URL && process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)' : '!!process.env.NEXTAUTH_SECRET'},
|
|
278
|
+
providers: ${isSupabaseAuth ? `[
|
|
279
|
+
{ name: 'Supabase', configured: !!(process.env.NEXT_PUBLIC_SUPABASE_URL && process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) }
|
|
280
|
+
]` : `[
|
|
268
281
|
{
|
|
269
282
|
name: 'Google',
|
|
270
283
|
clientId: !!process.env.GOOGLE_CLIENT_ID,
|
|
@@ -277,7 +290,7 @@ export async function GET() {
|
|
|
277
290
|
clientSecret: !!process.env.GITHUB_CLIENT_SECRET,
|
|
278
291
|
configured: !!(process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET)
|
|
279
292
|
}
|
|
280
|
-
]
|
|
293
|
+
]`}
|
|
281
294
|
},
|
|
282
295
|
stripe: {
|
|
283
296
|
configured: false,
|
|
@@ -293,6 +306,10 @@ export async function GET() {
|
|
|
293
306
|
|
|
294
307
|
// Check Database
|
|
295
308
|
try {
|
|
309
|
+
if (!process.env.DATABASE_URL${isSupabaseAuth ? ' && !process.env.NEXT_PUBLIC_SUPABASE_URL' : ''}) {
|
|
310
|
+
throw new Error('DATABASE_URL is not configured in .env');
|
|
311
|
+
}
|
|
312
|
+
const { db } = await import('@/lib/db');
|
|
296
313
|
const userCount = await db.user.count();
|
|
297
314
|
results.database.connected = true;
|
|
298
315
|
results.database.userCount = userCount;
|
|
@@ -315,12 +332,12 @@ export async function GET() {
|
|
|
315
332
|
}
|
|
316
333
|
`;
|
|
317
334
|
|
|
318
|
-
|
|
335
|
+
await writeFile(path.join(projectPath, 'src/app/api/setup/route.ts'), setupApi);
|
|
319
336
|
|
|
320
|
-
|
|
321
|
-
|
|
337
|
+
// Generate Test Email API route
|
|
338
|
+
await ensureDir(path.join(projectPath, 'src/app/api/setup/test-email'));
|
|
322
339
|
|
|
323
|
-
|
|
340
|
+
const testEmailApi = `import { NextResponse, NextRequest } from 'next/server';
|
|
324
341
|
import { Resend } from 'resend';
|
|
325
342
|
|
|
326
343
|
export async function POST(req: NextRequest) {
|
|
@@ -355,5 +372,5 @@ export async function POST(req: NextRequest) {
|
|
|
355
372
|
}
|
|
356
373
|
`;
|
|
357
374
|
|
|
358
|
-
|
|
375
|
+
await writeFile(path.join(projectPath, 'src/app/api/setup/test-email/route.ts'), testEmailApi);
|
|
359
376
|
}
|
package/src/index.js
CHANGED
|
@@ -153,7 +153,7 @@ export async function main() {
|
|
|
153
153
|
|
|
154
154
|
// Generate setup & diagnostics
|
|
155
155
|
spinner = ora('Adding diagnostics page').start();
|
|
156
|
-
await generateSetup(projectPath);
|
|
156
|
+
await generateSetup(projectPath, config);
|
|
157
157
|
spinner.succeed('Added diagnostics page (/setup)');
|
|
158
158
|
|
|
159
159
|
// Install dependencies
|