create-kofi-stack 1.2.17 → 1.2.19

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/dist/index.js +77 -616
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -80,16 +80,6 @@ async function promptMarketingSite(defaultValue) {
80
80
  }
81
81
  return marketing;
82
82
  }
83
- async function promptIncludeDocs(defaultValue) {
84
- const includeDocs = await p.confirm({
85
- message: "Include documentation site? (Fumadocs)",
86
- initialValue: defaultValue ?? true
87
- });
88
- if (p.isCancel(includeDocs)) {
89
- throw new Error("Operation cancelled");
90
- }
91
- return includeDocs;
92
- }
93
83
 
94
84
  // src/prompts/shadcn.ts
95
85
  import * as p2 from "@clack/prompts";
@@ -471,7 +461,6 @@ function parseOptions(options) {
471
461
  monorepo: options.monorepo,
472
462
  single: options.single,
473
463
  marketing: options.marketing,
474
- docs: options.docs,
475
464
  componentLibrary: options.componentLibrary,
476
465
  style: options.style,
477
466
  baseColor: options.baseColor,
@@ -505,18 +494,12 @@ async function runPrompts(projectName, rawOptions) {
505
494
  structure = await promptProjectStructure();
506
495
  }
507
496
  let marketingSite = "none";
508
- let includeDocs = false;
509
497
  if (structure === "monorepo") {
510
498
  if (options.marketing) {
511
499
  marketingSite = options.marketing;
512
500
  } else {
513
501
  marketingSite = await promptMarketingSite();
514
502
  }
515
- if (options.docs !== void 0) {
516
- includeDocs = options.docs;
517
- } else {
518
- includeDocs = await promptIncludeDocs();
519
- }
520
503
  }
521
504
  const shadcn = await promptShadcnConfig({
522
505
  componentLibrary: options.componentLibrary,
@@ -569,7 +552,6 @@ async function runPrompts(projectName, rawOptions) {
569
552
  name,
570
553
  structure,
571
554
  marketingSite,
572
- includeDocs,
573
555
  shadcn,
574
556
  designSystem,
575
557
  auth,
@@ -614,9 +596,6 @@ function showConfigSummary(config) {
614
596
  if (config.marketingSite !== "none") {
615
597
  apps.push(`marketing (${config.marketingSite})`);
616
598
  }
617
- if (config.includeDocs) {
618
- apps.push("docs");
619
- }
620
599
  }
621
600
  const authProviders = ["Email/Password", "Google", ...config.auth.providers];
622
601
  const extras = [];
@@ -660,9 +639,6 @@ async function showConfirmation(config) {
660
639
  if (config.marketingSite !== "none") {
661
640
  apps.push(`marketing (${config.marketingSite})`);
662
641
  }
663
- if (config.includeDocs) {
664
- apps.push("docs");
665
- }
666
642
  }
667
643
  const authProviders = ["Email/Password", "Google", ...config.auth.providers];
668
644
  const extras = [];
@@ -709,7 +685,7 @@ ${extras.length > 0 ? `${pc.bold("Extras:")} ${extras.join(", ")}` : ""}`,
709
685
  }
710
686
 
711
687
  // src/generators/index.ts
712
- import path19 from "path";
688
+ import path18 from "path";
713
689
  import * as p7 from "@clack/prompts";
714
690
  import pc3 from "picocolors";
715
691
  import ora from "ora";
@@ -1061,17 +1037,17 @@ export const {
1061
1037
  } = authClient
1062
1038
  `;
1063
1039
  await writeFile(path3.join(appDir, "src/lib/auth.ts"), authClientContent);
1064
- const isMonorepo = config.structure === "monorepo";
1065
- const convexContent = isMonorepo ? `import { ConvexProvider, ConvexReactClient } from 'convex/react'
1040
+ const convexContent = `import { ConvexProvider, ConvexReactClient } from 'convex/react'
1066
1041
  import { env } from '@/env'
1067
1042
 
1068
- export const convex = new ConvexReactClient(env.NEXT_PUBLIC_CONVEX_URL)
1069
-
1070
- export { ConvexProvider }
1071
- ` : `import { ConvexProvider, ConvexReactClient } from 'convex/react'
1072
- import { env } from '@/env'
1043
+ const convexUrl = env.NEXT_PUBLIC_CONVEX_URL
1044
+ if (!convexUrl) {
1045
+ throw new Error(
1046
+ 'NEXT_PUBLIC_CONVEX_URL is not set. Run "npx convex dev" to set up Convex.'
1047
+ )
1048
+ }
1073
1049
 
1074
- export const convex = new ConvexReactClient(env.NEXT_PUBLIC_CONVEX_URL)
1050
+ export const convex = new ConvexReactClient(convexUrl)
1075
1051
 
1076
1052
  export { ConvexProvider }
1077
1053
  `;
@@ -2058,12 +2034,19 @@ import { convexAdapter } from '@convex-dev/better-auth/adapter'
2058
2034
  import { ConvexHttpClient } from 'convex/browser'
2059
2035
  import { env } from '@/env'
2060
2036
 
2061
- const convex = new ConvexHttpClient(env.NEXT_PUBLIC_CONVEX_URL)
2037
+ const convexUrl = env.NEXT_PUBLIC_CONVEX_URL
2038
+ if (!convexUrl) {
2039
+ throw new Error(
2040
+ 'NEXT_PUBLIC_CONVEX_URL is not set. Run "npx convex dev" to set up Convex.'
2041
+ )
2042
+ }
2043
+
2044
+ const convex = new ConvexHttpClient(convexUrl)
2062
2045
 
2063
2046
  export const auth = betterAuth({
2064
2047
  database: convexAdapter(convex),
2065
- secret: env.BETTER_AUTH_SECRET,
2066
- baseURL: env.NEXT_PUBLIC_APP_URL,
2048
+ secret: env.BETTER_AUTH_SECRET || '',
2049
+ baseURL: env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
2067
2050
  emailAndPassword: {
2068
2051
  enabled: true,
2069
2052
  sendResetPassword: async ({ user, url }) => {
@@ -2762,19 +2745,18 @@ async function generateRateLimiting(config, appDir) {
2762
2745
  }
2763
2746
  }
2764
2747
  async function generateArcjet(appDir) {
2765
- const content = `import arcjet, { shield, rateLimit, detectBot } from '@arcjet/next'
2748
+ const content = `import arcjet, { shield, fixedWindow, detectBot } from '@arcjet/next'
2766
2749
  import { env } from '@/env'
2767
2750
 
2768
2751
  export const aj = arcjet({
2769
- key: env.ARCJET_KEY,
2770
- characteristics: ['ip.src'],
2752
+ key: env.ARCJET_KEY!,
2771
2753
  rules: [
2772
2754
  // Shield protects against common attacks
2773
2755
  shield({ mode: 'LIVE' }),
2774
- // Rate limit API requests
2775
- rateLimit({
2756
+ // Rate limit API requests - 100 requests per minute
2757
+ fixedWindow({
2776
2758
  mode: 'LIVE',
2777
- interval: '1m',
2759
+ window: '1m',
2778
2760
  max: 100,
2779
2761
  }),
2780
2762
  // Bot detection
@@ -4263,517 +4245,8 @@ S3_ENDPOINT="https://[PROJECT].supabase.co/storage/v1/s3"
4263
4245
  await writeFile(path15.join(marketingDir, ".env.local"), envContent);
4264
4246
  }
4265
4247
 
4266
- // src/generators/fumadocs.ts
4267
- import path16 from "path";
4268
- async function generateFumadocs(config, docsDir) {
4269
- await ensureDir(path16.join(docsDir, "content/docs"));
4270
- await ensureDir(path16.join(docsDir, "src/app/docs/[[...slug]]"));
4271
- await ensureDir(path16.join(docsDir, "src/lib"));
4272
- await generateFumadocsPackageJson(docsDir);
4273
- await generateFumadocsNextConfig(docsDir);
4274
- await generateFumadocsTsConfig(docsDir);
4275
- await generateFumadocsSource(docsDir);
4276
- await generateFumadocsAppFiles(config, docsDir);
4277
- await generateFumadocsContent(config, docsDir);
4278
- }
4279
- async function generateFumadocsPackageJson(docsDir) {
4280
- const packageJson2 = {
4281
- name: "@repo/docs",
4282
- version: "0.1.0",
4283
- private: true,
4284
- scripts: {
4285
- dev: "next dev --turbopack -p 3002",
4286
- build: "next build",
4287
- start: "next start",
4288
- lint: "biome check .",
4289
- "lint:fix": "biome check --write .",
4290
- typecheck: "tsc --noEmit"
4291
- },
4292
- dependencies: {
4293
- next: "^16.0.0",
4294
- react: "^19.0.0",
4295
- "react-dom": "^19.0.0",
4296
- "fumadocs-core": "^16.0.0",
4297
- "fumadocs-mdx": "^14.0.0",
4298
- "fumadocs-ui": "^16.0.0",
4299
- "@repo/ui": "workspace:*"
4300
- },
4301
- devDependencies: {
4302
- "@repo/config-typescript": "workspace:*",
4303
- "@types/node": "^20.0.0",
4304
- "@types/react": "^19.0.0",
4305
- "@types/react-dom": "^19.0.0",
4306
- "@types/mdx": "^2.0.0",
4307
- tailwindcss: "^4.0.0",
4308
- "@tailwindcss/postcss": "^4.0.0",
4309
- postcss: "^8.4.0",
4310
- typescript: "^5.0.0"
4311
- }
4312
- };
4313
- await writeJSON(path16.join(docsDir, "package.json"), packageJson2);
4314
- }
4315
- async function generateFumadocsNextConfig(docsDir) {
4316
- const content = `import { createMDX } from 'fumadocs-mdx/next'
4317
- import type { NextConfig } from 'next'
4318
-
4319
- const withMDX = createMDX()
4320
-
4321
- const config: NextConfig = {
4322
- reactStrictMode: true,
4323
- transpilePackages: ['@repo/ui'],
4324
- }
4325
-
4326
- export default withMDX(config)
4327
- `;
4328
- await writeFile(path16.join(docsDir, "next.config.ts"), content);
4329
- }
4330
- async function generateFumadocsTsConfig(docsDir) {
4331
- const tsConfig = {
4332
- compilerOptions: {
4333
- target: "ES2020",
4334
- lib: ["dom", "dom.iterable", "esnext"],
4335
- allowJs: true,
4336
- skipLibCheck: true,
4337
- strict: true,
4338
- noEmit: true,
4339
- esModuleInterop: true,
4340
- module: "esnext",
4341
- moduleResolution: "bundler",
4342
- resolveJsonModule: true,
4343
- isolatedModules: true,
4344
- jsx: "preserve",
4345
- incremental: true,
4346
- plugins: [{ name: "next" }],
4347
- paths: {
4348
- "@/*": ["./src/*"],
4349
- "@/.source": ["./.source"]
4350
- }
4351
- },
4352
- include: [
4353
- "next-env.d.ts",
4354
- "**/*.ts",
4355
- "**/*.tsx",
4356
- "**/*.mdx",
4357
- ".next/types/**/*.ts",
4358
- ".source/**/*.ts"
4359
- ],
4360
- exclude: ["node_modules"]
4361
- };
4362
- await writeJSON(path16.join(docsDir, "tsconfig.json"), tsConfig);
4363
- }
4364
- async function generateFumadocsSource(docsDir) {
4365
- const content = `import { docs } from '@/.source'
4366
- import { loader } from 'fumadocs-core/source'
4367
-
4368
- export const source = loader({
4369
- baseUrl: '/docs',
4370
- source: docs.toFumadocsSource(),
4371
- })
4372
- `;
4373
- await writeFile(path16.join(docsDir, "src/lib/source.ts"), content);
4374
- }
4375
- async function generateFumadocsAppFiles(config, docsDir) {
4376
- const layoutContent = `import { RootProvider } from 'fumadocs-ui/provider/next'
4377
- import { Inter } from 'next/font/google'
4378
- import type { Metadata } from 'next'
4379
- import type { ReactNode } from 'react'
4380
- import './global.css'
4381
-
4382
- const inter = Inter({
4383
- subsets: ['latin'],
4384
- })
4385
-
4386
- export const metadata: Metadata = {
4387
- title: {
4388
- template: '%s | ${config.name} Docs',
4389
- default: '${config.name} Documentation',
4390
- },
4391
- description: 'Documentation for ${config.name}',
4392
- }
4393
-
4394
- export default function RootLayout({ children }: { children: ReactNode }) {
4395
- return (
4396
- <html lang="en" className={inter.className} suppressHydrationWarning>
4397
- <body className="flex flex-col min-h-screen">
4398
- <RootProvider>{children}</RootProvider>
4399
- </body>
4400
- </html>
4401
- )
4402
- }
4403
- `;
4404
- await writeFile(path16.join(docsDir, "src/app/layout.tsx"), layoutContent);
4405
- const docsLayoutContent = `import { DocsLayout } from 'fumadocs-ui/layouts/docs'
4406
- import type { ReactNode } from 'react'
4407
- import { source } from '@/lib/source'
4408
-
4409
- export default function Layout({ children }: { children: ReactNode }) {
4410
- return (
4411
- <DocsLayout
4412
- tree={source.pageTree}
4413
- nav={{
4414
- title: '${config.name} Docs',
4415
- }}
4416
- >
4417
- {children}
4418
- </DocsLayout>
4419
- )
4420
- }
4421
- `;
4422
- await writeFile(
4423
- path16.join(docsDir, "src/app/docs/layout.tsx"),
4424
- docsLayoutContent
4425
- );
4426
- const docsPageContent = `import { source } from '@/lib/source'
4427
- import {
4428
- DocsPage,
4429
- DocsBody,
4430
- DocsDescription,
4431
- DocsTitle,
4432
- } from 'fumadocs-ui/page'
4433
- import { notFound } from 'next/navigation'
4434
- import defaultMdxComponents from 'fumadocs-ui/mdx'
4435
-
4436
- export default async function Page(props: {
4437
- params: Promise<{ slug?: string[] }>
4438
- }) {
4439
- const params = await props.params
4440
- const page = source.getPage(params.slug)
4441
- if (!page) notFound()
4442
-
4443
- const MDX = page.data.body
4444
-
4445
- return (
4446
- <DocsPage toc={page.data.toc} full={page.data.full}>
4447
- <DocsTitle>{page.data.title}</DocsTitle>
4448
- <DocsDescription>{page.data.description}</DocsDescription>
4449
- <DocsBody>
4450
- <MDX components={{ ...defaultMdxComponents }} />
4451
- </DocsBody>
4452
- </DocsPage>
4453
- )
4454
- }
4455
-
4456
- export async function generateStaticParams() {
4457
- return source.generateParams()
4458
- }
4459
-
4460
- export async function generateMetadata(props: {
4461
- params: Promise<{ slug?: string[] }>
4462
- }) {
4463
- const params = await props.params
4464
- const page = source.getPage(params.slug)
4465
- if (!page) notFound()
4466
-
4467
- return {
4468
- title: page.data.title,
4469
- description: page.data.description,
4470
- }
4471
- }
4472
- `;
4473
- await writeFile(
4474
- path16.join(docsDir, "src/app/docs/[[...slug]]/page.tsx"),
4475
- docsPageContent
4476
- );
4477
- const homePageContent = `import { redirect } from 'next/navigation'
4478
-
4479
- export default function HomePage() {
4480
- redirect('/docs')
4481
- }
4482
- `;
4483
- await writeFile(path16.join(docsDir, "src/app/page.tsx"), homePageContent);
4484
- const globalCssContent = `@import 'tailwindcss';
4485
- @import 'fumadocs-ui/css/neutral.css';
4486
- @import 'fumadocs-ui/css/preset.css';
4487
-
4488
- @source '../node_modules/fumadocs-ui/dist/**/*.js';
4489
- `;
4490
- await writeFile(path16.join(docsDir, "src/app/global.css"), globalCssContent);
4491
- const sourceConfigContent = `import { defineDocs, defineConfig } from 'fumadocs-mdx/config'
4492
-
4493
- export const { docs, meta } = defineDocs({
4494
- dir: 'content/docs',
4495
- })
4496
-
4497
- export default defineConfig()
4498
- `;
4499
- await writeFile(path16.join(docsDir, "source.config.ts"), sourceConfigContent);
4500
- const postcssContent = `export default {
4501
- plugins: {
4502
- '@tailwindcss/postcss': {},
4503
- },
4504
- }
4505
- `;
4506
- await writeFile(path16.join(docsDir, "postcss.config.mjs"), postcssContent);
4507
- }
4508
- async function generateFumadocsContent(config, docsDir) {
4509
- const metaJson = {
4510
- title: "Documentation",
4511
- pages: ["index", "getting-started", "---", "guides", "api"]
4512
- };
4513
- await writeJSON(path16.join(docsDir, "content/docs/meta.json"), metaJson);
4514
- const indexContent = `---
4515
- title: Introduction
4516
- description: Welcome to ${config.name} documentation
4517
- ---
4518
-
4519
- # Welcome to ${config.name}
4520
-
4521
- This is the documentation for ${config.name}, built with [Fumadocs](https://fumadocs.vercel.app).
4522
-
4523
- ## Features
4524
-
4525
- - Built with Next.js 15 and React 19
4526
- - Convex for real-time database
4527
- - Better-Auth for authentication
4528
- - shadcn/ui components
4529
- - Tailwind CSS v4
4530
-
4531
- ## Getting Started
4532
-
4533
- Check out the [Getting Started](/docs/getting-started) guide to begin.
4534
- `;
4535
- await writeFile(
4536
- path16.join(docsDir, "content/docs/index.mdx"),
4537
- indexContent
4538
- );
4539
- const gettingStartedContent = `---
4540
- title: Getting Started
4541
- description: Get started with ${config.name}
4542
- ---
4543
-
4544
- # Getting Started
4545
-
4546
- This guide will help you get ${config.name} up and running.
4547
-
4548
- ## Prerequisites
4549
-
4550
- - Node.js 18 or higher
4551
- - pnpm package manager
4552
-
4553
- ## Installation
4554
-
4555
- 1. Clone the repository
4556
- 2. Install dependencies:
4557
-
4558
- \`\`\`bash
4559
- pnpm install
4560
- \`\`\`
4561
-
4562
- 3. Copy environment variables:
4563
-
4564
- \`\`\`bash
4565
- cp .env.example .env.local
4566
- \`\`\`
4567
-
4568
- 4. Set up Convex:
4569
-
4570
- \`\`\`bash
4571
- pnpm convex dev
4572
- \`\`\`
4573
-
4574
- 5. Start the development server:
4575
-
4576
- \`\`\`bash
4577
- pnpm dev
4578
- \`\`\`
4579
-
4580
- ## Next Steps
4581
-
4582
- - [Configure authentication](/docs/guides/authentication)
4583
- - [Set up your database schema](/docs/guides/database)
4584
- - [Customize the UI](/docs/guides/customization)
4585
- `;
4586
- await writeFile(
4587
- path16.join(docsDir, "content/docs/getting-started.mdx"),
4588
- gettingStartedContent
4589
- );
4590
- await ensureDir(path16.join(docsDir, "content/docs/guides"));
4591
- const guidesMetaJson = {
4592
- title: "Guides",
4593
- pages: ["authentication", "database", "customization"]
4594
- };
4595
- await writeJSON(
4596
- path16.join(docsDir, "content/docs/guides/meta.json"),
4597
- guidesMetaJson
4598
- );
4599
- const authGuideContent = `---
4600
- title: Authentication
4601
- description: Learn how to configure authentication in ${config.name}
4602
- ---
4603
-
4604
- # Authentication
4605
-
4606
- ${config.name} uses Better-Auth with Convex for authentication.
4607
-
4608
- ## Supported Providers
4609
-
4610
- - Email/Password (always enabled)
4611
- - Google OAuth (always enabled)
4612
- ${config.auth.providers.map((p8) => `- ${p8.charAt(0).toUpperCase() + p8.slice(1)}`).join("\n")}
4613
-
4614
- ## Configuration
4615
-
4616
- Authentication is configured in \`convex/auth.ts\`.
4617
-
4618
- \`\`\`typescript
4619
- export const { auth, createAuth } = new BetterAuth<DataModel>(components.betterAuth, {
4620
- emailAndPassword: {
4621
- enabled: true,
4622
- },
4623
- socialProviders: {
4624
- google: {
4625
- clientId: process.env.GOOGLE_CLIENT_ID!,
4626
- clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
4627
- },
4628
- },
4629
- })
4630
- \`\`\`
4631
-
4632
- ## Using Authentication
4633
-
4634
- Use the auth client in your components:
4635
-
4636
- \`\`\`typescript
4637
- import { signIn, signOut, useSession } from '@/lib/auth'
4638
-
4639
- // Sign in
4640
- await signIn.email({ email, password })
4641
-
4642
- // Sign out
4643
- await signOut()
4644
-
4645
- // Get session
4646
- const { data: session } = useSession()
4647
- \`\`\`
4648
- `;
4649
- await writeFile(
4650
- path16.join(docsDir, "content/docs/guides/authentication.mdx"),
4651
- authGuideContent
4652
- );
4653
- const databaseGuideContent = `---
4654
- title: Database
4655
- description: Working with Convex database
4656
- ---
4657
-
4658
- # Database
4659
-
4660
- ${config.name} uses Convex as its database.
4661
-
4662
- ## Schema
4663
-
4664
- The database schema is defined in \`convex/schema.ts\`.
4665
-
4666
- ## Queries
4667
-
4668
- Create queries to read data:
4669
-
4670
- \`\`\`typescript
4671
- import { query } from './_generated/server'
4672
-
4673
- export const getUsers = query({
4674
- handler: async (ctx) => {
4675
- return await ctx.db.query('users').collect()
4676
- },
4677
- })
4678
- \`\`\`
4679
-
4680
- ## Mutations
4681
-
4682
- Create mutations to write data:
4683
-
4684
- \`\`\`typescript
4685
- import { mutation } from './_generated/server'
4686
- import { v } from 'convex/values'
4687
-
4688
- export const createUser = mutation({
4689
- args: {
4690
- name: v.string(),
4691
- email: v.string(),
4692
- },
4693
- handler: async (ctx, args) => {
4694
- return await ctx.db.insert('users', args)
4695
- },
4696
- })
4697
- \`\`\`
4698
- `;
4699
- await writeFile(
4700
- path16.join(docsDir, "content/docs/guides/database.mdx"),
4701
- databaseGuideContent
4702
- );
4703
- const customizationGuideContent = `---
4704
- title: Customization
4705
- description: Customize the look and feel of ${config.name}
4706
- ---
4707
-
4708
- # Customization
4709
-
4710
- ## Theme
4711
-
4712
- The theme is configured in \`src/app/globals.css\` using Tailwind CSS v4.
4713
-
4714
- ### Colors
4715
-
4716
- Update the theme colors in the CSS:
4717
-
4718
- \`\`\`css
4719
- @theme {
4720
- --color-primary: oklch(0.6 0.2 250);
4721
- --color-primary-foreground: oklch(0.98 0 0);
4722
- }
4723
- \`\`\`
4724
-
4725
- ### Dark Mode
4726
-
4727
- Dark mode is supported out of the box. Define dark mode styles with:
4728
-
4729
- \`\`\`css
4730
- .dark {
4731
- --color-background: oklch(0.145 0 0);
4732
- }
4733
- \`\`\`
4734
-
4735
- ## Components
4736
-
4737
- UI components are in \`src/components/ui\`. Customize or add new components as needed.
4738
- `;
4739
- await writeFile(
4740
- path16.join(docsDir, "content/docs/guides/customization.mdx"),
4741
- customizationGuideContent
4742
- );
4743
- await ensureDir(path16.join(docsDir, "content/docs/api"));
4744
- const apiMetaJson = {
4745
- title: "API Reference",
4746
- pages: ["overview"]
4747
- };
4748
- await writeJSON(
4749
- path16.join(docsDir, "content/docs/api/meta.json"),
4750
- apiMetaJson
4751
- );
4752
- const apiOverviewContent = `---
4753
- title: API Overview
4754
- description: API reference for ${config.name}
4755
- ---
4756
-
4757
- # API Reference
4758
-
4759
- This section contains the API reference for ${config.name}.
4760
-
4761
- ## Authentication API
4762
-
4763
- See the [Better-Auth documentation](https://www.better-auth.com) for detailed API reference.
4764
-
4765
- ## Database API
4766
-
4767
- See the [Convex documentation](https://docs.convex.dev) for database API reference.
4768
- `;
4769
- await writeFile(
4770
- path16.join(docsDir, "content/docs/api/overview.mdx"),
4771
- apiOverviewContent
4772
- );
4773
- }
4774
-
4775
4248
  // src/generators/design-system.ts
4776
- import path17 from "path";
4249
+ import path16 from "path";
4777
4250
  var fontImports = {
4778
4251
  inter: {
4779
4252
  import: "import { Inter } from 'next/font/google'",
@@ -4841,17 +4314,17 @@ var spacingMultipliers = {
4841
4314
  relaxed: 1.125
4842
4315
  };
4843
4316
  async function generateDesignSystemApp(config, targetDir) {
4844
- const appDir = path17.join(targetDir, "apps/design-system");
4845
- await ensureDir(path17.join(appDir, "src/app"));
4846
- await ensureDir(path17.join(appDir, "src/app/colors"));
4847
- await ensureDir(path17.join(appDir, "src/app/typography"));
4848
- await ensureDir(path17.join(appDir, "src/app/spacing"));
4849
- await ensureDir(path17.join(appDir, "src/app/brand"));
4850
- await ensureDir(path17.join(appDir, "src/app/blocks"));
4851
- await ensureDir(path17.join(appDir, "src/app/components"));
4852
- await ensureDir(path17.join(appDir, "src/app/components/[slug]"));
4853
- await ensureDir(path17.join(appDir, "src/lib"));
4854
- await ensureDir(path17.join(appDir, "public/brand"));
4317
+ const appDir = path16.join(targetDir, "apps/design-system");
4318
+ await ensureDir(path16.join(appDir, "src/app"));
4319
+ await ensureDir(path16.join(appDir, "src/app/colors"));
4320
+ await ensureDir(path16.join(appDir, "src/app/typography"));
4321
+ await ensureDir(path16.join(appDir, "src/app/spacing"));
4322
+ await ensureDir(path16.join(appDir, "src/app/brand"));
4323
+ await ensureDir(path16.join(appDir, "src/app/blocks"));
4324
+ await ensureDir(path16.join(appDir, "src/app/components"));
4325
+ await ensureDir(path16.join(appDir, "src/app/components/[slug]"));
4326
+ await ensureDir(path16.join(appDir, "src/lib"));
4327
+ await ensureDir(path16.join(appDir, "public/brand"));
4855
4328
  await generatePackageJson2(config, appDir);
4856
4329
  await generateTsConfig2(appDir);
4857
4330
  await generateNextConfig2(appDir);
@@ -4904,7 +4377,7 @@ async function generatePackageJson2(config, appDir) {
4904
4377
  typescript: "^5.0.0"
4905
4378
  }
4906
4379
  };
4907
- await writeJSON(path17.join(appDir, "package.json"), packageJson2);
4380
+ await writeJSON(path16.join(appDir, "package.json"), packageJson2);
4908
4381
  }
4909
4382
  async function generateTsConfig2(appDir) {
4910
4383
  const tsConfig = {
@@ -4932,7 +4405,7 @@ async function generateTsConfig2(appDir) {
4932
4405
  include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
4933
4406
  exclude: ["node_modules"]
4934
4407
  };
4935
- await writeJSON(path17.join(appDir, "tsconfig.json"), tsConfig);
4408
+ await writeJSON(path16.join(appDir, "tsconfig.json"), tsConfig);
4936
4409
  }
4937
4410
  async function generateNextConfig2(appDir) {
4938
4411
  const content = `import type { NextConfig } from 'next'
@@ -4943,7 +4416,7 @@ const nextConfig: NextConfig = {
4943
4416
 
4944
4417
  export default nextConfig
4945
4418
  `;
4946
- await writeFile(path17.join(appDir, "next.config.ts"), content);
4419
+ await writeFile(path16.join(appDir, "next.config.ts"), content);
4947
4420
  }
4948
4421
  async function generatePostCssConfig2(appDir) {
4949
4422
  const content = `export default {
@@ -4952,7 +4425,7 @@ async function generatePostCssConfig2(appDir) {
4952
4425
  },
4953
4426
  }
4954
4427
  `;
4955
- await writeFile(path17.join(appDir, "postcss.config.mjs"), content);
4428
+ await writeFile(path16.join(appDir, "postcss.config.mjs"), content);
4956
4429
  }
4957
4430
  async function generateGlobalsCss2(config, appDir) {
4958
4431
  const { designSystem } = config;
@@ -5212,7 +4685,7 @@ h1, h2, h3, h4, h5, h6 {
5212
4685
  }
5213
4686
  }
5214
4687
  `;
5215
- await writeFile(path17.join(appDir, "src/app/globals.css"), content);
4688
+ await writeFile(path16.join(appDir, "src/app/globals.css"), content);
5216
4689
  }
5217
4690
  async function generateLayoutTsx(config, appDir) {
5218
4691
  const { designSystem } = config;
@@ -5411,7 +4884,7 @@ function ThemeToggle() {
5411
4884
  )
5412
4885
  }
5413
4886
  `;
5414
- await writeFile(path17.join(appDir, "src/app/layout.tsx"), content);
4887
+ await writeFile(path16.join(appDir, "src/app/layout.tsx"), content);
5415
4888
  }
5416
4889
  async function generateHomePage(config, appDir) {
5417
4890
  const content = `export default function DesignSystemHome() {
@@ -5577,7 +5050,7 @@ function Principle({
5577
5050
  )
5578
5051
  }
5579
5052
  `;
5580
- await writeFile(path17.join(appDir, "src/app/page.tsx"), content);
5053
+ await writeFile(path16.join(appDir, "src/app/page.tsx"), content);
5581
5054
  }
5582
5055
  async function generateColorsPage(config, appDir) {
5583
5056
  const content = `export default function ColorsPage() {
@@ -5746,7 +5219,7 @@ function ColorCard({
5746
5219
  )
5747
5220
  }
5748
5221
  `;
5749
- await writeFile(path17.join(appDir, "src/app/colors/page.tsx"), content);
5222
+ await writeFile(path16.join(appDir, "src/app/colors/page.tsx"), content);
5750
5223
  }
5751
5224
  async function generateTypographyPage(config, appDir) {
5752
5225
  const { designSystem } = config;
@@ -5903,7 +5376,7 @@ function WeightCard({ weight, name }: { weight: string; name: string }) {
5903
5376
  )
5904
5377
  }
5905
5378
  `;
5906
- await writeFile(path17.join(appDir, "src/app/typography/page.tsx"), content);
5379
+ await writeFile(path16.join(appDir, "src/app/typography/page.tsx"), content);
5907
5380
  }
5908
5381
  async function generateSpacingPage(config, appDir) {
5909
5382
  const { designSystem } = config;
@@ -6036,7 +5509,7 @@ function PatternCard({
6036
5509
  )
6037
5510
  }
6038
5511
  `;
6039
- await writeFile(path17.join(appDir, "src/app/spacing/page.tsx"), content);
5512
+ await writeFile(path16.join(appDir, "src/app/spacing/page.tsx"), content);
6040
5513
  }
6041
5514
  async function generateBrandPage(config, appDir) {
6042
5515
  const content = `export default function BrandPage() {
@@ -6174,7 +5647,7 @@ function DownloadCard({
6174
5647
  )
6175
5648
  }
6176
5649
  `;
6177
- await writeFile(path17.join(appDir, "src/app/brand/page.tsx"), content);
5650
+ await writeFile(path16.join(appDir, "src/app/brand/page.tsx"), content);
6178
5651
  }
6179
5652
  async function generateBlocksPage(appDir) {
6180
5653
  const content = `export default function BlocksPage() {
@@ -6236,7 +5709,7 @@ function BlockCard({ title, description }: { title: string; description: string
6236
5709
  )
6237
5710
  }
6238
5711
  `;
6239
- await writeFile(path17.join(appDir, "src/app/blocks/page.tsx"), content);
5712
+ await writeFile(path16.join(appDir, "src/app/blocks/page.tsx"), content);
6240
5713
  }
6241
5714
  async function generateComponentsPage(appDir) {
6242
5715
  const content = `export default function ComponentsPage() {
@@ -6316,7 +5789,7 @@ function CategoryCard({
6316
5789
  )
6317
5790
  }
6318
5791
  `;
6319
- await writeFile(path17.join(appDir, "src/app/components/page.tsx"), content);
5792
+ await writeFile(path16.join(appDir, "src/app/components/page.tsx"), content);
6320
5793
  }
6321
5794
  async function generateComponentSlugPage(appDir) {
6322
5795
  const content = `import { notFound } from 'next/navigation'
@@ -6420,7 +5893,7 @@ export function generateStaticParams() {
6420
5893
  return components.map((slug) => ({ slug }))
6421
5894
  }
6422
5895
  `;
6423
- await writeFile(path17.join(appDir, "src/app/components/[slug]/page.tsx"), content);
5896
+ await writeFile(path16.join(appDir, "src/app/components/[slug]/page.tsx"), content);
6424
5897
  }
6425
5898
  async function generateUtils(appDir) {
6426
5899
  const content = `import { clsx, type ClassValue } from 'clsx'
@@ -6430,7 +5903,7 @@ export function cn(...inputs: ClassValue[]) {
6430
5903
  return twMerge(clsx(inputs))
6431
5904
  }
6432
5905
  `;
6433
- await writeFile(path17.join(appDir, "src/lib/utils.ts"), content);
5906
+ await writeFile(path16.join(appDir, "src/lib/utils.ts"), content);
6434
5907
  }
6435
5908
 
6436
5909
  // src/setup/env-wizard.ts
@@ -6438,7 +5911,7 @@ import * as p6 from "@clack/prompts";
6438
5911
  import pc2 from "picocolors";
6439
5912
  import { exec } from "child_process";
6440
5913
  import { promisify } from "util";
6441
- import path18 from "path";
5914
+ import path17 from "path";
6442
5915
  var execAsync = promisify(exec);
6443
5916
  async function runEnvSetupWizard(config) {
6444
5917
  console.log();
@@ -6519,7 +5992,7 @@ This will open your browser to create a new project on Convex.
6519
5992
  ${pc2.dim("Note: Make sure you have a Convex account at https://convex.dev")}
6520
5993
  `);
6521
5994
  try {
6522
- const convexDir = config.structure === "monorepo" ? path18.join(config.targetDir, "packages/backend") : config.targetDir;
5995
+ const convexDir = config.structure === "monorepo" ? path17.join(config.targetDir, "packages/backend") : config.targetDir;
6523
5996
  const { spawn } = await import("child_process");
6524
5997
  p6.log.info(`Installing dependencies in ${pc2.dim(convexDir)}...`);
6525
5998
  const installSuccess = await new Promise((resolve) => {
@@ -6795,7 +6268,7 @@ async function writeEnvFiles(config, envValues) {
6795
6268
  return;
6796
6269
  }
6797
6270
  p6.log.step("Writing environment files...");
6798
- const webEnvPath = config.structure === "monorepo" ? path18.join(config.targetDir, "apps/web/.env.local") : path18.join(config.targetDir, ".env.local");
6271
+ const webEnvPath = config.structure === "monorepo" ? path17.join(config.targetDir, "apps/web/.env.local") : path17.join(config.targetDir, ".env.local");
6799
6272
  if (await pathExists(webEnvPath)) {
6800
6273
  let content = await readFile(webEnvPath);
6801
6274
  for (const [key, value] of Object.entries(envValues)) {
@@ -6814,7 +6287,7 @@ ${key}="${value}"`;
6814
6287
  p6.log.success(`Updated ${config.structure === "monorepo" ? "apps/web/.env.local" : ".env.local"}`);
6815
6288
  }
6816
6289
  if (config.marketingSite === "payload" && config.structure === "monorepo") {
6817
- const marketingEnvPath = path18.join(config.targetDir, "apps/marketing/.env.local");
6290
+ const marketingEnvPath = path17.join(config.targetDir, "apps/marketing/.env.local");
6818
6291
  if (await pathExists(marketingEnvPath)) {
6819
6292
  let content = await readFile(marketingEnvPath);
6820
6293
  const payloadEnvKeys = ["PAYLOAD_SECRET", "DATABASE_URL", "S3_ENDPOINT", "S3_REGION", "S3_BUCKET", "S3_ACCESS_KEY_ID", "S3_SECRET_ACCESS_KEY", "CRON_SECRET", "PREVIEW_SECRET"];
@@ -6875,7 +6348,7 @@ async function generateSingleProject(config, spinner) {
6875
6348
  await generateShadcn(config, targetDir);
6876
6349
  spinner.succeed("shadcn/ui configured");
6877
6350
  spinner.start("Setting up Convex...");
6878
- await generateConvex(config, path19.join(targetDir, "convex"));
6351
+ await generateConvex(config, path18.join(targetDir, "convex"));
6879
6352
  spinner.succeed("Convex configured");
6880
6353
  spinner.start("Configuring Better-Auth...");
6881
6354
  await generateBetterAuth(config, targetDir);
@@ -6918,7 +6391,7 @@ async function generateMonorepoProject(config, spinner) {
6918
6391
  spinner.start("Creating shared UI package...");
6919
6392
  await generateUIPackage(config, targetDir);
6920
6393
  spinner.succeed("Shared UI package created");
6921
- const webDir = path19.join(targetDir, "apps/web");
6394
+ const webDir = path18.join(targetDir, "apps/web");
6922
6395
  spinner.start("Generating web application...");
6923
6396
  await generateBaseNextjs(config, webDir);
6924
6397
  await generateTailwind(config, webDir);
@@ -6928,10 +6401,10 @@ async function generateMonorepoProject(config, spinner) {
6928
6401
  await generateEmail(config, webDir);
6929
6402
  await updateWebTsConfig(webDir);
6930
6403
  spinner.succeed("Web application generated");
6931
- const backendDir = path19.join(targetDir, "packages/backend");
6404
+ const backendDir = path18.join(targetDir, "packages/backend");
6932
6405
  spinner.start("Setting up Convex backend...");
6933
6406
  await ensureDir(backendDir);
6934
- await generateConvex(config, path19.join(backendDir, "convex"));
6407
+ await generateConvex(config, path18.join(backendDir, "convex"));
6935
6408
  spinner.succeed("Convex backend configured");
6936
6409
  if (config.integrations.analytics !== "none") {
6937
6410
  spinner.start(`Setting up ${config.integrations.analytics} analytics...`);
@@ -6954,7 +6427,7 @@ async function generateMonorepoProject(config, spinner) {
6954
6427
  spinner.succeed(`${config.integrations.monitoring} monitoring configured`);
6955
6428
  }
6956
6429
  if (config.marketingSite !== "none") {
6957
- const marketingDir = path19.join(targetDir, "apps/marketing");
6430
+ const marketingDir = path18.join(targetDir, "apps/marketing");
6958
6431
  spinner.start(`Generating ${config.marketingSite} marketing site...`);
6959
6432
  if (config.marketingSite === "payload") {
6960
6433
  await generatePayload(config, marketingDir);
@@ -6963,12 +6436,6 @@ async function generateMonorepoProject(config, spinner) {
6963
6436
  }
6964
6437
  spinner.succeed(`${config.marketingSite} marketing site generated`);
6965
6438
  }
6966
- if (config.includeDocs) {
6967
- const docsDir = path19.join(targetDir, "apps/docs");
6968
- spinner.start("Generating Fumadocs documentation site...");
6969
- await generateFumadocs(config, docsDir);
6970
- spinner.succeed("Fumadocs documentation site generated");
6971
- }
6972
6439
  spinner.start("Generating design system app...");
6973
6440
  await generateDesignSystemApp(config, targetDir);
6974
6441
  spinner.succeed("Design system app generated");
@@ -6985,7 +6452,7 @@ async function runPostGenerationSteps(config, spinner) {
6985
6452
  }
6986
6453
  spinner.start("Installing shadcn/ui components...");
6987
6454
  try {
6988
- const shadcnDir = config.structure === "monorepo" ? path19.join(targetDir, "packages/ui") : targetDir;
6455
+ const shadcnDir = config.structure === "monorepo" ? path18.join(targetDir, "packages/ui") : targetDir;
6989
6456
  await runShadcnAdd(shadcnDir);
6990
6457
  spinner.succeed("shadcn/ui components installed");
6991
6458
  } catch (error) {
@@ -7045,7 +6512,7 @@ async function generateBiomeConfig(targetDir) {
7045
6512
  }
7046
6513
  };
7047
6514
  await writeFile(
7048
- path19.join(targetDir, "biome.json"),
6515
+ path18.join(targetDir, "biome.json"),
7049
6516
  JSON.stringify(biomeJson, null, 2)
7050
6517
  );
7051
6518
  }
@@ -7096,13 +6563,13 @@ yarn-error.log*
7096
6563
  *.pem
7097
6564
  .cache
7098
6565
  `;
7099
- await writeFile(path19.join(targetDir, ".gitignore"), gitignoreContent);
6566
+ await writeFile(path18.join(targetDir, ".gitignore"), gitignoreContent);
7100
6567
  }
7101
6568
  async function generateHuskyHooks(targetDir) {
7102
6569
  const preCommitContent = `pnpm lint-staged
7103
6570
  `;
7104
- await ensureDir(path19.join(targetDir, ".husky"));
7105
- await writeFile(path19.join(targetDir, ".husky/pre-commit"), preCommitContent);
6571
+ await ensureDir(path18.join(targetDir, ".husky"));
6572
+ await writeFile(path18.join(targetDir, ".husky/pre-commit"), preCommitContent);
7106
6573
  }
7107
6574
  async function updateWebTsConfig(webDir) {
7108
6575
  const tsConfig = {
@@ -7129,14 +6596,14 @@ async function updateWebTsConfig(webDir) {
7129
6596
  exclude: ["node_modules"]
7130
6597
  };
7131
6598
  await writeFile(
7132
- path19.join(webDir, "tsconfig.json"),
6599
+ path18.join(webDir, "tsconfig.json"),
7133
6600
  JSON.stringify(tsConfig, null, 2)
7134
6601
  );
7135
6602
  }
7136
6603
  async function generateNextjsMarketing(config, marketingDir) {
7137
- await ensureDir(path19.join(marketingDir, "src/app"));
7138
- await ensureDir(path19.join(marketingDir, "src/components"));
7139
- await ensureDir(path19.join(marketingDir, "public"));
6604
+ await ensureDir(path18.join(marketingDir, "src/app"));
6605
+ await ensureDir(path18.join(marketingDir, "src/components"));
6606
+ await ensureDir(path18.join(marketingDir, "public"));
7140
6607
  const packageJson2 = {
7141
6608
  name: "@repo/marketing",
7142
6609
  version: "0.1.0",
@@ -7167,7 +6634,7 @@ async function generateNextjsMarketing(config, marketingDir) {
7167
6634
  }
7168
6635
  };
7169
6636
  await writeFile(
7170
- path19.join(marketingDir, "package.json"),
6637
+ path18.join(marketingDir, "package.json"),
7171
6638
  JSON.stringify(packageJson2, null, 2)
7172
6639
  );
7173
6640
  const homePageContent = `export default function HomePage() {
@@ -7190,7 +6657,7 @@ async function generateNextjsMarketing(config, marketingDir) {
7190
6657
  }
7191
6658
  `;
7192
6659
  await writeFile(
7193
- path19.join(marketingDir, "src/app/page.tsx"),
6660
+ path18.join(marketingDir, "src/app/page.tsx"),
7194
6661
  homePageContent
7195
6662
  );
7196
6663
  const layoutContent = `import type { Metadata } from 'next'
@@ -7214,7 +6681,7 @@ export default function RootLayout({
7214
6681
  }
7215
6682
  `;
7216
6683
  await writeFile(
7217
- path19.join(marketingDir, "src/app/layout.tsx"),
6684
+ path18.join(marketingDir, "src/app/layout.tsx"),
7218
6685
  layoutContent
7219
6686
  );
7220
6687
  const globalsCss = `@import "tailwindcss";
@@ -7226,7 +6693,7 @@ export default function RootLayout({
7226
6693
  }
7227
6694
  `;
7228
6695
  await writeFile(
7229
- path19.join(marketingDir, "src/app/globals.css"),
6696
+ path18.join(marketingDir, "src/app/globals.css"),
7230
6697
  globalsCss
7231
6698
  );
7232
6699
  const tsConfig = {
@@ -7253,7 +6720,7 @@ export default function RootLayout({
7253
6720
  exclude: ["node_modules"]
7254
6721
  };
7255
6722
  await writeFile(
7256
- path19.join(marketingDir, "tsconfig.json"),
6723
+ path18.join(marketingDir, "tsconfig.json"),
7257
6724
  JSON.stringify(tsConfig, null, 2)
7258
6725
  );
7259
6726
  const nextConfig = `import type { NextConfig } from 'next'
@@ -7264,14 +6731,14 @@ const nextConfig: NextConfig = {
7264
6731
 
7265
6732
  export default nextConfig
7266
6733
  `;
7267
- await writeFile(path19.join(marketingDir, "next.config.ts"), nextConfig);
6734
+ await writeFile(path18.join(marketingDir, "next.config.ts"), nextConfig);
7268
6735
  const postcssConfig = `export default {
7269
6736
  plugins: {
7270
6737
  '@tailwindcss/postcss': {},
7271
6738
  },
7272
6739
  }
7273
6740
  `;
7274
- await writeFile(path19.join(marketingDir, "postcss.config.mjs"), postcssConfig);
6741
+ await writeFile(path18.join(marketingDir, "postcss.config.mjs"), postcssConfig);
7275
6742
  }
7276
6743
  function displaySuccessMessage(config) {
7277
6744
  const apps = ["web"];
@@ -7279,9 +6746,6 @@ function displaySuccessMessage(config) {
7279
6746
  if (config.marketingSite !== "none") {
7280
6747
  apps.push("marketing");
7281
6748
  }
7282
- if (config.includeDocs) {
7283
- apps.push("docs");
7284
- }
7285
6749
  apps.push("design-system");
7286
6750
  }
7287
6751
  console.log();
@@ -7314,9 +6778,6 @@ function displaySuccessMessage(config) {
7314
6778
  if (config.marketingSite === "payload") {
7315
6779
  console.log(` ${pc3.dim("-")} Payload CMS: ${pc3.cyan("https://payloadcms.com/docs")}`);
7316
6780
  }
7317
- if (config.includeDocs) {
7318
- console.log(` ${pc3.dim("-")} Fumadocs: ${pc3.cyan("https://fumadocs.vercel.app")}`);
7319
- }
7320
6781
  console.log();
7321
6782
  }
7322
6783
 
@@ -7344,7 +6805,7 @@ program.name("create-kofi-stack").description(
7344
6805
  ).version(packageJson.version).argument("[project-name]", "Name of the project").option("--monorepo", "Use monorepo structure with Turborepo").option("--single", "Use single app structure").option(
7345
6806
  "--marketing <type>",
7346
6807
  "Marketing site type: payload, nextjs, none"
7347
- ).option("--docs", "Include documentation site (Fumadocs)").option("--no-docs", "Exclude documentation site").option(
6808
+ ).option(
7348
6809
  "--component-library <library>",
7349
6810
  "Component library: base (Base UI), radix (Radix UI)"
7350
6811
  ).option(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kofi-stack",
3
- "version": "1.2.17",
3
+ "version": "1.2.19",
4
4
  "description": "Scaffold opinionated full-stack projects with Next.js, Convex, Better-Auth, and more",
5
5
  "type": "module",
6
6
  "bin": {