create-better-t-stack 1.8.0 → 1.8.1
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 +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ ${i}`}let o=`VitePWA({
|
|
|
21
21
|
${o}`):a.includes("tanstack-router")?i=i.replace(/plugins: \[\s*tailwindcss\(\)/,`plugins: [
|
|
22
22
|
tailwindcss(),
|
|
23
23
|
${o}`):i=i.replace(/plugins: \[/,`plugins: [
|
|
24
|
-
${o},`)),await E.writeFile(n,i)}let s=N.join(r,"package.json");if(await E.pathExists(s)){let i=await E.readJson(s);i.scripts={...i.scripts,"generate-pwa-assets":"pwa-assets-generator"},await E.writeJson(s,i,{spaces:2})}}import re from"node:path";import{log as ge}from"@clack/prompts";import we from"picocolors";function be(e=32){let a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t="",r=a.length;for(let n=0;n<e;n++)t+=a.charAt(Math.floor(Math.random()*r));return t}async function Pe(e,a,t=[]){if(!a)return;let r=re.join(e,"apps/server"),n=re.join(e,"apps/web"),s=re.join(e,"apps/native");try{(t.includes("react-router")||t.includes("tanstack-router")||t.includes("tanstack-start"))&&
|
|
24
|
+
${o},`)),await E.writeFile(n,i)}let s=N.join(r,"package.json");if(await E.pathExists(s)){let i=await E.readJson(s);i.scripts={...i.scripts,"generate-pwa-assets":"pwa-assets-generator"},await E.writeJson(s,i,{spaces:2})}}import re from"node:path";import{log as ge}from"@clack/prompts";import we from"picocolors";function be(e=32){let a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t="",r=a.length;for(let n=0;n<e;n++)t+=a.charAt(Math.floor(Math.random()*r));return t}async function Pe(e,a,t=[]){if(!a)return;let r=re.join(e,"apps/server"),n=re.join(e,"apps/web"),s=re.join(e,"apps/native");try{b({dependencies:["better-auth"],projectDir:r}),(t.includes("react-router")||t.includes("tanstack-router")||t.includes("tanstack-start"))&&b({dependencies:["better-auth"],projectDir:n}),t.includes("native")&&(b({dependencies:["better-auth","@better-auth/expo"],projectDir:s}),b({dependencies:["@better-auth/expo"],projectDir:r}))}catch(i){throw ge.error(we.red("Failed to configure authentication")),i instanceof Error&&ge.error(we.red(i.message)),i}}import Lt from"node:path";async function ye(e,a,t){let r=Lt.join(e,"apps/server"),n=[],s=[];a==="hono"?(n.push("hono","@hono/trpc-server"),t==="node"&&(n.push("@hono/node-server"),s.push("tsx","@types/node"))):a==="elysia"&&(n.push("elysia","@elysiajs/cors","@elysiajs/trpc"),t==="node"&&(n.push("@elysiajs/node"),s.push("tsx","@types/node"))),t==="bun"&&s.push("@types/bun"),b({dependencies:n,devDependencies:s,projectDir:r})}import Nt from"node:path";import _t from"fs-extra";async function je(e,a){let t=Nt.join(e,"README.md"),r=Ut(a);try{await _t.writeFile(t,r)}catch(n){console.error("Failed to create README.md file:",n)}}function Ut(e){let{projectName:a,packageManager:t,database:r,auth:n,addons:s=[],orm:i="drizzle",runtime:o="bun",frontend:c=["tanstack-router"]}=e,p=c.includes("react-router"),l=c.includes("tanstack-router"),m=c.includes("native"),x=t==="npm"?"npm run":t,y=p?"5173":"3001";return`# ${a}
|
|
25
25
|
|
|
26
26
|
This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack that combines React, ${l?"TanStack Router":"React Router"}, Hono, tRPC, and more.
|
|
27
27
|
|
|
@@ -233,7 +233,7 @@ serve(
|
|
|
233
233
|
`)}}async function ze(e,a){let t=u.join($,`template/with-${a}`);await d.pathExists(t)&&await d.copy(t,e,{overwrite:!0})}async function Ge(e,a,t,r){if(a==="none"||t==="none")return;let n=u.join($,Oa(a,t));if(await d.pathExists(n)&&(await d.copy(n,e,{overwrite:!0}),!r)){if(a==="prisma"){let s=u.join(e,"apps/server/prisma/schema/auth.prisma");await d.pathExists(s)&&await d.remove(s)}else if(a==="drizzle"){let s=u.join(e,"apps/server/src/db/schema/auth.ts");await d.pathExists(s)&&await d.remove(s)}}}async function Ve(e,a,t,r,n,s){if(!a)return;let i=u.join($,"template/with-auth");if(await d.pathExists(i)){let o=s.includes("react-router"),c=s.includes("tanstack-router"),p=s.includes("tanstack-start");if(o||c||p){let A=u.join(e,"apps/web"),I=u.join(i,"apps/web-base");if(await d.pathExists(I)&&await d.copy(I,A,{overwrite:!0}),o){let O=u.join(i,"apps/web-react-router");await d.pathExists(O)&&await d.copy(O,A,{overwrite:!0})}if(c){let O=u.join(i,"apps/web-tanstack-router");await d.pathExists(O)&&await d.copy(O,A,{overwrite:!0})}if(p){let O=u.join(i,"apps/web-tanstack-start");await d.pathExists(O)&&await d.copy(O,A,{overwrite:!0})}}let l=u.join(i,"apps/server/src"),m=u.join(e,"apps/server/src");await d.copy(u.join(l,"lib/trpc.ts"),u.join(m,"lib/trpc.ts"),{overwrite:!0}),await d.copy(u.join(l,"routers/index.ts"),u.join(m,"routers/index.ts"),{overwrite:!0});let x=`with-${t}-context.ts`;await d.copy(u.join(l,"lib",x),u.join(m,"lib/context.ts"),{overwrite:!0});let y=`with-${t}-index.ts`;await d.copy(u.join(l,y),u.join(m,"index.ts"),{overwrite:!0});let C=Da(r,n),j=u.join(l,C);if(await d.pathExists(j)){let A=await d.readdir(j);for(let I of A)await d.copy(u.join(j,I),u.join(m,"lib",I),{overwrite:!0})}if(s.includes("native")){let A=u.join(i,"apps/native"),I=u.join(e,"apps/native");await d.pathExists(A)&&await d.copy(A,I,{overwrite:!0}),b({dependencies:["@better-auth/expo"],projectDir:u.join(e,"apps/server")}),await Ia(e,r,n)}}}async function Ia(e,a,t){let r=u.join(e,"apps/server"),n;if(a==="drizzle"?t==="sqlite"?n=u.join(r,"src/lib/auth.ts"):t==="postgres"&&(n=u.join(r,"src/lib/auth.ts")):a==="prisma"&&(t==="sqlite"?n=u.join(r,"src/lib/auth.ts"):t==="postgres"&&(n=u.join(r,"src/lib/auth.ts"))),n&&await d.pathExists(n)){let s=await d.readFile(n,"utf8");if(!s.includes("@better-auth/expo")){let i=`import { expo } from "@better-auth/expo";
|
|
234
234
|
`,o=s.lastIndexOf("import"),c=s.indexOf(`
|
|
235
235
|
`,o)+1;s=s.substring(0,c)+i+s.substring(c)}s.includes("plugins:")?s.includes("expo()")||(s=s.replace(/plugins: \[(.*?)\]/s,(i,o)=>`plugins: [${o}${o.trim()?", ":""}expo()]`)):s=s.replace(/}\);/,` plugins: [expo()],
|
|
236
|
-
});`),s.includes("my-better-t-app://")||(s=s.replace(/trustedOrigins: \[(.*?)\]/s,(i,o)=>`trustedOrigins: [${o}${o.trim()?", ":""}"my-better-t-app://"]`)),await d.writeFile(n,s)}}async function qe(e){let a=await We(e);for(let t of a)if(await d.pathExists(t)){let r=u.join(u.dirname(t),".gitignore");await d.move(t,r,{overwrite:!0})}}async function We(e){let a=[],t=u.join(e,"_gitignore");await d.pathExists(t)&&a.push(t);try{let r=await d.readdir(e,{withFileTypes:!0});for(let n of r)if(n.isDirectory()&&n.name!=="node_modules"){let s=u.join(e,n.name),i=await We(s);a.push(...i)}}catch{}return a}function Oa(e,a){return e==="drizzle"?a==="sqlite"?"template/with-drizzle-sqlite":"template/with-drizzle-postgres":e==="prisma"?a==="sqlite"?"template/with-prisma-sqlite":"template/with-prisma-postgres":"template/base"}function Da(e,a){if(e==="drizzle")return a==="sqlite"?"with-drizzle-sqlite-lib":"with-drizzle-postgres-lib";if(e==="prisma")return a==="sqlite"?"with-prisma-sqlite-lib":"with-prisma-postgres-lib";throw new Error("Invalid ORM or database configuration for auth setup")}async function He(e){let a=_a(),t=La.resolve(process.cwd(),e.projectName);try{return await Ua.ensureDir(t),await Me(t),await Be(t,e.frontend),await qe(t),await ze(t,e.backend),await ye(t,e.backend,e.runtime),await Ge(t,e.orm,e.database,e.auth),await Ae(t,e.database,e.orm,e.packageManager,e.turso??e.database==="sqlite",e.prismaPostgres),await Ve(t,e.auth,e.backend,e.orm,e.database,e.frontend),await Pe(t,e.auth,e.frontend),await Ue(t,e.runtime,e.backend),await Re(t,e.examples,e.orm,e.auth,e.backend,e.frontend),await Ce(t,e),await _e(t,e.git),e.addons.length>0&&await he(t,e.addons,e.packageManager,e.frontend),await Ne(t,e),await je(t,e),e.noInstall||await Oe({projectDir:t,packageManager:e.packageManager,addons:e.addons}),De(e.database,e.projectName,e.packageManager,!e.noInstall,e.orm,e.addons,e.runtime,e.frontend),t}catch(r){throw a.message(Je.red("Failed")),r instanceof Error&&(Na(Je.red(`Error during project creation: ${r.message}`)),process.exit(1)),r}}import{cancel as Mr,group as Br}from"@clack/prompts";import zr from"picocolors";import{cancel as Ma,isCancel as Ba,multiselect as za}from"@clack/prompts";import Ga from"picocolors";async function Qe(e,a){if(e!==void 0)return e;let t=a?.includes("react-router")||a?.includes("tanstack-router"),r=[{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)"}],s=t?[...[{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"}],...r]:r,i=w.addons.filter(c=>t||c!=="pwa"&&c!=="tauri"),o=await za({message:"Select addons",options:s,initialValues:i,required:!1});return Ba(o)&&(Ma(Ga.red("Operation cancelled")),process.exit(0)),o.includes("husky")&&!o.includes("biome")&&o.push("biome"),o}import{cancel as Va,confirm as qa,isCancel as Wa}from"@clack/prompts";import Ja from"picocolors";async function Ke(e,a,t){if(!a)return!1;if(e!==void 0)return e;let r=await qa({message:"Add authentication with Better-Auth?",initialValue:w.auth});return Wa(r)&&(Va(Ja.red("Operation cancelled")),process.exit(0)),r}import{cancel as Ha,isCancel as Qa,select as Ka}from"@clack/prompts";import Xa from"picocolors";async function Xe(e){if(e!==void 0)return e;let a=await Ka({message:"Select backend framework",options:[{value:"hono",label:"Hono",hint:"Lightweight, ultrafast web framework"},{value:"elysia",label:"Elysia",hint:"Ergonomic web framework for building backend servers"}],initialValue:w.backend});return Qa(a)&&(Ha(Xa.red("Operation cancelled")),process.exit(0)),a}import{cancel as Ya,isCancel as Za,select as er}from"@clack/prompts";import tr from"picocolors";async function Ye(e){if(e!==void 0)return e;let a=await er({message:"Select database",options:[{value:"none",label:"None",hint:"No database setup"},{value:"sqlite",label:"SQLite",hint:"by Turso"},{value:"postgres",label:"PostgreSQL",hint:"Traditional relational database"}],initialValue:w.database});return Za(a)&&(Ya(tr.red("Operation cancelled")),process.exit(0)),a}import{cancel as ar,isCancel as rr,multiselect as Ze}from"@clack/prompts";import nr from"picocolors";async function et(e,a,t,r){if(e!==void 0)return e;if(a==="none")return[];if(!(t?.includes("react-router")||t?.includes("tanstack-router")||t?.includes("tanstack-start")))return[];let s=[];return r==="elysia"&&(s=await Ze({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"}],required:!1,initialValues:w.examples})),r==="hono"&&(s=await Ze({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"},{value:"ai",label:"AI Chat",hint:"A simple AI chat interface using AI SDK"}],required:!1,initialValues:w.examples})),rr(s)&&(ar(nr.red("Operation cancelled")),process.exit(0)),s}import{cancel as tt,isCancel as at,multiselect as sr,select as ir}from"@clack/prompts";import rt from"picocolors";async function nt(e){if(e!==void 0)return e;let a=await sr({message:"Select platforms to develop for",options:[{value:"web",label:"Web",hint:"React Web Application"},{value:"native",label:"Native",hint:"Create a React Native/Expo app"}],initialValues:w.frontend.some(r=>r==="tanstack-router"||r==="react-router"||r==="tanstack-start")?["web"]:[]});at(a)&&(tt(rt.red("Operation cancelled")),process.exit(0));let t=[];if(a.includes("web")){let r=await ir({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\u2011obsessed, standards\u2011focused, multi\u2011strategy router you can deploy anywhere."},{value:"tanstack-start",label:"TanStack Start (beta)",hint:"SSR, Streaming, Server Functions, API Routes, bundling and more powered by TanStack Router and Vite."}],initialValue:w.frontend.find(n=>n==="tanstack-router"||n==="react-router"||n==="tanstack-start")||"tanstack-router"});at(r)&&(tt(rt.red("Operation cancelled")),process.exit(0)),t.push(r)}return a.includes("native")&&t.push("native"),t}import{cancel as or,confirm as cr,isCancel as pr}from"@clack/prompts";import lr from"picocolors";async function st(e){if(e!==void 0)return e;let a=await cr({message:"Initialize git repository?",initialValue:w.git});return pr(a)&&(or(lr.red("Operation cancelled")),process.exit(0)),a}import{cancel as dr,confirm as ur,isCancel as mr}from"@clack/prompts";import fr from"picocolors";async function it(e){if(e!==void 0)return e;let a=await ur({message:"Install dependencies?",initialValue:!w.noInstall});return mr(a)&&(dr(fr.red("Operation cancelled")),process.exit(0)),!a}import{cancel as hr,isCancel as gr,select as wr}from"@clack/prompts";import br from"picocolors";async function ot(e,a){if(!a)return"none";if(e!==void 0)return e;let t=await wr({message:"Select ORM",options:[{value:"drizzle",label:"Drizzle",hint:"Type-safe, lightweight ORM"},{value:"prisma",label:"Prisma",hint:"Powerful, feature-rich ORM"}],initialValue:w.orm});return gr(t)&&(hr(br.red("Operation cancelled")),process.exit(0)),t}import{cancel as Pr,isCancel as yr,select as jr}from"@clack/prompts";import kr from"picocolors";async function ct(e){if(e!==void 0)return e;let a=Q(),t=await jr({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:a});return yr(t)&&(Pr(kr.red("Operation cancelled")),process.exit(0)),t}import{cancel as vr,confirm as xr,isCancel as $r}from"@clack/prompts";import Er from"picocolors";async function pt(e){if(e!==void 0)return e;let a=await xr({message:"Set up Prisma Postgres database?",initialValue:w.prismaPostgres});return $r(a)&&(vr(Er.red("Operation cancelled")),process.exit(0)),a}import H from"node:path";import{cancel as Tr,isCancel as Ar,text as Cr}from"@clack/prompts";import z from"fs-extra";import Rr from"picocolors";var Sr=["<",">",":",'"',"|","?","*"],lt=255;function dt(e){if(e!=="."){if(!e)return"Project name cannot be empty";if(e.length>lt)return`Project name must be less than ${lt} characters`;if(Sr.some(a=>e.includes(a)))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"||e.toLowerCase()==="favicon.ico")return"Project name is reserved"}}async function ut(e){if(e)if(e==="."){let s=process.cwd();if(z.readdirSync(s).length===0)return e}else{let s=H.basename(e);if(!dt(s)){let o=H.resolve(process.cwd(),e);if(!z.pathExistsSync(o)||z.readdirSync(o).length===0)return e}}let a=!1,t="",r=w.projectName,n=1;for(;z.pathExistsSync(H.resolve(process.cwd(),r));)r=`${w.projectName}-${n}`,n++;for(;!a;){let s=await Cr({message:"Enter your project name or path (relative to current directory)",placeholder:r,initialValue:e,defaultValue:r,validate:i=>{let o=i.trim()||r;if(o==="."){if(z.readdirSync(process.cwd()).length>0)return"Current directory is not empty. Please choose a different directory.";a=!0;return}let c=H.resolve(process.cwd(),o),p=H.basename(c),l=dt(p);if(l)return l;if(!c.startsWith(process.cwd()))return"Project path must be within current directory";if(z.pathExistsSync(c)&&z.readdirSync(c).length>0)return`Directory "${o}" already exists and is not empty. Please choose a different name or path.`;a=!0}});Ar(s)&&(Tr(Rr.red("Operation cancelled.")),process.exit(0)),t=s||r}return t}import{cancel as Fr,isCancel as Ir,select as Or}from"@clack/prompts";import Dr from"picocolors";async function mt(e){if(e!==void 0)return e;let a=await Or({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:w.runtime});return Ir(a)&&(Fr(Dr.red("Operation cancelled")),process.exit(0)),a}import{cancel as Lr,confirm as Nr,isCancel as _r}from"@clack/prompts";import Ur from"picocolors";async function ft(e){if(e!==void 0)return e;let a=await Nr({message:"Set up Turso database?",initialValue:w.turso});return _r(a)&&(Lr(Ur.red("Operation cancelled")),process.exit(0)),a}async function ht(e){let a=await Br({projectName:async()=>ut(e.projectName),frontend:()=>nt(e.frontend),backend:()=>Xe(e.backend),runtime:()=>mt(e.runtime),database:()=>Ye(e.database),orm:({results:t})=>ot(e.orm,t.database!=="none"),auth:({results:t})=>Ke(e.auth,t.database!=="none",t.frontend),turso:({results:t})=>t.database==="sqlite"&&t.orm!=="prisma"?ft(e.turso):Promise.resolve(!1),prismaPostgres:({results:t})=>t.database==="postgres"&&t.orm==="prisma"?pt(e.prismaPostgres):Promise.resolve(!1),addons:({results:t})=>Qe(e.addons,t.frontend),examples:({results:t})=>et(e.examples,t.database,t.frontend,t.backend),git:()=>st(e.git),packageManager:()=>ct(e.packageManager),noInstall:()=>it(e.noInstall)},{onCancel:()=>{Mr(zr.red("Operation cancelled")),process.exit(0)}});return{projectName:a.projectName,frontend:a.frontend,database:a.database,orm:a.orm,auth:a.auth,addons:a.addons,examples:a.examples,git:a.git,packageManager:a.packageManager,noInstall:a.noInstall,turso:a.turso,prismaPostgres:a.prismaPostgres,backend:a.backend,runtime:a.runtime}}import R from"picocolors";function ce(e){let a=[];if(e.projectName&&a.push(`${R.blue("Project Name:")} ${e.projectName}`),e.frontend!==void 0){let t=e.frontend.length>0?e.frontend.join(", "):"none";a.push(`${R.blue("Frontend:")} ${t}`)}if(e.backend!==void 0&&a.push(`${R.blue("Backend Framework:")} ${e.backend}`),e.runtime!==void 0&&a.push(`${R.blue("Runtime:")} ${e.runtime}`),e.database!==void 0&&a.push(`${R.blue("Database:")} ${e.database}`),e.orm!==void 0&&a.push(`${R.blue("ORM:")} ${e.orm}`),e.auth!==void 0&&a.push(`${R.blue("Authentication:")} ${e.auth}`),e.addons!==void 0){let t=e.addons.length>0?e.addons.join(", "):"none";a.push(`${R.blue("Addons:")} ${t}`)}if(e.examples!==void 0){let t=e.examples.length>0?e.examples.join(", "):"none";a.push(`${R.blue("Examples:")} ${t}`)}return e.git!==void 0&&a.push(`${R.blue("Git Init:")} ${e.git}`),e.packageManager!==void 0&&a.push(`${R.blue("Package Manager:")} ${e.packageManager}`),e.noInstall!==void 0&&a.push(`${R.blue("Skip Install:")} ${e.noInstall}`),e.turso!==void 0&&a.push(`${R.blue("Turso Setup:")} ${e.turso}`),e.prismaPostgres!==void 0&&a.push(`${R.blue("Prisma Postgres Setup:")} ${e.prismaPostgres?"Yes":"No"}`),a.join(`
|
|
236
|
+
});`),s.includes("my-better-t-app://")||(s=s.replace(/trustedOrigins: \[(.*?)\]/s,(i,o)=>`trustedOrigins: [${o}${o.trim()?", ":""}"my-better-t-app://"]`)),await d.writeFile(n,s)}}async function qe(e){let a=await We(e);for(let t of a)if(await d.pathExists(t)){let r=u.join(u.dirname(t),".gitignore");await d.move(t,r,{overwrite:!0})}}async function We(e){let a=[],t=u.join(e,"_gitignore");await d.pathExists(t)&&a.push(t);try{let r=await d.readdir(e,{withFileTypes:!0});for(let n of r)if(n.isDirectory()&&n.name!=="node_modules"){let s=u.join(e,n.name),i=await We(s);a.push(...i)}}catch{}return a}function Oa(e,a){return e==="drizzle"?a==="sqlite"?"template/with-drizzle-sqlite":"template/with-drizzle-postgres":e==="prisma"?a==="sqlite"?"template/with-prisma-sqlite":"template/with-prisma-postgres":"template/base"}function Da(e,a){if(e==="drizzle")return a==="sqlite"?"with-drizzle-sqlite-lib":"with-drizzle-postgres-lib";if(e==="prisma")return a==="sqlite"?"with-prisma-sqlite-lib":"with-prisma-postgres-lib";throw new Error("Invalid ORM or database configuration for auth setup")}async function He(e){let a=_a(),t=La.resolve(process.cwd(),e.projectName);try{return await Ua.ensureDir(t),await Me(t),await Be(t,e.frontend),await qe(t),await ze(t,e.backend),await ye(t,e.backend,e.runtime),await Ge(t,e.orm,e.database,e.auth),await Ae(t,e.database,e.orm,e.packageManager,e.turso??e.database==="sqlite",e.prismaPostgres),await Ve(t,e.auth,e.backend,e.orm,e.database,e.frontend),await Pe(t,e.auth,e.frontend),await Ue(t,e.runtime,e.backend),await Re(t,e.examples,e.orm,e.auth,e.backend,e.frontend),await Ce(t,e),await _e(t,e.git),e.addons.length>0&&await he(t,e.addons,e.packageManager,e.frontend),await Ne(t,e),await je(t,e),e.noInstall||await Oe({projectDir:t,packageManager:e.packageManager,addons:e.addons}),De(e.database,e.projectName,e.packageManager,!e.noInstall,e.orm,e.addons,e.runtime,e.frontend),t}catch(r){throw a.message(Je.red("Failed")),r instanceof Error&&(Na(Je.red(`Error during project creation: ${r.message}`)),process.exit(1)),r}}import{cancel as Mr,group as Br}from"@clack/prompts";import zr from"picocolors";import{cancel as Ma,isCancel as Ba,multiselect as za}from"@clack/prompts";import Ga from"picocolors";async function Qe(e,a){if(e!==void 0)return e;let t=a?.includes("react-router")||a?.includes("tanstack-router"),r=[{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)"}],s=t?[...[{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"}],...r]:r,i=w.addons.filter(c=>t||c!=="pwa"&&c!=="tauri"),o=await za({message:"Select addons",options:s,initialValues:i,required:!1});return Ba(o)&&(Ma(Ga.red("Operation cancelled")),process.exit(0)),o.includes("husky")&&!o.includes("biome")&&o.push("biome"),o}import{cancel as Va,confirm as qa,isCancel as Wa}from"@clack/prompts";import Ja from"picocolors";async function Ke(e,a,t){if(!a)return!1;if(e!==void 0)return e;let r=await qa({message:"Add authentication with Better-Auth?",initialValue:w.auth});return Wa(r)&&(Va(Ja.red("Operation cancelled")),process.exit(0)),r}import{cancel as Ha,isCancel as Qa,select as Ka}from"@clack/prompts";import Xa from"picocolors";async function Xe(e){if(e!==void 0)return e;let a=await Ka({message:"Select backend framework",options:[{value:"hono",label:"Hono",hint:"Lightweight, ultrafast web framework"},{value:"elysia",label:"Elysia",hint:"Ergonomic web framework for building backend servers"}],initialValue:w.backend});return Qa(a)&&(Ha(Xa.red("Operation cancelled")),process.exit(0)),a}import{cancel as Ya,isCancel as Za,select as er}from"@clack/prompts";import tr from"picocolors";async function Ye(e){if(e!==void 0)return e;let a=await er({message:"Select database",options:[{value:"none",label:"None",hint:"No database setup"},{value:"sqlite",label:"SQLite",hint:"by Turso"},{value:"postgres",label:"PostgreSQL",hint:"Traditional relational database"}],initialValue:w.database});return Za(a)&&(Ya(tr.red("Operation cancelled")),process.exit(0)),a}import{cancel as ar,isCancel as rr,multiselect as Ze}from"@clack/prompts";import nr from"picocolors";async function et(e,a,t,r){if(e!==void 0)return e;if(a==="none")return[];if(!(t?.includes("react-router")||t?.includes("tanstack-router")||t?.includes("tanstack-start")))return[];let s=[];return r==="elysia"&&(s=await Ze({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"}],required:!1,initialValues:w.examples})),r==="hono"&&(s=await Ze({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"},{value:"ai",label:"AI Chat",hint:"A simple AI chat interface using AI SDK"}],required:!1,initialValues:w.examples})),rr(s)&&(ar(nr.red("Operation cancelled")),process.exit(0)),s}import{cancel as tt,isCancel as at,multiselect as sr,select as ir}from"@clack/prompts";import rt from"picocolors";async function nt(e){if(e!==void 0)return e;let a=await sr({message:"Select platforms to develop for",options:[{value:"web",label:"Web",hint:"React Web Application"},{value:"native",label:"Native",hint:"Create a React Native/Expo app"}],required:!1,initialValues:w.frontend.some(r=>r==="tanstack-router"||r==="react-router"||r==="tanstack-start")?["web"]:[]});at(a)&&(tt(rt.red("Operation cancelled")),process.exit(0));let t=[];if(a.includes("web")){let r=await ir({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\u2011obsessed, standards\u2011focused, multi\u2011strategy router you can deploy anywhere."},{value:"tanstack-start",label:"TanStack Start (beta)",hint:"SSR, Streaming, Server Functions, API Routes, bundling and more powered by TanStack Router and Vite."}],initialValue:w.frontend.find(n=>n==="tanstack-router"||n==="react-router"||n==="tanstack-start")||"tanstack-router"});at(r)&&(tt(rt.red("Operation cancelled")),process.exit(0)),t.push(r)}return a.includes("native")&&t.push("native"),t}import{cancel as or,confirm as cr,isCancel as pr}from"@clack/prompts";import lr from"picocolors";async function st(e){if(e!==void 0)return e;let a=await cr({message:"Initialize git repository?",initialValue:w.git});return pr(a)&&(or(lr.red("Operation cancelled")),process.exit(0)),a}import{cancel as dr,confirm as ur,isCancel as mr}from"@clack/prompts";import fr from"picocolors";async function it(e){if(e!==void 0)return e;let a=await ur({message:"Install dependencies?",initialValue:!w.noInstall});return mr(a)&&(dr(fr.red("Operation cancelled")),process.exit(0)),!a}import{cancel as hr,isCancel as gr,select as wr}from"@clack/prompts";import br from"picocolors";async function ot(e,a){if(!a)return"none";if(e!==void 0)return e;let t=await wr({message:"Select ORM",options:[{value:"drizzle",label:"Drizzle",hint:"Type-safe, lightweight ORM"},{value:"prisma",label:"Prisma",hint:"Powerful, feature-rich ORM"}],initialValue:w.orm});return gr(t)&&(hr(br.red("Operation cancelled")),process.exit(0)),t}import{cancel as Pr,isCancel as yr,select as jr}from"@clack/prompts";import kr from"picocolors";async function ct(e){if(e!==void 0)return e;let a=Q(),t=await jr({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:a});return yr(t)&&(Pr(kr.red("Operation cancelled")),process.exit(0)),t}import{cancel as vr,confirm as xr,isCancel as $r}from"@clack/prompts";import Er from"picocolors";async function pt(e){if(e!==void 0)return e;let a=await xr({message:"Set up Prisma Postgres database?",initialValue:w.prismaPostgres});return $r(a)&&(vr(Er.red("Operation cancelled")),process.exit(0)),a}import H from"node:path";import{cancel as Tr,isCancel as Ar,text as Cr}from"@clack/prompts";import z from"fs-extra";import Rr from"picocolors";var Sr=["<",">",":",'"',"|","?","*"],lt=255;function dt(e){if(e!=="."){if(!e)return"Project name cannot be empty";if(e.length>lt)return`Project name must be less than ${lt} characters`;if(Sr.some(a=>e.includes(a)))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"||e.toLowerCase()==="favicon.ico")return"Project name is reserved"}}async function ut(e){if(e)if(e==="."){let s=process.cwd();if(z.readdirSync(s).length===0)return e}else{let s=H.basename(e);if(!dt(s)){let o=H.resolve(process.cwd(),e);if(!z.pathExistsSync(o)||z.readdirSync(o).length===0)return e}}let a=!1,t="",r=w.projectName,n=1;for(;z.pathExistsSync(H.resolve(process.cwd(),r));)r=`${w.projectName}-${n}`,n++;for(;!a;){let s=await Cr({message:"Enter your project name or path (relative to current directory)",placeholder:r,initialValue:e,defaultValue:r,validate:i=>{let o=i.trim()||r;if(o==="."){if(z.readdirSync(process.cwd()).length>0)return"Current directory is not empty. Please choose a different directory.";a=!0;return}let c=H.resolve(process.cwd(),o),p=H.basename(c),l=dt(p);if(l)return l;if(!c.startsWith(process.cwd()))return"Project path must be within current directory";if(z.pathExistsSync(c)&&z.readdirSync(c).length>0)return`Directory "${o}" already exists and is not empty. Please choose a different name or path.`;a=!0}});Ar(s)&&(Tr(Rr.red("Operation cancelled.")),process.exit(0)),t=s||r}return t}import{cancel as Fr,isCancel as Ir,select as Or}from"@clack/prompts";import Dr from"picocolors";async function mt(e){if(e!==void 0)return e;let a=await Or({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:w.runtime});return Ir(a)&&(Fr(Dr.red("Operation cancelled")),process.exit(0)),a}import{cancel as Lr,confirm as Nr,isCancel as _r}from"@clack/prompts";import Ur from"picocolors";async function ft(e){if(e!==void 0)return e;let a=await Nr({message:"Set up Turso database?",initialValue:w.turso});return _r(a)&&(Lr(Ur.red("Operation cancelled")),process.exit(0)),a}async function ht(e){let a=await Br({projectName:async()=>ut(e.projectName),frontend:()=>nt(e.frontend),backend:()=>Xe(e.backend),runtime:()=>mt(e.runtime),database:()=>Ye(e.database),orm:({results:t})=>ot(e.orm,t.database!=="none"),auth:({results:t})=>Ke(e.auth,t.database!=="none",t.frontend),turso:({results:t})=>t.database==="sqlite"&&t.orm!=="prisma"?ft(e.turso):Promise.resolve(!1),prismaPostgres:({results:t})=>t.database==="postgres"&&t.orm==="prisma"?pt(e.prismaPostgres):Promise.resolve(!1),addons:({results:t})=>Qe(e.addons,t.frontend),examples:({results:t})=>et(e.examples,t.database,t.frontend,t.backend),git:()=>st(e.git),packageManager:()=>ct(e.packageManager),noInstall:()=>it(e.noInstall)},{onCancel:()=>{Mr(zr.red("Operation cancelled")),process.exit(0)}});return{projectName:a.projectName,frontend:a.frontend,database:a.database,orm:a.orm,auth:a.auth,addons:a.addons,examples:a.examples,git:a.git,packageManager:a.packageManager,noInstall:a.noInstall,turso:a.turso,prismaPostgres:a.prismaPostgres,backend:a.backend,runtime:a.runtime}}import R from"picocolors";function ce(e){let a=[];if(e.projectName&&a.push(`${R.blue("Project Name:")} ${e.projectName}`),e.frontend!==void 0){let t=e.frontend.length>0?e.frontend.join(", "):"none";a.push(`${R.blue("Frontend:")} ${t}`)}if(e.backend!==void 0&&a.push(`${R.blue("Backend Framework:")} ${e.backend}`),e.runtime!==void 0&&a.push(`${R.blue("Runtime:")} ${e.runtime}`),e.database!==void 0&&a.push(`${R.blue("Database:")} ${e.database}`),e.orm!==void 0&&a.push(`${R.blue("ORM:")} ${e.orm}`),e.auth!==void 0&&a.push(`${R.blue("Authentication:")} ${e.auth}`),e.addons!==void 0){let t=e.addons.length>0?e.addons.join(", "):"none";a.push(`${R.blue("Addons:")} ${t}`)}if(e.examples!==void 0){let t=e.examples.length>0?e.examples.join(", "):"none";a.push(`${R.blue("Examples:")} ${t}`)}return e.git!==void 0&&a.push(`${R.blue("Git Init:")} ${e.git}`),e.packageManager!==void 0&&a.push(`${R.blue("Package Manager:")} ${e.packageManager}`),e.noInstall!==void 0&&a.push(`${R.blue("Skip Install:")} ${e.noInstall}`),e.turso!==void 0&&a.push(`${R.blue("Turso Setup:")} ${e.turso}`),e.prismaPostgres!==void 0&&a.push(`${R.blue("Prisma Postgres Setup:")} ${e.prismaPostgres?"Yes":"No"}`),a.join(`
|
|
237
237
|
`)}function gt(e){let a=[];e.database==="none"?a.push("--database none"):(a.push(`--database ${e.database}`),e.orm&&a.push(`--orm ${e.orm}`),e.database==="sqlite"&&a.push(e.turso?"--turso":"--no-turso")),a.push(e.auth?"--auth":"--no-auth"),a.push(e.git?"--git":"--no-git"),a.push(e.noInstall?"--no-install":"--install"),e.runtime&&a.push(`--runtime ${e.runtime}`),e.backend&&a.push(`--backend ${e.backend}`),e.frontend&&e.frontend.length>0&&a.push(`--frontend ${e.frontend.join(" ")}`),e.addons&&e.addons.length>0?a.push(`--addons ${e.addons.join(" ")}`):a.push("--addons none"),e.examples&&e.examples.length>0?a.push(`--examples ${e.examples.join(" ")}`):a.push("--no-examples"),e.packageManager&&a.push(`--package-manager ${e.packageManager}`);let t="",r=e.packageManager;r==="npm"?t="npx create-better-t-stack@latest":r==="pnpm"?t="pnpm create better-t-stack@latest":r==="bun"&&(t="bun create better-t-stack@latest");let n=e.projectName?` ${e.projectName}`:"";return`${t}${n} ${a.join(" ")}`}import Gr from"node:path";import Vr from"fs-extra";var wt=()=>{let e=Gr.join($,"package.json");return Vr.readJSONSync(e).version??"1.0.0"};import bt from"gradient-string";var Pt=`
|
|
238
238
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
239
239
|
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
package/package.json
CHANGED