create-better-t-stack 1.10.2 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{cancel as j,intro as rn,log as D,outro as nn,spinner as sn}from"@clack/prompts";import{Command as on}from"commander";import h from"picocolors";import we from"node:path";import{fileURLToPath as Ot}from"node:url";var K=()=>{let e=process.env.npm_config_user_agent;return e?.startsWith("pnpm")?"pnpm":e?.startsWith("bun")?"bun":"npm"};var Bt=Ot(import.meta.url),Lt=we.dirname(Bt),v=we.join(Lt,"../"),P={projectName:"my-better-t-app",frontend:["tanstack-router"],database:"sqlite",orm:"drizzle",auth:!0,addons:[],examples:[],git:!0,packageManager:K(),noInstall:!1,dbSetup:"none",backend:"hono",runtime:"bun"},se={"better-auth":"^1.2.4","@better-auth/expo":"^1.2.5","drizzle-orm":"^0.38.4","drizzle-kit":"^0.30.5","@libsql/client":"^0.14.0",postgres:"^3.4.5",mysql2:"^3.14.0","@prisma/client":"^6.5.0",prisma:"^6.5.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.5",cors:"^2.8.5",express:"^5.1.0","@types/express":"^5.0.1","@types/cors":"^2.8.17",ai:"^4.2.8","@ai-sdk/google":"^1.2.3","@prisma/extension-accelerate":"^1.3.0"};import Xa from"node:path";import{cancel as Ya,spinner as Za}from"@clack/prompts";import er from"fs-extra";import nt from"picocolors";import I from"node:path";import k from"fs-extra";import Mt from"node:path";import Pe from"fs-extra";var g=e=>{let{dependencies:a=[],devDependencies:t=[],projectDir:r}=e,n=Mt.join(r,"package.json"),s=Pe.readJSONSync(n);s.dependencies||(s.dependencies={}),s.devDependencies||(s.devDependencies={});for(let o of a){let i=se[o];s.dependencies[o]=i}for(let o of t){let i=se[o];s.devDependencies[o]=i}Pe.writeJSONSync(n,s,{spaces:2})};import X from"node:path";import{log as zt,spinner as Nt}from"@clack/prompts";import{execa as Ut}from"execa";import Y from"fs-extra";import ye from"picocolors";async function je(e,a,t){let r=Nt(),n=X.join(e,"apps/web");if(await Y.pathExists(n))try{r.start("Setting up Tauri desktop app support..."),g({devDependencies:["@tauri-apps/cli"],projectDir:n});let s=X.join(n,"package.json");if(await Y.pathExists(s)){let d=await Y.readJson(s);d.scripts={...d.scripts,tauri:"tauri","desktop:dev":"tauri dev","desktop:build":"tauri build"},await Y.writeJson(s,d,{spaces:2})}let o,i;switch(a){case"npm":o="npx",i=["@tauri-apps/cli@latest"];break;case"pnpm":o="pnpm",i=["dlx","@tauri-apps/cli@latest"];break;case"bun":o="bunx",i=["@tauri-apps/cli@latest"];break;default:o="npx",i=["@tauri-apps/cli@latest"]}let c=t.includes("react-router")?"http://localhost:5173":"http://localhost:3001";i=[...i,"init",`--app-name=${X.basename(e)}`,`--window-title=${X.basename(e)}`,"--frontend-dist=dist",`--dev-url=${c}`,`--before-dev-command=${a} run dev`,`--before-build-command=${a} run build`],await Ut(o,i,{cwd:n,env:{CI:"true"}}),r.stop("Tauri desktop app support configured successfully!")}catch(s){throw r.stop(ye.red("Failed to set up Tauri")),s instanceof Error&&zt.error(ye.red(s.message)),s}}async function ve(e,a,t,r){let n=r.includes("react-router")||r.includes("tanstack-router");a.includes("pwa")&&n&&await Gt(e,r),a.includes("tauri")&&n&&await je(e,t,r),a.includes("biome")&&await qt(e),a.includes("husky")&&await Vt(e)}function _t(e,a){return I.join(e,"apps/web")}async function qt(e){let a=I.join(v,"template/with-biome");await k.pathExists(a)&&await k.copy(a,e,{overwrite:!0}),g({devDependencies:["@biomejs/biome"],projectDir:e});let t=I.join(e,"package.json");if(await k.pathExists(t)){let r=await k.readJson(t);r.scripts={...r.scripts,check:"biome check --write ."},await k.writeJson(t,r,{spaces:2})}}async function Vt(e){let a=I.join(v,"template/with-husky");await k.pathExists(a)&&await k.copy(a,e,{overwrite:!0}),g({devDependencies:["husky","lint-staged"],projectDir:e});let t=I.join(e,"package.json");if(await k.pathExists(t)){let r=await k.readJson(t);r.scripts={...r.scripts,prepare:"husky"},r["lint-staged"]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":["biome check --write ."]},await k.writeJson(t,r,{spaces:2})}}async function Gt(e,a){let t=I.join(v,"template/with-pwa");await k.pathExists(t)&&await k.copy(t,e,{overwrite:!0});let r=_t(e,a);if(!await k.pathExists(r))return;g({dependencies:["vite-plugin-pwa"],devDependencies:["@vite-pwa/assets-generator"],projectDir:r});let n=I.join(r,"vite.config.ts");if(await k.pathExists(n)){let o=await k.readFile(n,"utf8");if(!o.includes("vite-plugin-pwa")){let p=o.match(/^import .* from ['"](.*)['"]/m);p?o=o.replace(p[0],`import { VitePWA } from "vite-plugin-pwa";
2
+ import{cancel as j,intro as rn,log as D,outro as nn,spinner as sn}from"@clack/prompts";import{Command as on}from"commander";import h from"picocolors";import we from"node:path";import{fileURLToPath as Ot}from"node:url";var K=()=>{let e=process.env.npm_config_user_agent;return e?.startsWith("pnpm")?"pnpm":e?.startsWith("bun")?"bun":"npm"};var Bt=Ot(import.meta.url),Lt=we.dirname(Bt),v=we.join(Lt,"../"),P={projectName:"my-better-t-app",frontend:["tanstack-router"],database:"sqlite",orm:"drizzle",auth:!0,addons:[],examples:[],git:!0,packageManager:K(),noInstall:!1,dbSetup:"none",backend:"hono",runtime:"bun"},se={"better-auth":"^1.2.4","@better-auth/expo":"^1.2.5","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.5.0",prisma:"^6.5.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.5",cors:"^2.8.5",express:"^5.1.0","@types/express":"^5.0.1","@types/cors":"^2.8.17",ai:"^4.2.8","@ai-sdk/google":"^1.2.3","@prisma/extension-accelerate":"^1.3.0"};import Xa from"node:path";import{cancel as Ya,spinner as Za}from"@clack/prompts";import er from"fs-extra";import nt from"picocolors";import I from"node:path";import k from"fs-extra";import Mt from"node:path";import Pe from"fs-extra";var g=e=>{let{dependencies:a=[],devDependencies:t=[],projectDir:r}=e,n=Mt.join(r,"package.json"),s=Pe.readJSONSync(n);s.dependencies||(s.dependencies={}),s.devDependencies||(s.devDependencies={});for(let o of a){let i=se[o];s.dependencies[o]=i}for(let o of t){let i=se[o];s.devDependencies[o]=i}Pe.writeJSONSync(n,s,{spaces:2})};import X from"node:path";import{log as zt,spinner as Nt}from"@clack/prompts";import{execa as Ut}from"execa";import Y from"fs-extra";import ye from"picocolors";async function je(e,a,t){let r=Nt(),n=X.join(e,"apps/web");if(await Y.pathExists(n))try{r.start("Setting up Tauri desktop app support..."),g({devDependencies:["@tauri-apps/cli"],projectDir:n});let s=X.join(n,"package.json");if(await Y.pathExists(s)){let d=await Y.readJson(s);d.scripts={...d.scripts,tauri:"tauri","desktop:dev":"tauri dev","desktop:build":"tauri build"},await Y.writeJson(s,d,{spaces:2})}let o,i;switch(a){case"npm":o="npx",i=["@tauri-apps/cli@latest"];break;case"pnpm":o="pnpm",i=["dlx","@tauri-apps/cli@latest"];break;case"bun":o="bunx",i=["@tauri-apps/cli@latest"];break;default:o="npx",i=["@tauri-apps/cli@latest"]}let c=t.includes("react-router")?"http://localhost:5173":"http://localhost:3001";i=[...i,"init",`--app-name=${X.basename(e)}`,`--window-title=${X.basename(e)}`,"--frontend-dist=dist",`--dev-url=${c}`,`--before-dev-command=${a} run dev`,`--before-build-command=${a} run build`],await Ut(o,i,{cwd:n,env:{CI:"true"}}),r.stop("Tauri desktop app support configured successfully!")}catch(s){throw r.stop(ye.red("Failed to set up Tauri")),s instanceof Error&&zt.error(ye.red(s.message)),s}}async function ve(e,a,t,r){let n=r.includes("react-router")||r.includes("tanstack-router");a.includes("pwa")&&n&&await Gt(e,r),a.includes("tauri")&&n&&await je(e,t,r),a.includes("biome")&&await qt(e),a.includes("husky")&&await Vt(e)}function _t(e,a){return I.join(e,"apps/web")}async function qt(e){let a=I.join(v,"template/with-biome");await k.pathExists(a)&&await k.copy(a,e,{overwrite:!0}),g({devDependencies:["@biomejs/biome"],projectDir:e});let t=I.join(e,"package.json");if(await k.pathExists(t)){let r=await k.readJson(t);r.scripts={...r.scripts,check:"biome check --write ."},await k.writeJson(t,r,{spaces:2})}}async function Vt(e){let a=I.join(v,"template/with-husky");await k.pathExists(a)&&await k.copy(a,e,{overwrite:!0}),g({devDependencies:["husky","lint-staged"],projectDir:e});let t=I.join(e,"package.json");if(await k.pathExists(t)){let r=await k.readJson(t);r.scripts={...r.scripts,prepare:"husky"},r["lint-staged"]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":["biome check --write ."]},await k.writeJson(t,r,{spaces:2})}}async function Gt(e,a){let t=I.join(v,"template/with-pwa");await k.pathExists(t)&&await k.copy(t,e,{overwrite:!0});let r=_t(e,a);if(!await k.pathExists(r))return;g({dependencies:["vite-plugin-pwa"],devDependencies:["@vite-pwa/assets-generator"],projectDir:r});let n=I.join(r,"vite.config.ts");if(await k.pathExists(n)){let o=await k.readFile(n,"utf8");if(!o.includes("vite-plugin-pwa")){let p=o.match(/^import .* from ['"](.*)['"]/m);p?o=o.replace(p[0],`import { VitePWA } from "vite-plugin-pwa";
3
3
  ${p[0]}`):o=`import { VitePWA } from "vite-plugin-pwa";
4
4
  ${o}`}let i=`VitePWA({
5
5
  registerType: "autoUpdate",
@@ -136,7 +136,7 @@ DATABASE_AUTH_TOKEN=`;await ha.writeFile(t,r)}function ee(){G.info(`Manual Turso
136
136
  4. Add these credentials to the .env file in apps/server/.env
137
137
 
138
138
  DATABASE_URL=your_database_url
139
- DATABASE_AUTH_TOKEN=your_auth_token`)}async function Be(e,a){if(!a){await J(e),G.info(T.blue("Skipping Turso setup. Setting up empty configuration.")),ee();return}let t=da.platform(),r=t==="darwin";if(!(t!=="win32")){G.warn(T.yellow("Automatic Turso setup is not supported on Windows.")),await J(e),ee();return}try{if(!await ga()){let w=await ua({message:"Would you like to install Turso CLI?",initialValue:!0});if(de(w)&&(le(T.red("Operation cancelled")),process.exit(0)),!w){await J(e),ee();return}await Pa(r)}await ba()||await wa();let i=await ja(),p=!1,c="",d=Oe.basename(e);for(;!p;){let w=await fa({message:"Enter a name for your database:",defaultValue:d,initialValue:d,placeholder:d});de(w)&&(le(T.red("Operation cancelled")),process.exit(0)),c=w;let $=ue();try{$.start(`Creating Turso database "${c}"${i?` in group "${i}"`:""}...`);let A=await va(c,i);await J(e,A),$.stop("Turso database configured successfully!"),p=!0}catch(A){if(A instanceof Error&&A.message==="DATABASE_EXISTS")$.stop(T.yellow(`Database "${T.red(c)}" already exists`)),d=`${c}-${Math.floor(Math.random()*1e3)}`;else throw $.stop(T.red("Failed to create Turso database")),A}}}catch(s){G.error(T.red(`Error during Turso setup: ${s}`)),await J(e),ee(),G.success("Setup completed with manual configuration required.")}}async function ze(e,a,t,r,n,s,o){let i=xa(),p=Le.join(e,"apps/server");if(a==="none"){await $a.remove(Le.join(p,"src/db"));return}try{t==="prisma"?g({dependencies:["@prisma/client"],devDependencies:["prisma"],projectDir:p}):t==="drizzle"&&(a==="sqlite"?g({dependencies:["drizzle-orm","@libsql/client"],devDependencies:["drizzle-kit"],projectDir:p}):a==="postgres"?g({dependencies:["drizzle-orm","postgres"],devDependencies:["drizzle-kit"],projectDir:p}):a==="mysql"&&g({dependencies:["drizzle-orm","mysql2"],devDependencies:["drizzle-kit"],projectDir:p})),a==="sqlite"&&n?await Be(e,t==="drizzle"):a==="postgres"&&t==="prisma"&&s?await Ie(e,r):a==="mongodb"&&o&&await Re(e)}catch(c){throw i.stop(Me.red("Failed to set up database")),c instanceof Error&&ka.error(Me.red(c.message)),c}}import U from"node:path";import te from"fs-extra";async function me(e,a){await te.ensureDir(U.dirname(e));let t="";await te.pathExists(e)&&(t=await te.readFile(e,"utf8"));let r=!1;for(let{key:n,value:s,condition:o}of a)if(o){let i=new RegExp(`^${n}=.*$`,"m");i.test(t)?s&&(t=t.replace(i,`${n}=${s}`),r=!0):(t+=`
139
+ DATABASE_AUTH_TOKEN=your_auth_token`)}async function Be(e,a){if(!a){await J(e),G.info(T.blue("Skipping Turso setup. Setting up empty configuration.")),ee();return}let t=da.platform(),r=t==="darwin";if(!(t!=="win32")){G.warn(T.yellow("Automatic Turso setup is not supported on Windows.")),await J(e),ee();return}try{if(!await ga()){let w=await ua({message:"Would you like to install Turso CLI?",initialValue:!0});if(de(w)&&(le(T.red("Operation cancelled")),process.exit(0)),!w){await J(e),ee();return}await Pa(r)}await ba()||await wa();let i=await ja(),p=!1,c="",d=Oe.basename(e);for(;!p;){let w=await fa({message:"Enter a name for your database:",defaultValue:d,initialValue:d,placeholder:d});de(w)&&(le(T.red("Operation cancelled")),process.exit(0)),c=w;let $=ue();try{$.start(`Creating Turso database "${c}"${i?` in group "${i}"`:""}...`);let A=await va(c,i);await J(e,A),$.stop("Turso database configured successfully!"),p=!0}catch(A){if(A instanceof Error&&A.message==="DATABASE_EXISTS")$.stop(T.yellow(`Database "${T.red(c)}" already exists`)),d=`${c}-${Math.floor(Math.random()*1e3)}`;else throw $.stop(T.red("Failed to create Turso database")),A}}}catch(s){G.error(T.red(`Error during Turso setup: ${s}`)),await J(e),ee(),G.success("Setup completed with manual configuration required.")}}async function ze(e,a,t,r,n,s,o){let i=xa(),p=Le.join(e,"apps/server");if(a==="none"){await $a.remove(Le.join(p,"src/db"));return}try{t==="prisma"?g({dependencies:["@prisma/client"],devDependencies:["prisma"],projectDir:p}):t==="drizzle"&&(a==="sqlite"?g({dependencies:["drizzle-orm","@libsql/client"],devDependencies:["drizzle-kit"],projectDir:p}):a==="postgres"?g({dependencies:["drizzle-orm","pg"],devDependencies:["drizzle-kit","@types/pg"],projectDir:p}):a==="mysql"&&g({dependencies:["drizzle-orm","mysql2"],devDependencies:["drizzle-kit"],projectDir:p})),a==="sqlite"&&n?await Be(e,t==="drizzle"):a==="postgres"&&t==="prisma"&&s?await Ie(e,r):a==="mongodb"&&o&&await Re(e)}catch(c){throw i.stop(Me.red("Failed to set up database")),c instanceof Error&&ka.error(Me.red(c.message)),c}}import U from"node:path";import te from"fs-extra";async function me(e,a){await te.ensureDir(U.dirname(e));let t="";await te.pathExists(e)&&(t=await te.readFile(e,"utf8"));let r=!1;for(let{key:n,value:s,condition:o}of a)if(o){let i=new RegExp(`^${n}=.*$`,"m");i.test(t)?s&&(t=t.replace(i,`${n}=${s}`),r=!0):(t+=`
140
140
  ${n}=${s}`,r=!0)}r&&await te.writeFile(e,t.trim())}async function Ne(e,a){let t=U.join(e,"apps/server"),r=U.join(t,".env"),n=a.frontend.includes("react-router"),s=a.frontend.includes("tanstack-router"),o=a.frontend.includes("tanstack-start"),i=n||s||o,p="http://localhost:3000";n?p="http://localhost:5173":(s||o)&&(p="http://localhost:3001");let c="",d=a.dbSetup==="turso"||a.dbSetup==="prisma-postgres"||a.dbSetup==="mongodb-atlas";d||(a.database==="postgres"?c="postgresql://postgres:postgres@localhost:5432/mydb?schema=public":a.database==="mysql"?c="mysql://root:password@localhost:3306/mydb":a.database==="mongodb"?c="mongodb://localhost:27017/mydatabase":a.database==="sqlite"&&(c="file:./local.db"));let w=[{key:"CORS_ORIGIN",value:p,condition:!0},{key:"BETTER_AUTH_SECRET",value:$e(),condition:!!a.auth},{key:"BETTER_AUTH_URL",value:"http://localhost:3000",condition:!!a.auth},{key:"DATABASE_URL",value:c,condition:a.database!=="none"&&c!==""&&!d},{key:"GOOGLE_GENERATIVE_AI_API_KEY",value:"",condition:a.examples?.includes("ai")||!1}];if(await me(r,w),i){let $=U.join(e,"apps/web"),A=[{key:"VITE_SERVER_URL",value:"http://localhost:3000",condition:!0}];await me(U.join($,".env"),A)}if(a.frontend.includes("native")){let $=U.join(e,"apps/native"),A=[{key:"EXPO_PUBLIC_SERVER_URL",value:"http://localhost:3000",condition:!0}];await me(U.join($,".env"),A)}}import x from"node:path";import b from"fs-extra";async function Ue(e,a,t,r,n,s=["tanstack-router"]){let o=s.includes("tanstack-router"),i=s.includes("tanstack-start"),p=s.includes("react-router"),c=o||p||i,d;o?d="web-tanstack-router":i?d="web-tanstack-start":d="web-react-router";let w=await b.pathExists(x.join(e,"apps/web"));a.includes("todo")&&c&&w?await Ta(e,t,r,d):await Ra(e,t),a.includes("ai")&&(n==="hono"||n==="express")&&c&&w&&await Aa(e,d)}async function Aa(e,a){let t=x.join(v,"template/examples/ai");if(await b.pathExists(t)){let r=x.join(t,`apps/${a}/src/routes/ai.tsx`),n=x.join(e,"apps/web/src/routes/ai.tsx");await b.pathExists(r)&&await b.copy(r,n,{overwrite:!0}),await Ea(e,a);let s=x.join(e,"apps/web");g({dependencies:["ai"],projectDir:s});let o=x.join(e,"apps/server");g({dependencies:["ai","@ai-sdk/google"],projectDir:o}),await Sa(e)}}async function Sa(e){let a=x.join(e,"apps/server/src/index.ts");if(await b.pathExists(a)){let t=await b.readFile(a,"utf8"),r=t.includes("hono"),n=t.includes("express");if(r){let s=`import { streamText } from "ai";
141
141
  import { google } from "@ai-sdk/google";
142
142
  import { stream } from "hono/streaming";`,o=`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "1.10.2",
3
+ "version": "1.10.3",
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,5 +1,3 @@
1
- import { drizzle } from "drizzle-orm/postgres-js";
2
- import postgres from "postgres";
1
+ import { drizzle } from "drizzle-orm/node-postgres";
3
2
 
4
- const queryClient = postgres(process.env.DATABASE_URL || "");
5
- export const db = drizzle({ client: queryClient });
3
+ export const db = drizzle(process.env.DATABASE_URL || "");