create-better-t-stack 2.5.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import e from"node:path";import{cancel as t,confirm as n,group as r,intro as i,isCancel as a,log as o,multiselect as s,outro as c,password as l,select as u,spinner as d,text as f}from"@clack/prompts";import p,{consola as m}from"consola";import h from"fs-extra";import g from"picocolors";import _ from"yargs";import{hideBin as v}from"yargs/helpers";import{fileURLToPath as y}from"node:url";import{$ as b,execa as x}from"execa";import S from"node:os";import{globby as C}from"globby";import w from"handlebars";import T from"gradient-string";const E=()=>{let e=process.env.npm_config_user_agent;return e?.startsWith(`pnpm`)?`pnpm`:e?.startsWith(`bun`)?`bun`:`npm`},D=y(import.meta.url),O=e.dirname(D),k=e.join(O,`../`),A={projectName:`my-better-t-app`,frontend:[`tanstack-router`],database:`sqlite`,orm:`drizzle`,auth:!0,addons:[],examples:[],git:!0,packageManager:E(),install:!0,dbSetup:`none`,backend:`hono`,runtime:`bun`,api:`trpc`},j={"better-auth":`^1.2.7`,"@better-auth/expo":`^1.2.7`,"drizzle-orm":`^0.38.4`,"drizzle-kit":`^0.30.5`,"@libsql/client":`^0.14.0`,pg:`^8.14.1`,"@types/pg":`^8.11.11`,mysql2:`^3.14.0`,"@prisma/client":`^6.7.0`,prisma:`^6.7.0`,"vite-plugin-pwa":`^0.21.2`,"@vite-pwa/assets-generator":`^0.2.6`,"@tauri-apps/cli":`^2.4.0`,"@biomejs/biome":`1.9.4`,husky:`^9.1.7`,"lint-staged":`^15.5.0`,"@hono/node-server":`^1.14.0`,tsx:`^4.19.2`,"@types/node":`^22.13.11`,"@types/bun":`^1.2.6`,"@elysiajs/node":`^1.2.6`,"@elysiajs/cors":`^1.2.0`,"@elysiajs/trpc":`^1.1.0`,elysia:`^1.2.25`,"@hono/trpc-server":`^0.3.4`,hono:`^4.7.6`,cors:`^2.8.5`,express:`^5.1.0`,"@types/express":`^5.0.1`,"@types/cors":`^2.8.17`,turbo:`^2.4.2`,ai:`^4.2.8`,"@ai-sdk/google":`^1.2.3`,"@ai-sdk/vue":`^1.2.8`,"@ai-sdk/svelte":`^2.1.9`,"@prisma/extension-accelerate":`^1.3.0`,"@orpc/server":`^1.1.0`,"@orpc/client":`^1.1.0`,"@orpc/react-query":`^1.1.0`,"@orpc/vue-query":`^1.1.0`,"@orpc/svelte-query":`^1.1.0`,"@trpc/tanstack-react-query":`^11.0.0`,"@trpc/server":`^11.0.0`,"@trpc/client":`^11.0.0`,convex:`^1.23.0`,"@convex-dev/react-query":`^0.0.0-alpha.8`,"convex-svelte":`^0.0.11`,"@tanstack/svelte-query":`^5.74.4`,"@tanstack/react-query-devtools":`^5.69.0`,"@tanstack/react-query":`^5.69.0`},M=async t=>{let{dependencies:n=[],devDependencies:r=[],projectDir:i}=t,a=e.join(i,`package.json`),o=await h.readJson(a);o.dependencies||={},o.devDependencies||={};for(let e of n){let t=j[e];t?o.dependencies[e]=t:console.warn(`Warning: Dependency ${e} not found in version map.`)}for(let e of r){let t=j[e];t?o.devDependencies[e]=t:console.warn(`Warning: Dev dependency ${e} not found in version map.`)}await h.writeJson(a,o,{spaces:2})};function N(e,t){switch(e){case`pnpm`:return`pnpm dlx ${t}`;case`bun`:return`bunx ${t}`;default:return`npx ${t}`}}async function ee(t){let{projectName:n,packageManager:r}=t,i=e.resolve(process.cwd(),n),a=d();try{a.start(`Setting up Starlight docs...`);let t=[`docs`,`--template`,`starlight`,`--no-install`,`--add`,`tailwind`,`--no-git`,`--skip-houston`],n=t.join(` `),o=`create-astro@latest ${n}`,s=N(r,o);await x(s,{cwd:e.join(i,`apps`),env:{CI:`true`},shell:!0}),a.stop(`Starlight docs setup successfully!`)}catch(e){a.stop(g.red(`Failed to set up Starlight docs`)),e instanceof Error&&p.error(g.red(e.message))}}async function te(t){let{projectName:n,packageManager:r,frontend:i}=t,a=e.resolve(process.cwd(),n),o=d(),s=e.join(a,`apps/web`);if(await h.pathExists(s))try{o.start(`Setting up Tauri desktop app support...`),await M({devDependencies:[`@tauri-apps/cli`],projectDir:s});let t=e.join(s,`package.json`);if(await h.pathExists(t)){let e=await h.readJson(t);e.scripts={...e.scripts,tauri:`tauri`,"desktop:dev":`tauri dev`,"desktop:build":`tauri build`},await h.writeJson(t,e,{spaces:2})}let n=i.includes(`tanstack-router`),c=i.includes(`react-router`),l=i.includes(`nuxt`),u=i.includes(`svelte`),d=c||u?`http://localhost:5173`:`http://localhost:3001`,f=l?`../.output/public`:u?`../build`:`../dist`,p=[`init`,`--app-name=${e.basename(a)}`,`--window-title=${e.basename(a)}`,`--frontend-dist=${f}`,`--dev-url=${d}`,`--before-dev-command=\"${r} run dev\"`,`--before-build-command=\"${r} run build\"`],m=p.join(` `),g=`@tauri-apps/cli@latest ${m}`,_=N(r,g);await x(_,{cwd:s,env:{CI:`true`},shell:!0}),o.stop(`Tauri desktop app support configured successfully!`)}catch(e){o.stop(g.red(`Failed to set up Tauri`)),e instanceof Error&&m.error(g.red(e.message))}}async function ne(t){let{projectName:n,addons:r,frontend:i}=t,a=e.resolve(process.cwd(),n),o=i.includes(`react-router`)||i.includes(`tanstack-router`),s=i.includes(`nuxt`),c=i.includes(`svelte`);r.includes(`turborepo`)&&await M({devDependencies:[`turbo`],projectDir:a}),r.includes(`pwa`)&&o&&await oe(a,i),r.includes(`tauri`)&&(o||s||c)&&await te(t),r.includes(`biome`)&&await ie(a),r.includes(`husky`)&&await ae(a),r.includes(`starlight`)&&await ee(t)}function re(t,n){return n.some(e=>[`react-router`,`tanstack-router`,`nuxt`,`svelte`].includes(e)),e.join(t,`apps/web`)}async function ie(t){await M({devDependencies:[`@biomejs/biome`],projectDir:t});let n=e.join(t,`package.json`);if(await h.pathExists(n)){let e=await h.readJson(n);e.scripts={...e.scripts,check:`biome check --write .`},await h.writeJson(n,e,{spaces:2})}}async function ae(t){await M({devDependencies:[`husky`,`lint-staged`],projectDir:t});let n=e.join(t,`package.json`);if(await h.pathExists(n)){let e=await h.readJson(n);e.scripts={...e.scripts,prepare:`husky`},e[`lint-staged`]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":[`biome check --write .`]},await h.writeJson(n,e,{spaces:2})}}async function oe(t,n){let r=n.some(e=>[`react-router`,`tanstack-router`].includes(e));if(!r)return;let i=re(t,n);if(!await h.pathExists(i))return;await M({dependencies:[`vite-plugin-pwa`],devDependencies:[`@vite-pwa/assets-generator`],projectDir:i});let a=e.join(i,`package.json`);if(await h.pathExists(a)){let e=await h.readJson(a);e.scripts={...e.scripts,"generate-pwa-assets":`pwa-assets-generator`},await h.writeJson(a,e,{spaces:2})}}async function se(t){let{api:n,projectName:r,frontend:i,backend:a,packageManager:o}=t,s=e.resolve(process.cwd(),r),c=a===`convex`,l=e.join(s,`apps/web`),u=e.join(s,`apps/native`),d=await h.pathExists(l),f=await h.pathExists(u),p=i.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),m=i.includes(`nuxt`),g=i.includes(`svelte`);if(!c&&n!==`none`){let r=e.join(s,`apps/server`),i=await h.pathExists(r);i&&(n===`orpc`?await M({dependencies:[`@orpc/server`,`@orpc/client`],projectDir:r}):n===`trpc`&&(await M({dependencies:[`@trpc/server`,`@trpc/client`],projectDir:r}),t.backend===`hono`?await M({dependencies:[`@hono/trpc-server`],projectDir:r}):t.backend===`elysia`&&await M({dependencies:[`@elysiajs/trpc`],projectDir:r}))),d&&(p?n===`orpc`?await M({dependencies:[`@orpc/react-query`,`@orpc/client`,`@orpc/server`],projectDir:l}):n===`trpc`&&await M({dependencies:[`@trpc/tanstack-react-query`,`@trpc/client`,`@trpc/server`],projectDir:l}):m?n===`orpc`&&await M({dependencies:[`@orpc/vue-query`,`@orpc/client`,`@orpc/server`],projectDir:l}):g&&n===`orpc`&&await M({dependencies:[`@orpc/svelte-query`,`@orpc/client`,`@orpc/server`,`@tanstack/svelte-query`],projectDir:l})),f&&(n===`trpc`?await M({dependencies:[`@trpc/tanstack-react-query`,`@trpc/client`,`@trpc/server`],projectDir:u}):n===`orpc`&&await M({dependencies:[`@orpc/react-query`,`@orpc/client`,`@orpc/server`],projectDir:u}))}let _=[`react-router`,`tanstack-router`,`tanstack-start`,`next`,`native`],v=i.some(e=>_.includes(e));if(v&&!c){let t=[`@tanstack/react-query`],n=[`@tanstack/react-query-devtools`],r=i.some(e=>e!==`native`&&_.includes(e)),a=i.includes(`native`);if(r&&d){let r=e.join(l,`package.json`);if(await h.pathExists(r))try{await M({dependencies:t,devDependencies:n,projectDir:l})}catch{}}if(a&&f){let n=e.join(u,`package.json`);if(await h.pathExists(n))try{await M({dependencies:t,projectDir:u})}catch{}}}if(c){if(d){let t=e.join(l,`package.json`);if(await h.pathExists(t))try{let e=[`convex`];i.includes(`tanstack-start`)&&e.push(`@convex-dev/react-query`),g&&e.push(`convex-svelte`),await M({dependencies:e,projectDir:l})}catch{}}if(f){let t=e.join(u,`package.json`);if(await h.pathExists(t))try{await M({dependencies:[`convex`],projectDir:u})}catch{}}let t=`@${r}/backend`,n=o===`npm`?`*`:`workspace:*`,a=async(e,t,n)=>{try{let r=await h.readJson(e);r.dependencies||={},r.dependencies[t]!==n&&(r.dependencies[t]=n,await h.writeJson(e,r,{spaces:2}))}catch{}};if(d){let r=e.join(l,`package.json`);await h.pathExists(r)&&await a(r,t,n)}if(f){let r=e.join(u,`package.json`);await h.pathExists(r)&&await a(r,t,n)}}}async function ce(t){let{projectName:n,auth:r,frontend:i,backend:a}=t;if(a===`convex`||!r)return;let o=e.resolve(process.cwd(),n),s=e.join(o,`apps/server`),c=e.join(o,`apps/web`),l=e.join(o,`apps/native`),u=await h.pathExists(c),d=await h.pathExists(l),f=await h.pathExists(s);try{f&&await M({dependencies:[`better-auth`],projectDir:s});let e=i.some(e=>[`react-router`,`tanstack-router`,`tanstack-start`,`next`,`nuxt`,`svelte`].includes(e));e&&u&&await M({dependencies:[`better-auth`],projectDir:c}),i.includes(`native`)&&d&&(await M({dependencies:[`better-auth`,`@better-auth/expo`],projectDir:l}),f&&await M({dependencies:[`@better-auth/expo`],projectDir:s}))}catch(e){p.error(g.red(`Failed to configure authentication dependencies`)),e instanceof Error&&p.error(g.red(e.message))}}function le(e=32){let t=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`,n=``,r=t.length;for(let i=0;i<e;i++)n+=t.charAt(Math.floor(Math.random()*r));return n}async function ue(t){let{projectName:n,backend:r,runtime:i,api:a}=t;if(r===`convex`)return;let o=e.resolve(process.cwd(),n),s=r,c=e.join(o,`apps/server`),l=[],u=[];s===`hono`?(l.push(`hono`),a===`trpc`&&l.push(`@hono/trpc-server`),i===`node`&&(l.push(`@hono/node-server`),u.push(`tsx`,`@types/node`))):s===`elysia`?(l.push(`elysia`,`@elysiajs/cors`),a===`trpc`&&l.push(`@elysiajs/trpc`),i===`node`&&(l.push(`@elysiajs/node`),u.push(`tsx`,`@types/node`))):s===`express`&&(l.push(`express`,`cors`),u.push(`@types/express`,`@types/cors`),i===`node`&&u.push(`tsx`,`@types/node`)),i===`bun`&&u.push(`@types/bun`),(l.length>0||u.length>0)&&await M({dependencies:l,devDependencies:u,projectDir:c})}async function de(t,n){let r=e.join(t,`README.md`),i=fe(n);try{await h.writeFile(r,i)}catch(e){p.error(`Failed to create README.md file:`,e)}}function fe(e){let{projectName:t,packageManager:n,database:r,auth:i,addons:a=[],orm:o=`drizzle`,runtime:s=`bun`,frontend:c=[`tanstack-router`],backend:l=`hono`}=e,u=c.includes(`react-router`),d=c.includes(`tanstack-router`),f=c.includes(`native`),p=c.includes(`next`),m=c.includes(`tanstack-start`),h=c.includes(`svelte`),g=c.includes(`nuxt`),_=n===`npm`?`npm run`:n,v=`3001`;return(u||h)&&(v=`5173`),`# ${t}
2
+ import e from"node:path";import{cancel as t,confirm as n,group as r,intro as i,isCancel as a,log as o,multiselect as s,outro as c,password as l,select as u,spinner as d,text as f}from"@clack/prompts";import p,{consola as m}from"consola";import h from"fs-extra";import g from"picocolors";import _ from"yargs";import{hideBin as v}from"yargs/helpers";import{fileURLToPath as y}from"node:url";import{$ as b,execa as x}from"execa";import S from"node:os";import{globby as C}from"globby";import w from"handlebars";import T from"gradient-string";const E=()=>{let e=process.env.npm_config_user_agent;return e?.startsWith(`pnpm`)?`pnpm`:e?.startsWith(`bun`)?`bun`:`npm`},D=y(import.meta.url),O=e.dirname(D),k=e.join(O,`../`),A={projectName:`my-better-t-app`,frontend:[`tanstack-router`],database:`sqlite`,orm:`drizzle`,auth:!0,addons:[],examples:[],git:!0,packageManager:E(),install:!0,dbSetup:`none`,backend:`hono`,runtime:`bun`,api:`trpc`},j={"better-auth":`^1.2.7`,"@better-auth/expo":`^1.2.7`,"drizzle-orm":`^0.38.4`,"drizzle-kit":`^0.30.5`,"@libsql/client":`^0.14.0`,pg:`^8.14.1`,"@types/pg":`^8.11.11`,mysql2:`^3.14.0`,"@prisma/client":`^6.7.0`,prisma:`^6.7.0`,"vite-plugin-pwa":`^0.21.2`,"@vite-pwa/assets-generator":`^0.2.6`,"@tauri-apps/cli":`^2.4.0`,"@biomejs/biome":`1.9.4`,husky:`^9.1.7`,"lint-staged":`^15.5.0`,"@hono/node-server":`^1.14.0`,tsx:`^4.19.2`,"@types/node":`^22.13.11`,"@types/bun":`^1.2.6`,"@elysiajs/node":`^1.2.6`,"@elysiajs/cors":`^1.2.0`,"@elysiajs/trpc":`^1.1.0`,elysia:`^1.2.25`,"@hono/trpc-server":`^0.3.4`,hono:`^4.7.6`,cors:`^2.8.5`,express:`^5.1.0`,"@types/express":`^5.0.1`,"@types/cors":`^2.8.17`,turbo:`^2.4.2`,ai:`^4.2.8`,"@ai-sdk/google":`^1.2.3`,"@ai-sdk/vue":`^1.2.8`,"@ai-sdk/svelte":`^2.1.9`,"@prisma/extension-accelerate":`^1.3.0`,"@orpc/server":`^1.1.1`,"@orpc/client":`^1.1.1`,"@orpc/react-query":`^1.1.1`,"@orpc/vue-query":`^1.1.1`,"@orpc/svelte-query":`^1.1.1`,"@trpc/tanstack-react-query":`^11.0.0`,"@trpc/server":`^11.0.0`,"@trpc/client":`^11.0.0`,convex:`^1.23.0`,"@convex-dev/react-query":`^0.0.0-alpha.8`,"convex-svelte":`^0.0.11`,"@tanstack/svelte-query":`^5.74.4`,"@tanstack/react-query-devtools":`^5.69.0`,"@tanstack/react-query":`^5.69.0`},M=async t=>{let{dependencies:n=[],devDependencies:r=[],projectDir:i}=t,a=e.join(i,`package.json`),o=await h.readJson(a);o.dependencies||={},o.devDependencies||={};for(let e of n){let t=j[e];t?o.dependencies[e]=t:console.warn(`Warning: Dependency ${e} not found in version map.`)}for(let e of r){let t=j[e];t?o.devDependencies[e]=t:console.warn(`Warning: Dev dependency ${e} not found in version map.`)}await h.writeJson(a,o,{spaces:2})};function N(e,t){switch(e){case`pnpm`:return`pnpm dlx ${t}`;case`bun`:return`bunx ${t}`;default:return`npx ${t}`}}async function ee(t){let{projectName:n,packageManager:r}=t,i=e.resolve(process.cwd(),n),a=d();try{a.start(`Setting up Starlight docs...`);let t=[`docs`,`--template`,`starlight`,`--no-install`,`--add`,`tailwind`,`--no-git`,`--skip-houston`],n=t.join(` `),o=`create-astro@latest ${n}`,s=N(r,o);await x(s,{cwd:e.join(i,`apps`),env:{CI:`true`},shell:!0}),a.stop(`Starlight docs setup successfully!`)}catch(e){a.stop(g.red(`Failed to set up Starlight docs`)),e instanceof Error&&p.error(g.red(e.message))}}async function te(t){let{projectName:n,packageManager:r,frontend:i}=t,a=e.resolve(process.cwd(),n),o=d(),s=e.join(a,`apps/web`);if(await h.pathExists(s))try{o.start(`Setting up Tauri desktop app support...`),await M({devDependencies:[`@tauri-apps/cli`],projectDir:s});let t=e.join(s,`package.json`);if(await h.pathExists(t)){let e=await h.readJson(t);e.scripts={...e.scripts,tauri:`tauri`,"desktop:dev":`tauri dev`,"desktop:build":`tauri build`},await h.writeJson(t,e,{spaces:2})}let n=i.includes(`tanstack-router`),c=i.includes(`react-router`),l=i.includes(`nuxt`),u=i.includes(`svelte`),d=c||u?`http://localhost:5173`:`http://localhost:3001`,f=l?`../.output/public`:u?`../build`:`../dist`,p=[`init`,`--app-name=${e.basename(a)}`,`--window-title=${e.basename(a)}`,`--frontend-dist=${f}`,`--dev-url=${d}`,`--before-dev-command=\"${r} run dev\"`,`--before-build-command=\"${r} run build\"`],m=p.join(` `),g=`@tauri-apps/cli@latest ${m}`,_=N(r,g);await x(_,{cwd:s,env:{CI:`true`},shell:!0}),o.stop(`Tauri desktop app support configured successfully!`)}catch(e){o.stop(g.red(`Failed to set up Tauri`)),e instanceof Error&&m.error(g.red(e.message))}}async function ne(t){let{projectName:n,addons:r,frontend:i}=t,a=e.resolve(process.cwd(),n),o=i.includes(`react-router`)||i.includes(`tanstack-router`),s=i.includes(`nuxt`),c=i.includes(`svelte`);r.includes(`turborepo`)&&await M({devDependencies:[`turbo`],projectDir:a}),r.includes(`pwa`)&&o&&await oe(a,i),r.includes(`tauri`)&&(o||s||c)&&await te(t),r.includes(`biome`)&&await ie(a),r.includes(`husky`)&&await ae(a),r.includes(`starlight`)&&await ee(t)}function re(t,n){return n.some(e=>[`react-router`,`tanstack-router`,`nuxt`,`svelte`].includes(e)),e.join(t,`apps/web`)}async function ie(t){await M({devDependencies:[`@biomejs/biome`],projectDir:t});let n=e.join(t,`package.json`);if(await h.pathExists(n)){let e=await h.readJson(n);e.scripts={...e.scripts,check:`biome check --write .`},await h.writeJson(n,e,{spaces:2})}}async function ae(t){await M({devDependencies:[`husky`,`lint-staged`],projectDir:t});let n=e.join(t,`package.json`);if(await h.pathExists(n)){let e=await h.readJson(n);e.scripts={...e.scripts,prepare:`husky`},e[`lint-staged`]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":[`biome check --write .`]},await h.writeJson(n,e,{spaces:2})}}async function oe(t,n){let r=n.some(e=>[`react-router`,`tanstack-router`].includes(e));if(!r)return;let i=re(t,n);if(!await h.pathExists(i))return;await M({dependencies:[`vite-plugin-pwa`],devDependencies:[`@vite-pwa/assets-generator`],projectDir:i});let a=e.join(i,`package.json`);if(await h.pathExists(a)){let e=await h.readJson(a);e.scripts={...e.scripts,"generate-pwa-assets":`pwa-assets-generator`},await h.writeJson(a,e,{spaces:2})}}async function se(t){let{api:n,projectName:r,frontend:i,backend:a,packageManager:o}=t,s=e.resolve(process.cwd(),r),c=a===`convex`,l=e.join(s,`apps/web`),u=e.join(s,`apps/native`),d=await h.pathExists(l),f=await h.pathExists(u),p=i.some(e=>[`tanstack-router`,`react-router`,`tanstack-start`,`next`].includes(e)),m=i.includes(`nuxt`),g=i.includes(`svelte`);if(!c&&n!==`none`){let r=e.join(s,`apps/server`),i=await h.pathExists(r);i&&(n===`orpc`?await M({dependencies:[`@orpc/server`,`@orpc/client`],projectDir:r}):n===`trpc`&&(await M({dependencies:[`@trpc/server`,`@trpc/client`],projectDir:r}),t.backend===`hono`?await M({dependencies:[`@hono/trpc-server`],projectDir:r}):t.backend===`elysia`&&await M({dependencies:[`@elysiajs/trpc`],projectDir:r}))),d&&(p?n===`orpc`?await M({dependencies:[`@orpc/react-query`,`@orpc/client`,`@orpc/server`],projectDir:l}):n===`trpc`&&await M({dependencies:[`@trpc/tanstack-react-query`,`@trpc/client`,`@trpc/server`],projectDir:l}):m?n===`orpc`&&await M({dependencies:[`@orpc/vue-query`,`@orpc/client`,`@orpc/server`],projectDir:l}):g&&n===`orpc`&&await M({dependencies:[`@orpc/svelte-query`,`@orpc/client`,`@orpc/server`,`@tanstack/svelte-query`],projectDir:l})),f&&(n===`trpc`?await M({dependencies:[`@trpc/tanstack-react-query`,`@trpc/client`,`@trpc/server`],projectDir:u}):n===`orpc`&&await M({dependencies:[`@orpc/react-query`,`@orpc/client`,`@orpc/server`],projectDir:u}))}let _=[`react-router`,`tanstack-router`,`tanstack-start`,`next`,`native`],v=i.some(e=>_.includes(e));if(v&&!c){let t=[`@tanstack/react-query`],n=[`@tanstack/react-query-devtools`],r=i.some(e=>e!==`native`&&_.includes(e)),a=i.includes(`native`);if(r&&d){let r=e.join(l,`package.json`);if(await h.pathExists(r))try{await M({dependencies:t,devDependencies:n,projectDir:l})}catch{}}if(a&&f){let n=e.join(u,`package.json`);if(await h.pathExists(n))try{await M({dependencies:t,projectDir:u})}catch{}}}if(c){if(d){let t=e.join(l,`package.json`);if(await h.pathExists(t))try{let e=[`convex`];i.includes(`tanstack-start`)&&e.push(`@convex-dev/react-query`),g&&e.push(`convex-svelte`),await M({dependencies:e,projectDir:l})}catch{}}if(f){let t=e.join(u,`package.json`);if(await h.pathExists(t))try{await M({dependencies:[`convex`],projectDir:u})}catch{}}let t=`@${r}/backend`,n=o===`npm`?`*`:`workspace:*`,a=async(e,t,n)=>{try{let r=await h.readJson(e);r.dependencies||={},r.dependencies[t]!==n&&(r.dependencies[t]=n,await h.writeJson(e,r,{spaces:2}))}catch{}};if(d){let r=e.join(l,`package.json`);await h.pathExists(r)&&await a(r,t,n)}if(f){let r=e.join(u,`package.json`);await h.pathExists(r)&&await a(r,t,n)}}}async function ce(t){let{projectName:n,auth:r,frontend:i,backend:a}=t;if(a===`convex`||!r)return;let o=e.resolve(process.cwd(),n),s=e.join(o,`apps/server`),c=e.join(o,`apps/web`),l=e.join(o,`apps/native`),u=await h.pathExists(c),d=await h.pathExists(l),f=await h.pathExists(s);try{f&&await M({dependencies:[`better-auth`],projectDir:s});let e=i.some(e=>[`react-router`,`tanstack-router`,`tanstack-start`,`next`,`nuxt`,`svelte`].includes(e));e&&u&&await M({dependencies:[`better-auth`],projectDir:c}),i.includes(`native`)&&d&&(await M({dependencies:[`better-auth`,`@better-auth/expo`],projectDir:l}),f&&await M({dependencies:[`@better-auth/expo`],projectDir:s}))}catch(e){p.error(g.red(`Failed to configure authentication dependencies`)),e instanceof Error&&p.error(g.red(e.message))}}function le(e=32){let t=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`,n=``,r=t.length;for(let i=0;i<e;i++)n+=t.charAt(Math.floor(Math.random()*r));return n}async function ue(t){let{projectName:n,backend:r,runtime:i,api:a}=t;if(r===`convex`)return;let o=e.resolve(process.cwd(),n),s=r,c=e.join(o,`apps/server`),l=[],u=[];s===`hono`?(l.push(`hono`),a===`trpc`&&l.push(`@hono/trpc-server`),i===`node`&&(l.push(`@hono/node-server`),u.push(`tsx`,`@types/node`))):s===`elysia`?(l.push(`elysia`,`@elysiajs/cors`),a===`trpc`&&l.push(`@elysiajs/trpc`),i===`node`&&(l.push(`@elysiajs/node`),u.push(`tsx`,`@types/node`))):s===`express`&&(l.push(`express`,`cors`),u.push(`@types/express`,`@types/cors`),i===`node`&&u.push(`tsx`,`@types/node`)),i===`bun`&&u.push(`@types/bun`),(l.length>0||u.length>0)&&await M({dependencies:l,devDependencies:u,projectDir:c})}async function de(t,n){let r=e.join(t,`README.md`),i=fe(n);try{await h.writeFile(r,i)}catch(e){p.error(`Failed to create README.md file:`,e)}}function fe(e){let{projectName:t,packageManager:n,database:r,auth:i,addons:a=[],orm:o=`drizzle`,runtime:s=`bun`,frontend:c=[`tanstack-router`],backend:l=`hono`}=e,u=c.includes(`react-router`),d=c.includes(`tanstack-router`),f=c.includes(`native`),p=c.includes(`next`),m=c.includes(`tanstack-start`),h=c.includes(`svelte`),g=c.includes(`nuxt`),_=n===`npm`?`npm run`:n,v=`3001`;return(u||h)&&(v=`5173`),`# ${t}
3
3
 
4
4
  This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack that combines React, ${d?`TanStack Router`:u?`React Router`:p?`Next.js`:m?`TanStack Start`:h?`SvelteKit`:g?`Nuxt`:``}, ${l[0].toUpperCase()+l.slice(1)}, tRPC, and more.
5
5
 
@@ -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.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.1",
3
+ "version": "2.6.0",
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",
@@ -1,15 +1,16 @@
1
1
  import { ScrollViewStyleReset } from 'expo-router/html';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  // This file is web-only and used to configure the root HTML for every
4
5
  // web page during static rendering.
5
6
  // The contents of this function only run in Node.js environments and
6
7
  // do not have access to the DOM or browser APIs.
7
- export default function Root({ children }: { children: React.ReactNode }) {
8
+ export default function Root({ children }: { children: ReactNode }) {
8
9
  return (
9
10
  <html lang="en">
10
11
  <head>
11
12
  <meta charSet="utf-8" />
12
- <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
13
+ <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
13
14
 
14
15
  {/*
15
16
  This viewport disables scaling which makes the mobile website act more like a native app.
@@ -17,8 +18,8 @@ export default function Root({ children }: { children: React.ReactNode }) {
17
18
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
18
19
  */}
19
20
  <meta
20
- name="viewport"
21
21
  content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
22
+ name="viewport"
22
23
  />
23
24
  {/*
24
25
  Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
@@ -35,7 +35,6 @@ const DARK_THEME: Theme = {
35
35
  };
36
36
 
37
37
  export const unstable_settings = {
38
- // Ensure that reloading on `/modal` keeps a back button present.
39
38
  initialRouteName: "(drawer)",
40
39
  };
41
40
 
@@ -56,7 +55,6 @@ export default function RootLayout() {
56
55
  }
57
56
 
58
57
  if (Platform.OS === "web") {
59
- // Adds the background color to the html element to prevent white background on overscroll.
60
58
  document.documentElement.classList.add("bg-background");
61
59
  }
62
60
  setAndroidNavigationBar(colorScheme);
@@ -11,7 +11,8 @@
11
11
  },
12
12
  "plugins": [
13
13
  "expo-router",
14
- "expo-secure-store"
14
+ "expo-secure-store",
15
+ "expo-web-browser"
15
16
  ],
16
17
  "experiments": {
17
18
  "typedRoutes": true,
@@ -26,7 +27,9 @@
26
27
  "resizeMode": "contain",
27
28
  "backgroundColor": "#ffffff"
28
29
  },
29
- "assetBundlePatterns": ["**/*"],
30
+ "assetBundlePatterns": [
31
+ "**/*"
32
+ ],
30
33
  "ios": {
31
34
  "supportsTablet": true,
32
35
  "bundleIdentifier": "com.amanvarshney01.mybettertapp"
@@ -1,4 +1,4 @@
1
- module.exports = function (api) {
1
+ export default function (api) {
2
2
  api.cache(true);
3
3
  const plugins = [];
4
4
 
@@ -6,7 +6,6 @@ module.exports = function (api) {
6
6
 
7
7
  return {
8
8
  presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
9
-
10
9
  plugins,
11
10
  };
12
11
  };
@@ -16,28 +16,28 @@
16
16
  "@react-navigation/native": "^7.0.14",
17
17
  "@tanstack/react-form": "^1.0.5",
18
18
  "@tanstack/react-query": "^5.69.2",
19
- "expo": "^52.0.44",
20
- "expo-constants": "~17.0.8",
21
- "expo-linking": "~7.0.5",
22
- "expo-navigation-bar": "~4.0.8",
23
- "expo-router": "~4.0.19",
24
- "expo-secure-store": "~14.0.1",
25
- "expo-status-bar": "~2.0.1",
26
- "expo-system-ui": "~4.0.8",
27
- "expo-web-browser": "~14.0.2",
28
- "nativewind": "^4.1.23",
29
- "react": "18.3.1",
30
- "react-dom": "18.3.1",
31
- "react-native": "0.76.9",
32
- "react-native-gesture-handler": "~2.20.2",
33
- "react-native-reanimated": "3.16.2",
34
- "react-native-safe-area-context": "4.12.0",
35
- "react-native-screens": "~4.4.0",
36
- "react-native-web": "~0.19.13"
19
+ "expo": "^53.0.4",
20
+ "expo-constants": "~17.1.4",
21
+ "expo-linking": "~7.1.4",
22
+ "expo-navigation-bar": "~4.2.3",
23
+ "expo-router": "~5.0.3",
24
+ "expo-secure-store": "~14.2.3",
25
+ "expo-status-bar": "~2.2.3",
26
+ "expo-system-ui": "~5.0.6",
27
+ "expo-web-browser": "~14.1.6",
28
+ "nativewind": "latest",
29
+ "react": "19.0.0",
30
+ "react-dom": "19.0.0",
31
+ "react-native": "0.79.1",
32
+ "react-native-gesture-handler": "~2.24.0",
33
+ "react-native-reanimated": "~3.17.4",
34
+ "react-native-safe-area-context": "5.3.0",
35
+ "react-native-screens": "~4.10.0",
36
+ "react-native-web": "^0.20.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@babel/core": "^7.26.10",
40
- "@types/react": "~18.3.12",
40
+ "@types/react": "~19.0.10",
41
41
  "tailwindcss": "^3.4.17",
42
42
  "typescript": "~5.8.2"
43
43
  },