create-better-t-stack 2.5.0 → 2.5.2

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/dist/index.js CHANGED
@@ -144,7 +144,7 @@ DATABASE_URL="your_connection_string"`)}async function Pe(n){let{projectName:r,p
144
144
  `)&&(r+=`
145
145
  `),r+=a),i&&await h.writeFile(t,r.trimEnd())}async function Ie(t){let{projectName:n,backend:r,frontend:i,database:a,orm:o,auth:s,examples:c,dbSetup:l}=t,u=e.resolve(process.cwd(),n),d=i.includes(`react-router`),f=i.includes(`tanstack-router`),p=i.includes(`tanstack-start`),m=i.includes(`next`),g=i.includes(`nuxt`),_=i.includes(`svelte`),v=d||f||p||m||g||_;if(v){let t=e.join(u,`apps/web`);if(await h.pathExists(t)){let n=`VITE_SERVER_URL`,i=`http://localhost:3000`;m?n=`NEXT_PUBLIC_SERVER_URL`:g?n=`NUXT_PUBLIC_SERVER_URL`:_&&(n=`PUBLIC_SERVER_URL`),r===`convex`&&(n=m?`NEXT_PUBLIC_CONVEX_URL`:g?`NUXT_PUBLIC_CONVEX_URL`:_?`PUBLIC_CONVEX_URL`:`VITE_CONVEX_URL`,i=`https://<YOUR_CONVEX_URL>`);let a=[{key:n,value:i,condition:!0}];await U(e.join(t,`.env`),a)}}if(i.includes(`native`)){let t=e.join(u,`apps/native`);if(await h.pathExists(t)){let n=`EXPO_PUBLIC_SERVER_URL`,i=`http://localhost:3000`;r===`convex`&&(n=`EXPO_PUBLIC_CONVEX_URL`,i=`https://<YOUR_CONVEX_URL>`);let a=[{key:n,value:i,condition:!0}];await U(e.join(t,`.env`),a)}}if(r===`convex`)return;let y=e.join(u,`apps/server`);if(!await h.pathExists(y))return;let b=e.join(y,`.env`),x=`http://localhost:3001`;(d||_)&&(x=`http://localhost:5173`);let S=null,C=l===`turso`||l===`prisma-postgres`||l===`mongodb-atlas`||l===`neon`;if(a!==`none`&&!C)switch(a){case`postgres`:S=`postgresql://postgres:postgres@localhost:5432/mydb?schema=public`;break;case`mysql`:S=`mysql://root:password@localhost:3306/mydb`;break;case`mongodb`:S=`mongodb://localhost:27017/mydatabase`;break;case`sqlite`:S=`file:./local.db`;break}let w=[{key:`CORS_ORIGIN`,value:x,condition:!0},{key:`BETTER_AUTH_SECRET`,value:le(),condition:!!s},{key:`BETTER_AUTH_URL`,value:`http://localhost:3000`,condition:!!s},{key:`DATABASE_URL`,value:S,condition:a!==`none`&&!C},{key:`GOOGLE_GENERATIVE_AI_API_KEY`,value:``,condition:c?.includes(`ai`)||!1}];await U(b,w)}async function Le(t){let{projectName:n,examples:r,frontend:i,backend:a}=t;if(a===`convex`||!r||r.length===0||r[0]===`none`)return;let o=e.resolve(process.cwd(),n);if(r.includes(`ai`)){let t=e.join(o,`apps/web`),n=e.join(o,`apps/server`),r=await h.pathExists(t),a=await h.pathExists(n),s=i.includes(`nuxt`),c=i.includes(`svelte`);if(r){let e=[`ai`];s?e.push(`@ai-sdk/vue`):c&&e.push(`@ai-sdk/svelte`),await M({dependencies:e,projectDir:t})}a&&await M({dependencies:[`ai`,`@ai-sdk/google`],projectDir:n})}}async function Re({projectDir:e,packageManager:t,addons:n=[]}){let r=d();try{r.start(`Running ${t} install...`),await b({cwd:e,stderr:`inherit`})`${t} install`,r.stop(`Dependencies installed successfully`),(n.includes(`biome`)||n.includes(`husky`))&&await ze(e,t)}catch(e){r.stop(g.red(`Failed to install dependencies`)),e instanceof Error&&p.error(g.red(`Installation error: ${e.message}`))}}async function ze(e,t){let n=d();try{n.start(`Running Biome format check...`),await b({cwd:e,stderr:`inherit`})`${t} biome check --write .`,n.stop(`Biome check completed successfully`)}catch{n.stop(g.yellow(`Biome check encountered issues`)),o.warn(g.yellow(`Some files may need manual formatting`))}}function Be(e){let{database:t,projectName:n,packageManager:r,depsInstalled:i,orm:a,addons:o,runtime:s,frontend:c,backend:l}=e,u=l===`convex`,d=r===`npm`?`npm run`:r,f=`cd ${n}`,p=o?.includes(`husky`)||o?.includes(`biome`),h=!u&&t!==`none`?Ue(t,a,d,s):``,_=o?.includes(`tauri`)?We(d):``,v=p?He(d):``,y=c?.includes(`native`)?Ve(u):``,b=o?.includes(`pwa`)&&(c?.includes(`react-router`)||c?.includes(`tanstack-router`))?Ge():``,x=o?.includes(`starlight`)?Ke(d):``,S=c?.some(e=>[`tanstack-router`,`react-router`,`next`,`tanstack-start`,`nuxt`,`svelte`].includes(e)),C=c?.includes(`native`),w=r===`bun`&&C&&S?Je():``,T=!u&&t!==`none`&&a===`none`?qe():``,E=c?.includes(`react-router`),D=c?.includes(`svelte`),O=E||D?`5173`:`3001`,k=N(r,`taze -r`),A=`${g.bold(`Next steps`)}\n${g.cyan(`1.`)} ${f}\n`,j=2;i||(A+=`${g.cyan(`${j++}.`)} ${r} install\n`),u&&(A+=`${g.cyan(`${j++}.`)} ${d} dev:setup ${g.dim(`(this will guide you through Convex project setup)`)}\n`),A+=`${g.cyan(`${j++}.`)} ${d} dev\n\n`,A+=`${g.bold(`Your project will be available at:`)}\n`,S?A+=`${g.cyan(`•`)} Frontend: http://localhost:${O}\n`:!C&&!o?.includes(`starlight`)&&(A+=`${g.yellow(`NOTE:`)} You are creating a backend-only app (no frontend selected)\n`),u||(A+=`${g.cyan(`•`)} Backend API: http://localhost:3000\n`),o?.includes(`starlight`)&&(A+=`${g.cyan(`•`)} Docs: http://localhost:4321\n`),y&&(A+=`\n${y.trim()}\n`),h&&(A+=`\n${h.trim()}\n`),_&&(A+=`\n${_.trim()}\n`),v&&(A+=`\n${v.trim()}\n`),b&&(A+=`\n${b.trim()}\n`),x&&(A+=`\n${x.trim()}\n`),T&&(A+=`\n${T.trim()}\n`),w&&(A+=`\n${w.trim()}\n`),A+=`\n${g.bold(`Update all dependencies:
146
146
  `)}${g.cyan(k)}\n\n`,A+=`${g.bold(`Like Better-T Stack?`)} Please consider giving us a star on GitHub:\n`,A+=g.cyan(`https://github.com/AmanVarshney01/create-better-t-stack`),m.box(A)}function Ve(e){let t=e?`EXPO_PUBLIC_CONVEX_URL`:`EXPO_PUBLIC_SERVER_URL`,n=e?`https://<YOUR_CONVEX_URL>`:`http://<YOUR_LOCAL_IP>:3000`,r=`.env`,i=e?`your Convex deployment URL (find after running 'dev:setup')`:`your local IP address`;return`${g.yellow(`NOTE:`)} For Expo connectivity issues, update apps/native/${r} \nwith ${i}:\n${`${t}=${n}`}\n`}function He(e){return`${g.bold(`Linting and formatting:`)}\n${g.cyan(`•`)} Format and lint fix: ${`${e} check`}\n`}function Ue(e,t,n,r){let i=[];return t===`prisma`?(e===`sqlite`&&i.push(`${g.yellow(`NOTE:`)} Turso support with Prisma is in Early Access and requires additional setup.`,`Learn more at: https://www.prisma.io/docs/orm/overview/databases/turso`),r===`bun`&&i.push(`${g.yellow(`NOTE:`)} Prisma with Bun may require additional configuration. If you encounter errors,\nfollow the guidance provided in the error messages`),i.push(`${g.cyan(`•`)} Apply schema: ${`${n} db:push`}`),i.push(`${g.cyan(`•`)} Database UI: ${`${n} db:studio`}`)):t===`drizzle`?(i.push(`${g.cyan(`•`)} Apply schema: ${`${n} db:push`}`),i.push(`${g.cyan(`•`)} Database UI: ${`${n} db:studio`}`),e===`sqlite`&&i.push(`${g.cyan(`•`)} Start local DB (if needed): ${`cd apps/server && ${n} db:local`}`)):t===`none`&&i.push(`${g.yellow(`NOTE:`)} Manual database schema setup required.`),i.length?`${g.bold(`Database commands:`)}\n${i.join(`
147
- `)}`:``}function We(e){return`\n${g.bold(`Desktop app with Tauri:`)}\n${g.cyan(`•`)} Start desktop app: ${`cd apps/web && ${e} desktop:dev`}\n${g.cyan(`•`)} Build desktop app: ${`cd apps/web && ${e} desktop:build`}\n${g.yellow(`NOTE:`)} Tauri requires Rust and platform-specific dependencies.\nSee: https://v2.tauri.app/start/prerequisites/`}function Ge(){return`\n${g.bold(`PWA with React Router v7:`)}\n${g.yellow(`NOTE:`)} There is a known compatibility issue between VitePWA and React Router v7.\nSee: https://github.com/vite-pwa/vite-plugin-pwa/issues/809`}function Ke(e){return`\n${g.bold(`Documentation with Starlight:`)}\n${g.cyan(`•`)} Start docs site: ${`cd apps/docs && ${e} dev`}\n${g.cyan(`•`)} Build docs site: ${`cd apps/docs && ${e} build`}`}function qe(){return`\n${g.yellow(`WARNING:`)} Database selected without an ORM. Features requiring database access (e.g., examples, auth) need manual setup.`}function Je(){return`\n${g.yellow(`WARNING:`)} 'bun' might cause issues with web + native apps in a monorepo. Use 'pnpm' if problems arise.`}async function W(e,t){await Ye(e,t),t.backend===`convex`?await Ze(e,t):await Xe(e,t)}async function Ye(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.name=n.projectName,i.scripts||={};let a=i.scripts,s=n.backend===`convex`?`@${n.projectName}/backend`:`server`,c=``;n.addons.includes(`turborepo`)?c=`turbo -F ${s} dev`:n.packageManager===`bun`?c=`bun run --filter ${s} dev`:n.packageManager===`pnpm`?c=`pnpm --filter ${s} dev`:n.packageManager===`npm`&&(c=`npm run dev --workspace ${s}`);let l=``;n.packageManager===`pnpm`?l=`pnpm -r dev`:n.packageManager===`npm`?l=`npm run dev --workspaces`:n.packageManager===`bun`&&(l=`bun run --filter '*' dev`);let u=n.backend!==`convex`&&n.database!==`none`&&n.orm!==`none`;n.addons.includes(`turborepo`)?(a.dev=`turbo dev`,a.build=`turbo build`,a[`check-types`]=`turbo check-types`,a[`dev:native`]=`turbo -F native dev`,a[`dev:web`]=`turbo -F web dev`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`turbo -F ${s} setup`),u&&(a[`db:push`]=`turbo -F ${s} db:push`,a[`db:studio`]=`turbo -F ${s} db:studio`)):n.packageManager===`pnpm`?(a.dev=l,a.build=`pnpm -r build`,a[`check-types`]=`pnpm -r check-types`,a[`dev:native`]=`pnpm --filter native dev`,a[`dev:web`]=`pnpm --filter web dev`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`pnpm --filter ${s} setup`),u&&(a[`db:push`]=`pnpm --filter ${s} db:push`,a[`db:studio`]=`pnpm --filter ${s} db:studio`)):n.packageManager===`npm`?(a.dev=l,a.build=`npm run build --workspaces`,a[`check-types`]=`npm run check-types --workspaces`,a[`dev:native`]=`npm run dev --workspace native`,a[`dev:web`]=`npm run dev --workspace web`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`npm run setup --workspace ${s}`),u&&(a[`db:push`]=`npm run db:push --workspace ${s}`,a[`db:studio`]=`npm run db:studio --workspace ${s}`)):n.packageManager===`bun`&&(a.dev=l,a.build=`bun run --filter '*' build`,a[`check-types`]=`bun run --filter '*' check-types`,a[`dev:native`]=`bun run --filter native dev`,a[`dev:web`]=`bun run --filter web dev`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`bun run --filter ${s} setup`),u&&(a[`db:push`]=`bun run --filter ${s} db:push`,a[`db:studio`]=`bun run --filter ${s} db:studio`)),n.addons.includes(`biome`)&&(a.check=`biome check --write .`),n.addons.includes(`husky`)&&(a.prepare=`husky`,i[`lint-staged`]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":[`biome check --write .`]});try{let{stdout:e}=await x(n.packageManager,[`-v`],{cwd:t});i.packageManager=`${n.packageManager}@${e.trim()}`}catch{o.warn(`Could not determine ${n.packageManager} version.`)}i.workspaces||=[];let d=i.workspaces;if(n.backend===`convex`){d.includes(`packages/*`)||d.push(`packages/*`);let e=n.frontend.length>0||n.addons.includes(`starlight`);e&&!d.includes(`apps/*`)&&d.push(`apps/*`)}else d.includes(`apps/*`)||d.push(`apps/*`),d.includes(`packages/*`)||d.push(`packages/*`);await h.writeJson(r,i,{spaces:2})}async function Xe(t,n){let r=e.join(t,`apps/server/package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts||={};let a=i.scripts;n.database!==`none`&&(n.database===`sqlite`&&n.orm===`drizzle`&&(a[`db:local`]=`turso dev --db-file local.db`),n.orm===`prisma`?(a[`db:push`]=`prisma db push --schema ./prisma/schema`,a[`db:studio`]=`prisma studio`):n.orm===`drizzle`&&(a[`db:push`]=`drizzle-kit push`,a[`db:studio`]=`drizzle-kit studio`)),await h.writeJson(r,i,{spaces:2})}async function Ze(t,n){let r=e.join(t,`packages/backend/package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.name=`@${n.projectName}/backend`,i.scripts||={},await h.writeJson(r,i,{spaces:2})}async function Qe(e,t){if(!t)return;let n=await b({cwd:e,reject:!1,stderr:`pipe`})`git --version`;if(n.exitCode!==0){o.warn(g.yellow(`Git is not installed`));return}let r=await b({cwd:e,reject:!1,stderr:`pipe`})`git init`;if(r.exitCode!==0)throw Error(`Git initialization failed: ${r.stderr}`)}async function $e(t){let{projectName:n,runtime:r,backend:i}=t;if(i===`convex`||i===`next`||r===`none`)return;let a=e.resolve(process.cwd(),n),o=e.join(a,`apps/server`);await h.pathExists(o)&&(r===`bun`?await et(o,i):r===`node`&&await tt(o,i))}async function et(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts={...i.scripts,dev:`bun run --hot src/index.ts`,start:`bun run dist/src/index.js`},await h.writeJson(r,i,{spaces:2}),await M({devDependencies:[`@types/bun`],projectDir:t})}async function tt(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts={...i.scripts,dev:`tsx watch src/index.ts`,start:`node dist/src/index.js`},await h.writeJson(r,i,{spaces:2}),await M({devDependencies:[`tsx`,`@types/node`],projectDir:t}),n===`hono`?await M({dependencies:[`@hono/node-server`],projectDir:t}):n===`elysia`&&await M({dependencies:[`@elysiajs/node`],projectDir:t})}async function G(t,n,r){try{let i=await h.readFile(t,`utf-8`),a=w.compile(i),o=a(r);await h.ensureDir(e.dirname(n)),await h.writeFile(n,o)}catch(e){throw p.error(`Error processing template ${t}:`,e),Error(`Failed to process template ${t}`)}}w.registerHelper(`or`,(e,t)=>e||t),w.registerHelper(`eq`,(e,t)=>e===t),w.registerHelper(`includes`,(e,t)=>Array.isArray(e)&&e.includes(t));async function K(t,n,r,i,a=!0){let o=await C(t,{cwd:n,dot:!0,onlyFiles:!0,absolute:!1});for(let t of o){let o=e.join(n,t),s=t;t.endsWith(`.hbs`)&&(s=t.slice(0,-4));let c=e.basename(t);c===`_gitignore`?s=e.join(e.dirname(t),`.gitignore`):c===`_npmrc`&&(s=e.join(e.dirname(t),`.npmrc`));let l=e.join(r,s);try{if(await h.ensureDir(e.dirname(l)),!a&&await h.pathExists(l))continue;o.endsWith(`.hbs`)?await G(o,l,i):await h.copy(o,l,{overwrite:!0})}catch{}}}async function nt(t,n){let r=e.join(k,`templates/base`);await K([`**/*`],r,t,n),await h.ensureDir(e.join(t,`packages`))}async function rt(t,n){let r=n.frontend.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),i=n.frontend.includes(`nuxt`),a=n.frontend.includes(`svelte`),o=n.frontend.includes(`native`),s=n.backend===`convex`;if(r||i||a){let o=e.join(t,`apps/web`);if(await h.ensureDir(o),r){let t=e.join(k,`templates/frontend/react/web-base`);await h.pathExists(t)&&await K(`**/*`,t,o,n);let r=n.frontend.find(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e));if(r){let t=e.join(k,`templates/frontend/react/${r}`);if(await h.pathExists(t)&&await K(`**/*`,t,o,n),!s&&n.api!==`none`){let t=e.join(k,`templates/api/${n.api}/web/react/base`);await h.pathExists(t)&&await K(`**/*`,t,o,n)}}}else if(i){let t=e.join(k,`templates/frontend/nuxt`);if(await h.pathExists(t)&&await K(`**/*`,t,o,n),!s&&n.api!==`none`){let t=e.join(k,`templates/api/${n.api}/web/nuxt`);await h.pathExists(t)&&await K(`**/*`,t,o,n)}}else if(a){let t=e.join(k,`templates/frontend/svelte`);if(await h.pathExists(t)&&await K(`**/*`,t,o,n),!s&&n.api===`orpc`){let t=e.join(k,`templates/api/${n.api}/web/svelte`);await h.pathExists(t)&&await K(`**/*`,t,o,n)}}}if(o){let r=e.join(t,`apps/native`);await h.ensureDir(r);let i=e.join(k,`templates/frontend/native`);if(await h.pathExists(i)&&await K(`**/*`,i,r,n),!s&&(n.api===`trpc`||n.api===`orpc`)){let t=e.join(k,`templates/api/${n.api}/native`);await h.pathExists(t)&&await K(`**/*`,t,r,n)}}}async function it(t,n){if(n.backend===`convex`){let r=e.join(t,`packages/backend`),i=e.join(k,`templates/backend/convex/packages/backend`);await h.ensureDir(r),await h.pathExists(i)&&await K(`**/*`,i,r,n);let a=e.join(t,`apps/server`);await h.pathExists(a)&&await h.remove(a);return}let r=e.join(t,`apps/server`);await h.ensureDir(r);let i=e.join(k,`templates/backend/server/server-base`);await h.pathExists(i)&&await K(`**/*`,i,r,n);let a=e.join(k,`templates/backend/server/${n.backend}`);if(await h.pathExists(a)&&await K(`**/*`,a,r,n,!0),n.api!==`none`){let t=e.join(k,`templates/api/${n.api}/server/base`);await h.pathExists(t)&&await K(`**/*`,t,r,n,!0);let i=e.join(k,`templates/api/${n.api}/server/${n.backend}`);await h.pathExists(i)&&await K(`**/*`,i,r,n,!0)}}async function at(t,n){if(n.backend===`convex`||n.orm===`none`||n.database===`none`)return;let r=e.join(t,`apps/server`);await h.ensureDir(r);let i=e.join(k,`templates/db/${n.orm}/${n.database}`);await h.pathExists(i)&&await K(`**/*`,i,r,n)}async function ot(t,n){if(n.backend===`convex`||!n.auth)return;let r=e.join(t,`apps/server`),i=e.join(t,`apps/web`),a=e.join(t,`apps/native`),o=await h.pathExists(r),s=await h.pathExists(i),c=await h.pathExists(a),l=n.frontend.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),u=n.frontend.includes(`nuxt`),d=n.frontend.includes(`svelte`),f=n.frontend.includes(`native`);if(o){let t=e.join(k,`templates/auth/server/base`);if(await h.pathExists(t)&&await K(`**/*`,t,r,n),n.backend===`next`){let t=e.join(k,`templates/auth/server/next`);await h.pathExists(t)&&await K(`**/*`,t,r,n)}if(n.orm!==`none`&&n.database!==`none`){let t=n.orm,i=n.database,a=``;t===`drizzle`?a=e.join(k,`templates/auth/server/db/drizzle/${i}`):t===`prisma`&&(a=e.join(k,`templates/auth/server/db/prisma/${i}`)),a&&await h.pathExists(a)&&await K(`**/*`,a,r,n)}}if((l||u||d)&&s){if(l){let t=e.join(k,`templates/auth/web/react/base`);await h.pathExists(t)&&await K(`**/*`,t,i,n);let r=n.frontend.find(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e));if(r){let t=e.join(k,`templates/auth/web/react/${r}`);await h.pathExists(t)&&await K(`**/*`,t,i,n)}}else if(u){let t=e.join(k,`templates/auth/web/nuxt`);await h.pathExists(t)&&await K(`**/*`,t,i,n)}else if(d&&n.api===`orpc`){let t=e.join(k,`templates/auth/web/svelte`);await h.pathExists(t)&&await K(`**/*`,t,i,n)}}if(f&&c){let t=e.join(k,`templates/auth/native`);await h.pathExists(t)&&await K(`**/*`,t,a,n)}}async function st(t,n){if(!(!n.addons||n.addons.length===0))for(let r of n.addons){if(r===`none`)continue;let i=e.join(k,`templates/addons/${r}`),a=t;if(r===`pwa`&&(i=e.join(k,`templates/addons/pwa/apps/web`),a=e.join(t,`apps/web`),!await h.pathExists(a)))continue;await h.pathExists(i)&&await K(`**/*`,i,a,n)}}async function ct(t,n){let r=e.join(t,`apps/server`),i=e.join(t,`apps/web`),a=await h.pathExists(r),o=await h.pathExists(i),s=n.frontend.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),c=n.frontend.includes(`nuxt`),l=n.frontend.includes(`svelte`);for(let t of n.examples){if(!n.examples||n.examples.length===0||n.examples[0]===`none`||t===`none`)continue;let u=e.join(k,`templates/examples/${t}`);if(a){let t=e.join(u,`server`);if(await h.pathExists(t)&&n.backend!==`convex`){if(n.orm!==`none`&&n.database!==`none`){let i=e.join(t,n.orm,`base`);await h.pathExists(i)&&await K(`**/*`,i,r,n,!1);let a=e.join(t,n.orm,n.database);await h.pathExists(a)&&await K(`**/*`,a,r,n,!1)}let i=await C([`*.ts`,`*.hbs`],{cwd:t,onlyFiles:!0,deep:1,ignore:[`${n.orm}/**`]});for(let a of i){let i=e.join(t,a),o=e.join(r,a.replace(`.hbs`,``));i.endsWith(`.hbs`)?await G(i,o,n):await h.copy(i,o,{overwrite:!1})}}}if(o){if(s){let t=e.join(u,`web/react`);if(await h.pathExists(t)){let r=n.frontend.find(e=>[`next`,`react-router`,`tanstack-router`,`tanstack-start`].includes(e));if(r){let a=e.join(t,r);await h.pathExists(a)&&await K(`**/*`,a,i,n,!1)}}}else if(c){let t=e.join(u,`web/nuxt`);await h.pathExists(t)&&await K(`**/*`,t,i,n,!1)}else if(l){let t=e.join(u,`web/svelte`);await h.pathExists(t)&&await K(`**/*`,t,i,n,!1)}}}}async function lt(t,n){let r=e.join(k,`templates/extras`);if(n.packageManager===`pnpm`){let n=e.join(r,`pnpm-workspace.yaml`),i=e.join(t,`pnpm-workspace.yaml`);await h.pathExists(n)&&await h.copy(n,i)}if(n.packageManager===`pnpm`&&(n.frontend.includes(`native`)||n.frontend.includes(`nuxt`))){let i=e.join(r,`_npmrc.hbs`),a=e.join(t,`.npmrc`);await h.pathExists(i)&&await G(i,a,n)}}async function ut(n){let r=e.resolve(process.cwd(),n.projectName),i=n.backend===`convex`;try{return await h.ensureDir(r),await nt(r,n),await rt(r,n),await it(r,n),i||(await at(r,n),await ot(r,n)),n.examples.length>0&&n.examples[0]!==`none`&&await ct(r,n),await st(r,n),await se(n),i||(await ue(n),await Fe(n),await $e(n),n.examples.length>0&&n.examples[0]!==`none`&&await Le(n)),n.addons.length>0&&n.addons[0]!==`none`&&await ne(n),!i&&n.auth&&await ce(n),await lt(r,n),await Ie(n),await W(r,n),await de(r,n),await Qe(r,n.git),o.success(`Project template successfully scaffolded!`),n.install&&await Re({projectDir:r,packageManager:n.packageManager,addons:n.addons}),Be({...n,depsInstalled:n.install}),r}catch(e){e instanceof Error?(t(g.red(`Error during project creation: ${e.message}`)),console.error(e.stack),process.exit(1)):(t(g.red(`An unexpected error occurred: ${String(e)}`)),console.error(e),process.exit(1))}}async function dt(e,n){if(e!==void 0)return e;let r=n?.includes(`react-router`)||n?.includes(`tanstack-router`),i=n?.includes(`react-router`)||n?.includes(`tanstack-router`)||n?.includes(`nuxt`)||n?.includes(`svelte`),o=[{value:`turborepo`,label:`Turborepo (Recommended)`,hint:`Optimize builds for monorepos`},{value:`starlight`,label:`Starlight`,hint:`Add Astro Starlight documentation site`},{value:`biome`,label:`Biome`,hint:`Add Biome for linting and formatting`},{value:`husky`,label:`Husky`,hint:`Add Git hooks with Husky, lint-staged (requires Biome)`},{value:`pwa`,label:`PWA (Progressive Web App)`,hint:`Make your app installable and work offline`},{value:`tauri`,label:`Tauri Desktop App`,hint:`Build native desktop apps from your web frontend`}],c=o.filter(e=>e.value===`pwa`?r:e.value===`tauri`?i:!0),l=A.addons.filter(e=>c.some(t=>t.value===e)),u=await s({message:`Select addons`,options:c,initialValues:l,required:!1});return a(u)&&(t(g.red(`Operation cancelled`)),process.exit(0)),u.includes(`husky`)&&!u.includes(`biome`)&&u.push(`biome`),u}async function ft(e,n,r){if(r===`convex`)return`none`;if(e)return e;let i=n?.includes(`nuxt`),o=n?.includes(`svelte`),s=[{value:`trpc`,label:`tRPC`,hint:`End-to-end typesafe APIs made easy`},{value:`orpc`,label:`oRPC`,hint:`End-to-end type-safe APIs that adhere to OpenAPI standards`}];(i||o)&&(s=[{value:`orpc`,label:`oRPC`,hint:`End-to-end type-safe APIs (Required for ${i?`Nuxt`:`Svelte`} frontend)`}]);let c=await u({message:`Select API type`,options:s,initialValue:i||o?`orpc`:A.api});return a(c)&&(t(g.red(`Operation cancelled`)),process.exit(0)),(i||o)&&c!==`orpc`?`orpc`:c}async function pt(e,r,i){if(i===`convex`||!r)return!1;if(e!==void 0)return e;let o=await n({message:`Add authentication with Better-Auth?`,initialValue:A.auth});return a(o)&&(t(g.red(`Operation cancelled`)),process.exit(0)),o}async function mt(e){if(e!==void 0)return e;let n=await u({message:`Select backend framework`,options:[{value:`hono`,label:`Hono`,hint:`Lightweight, ultrafast web framework`},{value:`next`,label:`Next.js`,hint:`Full-stack framework with API routes`},{value:`express`,label:`Express`,hint:`Fast, unopinionated, minimalist web framework for Node.js`},{value:`elysia`,label:`Elysia`,hint:`Ergonomic web framework for building backend servers`},{value:`convex`,label:`Convex`,hint:`Reactive backend-as-a-service platform`}],initialValue:A.backend});return a(n)&&(t(g.red(`Operation cancelled`)),process.exit(0)),n}async function ht(e,n){if(n===`convex`)return`none`;if(e!==void 0)return e;let r=await u({message:`Select database`,options:[{value:`none`,label:`None`,hint:`No database setup`},{value:`sqlite`,label:`SQLite`,hint:`lightweight, server-less, embedded relational database`},{value:`postgres`,label:`PostgreSQL`,hint:`powerful, open source object-relational database system`},{value:`mysql`,label:`MySQL`,hint:`popular open-source relational database system`},{value:`mongodb`,label:`MongoDB`,hint:`open-source NoSQL database that stores data in JSON-like documents called BSON`}],initialValue:A.database});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function gt(e,n,r,i){if(i===`convex`)return`none`;if(n!==void 0)return n;if(e===`none`||e===`sqlite`&&r===`prisma`)return`none`;let o=[];if(e===`sqlite`)o=[{value:`turso`,label:`Turso`,hint:`SQLite for Production. Powered by libSQL`},{value:`none`,label:`None`,hint:`Manual setup`}];else if(e===`postgres`)o=[{value:`neon`,label:`Neon Postgres`,hint:`Serverless Postgres with branching capability`},...r===`prisma`?[{value:`prisma-postgres`,label:`Prisma Postgres`,hint:`Instant Postgres for Global Applications`}]:[],{value:`none`,label:`None`,hint:`Manual setup`}];else if(e===`mongodb`)o=[{value:`mongodb-atlas`,label:`MongoDB Atlas`,hint:`The most effective way to deploy MongoDB`},{value:`none`,label:`None`,hint:`Manual setup`}];else return`none`;let s=await u({message:`Select ${e} setup option`,options:o,initialValue:`none`});return a(s)&&(t(g.red(`Operation cancelled`)),process.exit(0)),s}async function _t(e,n,r,i){if(e!==void 0)return e;if(i===`convex`)return[`todo`];if(n===`none`)return[];let o=r&&r.length===1&&r[0]===`native`;if(o)return[];let c=r?.some(e=>[`react-router`,`tanstack-router`,`tanstack-start`,`next`,`nuxt`,`svelte`].includes(e))??!1,l=!r||r.length===0;if(!c&&!l)return[];let u=[],d=[{value:`todo`,label:`Todo App`,hint:`A simple CRUD example app`}];return i!==`elysia`&&d.push({value:`ai`,label:`AI Chat`,hint:`A simple AI chat interface using AI SDK`}),u=await s({message:`Include examples`,options:d,required:!1,initialValues:A.examples}),a(u)&&(t(g.red(`Operation cancelled`)),process.exit(0)),u}async function vt(e){if(e!==void 0)return e;let n=await s({message:`Select platforms to develop for`,options:[{value:`web`,label:`Web`,hint:`React, Vue or Svelte Web Application`},{value:`native`,label:`Native`,hint:`Create a React Native/Expo app`}],required:!1,initialValues:A.frontend.some(e=>e===`tanstack-router`||e===`react-router`||e===`tanstack-start`||e===`next`||e===`nuxt`||e===`svelte`)?[`web`]:[]});a(n)&&(t(g.red(`Operation cancelled`)),process.exit(0));let r=[];if(n.includes(`web`)){let e=await u({message:`Choose frontend framework`,options:[{value:`tanstack-router`,label:`TanStack Router`,hint:`Modern and scalable routing for React Applications`},{value:`react-router`,label:`React Router`,hint:`A user‑obsessed, standards‑focused, multi‑strategy router`},{value:`next`,label:`Next.js`,hint:`The React Framework for the Web`},{value:`nuxt`,label:`Nuxt`,hint:`The Progressive Web Framework for Vue.js`},{value:`svelte`,label:`Svelte`,hint:`web development for the rest of us`},{value:`tanstack-start`,label:`TanStack Start (beta)`,hint:`SSR, Server Functions, API Routes and more with TanStack Router`}],initialValue:A.frontend.find(e=>e===`tanstack-router`||e===`react-router`||e===`tanstack-start`||e===`next`||e===`nuxt`||e===`svelte`)||`tanstack-router`});a(e)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r.push(e)}return n.includes(`native`)&&r.push(`native`),r}async function yt(e){if(e!==void 0)return e;let r=await n({message:`Initialize git repository?`,initialValue:A.git});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function bt(e){if(e!==void 0)return e;let r=await n({message:`Install dependencies?`,initialValue:A.install});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function xt(e,n,r,i){if(i===`convex`||!n)return`none`;if(e!==void 0)return e;if(r===`mongodb`)return o.info(`Only Prisma is supported with MongoDB.`),`prisma`;let s=await u({message:`Select ORM`,options:[{value:`drizzle`,label:`Drizzle`,hint:`lightweight and performant TypeScript ORM`},{value:`prisma`,label:`Prisma`,hint:`Powerful, feature-rich ORM`}],initialValue:A.orm});return a(s)&&(t(g.red(`Operation cancelled`)),process.exit(0)),s}async function St(e){if(e!==void 0)return e;let n=E(),r=await u({message:`Choose package manager`,options:[{value:`npm`,label:`npm`,hint:`Node Package Manager`},{value:`pnpm`,label:`pnpm`,hint:`Fast, disk space efficient package manager`},{value:`bun`,label:`bun`,hint:`All-in-one JavaScript runtime & toolkit`}],initialValue:n});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}const Ct=[`<`,`>`,`:`,`"`,`|`,`?`,`*`],q=255;function J(e){if(e!==`.`){if(!e)return`Project name cannot be empty`;if(e.length>q)return`Project name must be less than ${q} characters`;if(Ct.some(t=>e.includes(t)))return`Project name contains invalid characters`;if(e.startsWith(`.`)||e.startsWith(`-`))return`Project name cannot start with a dot or dash`;if(e.toLowerCase()===`node_modules`)return`Project name is reserved`}}async function Y(n){if(n)if(n===`.`){let e=process.cwd();if(h.readdirSync(e).length===0)return n}else{let t=e.basename(n),r=J(t);if(!r){let t=e.resolve(process.cwd(),n);if(!h.pathExistsSync(t)||h.readdirSync(t).length===0)return n}}let r=!1,i=``,o=A.projectName,s=1;for(;h.pathExistsSync(e.resolve(process.cwd(),o));)o=`${A.projectName}-${s}`,s++;for(;!r;){let s=await f({message:`Enter your project name or path (relative to current directory)`,placeholder:o,initialValue:n,defaultValue:o,validate:t=>{let n=t.trim()||o;if(n===`.`){let e=h.readdirSync(process.cwd());if(e.length>0)return`Current directory is not empty. Please choose a different directory.`;r=!0;return}let i=e.resolve(process.cwd(),n),a=e.basename(i),s=J(a);if(s)return s;if(!i.startsWith(process.cwd()))return`Project path must be within current directory`;if(h.pathExistsSync(i)){let e=h.readdirSync(i);if(e.length>0)return`Directory "${n}" already exists and is not empty. Please choose a different name or path.`}r=!0}});a(s)&&(t(g.red(`Operation cancelled.`)),process.exit(0)),i=s||o}return i}async function wt(e,n){if(n===`convex`)return`none`;if(e!==void 0)return e;if(n===`next`)return`node`;let r=await u({message:`Select runtime`,options:[{value:`bun`,label:`Bun`,hint:`Fast all-in-one JavaScript runtime`},{value:`node`,label:`Node.js`,hint:`Traditional Node.js runtime`}],initialValue:A.runtime});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function Tt(e){let n=await r({projectName:async()=>Y(e.projectName),frontend:()=>vt(e.frontend),backend:()=>mt(e.backend),runtime:({results:t})=>wt(e.runtime,t.backend),database:({results:t})=>ht(e.database,t.backend),orm:({results:t})=>xt(e.orm,t.database!==`none`,t.database,t.backend),api:({results:t})=>ft(e.api,t.frontend,t.backend),auth:({results:t})=>pt(e.auth,t.database!==`none`,t.backend),addons:({results:t})=>dt(e.addons,t.frontend),examples:({results:t})=>_t(e.examples,t.database,t.frontend,t.backend),dbSetup:({results:t})=>gt(t.database??`none`,e.dbSetup,t.orm,t.backend),git:()=>yt(e.git),packageManager:()=>St(e.packageManager),install:()=>bt(e.install)},{onCancel:()=>{t(g.red(`Operation cancelled`)),process.exit(0)}});return n.backend===`convex`&&(n.runtime=`none`,n.database=`none`,n.orm=`none`,n.api=`none`,n.auth=!1,n.dbSetup=`none`),{projectName:n.projectName,frontend:n.frontend,backend:n.backend,runtime:n.runtime,database:n.database,orm:n.orm,auth:n.auth,addons:n.addons,examples:n.examples,git:n.git,packageManager:n.packageManager,install:n.install,dbSetup:n.dbSetup,api:n.api}}function X(e){let t=[];if(e.projectName&&t.push(`${g.blue(`Project Name:`)} ${e.projectName}`),e.frontend!==void 0){let n=Array.isArray(e.frontend)?e.frontend:[e.frontend],r=n.length>0&&n[0]!==void 0?n.join(`, `):`none`;t.push(`${g.blue(`Frontend:`)} ${r}`)}if(e.backend!==void 0&&t.push(`${g.blue(`Backend Framework:`)} ${String(e.backend)}`),e.runtime!==void 0&&t.push(`${g.blue(`Runtime:`)} ${String(e.runtime)}`),e.api!==void 0&&t.push(`${g.blue(`API:`)} ${String(e.api)}`),e.database!==void 0&&t.push(`${g.blue(`Database:`)} ${String(e.database)}`),e.orm!==void 0&&t.push(`${g.blue(`ORM:`)} ${String(e.orm)}`),e.auth!==void 0){let n=typeof e.auth==`boolean`?e.auth?`Yes`:`No`:String(e.auth);t.push(`${g.blue(`Authentication:`)} ${n}`)}if(e.addons!==void 0){let n=Array.isArray(e.addons)?e.addons:[e.addons],r=n.length>0&&n[0]!==void 0?n.join(`, `):`none`;t.push(`${g.blue(`Addons:`)} ${r}`)}if(e.examples!==void 0){let n=Array.isArray(e.examples)?e.examples:[e.examples],r=n.length>0&&n[0]!==void 0?n.join(`, `):`none`;t.push(`${g.blue(`Examples:`)} ${r}`)}if(e.git!==void 0){let n=typeof e.git==`boolean`?e.git?`Yes`:`No`:String(e.git);t.push(`${g.blue(`Git Init:`)} ${n}`)}if(e.packageManager!==void 0&&t.push(`${g.blue(`Package Manager:`)} ${String(e.packageManager)}`),e.install!==void 0){let n=typeof e.install==`boolean`?e.install?`Yes`:`No`:String(e.install);t.push(`${g.blue(`Install Dependencies:`)} ${n}`)}return e.dbSetup!==void 0&&t.push(`${g.blue(`Database Setup:`)} ${String(e.dbSetup)}`),t.length===0?g.yellow(`No configuration selected.`):t.join(`
147
+ `)}`:``}function We(e){return`\n${g.bold(`Desktop app with Tauri:`)}\n${g.cyan(`•`)} Start desktop app: ${`cd apps/web && ${e} desktop:dev`}\n${g.cyan(`•`)} Build desktop app: ${`cd apps/web && ${e} desktop:build`}\n${g.yellow(`NOTE:`)} Tauri requires Rust and platform-specific dependencies.\nSee: https://v2.tauri.app/start/prerequisites/`}function Ge(){return`\n${g.bold(`PWA with React Router v7:`)}\n${g.yellow(`NOTE:`)} There is a known compatibility issue between VitePWA and React Router v7.\nSee: https://github.com/vite-pwa/vite-plugin-pwa/issues/809`}function Ke(e){return`\n${g.bold(`Documentation with Starlight:`)}\n${g.cyan(`•`)} Start docs site: ${`cd apps/docs && ${e} dev`}\n${g.cyan(`•`)} Build docs site: ${`cd apps/docs && ${e} build`}`}function qe(){return`\n${g.yellow(`WARNING:`)} Database selected without an ORM. Features requiring database access (e.g., examples, auth) need manual setup.`}function Je(){return`\n${g.yellow(`WARNING:`)} 'bun' might cause issues with web + native apps in a monorepo. Use 'pnpm' if problems arise.`}async function W(e,t){await Ye(e,t),t.backend===`convex`?await Ze(e,t):await Xe(e,t)}async function Ye(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.name=n.projectName,i.scripts||={};let a=i.scripts,s=n.backend===`convex`?`@${n.projectName}/backend`:`server`,c=``;n.addons.includes(`turborepo`)?c=`turbo -F ${s} dev`:n.packageManager===`bun`?c=`bun run --filter ${s} dev`:n.packageManager===`pnpm`?c=`pnpm --filter ${s} dev`:n.packageManager===`npm`&&(c=`npm run dev --workspace ${s}`);let l=``;n.packageManager===`pnpm`?l=`pnpm -r dev`:n.packageManager===`npm`?l=`npm run dev --workspaces`:n.packageManager===`bun`&&(l=`bun run --filter '*' dev`);let u=n.backend!==`convex`&&n.database!==`none`&&n.orm!==`none`;n.addons.includes(`turborepo`)?(a.dev=`turbo dev`,a.build=`turbo build`,a[`check-types`]=`turbo check-types`,a[`dev:native`]=`turbo -F native dev`,a[`dev:web`]=`turbo -F web dev`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`turbo -F ${s} setup`),u&&(a[`db:push`]=`turbo -F ${s} db:push`,a[`db:studio`]=`turbo -F ${s} db:studio`)):n.packageManager===`pnpm`?(a.dev=l,a.build=`pnpm -r build`,a[`check-types`]=`pnpm -r check-types`,a[`dev:native`]=`pnpm --filter native dev`,a[`dev:web`]=`pnpm --filter web dev`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`pnpm --filter ${s} setup`),u&&(a[`db:push`]=`pnpm --filter ${s} db:push`,a[`db:studio`]=`pnpm --filter ${s} db:studio`)):n.packageManager===`npm`?(a.dev=l,a.build=`npm run build --workspaces`,a[`check-types`]=`npm run check-types --workspaces`,a[`dev:native`]=`npm run dev --workspace native`,a[`dev:web`]=`npm run dev --workspace web`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`npm run setup --workspace ${s}`),u&&(a[`db:push`]=`npm run db:push --workspace ${s}`,a[`db:studio`]=`npm run db:studio --workspace ${s}`)):n.packageManager===`bun`&&(a.dev=l,a.build=`bun run --filter '*' build`,a[`check-types`]=`bun run --filter '*' check-types`,a[`dev:native`]=`bun run --filter native dev`,a[`dev:web`]=`bun run --filter web dev`,a[`dev:server`]=c,n.backend===`convex`&&(a[`dev:setup`]=`bun run --filter ${s} setup`),u&&(a[`db:push`]=`bun run --filter ${s} db:push`,a[`db:studio`]=`bun run --filter ${s} db:studio`)),n.addons.includes(`biome`)&&(a.check=`biome check --write .`),n.addons.includes(`husky`)&&(a.prepare=`husky`,i[`lint-staged`]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":[`biome check --write .`]});try{let{stdout:e}=await x(n.packageManager,[`-v`],{cwd:t});i.packageManager=`${n.packageManager}@${e.trim()}`}catch{o.warn(`Could not determine ${n.packageManager} version.`)}i.workspaces||=[];let d=i.workspaces;if(n.backend===`convex`){d.includes(`packages/*`)||d.push(`packages/*`);let e=n.frontend.length>0||n.addons.includes(`starlight`);e&&!d.includes(`apps/*`)&&d.push(`apps/*`)}else d.includes(`apps/*`)||d.push(`apps/*`),d.includes(`packages/*`)||d.push(`packages/*`);await h.writeJson(r,i,{spaces:2})}async function Xe(t,n){let r=e.join(t,`apps/server/package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts||={};let a=i.scripts;n.database!==`none`&&(n.database===`sqlite`&&n.orm===`drizzle`&&(a[`db:local`]=`turso dev --db-file local.db`),n.orm===`prisma`?(a[`db:push`]=`prisma db push --schema ./prisma/schema`,a[`db:studio`]=`prisma studio`):n.orm===`drizzle`&&(a[`db:push`]=`drizzle-kit push`,a[`db:studio`]=`drizzle-kit studio`)),await h.writeJson(r,i,{spaces:2})}async function Ze(t,n){let r=e.join(t,`packages/backend/package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.name=`@${n.projectName}/backend`,i.scripts||={},await h.writeJson(r,i,{spaces:2})}async function Qe(e,t){if(!t)return;let n=await b({cwd:e,reject:!1,stderr:`pipe`})`git --version`;if(n.exitCode!==0){o.warn(g.yellow(`Git is not installed`));return}let r=await b({cwd:e,reject:!1,stderr:`pipe`})`git init`;if(r.exitCode!==0)throw Error(`Git initialization failed: ${r.stderr}`)}async function $e(t){let{projectName:n,runtime:r,backend:i}=t;if(i===`convex`||i===`next`||r===`none`)return;let a=e.resolve(process.cwd(),n),o=e.join(a,`apps/server`);await h.pathExists(o)&&(r===`bun`?await et(o,i):r===`node`&&await tt(o,i))}async function et(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts={...i.scripts,dev:`bun run --hot src/index.ts`,start:`bun run dist/src/index.js`},await h.writeJson(r,i,{spaces:2}),await M({devDependencies:[`@types/bun`],projectDir:t})}async function tt(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts={...i.scripts,dev:`tsx watch src/index.ts`,start:`node dist/src/index.js`},await h.writeJson(r,i,{spaces:2}),await M({devDependencies:[`tsx`,`@types/node`],projectDir:t}),n===`hono`?await M({dependencies:[`@hono/node-server`],projectDir:t}):n===`elysia`&&await M({dependencies:[`@elysiajs/node`],projectDir:t})}async function G(t,n,r){try{let i=await h.readFile(t,`utf-8`),a=w.compile(i),o=a(r);await h.ensureDir(e.dirname(n)),await h.writeFile(n,o)}catch(e){throw p.error(`Error processing template ${t}:`,e),Error(`Failed to process template ${t}`)}}w.registerHelper(`or`,(e,t)=>e||t),w.registerHelper(`eq`,(e,t)=>e===t),w.registerHelper(`includes`,(e,t)=>Array.isArray(e)&&e.includes(t));async function K(t,n,r,i,a=!0){let o=await C(t,{cwd:n,dot:!0,onlyFiles:!0,absolute:!1});for(let t of o){let o=e.join(n,t),s=t;t.endsWith(`.hbs`)&&(s=t.slice(0,-4));let c=e.basename(t);c===`_gitignore`?s=e.join(e.dirname(t),`.gitignore`):c===`_npmrc`&&(s=e.join(e.dirname(t),`.npmrc`));let l=e.join(r,s);try{if(await h.ensureDir(e.dirname(l)),!a&&await h.pathExists(l))continue;o.endsWith(`.hbs`)?await G(o,l,i):await h.copy(o,l,{overwrite:!0})}catch{}}}async function nt(t,n){let r=e.join(k,`templates/base`);await K([`**/*`],r,t,n),await h.ensureDir(e.join(t,`packages`))}async function rt(t,n){let r=n.frontend.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),i=n.frontend.includes(`nuxt`),a=n.frontend.includes(`svelte`),o=n.frontend.includes(`native`),s=n.backend===`convex`;if(r||i||a){let o=e.join(t,`apps/web`);if(await h.ensureDir(o),r){let t=e.join(k,`templates/frontend/react/web-base`);await h.pathExists(t)&&await K(`**/*`,t,o,n);let r=n.frontend.find(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e));if(r){let t=e.join(k,`templates/frontend/react/${r}`);if(await h.pathExists(t)&&await K(`**/*`,t,o,n),!s&&n.api!==`none`){let t=e.join(k,`templates/api/${n.api}/web/react/base`);await h.pathExists(t)&&await K(`**/*`,t,o,n)}}}else if(i){let t=e.join(k,`templates/frontend/nuxt`);if(await h.pathExists(t)&&await K(`**/*`,t,o,n),!s&&n.api!==`none`){let t=e.join(k,`templates/api/${n.api}/web/nuxt`);await h.pathExists(t)&&await K(`**/*`,t,o,n)}}else if(a){let t=e.join(k,`templates/frontend/svelte`);if(await h.pathExists(t)&&await K(`**/*`,t,o,n),!s&&n.api===`orpc`){let t=e.join(k,`templates/api/${n.api}/web/svelte`);await h.pathExists(t)&&await K(`**/*`,t,o,n)}}}if(o){let r=e.join(t,`apps/native`);await h.ensureDir(r);let i=e.join(k,`templates/frontend/native`);if(await h.pathExists(i)&&await K(`**/*`,i,r,n),!s&&(n.api===`trpc`||n.api===`orpc`)){let t=e.join(k,`templates/api/${n.api}/native`);await h.pathExists(t)&&await K(`**/*`,t,r,n)}}}async function it(t,n){if(n.backend===`convex`){let r=e.join(t,`packages/backend`),i=e.join(k,`templates/backend/convex/packages/backend`);await h.ensureDir(r),await h.pathExists(i)&&await K(`**/*`,i,r,n);let a=e.join(t,`apps/server`);await h.pathExists(a)&&await h.remove(a);return}let r=e.join(t,`apps/server`);await h.ensureDir(r);let i=e.join(k,`templates/backend/server/server-base`);await h.pathExists(i)&&await K(`**/*`,i,r,n);let a=e.join(k,`templates/backend/server/${n.backend}`);if(await h.pathExists(a)&&await K(`**/*`,a,r,n,!0),n.api!==`none`){let t=e.join(k,`templates/api/${n.api}/server/base`);await h.pathExists(t)&&await K(`**/*`,t,r,n,!0);let i=e.join(k,`templates/api/${n.api}/server/${n.backend}`);await h.pathExists(i)&&await K(`**/*`,i,r,n,!0)}}async function at(t,n){if(n.backend===`convex`||n.orm===`none`||n.database===`none`)return;let r=e.join(t,`apps/server`);await h.ensureDir(r);let i=e.join(k,`templates/db/${n.orm}/${n.database}`);await h.pathExists(i)&&await K(`**/*`,i,r,n)}async function ot(t,n){if(n.backend===`convex`||!n.auth)return;let r=e.join(t,`apps/server`),i=e.join(t,`apps/web`),a=e.join(t,`apps/native`),o=await h.pathExists(r),s=await h.pathExists(i),c=await h.pathExists(a),l=n.frontend.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),u=n.frontend.includes(`nuxt`),d=n.frontend.includes(`svelte`),f=n.frontend.includes(`native`);if(o){let t=e.join(k,`templates/auth/server/base`);if(await h.pathExists(t)&&await K(`**/*`,t,r,n),n.backend===`next`){let t=e.join(k,`templates/auth/server/next`);await h.pathExists(t)&&await K(`**/*`,t,r,n)}if(n.orm!==`none`&&n.database!==`none`){let t=n.orm,i=n.database,a=``;t===`drizzle`?a=e.join(k,`templates/auth/server/db/drizzle/${i}`):t===`prisma`&&(a=e.join(k,`templates/auth/server/db/prisma/${i}`)),a&&await h.pathExists(a)&&await K(`**/*`,a,r,n)}}if((l||u||d)&&s){if(l){let t=e.join(k,`templates/auth/web/react/base`);await h.pathExists(t)&&await K(`**/*`,t,i,n);let r=n.frontend.find(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e));if(r){let t=e.join(k,`templates/auth/web/react/${r}`);await h.pathExists(t)&&await K(`**/*`,t,i,n)}}else if(u){let t=e.join(k,`templates/auth/web/nuxt`);await h.pathExists(t)&&await K(`**/*`,t,i,n)}else if(d&&n.api===`orpc`){let t=e.join(k,`templates/auth/web/svelte`);await h.pathExists(t)&&await K(`**/*`,t,i,n)}}if(f&&c){let t=e.join(k,`templates/auth/native`);await h.pathExists(t)&&await K(`**/*`,t,a,n)}}async function st(t,n){if(!(!n.addons||n.addons.length===0))for(let r of n.addons){if(r===`none`)continue;let i=e.join(k,`templates/addons/${r}`),a=t;if(r===`pwa`&&(i=e.join(k,`templates/addons/pwa/apps/web`),a=e.join(t,`apps/web`),!await h.pathExists(a)))continue;await h.pathExists(i)&&await K(`**/*`,i,a,n)}}async function ct(t,n){let r=e.join(t,`apps/server`),i=e.join(t,`apps/web`),a=await h.pathExists(r),o=await h.pathExists(i),s=n.frontend.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),c=n.frontend.includes(`nuxt`),l=n.frontend.includes(`svelte`);for(let t of n.examples){if(!n.examples||n.examples.length===0||n.examples[0]===`none`||t===`none`)continue;let u=e.join(k,`templates/examples/${t}`);if(t===`ai`&&n.backend===`next`&&a){let t=e.join(u,`server/next`);await h.pathExists(t)&&await K(`**/*`,t,r,n,!1)}if(a){let t=e.join(u,`server`);if(await h.pathExists(t)&&n.backend!==`convex`){if(n.orm!==`none`&&n.database!==`none`){let i=e.join(t,n.orm,`base`);await h.pathExists(i)&&await K(`**/*`,i,r,n,!1);let a=e.join(t,n.orm,n.database);await h.pathExists(a)&&await K(`**/*`,a,r,n,!1)}let i=await C([`*.ts`,`*.hbs`],{cwd:t,onlyFiles:!0,deep:1,ignore:[`${n.orm}/**`]});for(let a of i){let i=e.join(t,a),o=e.join(r,a.replace(`.hbs`,``));i.endsWith(`.hbs`)?await G(i,o,n):await h.copy(i,o,{overwrite:!1})}}}if(o){if(s){let t=e.join(u,`web/react`);if(await h.pathExists(t)){let r=n.frontend.find(e=>[`next`,`react-router`,`tanstack-router`,`tanstack-start`].includes(e));if(r){let a=e.join(t,r);await h.pathExists(a)&&await K(`**/*`,a,i,n,!1)}}}else if(c){let t=e.join(u,`web/nuxt`);await h.pathExists(t)&&await K(`**/*`,t,i,n,!1)}else if(l){let t=e.join(u,`web/svelte`);await h.pathExists(t)&&await K(`**/*`,t,i,n,!1)}}}}async function lt(t,n){let r=e.join(k,`templates/extras`);if(n.packageManager===`pnpm`){let n=e.join(r,`pnpm-workspace.yaml`),i=e.join(t,`pnpm-workspace.yaml`);await h.pathExists(n)&&await h.copy(n,i)}if(n.packageManager===`pnpm`&&(n.frontend.includes(`native`)||n.frontend.includes(`nuxt`))){let i=e.join(r,`_npmrc.hbs`),a=e.join(t,`.npmrc`);await h.pathExists(i)&&await G(i,a,n)}}async function ut(n){let r=e.resolve(process.cwd(),n.projectName),i=n.backend===`convex`;try{return await h.ensureDir(r),await nt(r,n),await rt(r,n),await it(r,n),i||(await at(r,n),await ot(r,n)),n.examples.length>0&&n.examples[0]!==`none`&&await ct(r,n),await st(r,n),await se(n),i||(await ue(n),await Fe(n),await $e(n),n.examples.length>0&&n.examples[0]!==`none`&&await Le(n)),n.addons.length>0&&n.addons[0]!==`none`&&await ne(n),!i&&n.auth&&await ce(n),await lt(r,n),await Ie(n),await W(r,n),await de(r,n),await Qe(r,n.git),o.success(`Project template successfully scaffolded!`),n.install&&await Re({projectDir:r,packageManager:n.packageManager,addons:n.addons}),Be({...n,depsInstalled:n.install}),r}catch(e){e instanceof Error?(t(g.red(`Error during project creation: ${e.message}`)),console.error(e.stack),process.exit(1)):(t(g.red(`An unexpected error occurred: ${String(e)}`)),console.error(e),process.exit(1))}}async function dt(e,n){if(e!==void 0)return e;let r=n?.includes(`react-router`)||n?.includes(`tanstack-router`),i=n?.includes(`react-router`)||n?.includes(`tanstack-router`)||n?.includes(`nuxt`)||n?.includes(`svelte`),o=[{value:`turborepo`,label:`Turborepo (Recommended)`,hint:`Optimize builds for monorepos`},{value:`starlight`,label:`Starlight`,hint:`Add Astro Starlight documentation site`},{value:`biome`,label:`Biome`,hint:`Add Biome for linting and formatting`},{value:`husky`,label:`Husky`,hint:`Add Git hooks with Husky, lint-staged (requires Biome)`},{value:`pwa`,label:`PWA (Progressive Web App)`,hint:`Make your app installable and work offline`},{value:`tauri`,label:`Tauri Desktop App`,hint:`Build native desktop apps from your web frontend`}],c=o.filter(e=>e.value===`pwa`?r:e.value===`tauri`?i:!0),l=A.addons.filter(e=>c.some(t=>t.value===e)),u=await s({message:`Select addons`,options:c,initialValues:l,required:!1});return a(u)&&(t(g.red(`Operation cancelled`)),process.exit(0)),u.includes(`husky`)&&!u.includes(`biome`)&&u.push(`biome`),u}async function ft(e,n,r){if(r===`convex`)return`none`;if(e)return e;let i=n?.includes(`nuxt`),o=n?.includes(`svelte`),s=[{value:`trpc`,label:`tRPC`,hint:`End-to-end typesafe APIs made easy`},{value:`orpc`,label:`oRPC`,hint:`End-to-end type-safe APIs that adhere to OpenAPI standards`}];(i||o)&&(s=[{value:`orpc`,label:`oRPC`,hint:`End-to-end type-safe APIs (Required for ${i?`Nuxt`:`Svelte`} frontend)`}]);let c=await u({message:`Select API type`,options:s,initialValue:i||o?`orpc`:A.api});return a(c)&&(t(g.red(`Operation cancelled`)),process.exit(0)),(i||o)&&c!==`orpc`?`orpc`:c}async function pt(e,r,i){if(i===`convex`||!r)return!1;if(e!==void 0)return e;let o=await n({message:`Add authentication with Better-Auth?`,initialValue:A.auth});return a(o)&&(t(g.red(`Operation cancelled`)),process.exit(0)),o}async function mt(e){if(e!==void 0)return e;let n=await u({message:`Select backend framework`,options:[{value:`hono`,label:`Hono`,hint:`Lightweight, ultrafast web framework`},{value:`next`,label:`Next.js`,hint:`Full-stack framework with API routes`},{value:`express`,label:`Express`,hint:`Fast, unopinionated, minimalist web framework for Node.js`},{value:`elysia`,label:`Elysia`,hint:`Ergonomic web framework for building backend servers`},{value:`convex`,label:`Convex`,hint:`Reactive backend-as-a-service platform`}],initialValue:A.backend});return a(n)&&(t(g.red(`Operation cancelled`)),process.exit(0)),n}async function ht(e,n){if(n===`convex`)return`none`;if(e!==void 0)return e;let r=await u({message:`Select database`,options:[{value:`none`,label:`None`,hint:`No database setup`},{value:`sqlite`,label:`SQLite`,hint:`lightweight, server-less, embedded relational database`},{value:`postgres`,label:`PostgreSQL`,hint:`powerful, open source object-relational database system`},{value:`mysql`,label:`MySQL`,hint:`popular open-source relational database system`},{value:`mongodb`,label:`MongoDB`,hint:`open-source NoSQL database that stores data in JSON-like documents called BSON`}],initialValue:A.database});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function gt(e,n,r,i){if(i===`convex`)return`none`;if(n!==void 0)return n;if(e===`none`||e===`sqlite`&&r===`prisma`)return`none`;let o=[];if(e===`sqlite`)o=[{value:`turso`,label:`Turso`,hint:`SQLite for Production. Powered by libSQL`},{value:`none`,label:`None`,hint:`Manual setup`}];else if(e===`postgres`)o=[{value:`neon`,label:`Neon Postgres`,hint:`Serverless Postgres with branching capability`},...r===`prisma`?[{value:`prisma-postgres`,label:`Prisma Postgres`,hint:`Instant Postgres for Global Applications`}]:[],{value:`none`,label:`None`,hint:`Manual setup`}];else if(e===`mongodb`)o=[{value:`mongodb-atlas`,label:`MongoDB Atlas`,hint:`The most effective way to deploy MongoDB`},{value:`none`,label:`None`,hint:`Manual setup`}];else return`none`;let s=await u({message:`Select ${e} setup option`,options:o,initialValue:`none`});return a(s)&&(t(g.red(`Operation cancelled`)),process.exit(0)),s}async function _t(e,n,r,i){if(e!==void 0)return e;if(i===`convex`)return[`todo`];if(n===`none`)return[];let o=r&&r.length===1&&r[0]===`native`;if(o)return[];let c=r?.some(e=>[`react-router`,`tanstack-router`,`tanstack-start`,`next`,`nuxt`,`svelte`].includes(e))??!1,l=!r||r.length===0;if(!c&&!l)return[];let u=[],d=[{value:`todo`,label:`Todo App`,hint:`A simple CRUD example app`}];return i!==`elysia`&&d.push({value:`ai`,label:`AI Chat`,hint:`A simple AI chat interface using AI SDK`}),u=await s({message:`Include examples`,options:d,required:!1,initialValues:A.examples}),a(u)&&(t(g.red(`Operation cancelled`)),process.exit(0)),u}async function vt(e){if(e!==void 0)return e;let n=await s({message:`Select platforms to develop for`,options:[{value:`web`,label:`Web`,hint:`React, Vue or Svelte Web Application`},{value:`native`,label:`Native`,hint:`Create a React Native/Expo app`}],required:!1,initialValues:A.frontend.some(e=>e===`tanstack-router`||e===`react-router`||e===`tanstack-start`||e===`next`||e===`nuxt`||e===`svelte`)?[`web`]:[]});a(n)&&(t(g.red(`Operation cancelled`)),process.exit(0));let r=[];if(n.includes(`web`)){let e=await u({message:`Choose frontend framework`,options:[{value:`tanstack-router`,label:`TanStack Router`,hint:`Modern and scalable routing for React Applications`},{value:`react-router`,label:`React Router`,hint:`A user‑obsessed, standards‑focused, multi‑strategy router`},{value:`next`,label:`Next.js`,hint:`The React Framework for the Web`},{value:`nuxt`,label:`Nuxt`,hint:`The Progressive Web Framework for Vue.js`},{value:`svelte`,label:`Svelte`,hint:`web development for the rest of us`},{value:`tanstack-start`,label:`TanStack Start (beta)`,hint:`SSR, Server Functions, API Routes and more with TanStack Router`}],initialValue:A.frontend.find(e=>e===`tanstack-router`||e===`react-router`||e===`tanstack-start`||e===`next`||e===`nuxt`||e===`svelte`)||`tanstack-router`});a(e)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r.push(e)}return n.includes(`native`)&&r.push(`native`),r}async function yt(e){if(e!==void 0)return e;let r=await n({message:`Initialize git repository?`,initialValue:A.git});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function bt(e){if(e!==void 0)return e;let r=await n({message:`Install dependencies?`,initialValue:A.install});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function xt(e,n,r,i){if(i===`convex`||!n)return`none`;if(e!==void 0)return e;if(r===`mongodb`)return o.info(`Only Prisma is supported with MongoDB.`),`prisma`;let s=await u({message:`Select ORM`,options:[{value:`drizzle`,label:`Drizzle`,hint:`lightweight and performant TypeScript ORM`},{value:`prisma`,label:`Prisma`,hint:`Powerful, feature-rich ORM`}],initialValue:A.orm});return a(s)&&(t(g.red(`Operation cancelled`)),process.exit(0)),s}async function St(e){if(e!==void 0)return e;let n=E(),r=await u({message:`Choose package manager`,options:[{value:`npm`,label:`npm`,hint:`Node Package Manager`},{value:`pnpm`,label:`pnpm`,hint:`Fast, disk space efficient package manager`},{value:`bun`,label:`bun`,hint:`All-in-one JavaScript runtime & toolkit`}],initialValue:n});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}const Ct=[`<`,`>`,`:`,`"`,`|`,`?`,`*`],q=255;function J(e){if(e!==`.`){if(!e)return`Project name cannot be empty`;if(e.length>q)return`Project name must be less than ${q} characters`;if(Ct.some(t=>e.includes(t)))return`Project name contains invalid characters`;if(e.startsWith(`.`)||e.startsWith(`-`))return`Project name cannot start with a dot or dash`;if(e.toLowerCase()===`node_modules`)return`Project name is reserved`}}async function Y(n){if(n)if(n===`.`){let e=process.cwd();if(h.readdirSync(e).length===0)return n}else{let t=e.basename(n),r=J(t);if(!r){let t=e.resolve(process.cwd(),n);if(!h.pathExistsSync(t)||h.readdirSync(t).length===0)return n}}let r=!1,i=``,o=A.projectName,s=1;for(;h.pathExistsSync(e.resolve(process.cwd(),o));)o=`${A.projectName}-${s}`,s++;for(;!r;){let s=await f({message:`Enter your project name or path (relative to current directory)`,placeholder:o,initialValue:n,defaultValue:o,validate:t=>{let n=t.trim()||o;if(n===`.`){let e=h.readdirSync(process.cwd());if(e.length>0)return`Current directory is not empty. Please choose a different directory.`;r=!0;return}let i=e.resolve(process.cwd(),n),a=e.basename(i),s=J(a);if(s)return s;if(!i.startsWith(process.cwd()))return`Project path must be within current directory`;if(h.pathExistsSync(i)){let e=h.readdirSync(i);if(e.length>0)return`Directory "${n}" already exists and is not empty. Please choose a different name or path.`}r=!0}});a(s)&&(t(g.red(`Operation cancelled.`)),process.exit(0)),i=s||o}return i}async function wt(e,n){if(n===`convex`)return`none`;if(e!==void 0)return e;if(n===`next`)return`node`;let r=await u({message:`Select runtime`,options:[{value:`bun`,label:`Bun`,hint:`Fast all-in-one JavaScript runtime`},{value:`node`,label:`Node.js`,hint:`Traditional Node.js runtime`}],initialValue:A.runtime});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function Tt(e){let n=await r({projectName:async()=>Y(e.projectName),frontend:()=>vt(e.frontend),backend:()=>mt(e.backend),runtime:({results:t})=>wt(e.runtime,t.backend),database:({results:t})=>ht(e.database,t.backend),orm:({results:t})=>xt(e.orm,t.database!==`none`,t.database,t.backend),api:({results:t})=>ft(e.api,t.frontend,t.backend),auth:({results:t})=>pt(e.auth,t.database!==`none`,t.backend),addons:({results:t})=>dt(e.addons,t.frontend),examples:({results:t})=>_t(e.examples,t.database,t.frontend,t.backend),dbSetup:({results:t})=>gt(t.database??`none`,e.dbSetup,t.orm,t.backend),git:()=>yt(e.git),packageManager:()=>St(e.packageManager),install:()=>bt(e.install)},{onCancel:()=>{t(g.red(`Operation cancelled`)),process.exit(0)}});return n.backend===`convex`&&(n.runtime=`none`,n.database=`none`,n.orm=`none`,n.api=`none`,n.auth=!1,n.dbSetup=`none`),{projectName:n.projectName,frontend:n.frontend,backend:n.backend,runtime:n.runtime,database:n.database,orm:n.orm,auth:n.auth,addons:n.addons,examples:n.examples,git:n.git,packageManager:n.packageManager,install:n.install,dbSetup:n.dbSetup,api:n.api}}function X(e){let t=[];if(e.projectName&&t.push(`${g.blue(`Project Name:`)} ${e.projectName}`),e.frontend!==void 0){let n=Array.isArray(e.frontend)?e.frontend:[e.frontend],r=n.length>0&&n[0]!==void 0?n.join(`, `):`none`;t.push(`${g.blue(`Frontend:`)} ${r}`)}if(e.backend!==void 0&&t.push(`${g.blue(`Backend Framework:`)} ${String(e.backend)}`),e.runtime!==void 0&&t.push(`${g.blue(`Runtime:`)} ${String(e.runtime)}`),e.api!==void 0&&t.push(`${g.blue(`API:`)} ${String(e.api)}`),e.database!==void 0&&t.push(`${g.blue(`Database:`)} ${String(e.database)}`),e.orm!==void 0&&t.push(`${g.blue(`ORM:`)} ${String(e.orm)}`),e.auth!==void 0){let n=typeof e.auth==`boolean`?e.auth?`Yes`:`No`:String(e.auth);t.push(`${g.blue(`Authentication:`)} ${n}`)}if(e.addons!==void 0){let n=Array.isArray(e.addons)?e.addons:[e.addons],r=n.length>0&&n[0]!==void 0?n.join(`, `):`none`;t.push(`${g.blue(`Addons:`)} ${r}`)}if(e.examples!==void 0){let n=Array.isArray(e.examples)?e.examples:[e.examples],r=n.length>0&&n[0]!==void 0?n.join(`, `):`none`;t.push(`${g.blue(`Examples:`)} ${r}`)}if(e.git!==void 0){let n=typeof e.git==`boolean`?e.git?`Yes`:`No`:String(e.git);t.push(`${g.blue(`Git Init:`)} ${n}`)}if(e.packageManager!==void 0&&t.push(`${g.blue(`Package Manager:`)} ${String(e.packageManager)}`),e.install!==void 0){let n=typeof e.install==`boolean`?e.install?`Yes`:`No`:String(e.install);t.push(`${g.blue(`Install Dependencies:`)} ${n}`)}return e.dbSetup!==void 0&&t.push(`${g.blue(`Database Setup:`)} ${String(e.dbSetup)}`),t.length===0?g.yellow(`No configuration selected.`):t.join(`
148
148
  `)}function Et(e){let t=[];e.database===`none`?t.push(`--database none`):(t.push(`--database ${e.database}`),e.orm&&t.push(`--orm ${e.orm}`),e.dbSetup&&t.push(`--db-setup ${e.dbSetup}`)),e.api&&t.push(`--api ${e.api}`),t.push(e.auth?`--auth`:`--no-auth`),t.push(e.git?`--git`:`--no-git`),t.push(e.install?`--install`:`--no-install`),e.runtime&&t.push(`--runtime ${e.runtime}`),e.backend&&t.push(`--backend ${e.backend}`),e.frontend&&e.frontend.length>0&&t.push(`--frontend ${e.frontend.join(` `)}`),e.addons&&e.addons.length>0?t.push(`--addons ${e.addons.join(` `)}`):t.push(`--addons none`),e.examples&&e.examples.length>0?t.push(`--examples ${e.examples.join(` `)}`):t.push(`--examples none`),e.packageManager&&t.push(`--package-manager ${e.packageManager}`);let n=``,r=e.packageManager;r===`npm`?n=`npx create-better-t-stack@latest`:r===`pnpm`?n=`pnpm create better-t-stack@latest`:r===`bun`&&(n=`bun create better-t-stack@latest`);let i=e.projectName?` ${e.projectName}`:``;return`${n}${i} ${t.join(` `)}`}const Dt=()=>{let t=e.join(k,`package.json`),n=h.readJSONSync(t);return n.version??`1.0.0`},Z=`
149
149
  ██████╗ ███████╗████████╗████████╗███████╗██████╗
150
150
  ██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗
@@ -164,4 +164,4 @@ DATABASE_URL="your_connection_string"`)}async function Pe(n){let{projectName:r,p
164
164
  ╔══════════════════╗
165
165
  ║ Better T-Stack ║
166
166
  ╚══════════════════╝
167
- `;console.log(T(Object.values(Q)).multiline(e))}else console.log(T(Object.values(Q)).multiline(Z))},$=()=>process.exit(0);process.on(`SIGINT`,$),process.on(`SIGTERM`,$);async function kt(){let n=Date.now();try{let t=await _(v(process.argv)).scriptName(`create-better-t-stack`).usage(`$0 [project-directory] [options]`,`Create a new Better-T Stack project`).positional(`project-directory`,{describe:`Project name/directory`,type:`string`}).option(`yes`,{alias:`y`,type:`boolean`,describe:`Use default configuration and skip prompts`,default:!1}).option(`database`,{type:`string`,describe:`Database type`,choices:[`none`,`sqlite`,`postgres`,`mysql`,`mongodb`]}).option(`orm`,{type:`string`,describe:`ORM type`,choices:[`drizzle`,`prisma`,`none`]}).option(`auth`,{type:`boolean`,describe:`Include authentication (use --no-auth to exclude)`}).option(`frontend`,{type:`array`,string:!0,describe:`Frontend types`,choices:[`tanstack-router`,`react-router`,`tanstack-start`,`next`,`nuxt`,`native`,`svelte`,`none`]}).option(`addons`,{type:`array`,string:!0,describe:`Additional addons`,choices:[`pwa`,`tauri`,`starlight`,`biome`,`husky`,`turborepo`,`none`]}).option(`examples`,{type:`array`,string:!0,describe:`Examples to include`,choices:[`todo`,`ai`,`none`]}).option(`git`,{type:`boolean`,describe:`Initialize git repository (use --no-git to skip)`}).option(`package-manager`,{alias:`pm`,type:`string`,describe:`Package manager`,choices:[`npm`,`pnpm`,`bun`]}).option(`install`,{type:`boolean`,describe:`Install dependencies (use --no-install to skip)`}).option(`db-setup`,{type:`string`,describe:`Database setup`,choices:[`turso`,`neon`,`prisma-postgres`,`mongodb-atlas`,`none`]}).option(`backend`,{type:`string`,describe:`Backend framework`,choices:[`hono`,`express`,`next`,`elysia`,`convex`]}).option(`runtime`,{type:`string`,describe:`Runtime`,choices:[`bun`,`node`,`none`]}).option(`api`,{type:`string`,describe:`API type`,choices:[`trpc`,`orpc`,`none`]}).completion().recommendCommands().version(Dt()).alias(`version`,`v`).help().alias(`help`,`h`).strict().wrap(null).parse(),r=t,a=r.projectDirectory;Ot();let s=At(r,a);i(g.magenta(`Creating a new Better-T-Stack project`)),!r.yes&&Object.keys(s).length>0&&(o.info(g.yellow(`Using these pre-selected options:`)),o.message(X(s)),o.message(``));let l;r.yes?(l={...A,projectName:a??A.projectName,...s},l.backend===`convex`?(l.auth=!1,l.database=`none`,l.orm=`none`,l.api=`none`,l.runtime=`none`,l.dbSetup=`none`):l.database===`none`&&(l.orm=`none`,l.auth=!1,l.dbSetup=`none`),o.info(g.yellow(`Using these default/flag options:`)),o.message(X(l)),o.message(``)):l=await Tt(s);let u=e.resolve(process.cwd(),l.projectName);if(h.pathExistsSync(u)&&h.readdirSync(u).length>0){let e=await Y();l.projectName=e}await ut(l),o.success(g.blue(`You can reproduce this setup with the following command:\n${Et(l)}`));let d=((Date.now()-n)/1e3).toFixed(2);c(g.magenta(`Project created successfully in ${g.bold(d)} seconds!`))}catch(e){e instanceof Error?(e.name===`YError`?t(g.red(`Invalid arguments: ${e.message}`)):(m.error(`An unexpected error occurred: ${e.message}`),e.message.includes(`is only supported with`)||m.error(e.stack)),process.exit(1)):(m.error(`An unexpected error occurred.`),console.error(e),process.exit(1))}}function At(e,t){let n={},r=new Set(Object.keys(e).filter(e=>e!==`_`&&e!==`$0`));if(e.backend&&(n.backend=e.backend),r.has(`backend`)&&n.backend&&n.backend!==`convex`&&(r.has(`api`)&&e.api===`none`&&(m.fatal(`'--api none' is only supported with '--backend convex'. Please choose 'trpc', 'orpc', or remove the --api flag.`),process.exit(1)),r.has(`runtime`)&&e.runtime===`none`&&(m.fatal(`'--runtime none' is only supported with '--backend convex'. Please choose 'bun', 'node', or remove the --runtime flag.`),process.exit(1))),e.database&&(n.database=e.database),e.orm&&(n.orm=e.orm),e.auth!==void 0&&(n.auth=e.auth),e.git!==void 0&&(n.git=e.git),e.install!==void 0&&(n.install=e.install),e.runtime&&(n.runtime=e.runtime),e.api&&(n.api=e.api),e.dbSetup&&(n.dbSetup=e.dbSetup),e.packageManager&&(n.packageManager=e.packageManager),t&&(n.projectName=t),e.frontend&&e.frontend.length>0)if(e.frontend.includes(`none`))e.frontend.length>1&&(m.fatal(`Cannot combine 'none' with other frontend options.`),process.exit(1)),n.frontend=[];else{let t=e.frontend.filter(e=>e!==`none`),r=t.filter(e=>e===`tanstack-router`||e===`react-router`||e===`tanstack-start`||e===`next`||e===`nuxt`||e===`svelte`);r.length>1&&(m.fatal(`Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte`),process.exit(1)),n.frontend=t}if(e.addons&&e.addons.length>0&&(e.addons.includes(`none`)?(e.addons.length>1&&(m.fatal(`Cannot combine 'none' with other addons.`),process.exit(1)),n.addons=[]):n.addons=e.addons.filter(e=>e!==`none`)),e.examples&&e.examples.length>0&&(e.examples.includes(`none`)?(e.examples.length>1&&(m.fatal(`Cannot combine 'none' with other examples.`),process.exit(1)),n.examples=[]):(n.examples=e.examples.filter(e=>e!==`none`),n.backend!==`convex`&&e.examples.includes(`none`)?n.examples=[]:n.examples=[`todo`])),n.backend===`convex`){let t=[];r.has(`auth`)&&e.auth===!0&&t.push(`--auth`),r.has(`database`)&&e.database!==`none`&&t.push(`--database ${e.database}`),r.has(`orm`)&&e.orm!==`none`&&t.push(`--orm ${e.orm}`),r.has(`api`)&&e.api!==`none`&&t.push(`--api ${e.api}`),r.has(`runtime`)&&e.runtime!==`none`&&t.push(`--runtime ${e.runtime}`),r.has(`dbSetup`)&&e.dbSetup!==`none`&&t.push(`--db-setup ${e.dbSetup}`),r.has(`examples`)&&t.push(`--examples`),t.length>0&&(m.fatal(`The following flags are incompatible with '--backend convex': ${t.join(`, `)}. Please remove them. The 'todo' example is included automatically with Convex.`),process.exit(1)),n.auth=!1,n.database=`none`,n.orm=`none`,n.api=`none`,n.runtime=`none`,n.dbSetup=`none`,n.examples=[`todo`]}else{let t=n.database??(e.yes?A.database:void 0),i=n.orm??(e.yes?A.orm:void 0),a=n.auth??(e.yes?A.auth:void 0),o=n.dbSetup??(e.yes?A.dbSetup:void 0),s=n.examples??(e.yes?A.examples:void 0),c=n.frontend??(e.yes?A.frontend:void 0),l=n.api??(e.yes?A.api:void 0),u=n.backend??(e.yes?A.backend:void 0);if(t===`none`&&(r.has(`orm`)&&e.orm!==`none`&&(m.fatal(`Cannot use ORM '--orm ${e.orm}' when database is 'none'.`),process.exit(1)),n.orm=`none`,r.has(`auth`)&&e.auth===!0&&(m.fatal(`Authentication requires a database. Cannot use --auth when database is 'none'.`),process.exit(1)),n.auth=!1,r.has(`dbSetup`)&&e.dbSetup!==`none`&&(m.fatal(`Database setup '--db-setup ${e.dbSetup}' requires a database. Cannot use when database is 'none'.`),process.exit(1)),n.dbSetup=`none`),t===`mongodb`&&i===`drizzle`&&(m.fatal(`MongoDB is only available with Prisma. Cannot use --database mongodb with --orm drizzle`),process.exit(1)),n.dbSetup&&n.dbSetup!==`none`){let e=n.dbSetup;e===`turso`?(t&&t!==`sqlite`&&(m.fatal(`Turso setup requires SQLite. Cannot use --db-setup turso with --database ${t}`),process.exit(1)),i===`prisma`&&(m.fatal(`Turso setup is not compatible with Prisma. Cannot use --db-setup turso with --orm prisma`),process.exit(1)),n.database=`sqlite`,n.orm=`drizzle`):e===`prisma-postgres`?(t&&t!==`postgres`&&(m.fatal(`Prisma PostgreSQL setup requires PostgreSQL. Cannot use --db-setup prisma-postgres with --database ${t}.`),process.exit(1)),i&&i!==`prisma`&&i!==`none`&&(m.fatal(`Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with --orm ${i}.`),process.exit(1)),n.database=`postgres`,n.orm=`prisma`):e===`mongodb-atlas`?(t&&t!==`mongodb`&&(m.fatal(`MongoDB Atlas setup requires MongoDB. Cannot use --db-setup mongodb-atlas with --database ${t}.`),process.exit(1)),i&&i!==`prisma`&&i!==`none`&&(m.fatal(`MongoDB Atlas setup requires Prisma ORM. Cannot use --db-setup mongodb-atlas with --orm ${i}.`),process.exit(1)),n.database=`mongodb`,n.orm=`prisma`):e===`neon`&&(t&&t!==`postgres`&&(m.fatal(`Neon PostgreSQL setup requires PostgreSQL. Cannot use --db-setup neon with --database ${t}.`),process.exit(1)),n.database=`postgres`)}let d=c?.includes(`nuxt`),f=c?.includes(`svelte`);if((d||f)&&l===`trpc`&&(m.fatal(`tRPC API is not supported with '${d?`nuxt`:`svelte`}' frontend. Please use --api orpc or remove '${d?`nuxt`:`svelte`}' from --frontend.`),process.exit(1)),(d||f)&&l!==`orpc`&&(!e.api||e.yes&&e.api!==`trpc`)&&n.api!==`none`&&(n.api=`orpc`),n.addons&&n.addons.length>0){let e=[`pwa`,`tauri`],t=n.addons.some(t=>e.includes(t)),r=c?.some(e=>e===`tanstack-router`||e===`react-router`||e===`nuxt`&&n.addons?.includes(`tauri`)&&!n.addons?.includes(`pwa`)||e===`svelte`&&n.addons?.includes(`tauri`)&&!n.addons?.includes(`pwa`));if(t&&!r){let e=``;n.addons.includes(`pwa`)&&d?e=`PWA addon is not compatible with Nuxt.`:(n.addons.includes(`pwa`)||n.addons.includes(`tauri`))&&(e=`PWA and Tauri addons require tanstack-router, react-router, or Nuxt/Svelte (Tauri only).`),m.fatal(`${e} Cannot use these addons with your frontend selection.`),process.exit(1)}n.addons.includes(`husky`)&&!n.addons.includes(`biome`)&&m.warn(`Husky addon is recommended to be used with Biome for lint-staged configuration.`),n.addons=[...new Set(n.addons)]}let p=c&&c.length===1&&c[0]===`native`;if(p&&n.examples&&n.examples.length>0&&!n.examples.includes(`none`)&&(m.fatal(`Examples are not supported when only the 'native' frontend is selected.`),process.exit(1)),n.examples&&n.examples.length>0&&!n.examples.includes(`none`)){n.examples.includes(`todo`)&&u!==`convex`&&t===`none`&&(m.fatal(`The 'todo' example requires a database (unless using Convex). Cannot use --examples todo when database is 'none'.`),process.exit(1)),n.examples.includes(`ai`)&&u===`elysia`&&(m.fatal(`The 'ai' example is not compatible with the Elysia backend.`),process.exit(1));let e=c?.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`,`nuxt`,`svelte`].includes(e)),r=!c||c.length===0}}return n}kt().catch(e=>{m.error(`Aborting installation due to unexpected error...`),e instanceof Error?!e.message.includes(`is only supported with`)&&!e.message.includes(`incompatible with`)&&(m.error(e.message),m.error(e.stack)):console.error(e),process.exit(1)});
167
+ `;console.log(T(Object.values(Q)).multiline(e))}else console.log(T(Object.values(Q)).multiline(Z))},$=()=>process.exit(0);process.on(`SIGINT`,$),process.on(`SIGTERM`,$);async function kt(){let n=Date.now();try{let t=await _(v(process.argv)).scriptName(`create-better-t-stack`).usage(`$0 [project-directory] [options]`,`Create a new Better-T Stack project`).positional(`project-directory`,{describe:`Project name/directory`,type:`string`}).option(`yes`,{alias:`y`,type:`boolean`,describe:`Use default configuration and skip prompts`,default:!1}).option(`database`,{type:`string`,describe:`Database type`,choices:[`none`,`sqlite`,`postgres`,`mysql`,`mongodb`]}).option(`orm`,{type:`string`,describe:`ORM type`,choices:[`drizzle`,`prisma`,`none`]}).option(`auth`,{type:`boolean`,describe:`Include authentication (use --no-auth to exclude)`}).option(`frontend`,{type:`array`,string:!0,describe:`Frontend types`,choices:[`tanstack-router`,`react-router`,`tanstack-start`,`next`,`nuxt`,`native`,`svelte`,`none`]}).option(`addons`,{type:`array`,string:!0,describe:`Additional addons`,choices:[`pwa`,`tauri`,`starlight`,`biome`,`husky`,`turborepo`,`none`]}).option(`examples`,{type:`array`,string:!0,describe:`Examples to include`,choices:[`todo`,`ai`,`none`]}).option(`git`,{type:`boolean`,describe:`Initialize git repository (use --no-git to skip)`}).option(`package-manager`,{alias:`pm`,type:`string`,describe:`Package manager`,choices:[`npm`,`pnpm`,`bun`]}).option(`install`,{type:`boolean`,describe:`Install dependencies (use --no-install to skip)`}).option(`db-setup`,{type:`string`,describe:`Database setup`,choices:[`turso`,`neon`,`prisma-postgres`,`mongodb-atlas`,`none`]}).option(`backend`,{type:`string`,describe:`Backend framework`,choices:[`hono`,`express`,`next`,`elysia`,`convex`]}).option(`runtime`,{type:`string`,describe:`Runtime`,choices:[`bun`,`node`,`none`]}).option(`api`,{type:`string`,describe:`API type`,choices:[`trpc`,`orpc`,`none`]}).completion().recommendCommands().version(Dt()).alias(`version`,`v`).help().alias(`help`,`h`).strict().wrap(null).parse(),r=t,a=r.projectDirectory;Ot();let s=At(r,a);i(g.magenta(`Creating a new Better-T-Stack project`)),!r.yes&&Object.keys(s).length>0&&(o.info(g.yellow(`Using these pre-selected options:`)),o.message(X(s)),o.message(``));let l;r.yes?(l={...A,projectName:a??A.projectName,...s},l.backend===`convex`?(l.auth=!1,l.database=`none`,l.orm=`none`,l.api=`none`,l.runtime=`none`,l.dbSetup=`none`):l.database===`none`&&(l.orm=`none`,l.auth=!1,l.dbSetup=`none`),o.info(g.yellow(`Using these default/flag options:`)),o.message(X(l)),o.message(``)):l=await Tt(s);let u=e.resolve(process.cwd(),l.projectName);if(h.pathExistsSync(u)&&h.readdirSync(u).length>0){let e=await Y();l.projectName=e}await ut(l),o.success(g.blue(`You can reproduce this setup with the following command:\n${Et(l)}`));let d=((Date.now()-n)/1e3).toFixed(2);c(g.magenta(`Project created successfully in ${g.bold(d)} seconds!`))}catch(e){e instanceof Error?(e.name===`YError`?t(g.red(`Invalid arguments: ${e.message}`)):(m.error(`An unexpected error occurred: ${e.message}`),e.message.includes(`is only supported with`)||m.error(e.stack)),process.exit(1)):(m.error(`An unexpected error occurred.`),console.error(e),process.exit(1))}}function At(e,t){let n={},r=new Set(Object.keys(e).filter(e=>e!==`_`&&e!==`$0`));if(e.api&&(n.api=e.api,e.api===`none`&&(e.backend&&e.backend!==`convex`&&(m.fatal(`'--api none' is only supported with '--backend convex'. Please choose a different API setting or use '--backend convex'.`),process.exit(1)),n.backend=`convex`)),e.backend&&(n.backend=e.backend),r.has(`backend`)&&n.backend&&n.backend!==`convex`&&(r.has(`api`)&&e.api===`none`&&(m.fatal(`'--api none' is only supported with '--backend convex'. Please choose 'trpc', 'orpc', or remove the --api flag.`),process.exit(1)),r.has(`runtime`)&&e.runtime===`none`&&(m.fatal(`'--runtime none' is only supported with '--backend convex'. Please choose 'bun', 'node', or remove the --runtime flag.`),process.exit(1))),e.database&&(n.database=e.database),e.orm&&(n.orm=e.orm),e.auth!==void 0&&(n.auth=e.auth),e.git!==void 0&&(n.git=e.git),e.install!==void 0&&(n.install=e.install),e.runtime&&(n.runtime=e.runtime),e.dbSetup&&(n.dbSetup=e.dbSetup),e.packageManager&&(n.packageManager=e.packageManager),t&&(n.projectName=t),e.frontend&&e.frontend.length>0)if(e.frontend.includes(`none`))e.frontend.length>1&&(m.fatal(`Cannot combine 'none' with other frontend options.`),process.exit(1)),n.frontend=[];else{let t=e.frontend.filter(e=>e!==`none`),r=t.filter(e=>e===`tanstack-router`||e===`react-router`||e===`tanstack-start`||e===`next`||e===`nuxt`||e===`svelte`);r.length>1&&(m.fatal(`Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte`),process.exit(1)),n.frontend=t}if(e.addons&&e.addons.length>0&&(e.addons.includes(`none`)?(e.addons.length>1&&(m.fatal(`Cannot combine 'none' with other addons.`),process.exit(1)),n.addons=[]):n.addons=e.addons.filter(e=>e!==`none`)),e.examples&&e.examples.length>0&&(e.examples.includes(`none`)?(e.examples.length>1&&(m.fatal(`Cannot combine 'none' with other examples.`),process.exit(1)),n.examples=[]):(n.examples=e.examples.filter(e=>e!==`none`),n.backend!==`convex`&&e.examples.includes(`none`)&&(n.examples=[]))),n.backend===`convex`){let t=[];r.has(`auth`)&&e.auth===!0&&t.push(`--auth`),r.has(`database`)&&e.database!==`none`&&t.push(`--database ${e.database}`),r.has(`orm`)&&e.orm!==`none`&&t.push(`--orm ${e.orm}`),r.has(`api`)&&e.api!==`none`&&t.push(`--api ${e.api}`),r.has(`runtime`)&&e.runtime!==`none`&&t.push(`--runtime ${e.runtime}`),r.has(`dbSetup`)&&e.dbSetup!==`none`&&t.push(`--db-setup ${e.dbSetup}`),r.has(`examples`)&&t.push(`--examples`),t.length>0&&(m.fatal(`The following flags are incompatible with '--backend convex': ${t.join(`, `)}. Please remove them. The 'todo' example is included automatically with Convex.`),process.exit(1)),n.auth=!1,n.database=`none`,n.orm=`none`,n.api=`none`,n.runtime=`none`,n.dbSetup=`none`,n.examples=[`todo`]}else{let t=n.database??(e.yes?A.database:void 0),i=n.orm??(e.yes?A.orm:void 0),a=n.auth??(e.yes?A.auth:void 0),o=n.dbSetup??(e.yes?A.dbSetup:void 0),s=n.examples??(e.yes?A.examples:void 0),c=n.frontend??(e.yes?A.frontend:void 0),l=n.api??(e.yes?A.api:void 0),u=n.backend??(e.yes?A.backend:void 0);if(t===`none`&&(r.has(`orm`)&&e.orm!==`none`&&(m.fatal(`Cannot use ORM '--orm ${e.orm}' when database is 'none'.`),process.exit(1)),n.orm=`none`,r.has(`auth`)&&e.auth===!0&&(m.fatal(`Authentication requires a database. Cannot use --auth when database is 'none'.`),process.exit(1)),n.auth=!1,r.has(`dbSetup`)&&e.dbSetup!==`none`&&(m.fatal(`Database setup '--db-setup ${e.dbSetup}' requires a database. Cannot use when database is 'none'.`),process.exit(1)),n.dbSetup=`none`),t===`mongodb`&&i===`drizzle`&&(m.fatal(`MongoDB is only available with Prisma. Cannot use --database mongodb with --orm drizzle`),process.exit(1)),n.dbSetup&&n.dbSetup!==`none`){let e=n.dbSetup;e===`turso`?(t&&t!==`sqlite`&&(m.fatal(`Turso setup requires SQLite. Cannot use --db-setup turso with --database ${t}`),process.exit(1)),i===`prisma`&&(m.fatal(`Turso setup is not compatible with Prisma. Cannot use --db-setup turso with --orm prisma`),process.exit(1)),n.database=`sqlite`,n.orm=`drizzle`):e===`prisma-postgres`?(t&&t!==`postgres`&&(m.fatal(`Prisma PostgreSQL setup requires PostgreSQL. Cannot use --db-setup prisma-postgres with --database ${t}.`),process.exit(1)),i&&i!==`prisma`&&i!==`none`&&(m.fatal(`Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with --orm ${i}.`),process.exit(1)),n.database=`postgres`,n.orm=`prisma`):e===`mongodb-atlas`?(t&&t!==`mongodb`&&(m.fatal(`MongoDB Atlas setup requires MongoDB. Cannot use --db-setup mongodb-atlas with --database ${t}.`),process.exit(1)),i&&i!==`prisma`&&i!==`none`&&(m.fatal(`MongoDB Atlas setup requires Prisma ORM. Cannot use --db-setup mongodb-atlas with --orm ${i}.`),process.exit(1)),n.database=`mongodb`,n.orm=`prisma`):e===`neon`&&(t&&t!==`postgres`&&(m.fatal(`Neon PostgreSQL setup requires PostgreSQL. Cannot use --db-setup neon with --database ${t}.`),process.exit(1)),n.database=`postgres`)}let d=c?.includes(`nuxt`),f=c?.includes(`svelte`);if((d||f)&&l===`trpc`&&(m.fatal(`tRPC API is not supported with '${d?`nuxt`:`svelte`}' frontend. Please use --api orpc or remove '${d?`nuxt`:`svelte`}' from --frontend.`),process.exit(1)),(d||f)&&l!==`orpc`&&(!e.api||e.yes&&e.api!==`trpc`)&&n.api!==`none`&&(n.api=`orpc`),n.addons&&n.addons.length>0){let e=[`pwa`,`tauri`],t=n.addons.some(t=>e.includes(t)),r=c?.some(e=>e===`tanstack-router`||e===`react-router`||e===`nuxt`&&n.addons?.includes(`tauri`)&&!n.addons?.includes(`pwa`)||e===`svelte`&&n.addons?.includes(`tauri`)&&!n.addons?.includes(`pwa`));if(t&&!r){let e=``;n.addons.includes(`pwa`)&&d?e=`PWA addon is not compatible with Nuxt.`:(n.addons.includes(`pwa`)||n.addons.includes(`tauri`))&&(e=`PWA and Tauri addons require tanstack-router, react-router, or Nuxt/Svelte (Tauri only).`),m.fatal(`${e} Cannot use these addons with your frontend selection.`),process.exit(1)}n.addons.includes(`husky`)&&!n.addons.includes(`biome`)&&m.warn(`Husky addon is recommended to be used with Biome for lint-staged configuration.`),n.addons=[...new Set(n.addons)]}let p=c&&c.length===1&&c[0]===`native`;if(p&&n.examples&&n.examples.length>0&&!n.examples.includes(`none`)&&(m.fatal(`Examples are not supported when only the 'native' frontend is selected.`),process.exit(1)),n.examples&&n.examples.length>0&&!n.examples.includes(`none`)){n.examples.includes(`todo`)&&u!==`convex`&&t===`none`&&(m.fatal(`The 'todo' example requires a database (unless using Convex). Cannot use --examples todo when database is 'none'.`),process.exit(1)),n.examples.includes(`ai`)&&u===`elysia`&&(m.fatal(`The 'ai' example is not compatible with the Elysia backend.`),process.exit(1));let e=c?.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`,`nuxt`,`svelte`].includes(e)),r=!c||c.length===0}}return n}kt().catch(e=>{m.error(`Aborting installation due to unexpected error...`),e instanceof Error?!e.message.includes(`is only supported with`)&&!e.message.includes(`incompatible with`)&&(m.error(e.message),m.error(e.stack)):console.error(e),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "2.5.0",
3
+ "version": "2.5.2",
4
4
  "description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,15 @@
1
+ import { google } from '@ai-sdk/google';
2
+ import { streamText } from 'ai';
3
+
4
+ export const maxDuration = 30;
5
+
6
+ export async function POST(req: Request) {
7
+ const { messages } = await req.json();
8
+
9
+ const result = streamText({
10
+ model: google('gemini-2.0-flash'),
11
+ messages,
12
+ });
13
+
14
+ return result.toDataStreamResponse();
15
+ }
@@ -0,0 +1,67 @@
1
+ "use client"
2
+
3
+ import { useChat } from "@ai-sdk/react";
4
+ import { Input } from "@/components/ui/input";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Send } from "lucide-react";
7
+ import { useRef, useEffect } from "react";
8
+
9
+
10
+ export default function AIPage() {
11
+ const { messages, input, handleInputChange, handleSubmit } = useChat({
12
+ api: `${process.env.NEXT_PUBLIC_SERVER_URL}/ai`,
13
+ });
14
+
15
+ const messagesEndRef = useRef<HTMLDivElement>(null);
16
+
17
+ useEffect(() => {
18
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
19
+ }, [messages]);
20
+
21
+ return (
22
+ <div className="grid grid-rows-[1fr_auto] overflow-hidden w-full mx-auto p-4">
23
+ <div className="overflow-y-auto space-y-4 pb-4">
24
+ {messages.length === 0 ? (
25
+ <div className="text-center text-muted-foreground mt-8">
26
+ Ask me anything to get started!
27
+ </div>
28
+ ) : (
29
+ messages.map((message) => (
30
+ <div
31
+ key={message.id}
32
+ className={`p-3 rounded-lg ${
33
+ message.role === "user"
34
+ ? "bg-primary/10 ml-8"
35
+ : "bg-secondary/20 mr-8"
36
+ }`}
37
+ >
38
+ <p className="text-sm font-semibold mb-1">
39
+ {message.role === "user" ? "You" : "AI Assistant"}
40
+ </p>
41
+ <div className="whitespace-pre-wrap">{message.content}</div>
42
+ </div>
43
+ ))
44
+ )}
45
+ <div ref={messagesEndRef} />
46
+ </div>
47
+
48
+ <form
49
+ onSubmit={handleSubmit}
50
+ className="w-full flex items-center space-x-2 pt-2 border-t"
51
+ >
52
+ <Input
53
+ name="prompt"
54
+ value={input}
55
+ onChange={handleInputChange}
56
+ placeholder="Type your message..."
57
+ className="flex-1"
58
+ autoComplete="off"
59
+ autoFocus
60
+ />
61
+ <Button type="submit" size="icon">
62
+ <Send size={18} />
63
+ </Button>
64
+ </form>
65
+ </div>
66
+ );
67
+ }
@@ -0,0 +1,162 @@
1
+ "use client"
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from "@/components/ui/card";
11
+ import { Checkbox } from "@/components/ui/checkbox";
12
+ import { Input } from "@/components/ui/input";
13
+ import { Loader2, Trash2 } from "lucide-react";
14
+ import { useState } from "react";
15
+ import { useMutation, useQuery } from "@tanstack/react-query";
16
+
17
+ {{#if (eq api "orpc")}}
18
+ import { orpc } from "@/utils/orpc";
19
+ {{/if}}
20
+ {{#if (eq api "trpc")}}
21
+ import { trpc } from "@/utils/trpc";
22
+ {{/if}}
23
+
24
+
25
+ export default function TodosPage() {
26
+ const [newTodoText, setNewTodoText] = useState("");
27
+
28
+ {{#if (eq api "orpc")}}
29
+ const todos = useQuery(orpc.todo.getAll.queryOptions());
30
+ const createMutation = useMutation(
31
+ orpc.todo.create.mutationOptions({
32
+ onSuccess: () => {
33
+ todos.refetch();
34
+ setNewTodoText("");
35
+ },
36
+ }),
37
+ );
38
+ const toggleMutation = useMutation(
39
+ orpc.todo.toggle.mutationOptions({
40
+ onSuccess: () => todos.refetch(),
41
+ }),
42
+ );
43
+ const deleteMutation = useMutation(
44
+ orpc.todo.delete.mutationOptions({
45
+ onSuccess: () => todos.refetch(),
46
+ }),
47
+ );
48
+ {{/if}}
49
+ {{#if (eq api "trpc")}}
50
+ const todos = useQuery(trpc.todo.getAll.queryOptions());
51
+ const createMutation = useMutation(
52
+ trpc.todo.create.mutationOptions({
53
+ onSuccess: () => {
54
+ todos.refetch();
55
+ setNewTodoText("");
56
+ },
57
+ }),
58
+ );
59
+ const toggleMutation = useMutation(
60
+ trpc.todo.toggle.mutationOptions({
61
+ onSuccess: () => todos.refetch(),
62
+ }),
63
+ );
64
+ const deleteMutation = useMutation(
65
+ trpc.todo.delete.mutationOptions({
66
+ onSuccess: () => todos.refetch(),
67
+ }),
68
+ );
69
+ {{/if}}
70
+
71
+ const handleAddTodo = (e: React.FormEvent) => {
72
+ e.preventDefault();
73
+ if (newTodoText.trim()) {
74
+ createMutation.mutate({ text: newTodoText });
75
+ }
76
+ };
77
+
78
+ const handleToggleTodo = (id: number, completed: boolean) => {
79
+ toggleMutation.mutate({ id, completed: !completed });
80
+ };
81
+
82
+ const handleDeleteTodo = (id: number) => {
83
+ deleteMutation.mutate({ id });
84
+ };
85
+
86
+ return (
87
+ <div className="mx-auto w-full max-w-md py-10">
88
+ <Card>
89
+ <CardHeader>
90
+ <CardTitle>Todo List</CardTitle>
91
+ <CardDescription>Manage your tasks efficiently</CardDescription>
92
+ </CardHeader>
93
+ <CardContent>
94
+ <form
95
+ onSubmit={handleAddTodo}
96
+ className="mb-6 flex items-center space-x-2"
97
+ >
98
+ <Input
99
+ value={newTodoText}
100
+ onChange={(e) => setNewTodoText(e.target.value)}
101
+ placeholder="Add a new task..."
102
+ disabled={createMutation.isPending}
103
+ />
104
+ <Button
105
+ type="submit"
106
+ disabled={createMutation.isPending || !newTodoText.trim()}
107
+ >
108
+ {createMutation.isPending ? (
109
+ <Loader2 className="h-4 w-4 animate-spin" />
110
+ ) : (
111
+ "Add"
112
+ )}
113
+ </Button>
114
+ </form>
115
+
116
+ {todos.isLoading ? (
117
+ <div className="flex justify-center py-4">
118
+ <Loader2 className="h-6 w-6 animate-spin" />
119
+ </div>
120
+ ) : todos.data?.length === 0 ? (
121
+ <p className="py-4 text-center">
122
+ No todos yet. Add one above!
123
+ </p>
124
+ ) : (
125
+ <ul className="space-y-2">
126
+ {todos.data?.map((todo) => (
127
+ <li
128
+ key={todo.id}
129
+ className="flex items-center justify-between rounded-md border p-2"
130
+ >
131
+ <div className="flex items-center space-x-2">
132
+ <Checkbox
133
+ checked={todo.completed}
134
+ onCheckedChange={() =>
135
+ handleToggleTodo(todo.id, todo.completed)
136
+ }
137
+ id={`todo-${todo.id}`}
138
+ />
139
+ <label
140
+ htmlFor={`todo-${todo.id}`}
141
+ className={`${todo.completed ? "line-through text-muted-foreground" : ""}`}
142
+ >
143
+ {todo.text}
144
+ </label>
145
+ </div>
146
+ <Button
147
+ variant="ghost"
148
+ size="icon"
149
+ onClick={() => handleDeleteTodo(todo.id)}
150
+ aria-label="Delete todo"
151
+ >
152
+ <Trash2 className="h-4 w-4" />
153
+ </Button>
154
+ </li>
155
+ ))}
156
+ </ul>
157
+ )}
158
+ </CardContent>
159
+ </Card>
160
+ </div>
161
+ );
162
+ }