create-imr-app
Version:
Create web application with the imr stack
77 lines (72 loc) • 30.3 kB
JavaScript
import pe from"path";import{execa as Qe}from"execa";import me from"fs-extra";import*as P from"@clack/prompts";import Lt from"chalk";import{Command as Te}from"commander";import Y from"path";import{fileURLToPath as ue}from"url";var fe=ue(import.meta.url),ge=Y.dirname(fe),j=Y.join(ge,"../"),A=Y.join(j,"template/extras"),u=t=>Y.join(A,t),vt=` ___ __ __ ____ _ ___ ____ _____ ____
|_ _| \\/ | _ \\| | / _ \\| _ \\| ____|__ /
| || |\\/| | |_) | | | | | | |_) | _| / /
| || | | | _ <| |__| |_| | __/| |___ / /_
|___|_| |_|_| \\_\\\\____\\___/|_| |_____/____|
`,Q="my-fast-app",st="IMR-Project CLI",q={sqlite:"with-sqlite",postgres:"with-pg"};import f from"path";import w from"fs-extra";import Pt from"path";import xt from"fs-extra";import he from"sort-package-json";var St={"better-auth":"1.3.18","drizzle-kit":"0.31.5","drizzle-orm":"0.44.5",postgres:"3.4.7","@libsql/client":"0.15.15",tailwindcss:"4.1.13",postcss:"8.5.3","@tailwindcss/postcss":"4.0.15","@tailwindcss/vite":"4.1.13","@trpc/client":"11.6.0","@trpc/next":"11.6.0","@trpc/react-query":"11.6.0","@trpc/server":"11.6.0","@tanstack/react-query":"5.90.2",superjson:"2.2.1","server-only":"0.0.1","@trpc/tanstack-react-query":"11.6.0","@biomejs/biome":"2.2.2","@apollo/server":"5.0.0","@as-integrations/next":"4.0.0",graphql:"16.8.1","@graphql-tools/schema":"10.0.0"};var y=t=>{let{dependencies:e,devMode:n,projectDir:o}=t,s=xt.readJSONSync(Pt.join(o,"package.json"));e.forEach(i=>{let a=St[i];n&&s.devDependencies?s.devDependencies[i]=a:s.dependencies&&(s.dependencies[i]=a)});let r=he(s);xt.writeJSONSync(Pt.join(o,"package.json"),r,{spaces:2})};import ye from"path";import It from"fs-extra";import be from"sort-package-json";var L=t=>{let{scripts:e,projectDir:n}=t,o=ye.join(n,"package.json"),s=It.readJSONSync(o);s.scripts={...s.scripts,...e};let r=be(s);It.writeJSONSync(o,r,{spaces:2})};var _t=({projectDir:t,packages:e,databaseProvider:n,framework:o})=>{let s=e?.drizzle.inUse;y({projectDir:t,dependencies:["better-auth"],devMode:!1});let i=u(o),a="src/app/api/auth/[...all]/route.ts",c=f.join(i,a),m=f.join(t,a);w.copySync(c,m);let d="src/lib/$auth/index.ts",S=f.join(i,d),k=f.join(t,d),h="src/middleware.ts",x=f.join(i,h),R=f.join(t,h),U="src/hooks/use-auth.ts",H=f.join(i,U),E=f.join(t,U);if(w.copySync(S,k),w.copySync(x,R),w.copySync(H,E),s){let G=`src/server/auth/${q[n]}-index.ts`,nt=f.join(i,G),K=f.join(t,"src/server/auth/index.ts");w.ensureDirSync(f.dirname(K)),w.copySync(nt,K)}L({projectDir:t,scripts:{"auth:gen":"@better-auth/cli generate --config ./src/server/auth/index.ts"}})},wt=({projectDir:t,packages:e,databaseProvider:n,framework:o})=>{let s=e?.drizzle.inUse;y({projectDir:t,dependencies:["better-auth"],devMode:!1});let i=u(o),a="src/app/api/auth/$.ts",c=f.join(i,a),m=f.join(t,a);w.copySync(c,m);let d="src/lib/$auth/index.ts",S=f.join(i,d),k=f.join(t,d),h="src/hooks/use-auth.ts",x=f.join(i,h),R=f.join(t,h);if(w.copySync(S,k),w.copySync(x,R),s){let U=`src/server/auth/${q[n]}-index.ts`,H=f.join(i,U),E=f.join(t,"src/server/auth/index.ts");w.ensureDirSync(f.dirname(E)),w.copySync(H,E)}};import F from"path";import rt from"fs-extra";var kt=({projectDir:t,framework:e})=>{y({projectDir:t,dependencies:["tailwindcss","postcss","@tailwindcss/postcss"],devMode:!0});let n=u(e),o=F.join(A,"config/postcss.config.js"),s=F.join(t,"postcss.config.js"),r=F.join(n,"src/app/globals.css"),i=F.join(t,"src/app/globals.css");rt.copySync(o,s),rt.copySync(r,i)},Tt=({projectDir:t,framework:e})=>{y({projectDir:t,dependencies:["tailwindcss","@tailwindcss/vite"],devMode:!0});let n=u(e),o=F.join(n,"src/app/index.css"),s=F.join(t,"src/app/index.css");rt.copySync(o,s)};import I from"path";import At from"fs-extra";var Ct=({projectDir:t,packages:e,framework:n})=>{y({projectDir:t,dependencies:["@tanstack/react-query","superjson","@trpc/server","@trpc/client","@trpc/react-query","@trpc/tanstack-react-query","server-only"],devMode:!1});let o=e?.["better-auth"].inUse,s={SERVER:{INIT:{DEST:"src/server/trpc/init.ts",WITH_AUTH:"src/server/trpc/with-auth-init.ts",NO_AUTH:"src/server/trpc/init.ts"},ROOT:{DEST:"src/server/trpc/root.ts",WITH_AUTH:"src/server/trpc/root.ts",NO_AUTH:"src/server/trpc/root.ts"},ROUTES:{DEST:"src/server/trpc/routes",WITH_AUTH:"src/server/trpc/routes",NO_AUTH:"src/server/trpc/routes"}},CLIENT:{SRC:"src/lib/trpc",DEST:"src/lib/trpc"},API_HANDLER:{DEST:"src/app/api/[trpc]/route.ts",SRC:"src/app/api/[trpc]/route.ts"}},r=u(n),i=[];i.push([I.join(r,s.CLIENT.SRC),I.join(t,s.CLIENT.DEST)]),i.push([I.join(r,s.API_HANDLER.SRC),I.join(t,s.API_HANDLER.DEST)]),Object.values(s.SERVER).forEach(({DEST:a,NO_AUTH:c,WITH_AUTH:m})=>{i.push([I.join(r,o?m:c),I.join(t,a)])}),i.forEach(([a,c])=>{At.copySync(a,c)})},Et=({projectDir:t,packages:e,framework:n})=>{y({projectDir:t,dependencies:["@tanstack/react-query","superjson","@trpc/server","@trpc/client","@trpc/react-query","@trpc/tanstack-react-query"],devMode:!1});let o=e?.["better-auth"].inUse,s={SERVER:{INIT:{DEST:"src/server/trpc/init.ts",WITH_AUTH:"src/server/trpc/with-auth-init.ts",NO_AUTH:"src/server/trpc/init.ts"},ROOT:{DEST:"src/server/trpc/root.ts",WITH_AUTH:"src/server/trpc/root.ts",NO_AUTH:"src/server/trpc/root.ts"},ROUTES:{DEST:"src/server/trpc/routes",WITH_AUTH:"src/server/trpc/routes",NO_AUTH:"src/server/trpc/routes"}},CLIENT:{SRC:"src/lib/trpc",DEST:"src/lib/trpc"},API_HANDLER:{DEST:"src/app/api/trpc/$.ts",SRC:"src/app/api/trpc/$.ts"}},r=u(n),i=[];i.push([I.join(r,s.CLIENT.SRC),I.join(t,s.CLIENT.DEST)]),i.push([I.join(r,s.API_HANDLER.SRC),I.join(t,s.API_HANDLER.DEST)]),Object.values(s.SERVER).forEach(({DEST:a,NO_AUTH:c,WITH_AUTH:m})=>{i.push([I.join(r,o?m:c),I.join(t,a)])}),i.forEach(([a,c])=>{At.copySync(a,c)})};import jt from"path";import ve from"fs-extra";var it=({projectDir:t})=>{y({projectDir:t,dependencies:["@biomejs/biome"],devMode:!0});let e=jt.join(A,"config/biome.jsonc"),n=jt.join(t,"biome.json");ve.copySync(e,n),L({projectDir:t,scripts:{lint:"biome check --write --unsafe .","check:unsafe":"biome check --write --unsafe .","check:write":"biome check --write .",check:"biome check ."}})};import at from"fs";import Nt from"path";import Rt from"path";var X=t=>(t.length>1&&t.endsWith("/")&&(t=t.slice(0,-1)),t);var Z=t=>{let n=X(t).split("/"),o=n[n.length-1];if(o==="."){let i=Rt.resolve(process.cwd());o=Rt.basename(i)}let s=n.findIndex(i=>i.startsWith("@"));n.findIndex(i=>i.startsWith("@"))!==-1&&(o=n.slice(s).join("/"));let r=n.filter(i=>!i.startsWith("@")).join("/");return[o,r]};var Se=t=>t.replace(/[^a-zA-Z0-9_.-]/g,"_").toLowerCase(),ct=({projectDir:t,databaseProvider:e,projectName:n})=>{let o=Nt.join(A,`start-database/${e}.sh`),s=at.readFileSync(o,"utf-8"),r=Nt.join(t,"start-database.sh"),[i]=n==="."?Z(t):[n],a=Se(i);at.writeFileSync(r,s.replaceAll("project1",a)),at.chmodSync(r,"755")};import b from"path";import T from"fs-extra";var N={INDEX:"src/server/db/entities/index.ts",SCHEMA:"src/server/db/entities/schemas.entity.ts",AUTH:"src/server/db/entities/auth.entity.ts",CLIENT:"src/server/db/index.ts",CONFIG:"drizzle.config.ts",ENTITIES_DIR:"src/server/db/entities"},lt=({projectDir:t,packages:e,scopedAppName:n,databaseProvider:o,framework:s,projectName:r})=>{y({projectDir:t,dependencies:["drizzle-kit"],devMode:!0}),y({projectDir:t,dependencies:["drizzle-orm",{postgres:"postgres",sqlite:"@libsql/client"}[o]],devMode:!1});let i=u(s),a=b.join(A,`config/drizzle-config-${o}.ts`),c=b.join(t,N.CONFIG),m=b.join(i,N.ENTITIES_DIR);if(e?.["better-auth"])switch(o){case"postgres":{let E=b.join(m,"with-pg-schema.ts"),G=b.join(t,N.SCHEMA),nt=b.join(m,"with-pg-auth.ts"),K=b.join(t,N.AUTH),de=`DATABASE_URL=postgresql://postgres:postgres@localhost:5432/${r}`,bt=b.join(t,".env");T.existsSync(bt)||T.writeFileSync(bt,de),T.copySync(E,G),T.copySync(nt,K);break}case"sqlite":{let E=b.join(m,"with-sqlite-auth.ts"),G=b.join(t,N.AUTH);T.copySync(E,G);break}}let d=b.join(m,"index.ts"),S=b.join(t,N.INDEX),k=`src/server/db/${q[o]}-index.ts`,h=b.join(i,k),x=b.join(t,N.CLIENT);L({projectDir:t,scripts:{"db:push":"drizzle-kit push","db:studio":"drizzle-kit studio","db:generate":"drizzle-kit generate","db:migrate":"drizzle-kit migrate"}}),T.copySync(a,c),T.mkdirSync(b.dirname(S),{recursive:!0}),T.copySync(d,S),T.copySync(h,x);let R=b.join(t,"src/lib/env.ts"),U=n.replace(/-/g,"_"),H=o==="sqlite"?xe:Pe(U);T.appendFileSync(R,H)},Pe=t=>`
import { z } from 'zod'
export const env = z
.object({
NODE_ENV: z
.enum(['development', 'production', 'test'])
.default('development'),
DATABASE_URL: z.string().default('postgres://postgres:postgres@localhost:5432/${t}'),
AUTH_SECRET: z.string().default('SUPER_SECRET_KEY'),
})
.parse(process.env)
`,xe=`
import { z } from 'zod'
export const env = z
.object({
NODE_ENV: z
.enum(['development', 'production', 'test'])
.default('development'),
DATABASE_URL: z.string().default('file:./src/server/db/dev.db'),
DB_AUTH_TOKEN: z.string().optional(),
AUTH_SECRET: z.string().default('SUPER_SECRET_KEY'),
})
.parse(process.env)
`;import Dt from"path";import Ie from"fs-extra";var pt=({projectDir:t,framework:e})=>{y({projectDir:t,dependencies:["@apollo/server","@as-integrations/next","graphql","@graphql-tools/schema"],devMode:!1});let o=u(e),s="src/app/api/graphql/route.ts",r=Dt.join(o,s),i=Dt.join(t,s);Ie.copySync(r,i)};var tt=["postgres","sqlite"],Ot=(t,e)=>({"better-auth":{inUse:t.includes("better-auth"),installer:_t},drizzle:{inUse:t.includes("drizzle"),installer:lt},tailwind:{inUse:t.includes("tailwind"),installer:kt},trpc:{inUse:t.includes("trpc"),installer:Ct},dbContainer:{inUse:["postgres"].includes(e),installer:ct},biome:{inUse:t.includes("biome"),installer:it},graphql:{inUse:t.includes("graphql"),installer:pt}}),zt=(t,e)=>({"better-auth":{inUse:t.includes("better-auth"),installer:wt},drizzle:{inUse:t.includes("drizzle"),installer:lt},tailwind:{inUse:t.includes("tailwind"),installer:Tt},trpc:{inUse:t.includes("trpc"),installer:Et},dbContainer:{inUse:["postgres"].includes(e),installer:ct},biome:{inUse:t.includes("biome"),installer:it},graphql:{inUse:t.includes("graphql"),installer:pt}});import _e from"path";import we from"fs-extra";var $=()=>{let t=_e.join(j,"package.json");return we.readJSONSync(t).version??"1.0.0"};var _=()=>{let t=process.env.npm_config_user_agent;return t?t.startsWith("yarn")?"yarn":t.startsWith("pnpm")?"pnpm":t.startsWith("bun")?"bun":"npm":"npm"};var V=class extends Error{constructor(e){super(e)}};import et from"chalk";var l={error(...t){console.log(et.red(...t))},warn(...t){console.log(et.yellow(...t))},info(...t){console.log(et.cyan(...t))},success(...t){console.log(et.green(...t))}};var ke=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,Mt=t=>{let e=X(t),n=e.split("/"),o=n.findIndex(r=>r.startsWith("@")),s=n[n.length-1];if(n.findIndex(r=>r.startsWith("@"))!==-1&&(s=n.slice(o).join("/")),!(e==="."||ke.test(s??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};var Ut=t=>{if(t.startsWith(".")||t.startsWith("/"))return"Import alias can't start with '.' or '/'"};var D={appName:Q,packages:["better-auth","drizzle","tailwind","trpc","biome"],framework:"next",flags:{noGit:!1,noInstall:!1,default:!1,CI:!1,tailwind:!0,trpc:!0,drizzle:!0,betterAuth:!0,importAlias:"@/",appRouter:!0,dbProvider:"postgres",biome:!0,graphql:!1},databaseProvider:"postgres"},Ft=async()=>{let t=D,e=new Te().name(st).description("A CLI for creating web applications with the fast vibe stack").argument("[dir]","The name of the application, as well as the name of the directory to create").option("--noGit","Explicitly tell the CLI to not initialize a new git repo in the project",!1).option("--noInstall","Explicitly tell the CLI to not run the package manager's install command",!1).option("-y, --default","Bypass the CLI and use all default options to bootstrap a new t3-app",!1).option("--framework [framework]","Choose the framework to use. Possible values: next, tanstack-star","next").option("--trpc [boolean]","Experimental: Boolean value if we should install tRPC. Must be used in conjunction with `--CI`.",o=>!!o&&o!=="false").option("--graphql [boolean]","Experimental: Boolean value if we should install GraphQL. Must be used in conjunction with `--CI`.",o=>!!o&&o!=="false").option("-i, --import-alias","Explicitly tell the CLI to use a custom import alias",D.flags.importAlias).option("--dbProvider [provider]",`Choose a database provider to use. Possible values: ${tt.join(", ")}`,D.flags.dbProvider).option("--appRouter [boolean]","Explicitly tell the CLI to use the new Next app router",o=>!!o&&o!=="false").version($(),"-v, --version","Display the version number").addHelpText("afterAll",`
Run ${Lt.bold.green("npx create-imr-app@latest")} to use the latest version without installing.
Visit ${Lt.underline.blue("https://imrlopez.dev/")} for more information.
`).parse(process.argv);process.env.npm_config_user_agent?.startsWith("yarn/3")&&l.warn(` WARNING: It looks like you are using Yarn 3. This is currently not supported,
and likely to result in a crash. Please run create-imr-app with another
package manager such as pnpm, npm, or Yarn Classic.
See: https://github.com/t3-oss/create-imr-app/issues/57`);let n=e.args[0];if(n&&(t.appName=n),t.flags=e.opts(),t.flags.CI)return t.packages=[],t.flags.trpc&&t.packages.push("trpc"),t.flags.tailwind&&t.packages.push("tailwind"),t.flags.drizzle&&t.packages.push("drizzle"),t.flags.betterAuth&&t.packages.push("better-auth"),t.flags.biome&&t.packages.push("biome"),t.flags.graphql&&t.packages.push("graphql"),tt.includes(t.flags.dbProvider)===!1&&(l.warn(`Incompatible database provided. Use: ${tt.join(", ")}. Exiting.`),process.exit(0)),t.databaseProvider=t.packages.includes("drizzle")?t.flags.dbProvider:"sqlite",t;if(t.flags.default)return t;try{if(process.env.TERM_PROGRAM?.toLowerCase().includes("mintty"))throw l.warn(` WARNING: It looks like you are using MinTTY, which is non-interactive. This is most likely because you are
using Git Bash. If that's that case, please use Git Bash from another terminal, such as Windows Terminal. Alternatively, you
can provide the arguments from the CLI directly: https://create.t3.gg/en/installation#experimental-usage to skip the prompts.`),new V("Non-interactive environment");let o=_(),s=await P.group({...!n&&{name:()=>P.text({message:"What will your project be called?",defaultValue:n,validate:Mt})},framework:()=>P.select({message:"What framework would you like to use?",options:[{value:"next",label:"Next.js"},{value:"tanstack-star",label:"TanStack Star"}],initialValue:"next"}),authentication:()=>P.select({message:"What authentication would you like to use?",options:[{value:"none",label:"No authentication"},{value:"better-auth",label:"Better Auth"}],initialValue:"better-auth"}),databaseProvider:()=>P.select({message:"What database provider would you like to use?",options:[{value:"postgres",label:"PostgreSQL"},{value:"sqlite",label:"SQLite"}],initialValue:"postgres"}),apiLayer:({results:i})=>P.select({message:"What API layer would you like to use?",options:[{value:"trpc",label:"tRPC (recommended)"},...i.framework==="next"?[{value:"graphql",label:"GraphQL"},{value:"both",label:"Both tRPC and GraphQL"}]:[]],initialValue:"trpc"}),...!t.flags.noGit&&{git:()=>P.confirm({message:"Should we initialize a Git repository and stage the changes?",initialValue:!D.flags.noGit})},...!t.flags.noInstall&&{install:()=>P.confirm({message:`Should we run '${o}`+(o==="yarn"?"'?":" install' for you?"),initialValue:!D.flags.noInstall})},importAlias:()=>P.text({message:"What import alias would you like to use?",defaultValue:D.flags.importAlias,placeholder:D.flags.importAlias,validate:Ut})},{onCancel(){process.exit(1)}}),r=[];return r.push("tailwind","drizzle","biome"),s.authentication==="better-auth"&&r.push("better-auth"),s.apiLayer==="trpc"&&r.push("trpc"),s.apiLayer==="graphql"&&r.push("graphql"),s.apiLayer==="both"&&r.push("trpc","graphql"),{appName:s.name??t.appName,packages:r,framework:s.framework,databaseProvider:s.databaseProvider||"postgres",flags:{...t.flags,appRouter:!0,noGit:!s.git||t.flags.noGit,noInstall:!s.install||t.flags.noInstall,importAlias:s.importAlias??t.flags.importAlias}}}catch(o){if(o instanceof V)l.warn(`
${st} needs an interactive terminal to provide options`),await P.confirm({message:"Continue scaffolding a default T3 app?",initialValue:!0})||(l.info("Exiting..."),process.exit(0)),l.info(`Bootstrapping a default T3 app in ./${t.appName}`);else throw o}return t};import Re from"fs";import mt from"path";import $t from"chalk";import Ae from"ora";var Ht=t=>{let{packages:e}=t;l.info("Adding boilerplate...");for(let[n,o]of Object.entries(e))if(o.inUse){let s=Ae(`Boilerplating ${n}...`).start();o.installer(t),s.succeed($t.green(`Successfully setup boilerplate for ${$t.green.bold(n)}`))}l.info("")};import g from"path";import C from"fs-extra";var Gt=({projectDir:t,framework:e})=>{let n=g.join(u(e),"src/app/"),o=g.join(n,"layout.tsx"),s=g.join(t,"src/app/layout.tsx");C.copySync(o,s)},qt=({projectDir:t,packages:e,framework:n})=>{let o=g.join(u(n),"src/app"),s=g.join(o,"page.tsx"),r=g.join(t,"src/app/page.tsx");if(C.copySync(s,r),e?.["better-auth"].inUse){let i=g.join(o,"(unauth)"),a=g.join(t,"src/app/(unauth)");C.copySync(i,a)}},Vt=({projectDir:t,packages:e,framework:n})=>{let o=g.join(u(n),"src/components/"),s=g.join(o,"ui"),r=g.join(t,"src/components/ui");C.copySync(s,r);let i=g.join(o,"providers"),a=g.join(t,"src/components/providers");C.ensureDirSync(a);let c=Ce({auth:e?.["better-auth"]?.inUse??!1,trpc:e?.trpc?.inUse??!1});if(C.writeFileSync(g.join(a,"index.tsx"),c),C.copySync(g.join(i,"theme.tsx"),g.join(a,"theme.tsx")),e?.["better-auth"].inUse){C.copySync(g.join(i,"auth.tsx"),g.join(a,"auth.tsx"));let m=g.join(o,"auth"),d=g.join(t,"src/components/auth");C.copySync(m,d)}};function Ce(t){let e=['import { Toaster } from "~ui/sonner";','import type { PropsWithChildren } from "react";','import { ThemeProvider } from "./theme";'],n=[{open:'<ThemeProvider attribute="class" defaultTheme="system" enableSystem>',close:"</ThemeProvider>"}];t.trpc&&(e.push("import { TRPCReactProvider } from '~lib/trpc/react';"),n.unshift({open:"<TRPCReactProvider>",close:"</TRPCReactProvider>"})),t.auth&&(e.push('import { AuthProvider } from "./auth";'),n.splice(t.trpc?1:0,0,{open:"<AuthProvider>",close:"</AuthProvider>"}));let o=n.map(r=>r.open).join(`
`),s=n.map(r=>r.close).reverse().join(`
`);return`${e.join(`
`)}
export function Providers({ children }: PropsWithChildren) {
return (
${o}
{children}
<Toaster richColors position="top-center" />
${s}
);
}`}import ot from"path";import*as z from"@clack/prompts";import O from"chalk";import W from"fs-extra";import Ee from"ora";var Wt=async({projectName:t,projectDir:e,pkgManager:n,noInstall:o,framework:s})=>{let i={next:ot.join(j,"template/base/nextjs"),"tanstack-star":ot.join(j,"template/base/tts")}[s];if(!i)throw new Error(`Unsupported framework: ${s}`);o?l.info(""):l.info(`
Using: ${O.cyan.bold(n)}
`);let a=Ee(`Scaffolding in: ${e}...
`).start();if(W.existsSync(e))if(W.readdirSync(e).length===0)t!=="."&&a.info(`${O.cyan.bold(t)} exists but is empty, continuing...
`);else{a.stopAndPersist();let m=await z.select({message:`${O.redBright.bold("Warning:")} ${O.cyan.bold(t)} already exists and isn't empty. How would you like to proceed?`,options:[{label:"Abort installation (recommended)",value:"abort"},{label:"Clear the directory and continue installation",value:"clear"},{label:"Continue installation and overwrite conflicting files",value:"overwrite"}],initialValue:"abort"});(z.isCancel(m)||m==="abort")&&(a.fail("Aborting installation..."),process.exit(1));let d=await z.confirm({message:`Are you sure you want to ${m==="clear"?"clear the directory":"overwrite conflicting files"}?`,initialValue:!1});(z.isCancel(d)||!d)&&(a.fail("Aborting installation..."),process.exit(1)),m==="clear"&&(a.info(`Emptying ${O.cyan.bold(t)} and creating t3 app..
`),W.emptyDirSync(e))}a.start(),W.copySync(i,e),W.renameSync(ot.join(e,"_gitignore"),ot.join(e,".gitignore"));let c=t==="."?"App":O.cyan.bold(t);a.succeed(`${c} ${O.green("scaffolded successfully!")}
`)};import p from"path";import v from"fs-extra";var Bt=({projectDir:t,framework:e,packages:n})=>{let o=p.join(u(e),"src"),s=p.join(o,"app"),r=p.join(o,"routeTree.gen.ts"),i=p.join(t,"src/routeTree.gen.ts");if(v.copySync(r,i),n?.["better-auth"].inUse){let a=p.join(o,"with-auth-router.tsx"),c=p.join(t,"src/router.tsx");v.copySync(a,c);let m=p.join(s,"with-auth-root.tsx"),d=p.join(t,"src/app/__root.tsx");v.copySync(m,d)}else{let a=p.join(o,"router.tsx"),c=p.join(t,"src/router.tsx");v.copySync(a,c);let m=p.join(s,"root.tsx"),d=p.join(t,"src/app/__root.tsx");v.copySync(m,d)}},Jt=({projectDir:t,packages:e,framework:n})=>{let o=p.join(u(n),"src/app");if(e?.["better-auth"].inUse){let s=p.join(o,"_auth"),r=p.join(t,"src/app/_auth");v.copySync(s,r);let i=p.join(o,"_unauth"),a=p.join(t,"src/app/_unauth");v.copySync(i,a)}else{let s=p.join(o,"_auth/index.tsx"),r=p.join(t,"src/app/index.tsx");v.copySync(s,r)}},Kt=({projectDir:t,packages:e,framework:n})=>{let o=p.join(u(n),"src/components/"),s=p.join(o,"ui"),r=p.join(t,"src/components/ui");v.copySync(s,r);let i=p.join(u(n),"src/hooks"),a=p.join(t,"src/hooks");v.copySync(i,a);let c=p.join(o,"loader.tsx"),m=p.join(t,"src/components/loader.tsx");v.copySync(c,m);let d=p.join(o,"providers"),S=p.join(t,"src/components/providers");v.ensureDirSync(S);let k=je({auth:e?.["better-auth"]?.inUse??!1,trpc:e?.trpc?.inUse??!1});if(v.writeFileSync(p.join(S,"index.tsx"),k),v.copySync(p.join(d,"theme"),p.join(S,"theme")),e?.["better-auth"].inUse){v.copySync(p.join(d,"auth.tsx"),p.join(S,"auth.tsx"));let h=p.join(o,"auth"),x=p.join(t,"src/components/auth");v.copySync(h,x)}};function je(t){let e=['import { Toaster } from "~ui/sonner";','import type { PropsWithChildren } from "react";','import { ThemeProvider } from "./theme";'],n=[{open:'<ThemeProvider attribute="class" defaultTheme="system" enableSystem>',close:"</ThemeProvider>"}];t.auth&&(e.push('import { AuthProvider } from "./auth";'),n.splice(t.trpc?1:0,0,{open:"<AuthProvider>",close:"</AuthProvider>"}));let o=n.map(r=>r.open).join(`
`),s=n.map(r=>r.close).reverse().join(`
`);return`${e.join(`
`)}
export function Providers({ children }: PropsWithChildren) {
return (
${o}
{children}
<Toaster richColors position="top-center" />
${s}
);
}`}var Yt=async({projectName:t,scopedAppName:e,packages:n,noInstall:o,appRouter:s,framework:r,databaseProvider:i})=>{let a=_(),c=mt.resolve(process.cwd(),t);return await Wt({projectName:t,projectDir:c,pkgManager:a,scopedAppName:e,noInstall:o,appRouter:s,databaseProvider:i,framework:r}),Ht({projectName:t,scopedAppName:e,projectDir:c,pkgManager:a,packages:n,noInstall:o,appRouter:s,databaseProvider:i,framework:r}),r==="next"&&(Re.copyFileSync(mt.join(j,"template/extras/config/next-config.ts"),mt.join(c,"next.config.ts")),Gt({projectDir:c,packages:n,framework:r}),qt({projectDir:c,packages:n,framework:r}),Vt({projectDir:c,packages:n,framework:r})),r==="tanstack-star"&&(Bt({projectDir:c,packages:n,framework:r}),Jt({projectDir:c,packages:n,framework:r}),Kt({projectDir:c,packages:n,framework:r})),c};import{execSync as ft}from"child_process";import dt from"path";import*as ut from"@clack/prompts";import B from"chalk";import{execa as J}from"execa";import Qt from"fs-extra";import Ne from"ora";var De=t=>{try{return ft("git --version",{cwd:t}),!0}catch{return!1}},gt=t=>Qt.existsSync(dt.join(t,".git")),ht=async t=>{try{return await J("git",["rev-parse","--is-inside-work-tree"],{cwd:t,stdout:"ignore"}),!0}catch{return!1}},Oe=()=>{let e=ft("git --version").toString().trim().split(" ")[2],n=e?.split(".")[0],o=e?.split(".")[1];return{major:Number(n),minor:Number(o)}},ze=()=>ft("git config --global init.defaultBranch || echo main").toString().trim(),Xt=async t=>{if(l.info("Initializing Git..."),!De(t)){l.warn("Git is not installed. Skipping Git initialization.");return}let e=Ne(`Creating a new git repo...
`).start(),n=gt(t),o=await ht(t),s=dt.parse(t).name;if(o&&n){if(e.stop(),!await ut.confirm({message:`${B.redBright.bold("Warning:")} Git is already initialized in "${s}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,initialValue:!1})){e.info("Skipping Git initialization.");return}Qt.removeSync(dt.join(t,".git"))}else if(o&&!n&&(e.stop(),!await ut.confirm({message:`${B.redBright.bold("Warning:")} "${s}" is already in a git worktree. Would you still like to initialize a new git repository in this directory?`,initialValue:!1}))){e.info("Skipping Git initialization.");return}try{let r=ze(),{major:i,minor:a}=Oe();i<2||i===2&&a<28?(await J("git",["init"],{cwd:t}),await J("git",["symbolic-ref","HEAD",`refs/heads/${r}`],{cwd:t})):await J("git",["init",`--initial-branch=${r}`],{cwd:t}),await J("git",["add","."],{cwd:t}),e.succeed(`${B.green("Successfully initialized and staged")} ${B.green.bold("git")}
`)}catch{e.fail(`${B.bold.red("Failed:")} could not initialize git. Update git to the latest version!
`)}};var Zt=async({projectName:t=Q,packages:e,noInstall:n,projectDir:o,databaseProvider:s})=>{let r=_();l.info("Next steps:"),t!=="."&&l.info(` cd ${t}`),n&&(r==="yarn"?l.info(` ${r}`):l.info(` ${r} install`)),["postgres","mysql"].includes(s)&&l.info(" Start up a database, if needed using './start-database.sh'"),e?.["better-auth"].inUse&&l.info(" Fill in your .env with necessary values. See https://imrlopez.dev/en/usage/first-steps for more info."),["npm","bun"].includes(r)?l.info(` ${r} run dev`):l.info(` ${r} dev`),!await ht(o)&&!gt(o)&&l.info(" git init"),l.info(' git commit -m "initial commit"')};import M from"fs";import te from"path";import{applyEdits as Me,modify as Ue,parse as Le}from"jsonc-parser";function ee(t,e,n){M.readdirSync(t).forEach(s=>{let r=te.join(t,s);if(M.statSync(r).isDirectory())ee(r,e,n);else{let a=M.readFileSync(r,"utf8").replace(new RegExp(e,"g"),n);M.writeFileSync(r,a,"utf8")}})}function Fe(t,e){let n=te.join(t,"tsconfig.json");if(M.existsSync(n))try{let o=M.readFileSync(n,"utf8"),s=Le(o);if(s?.compilerOptions?.paths){let r={};Object.entries(s.compilerOptions.paths).forEach(([c,m])=>{if(c.startsWith("~/")){let d=c.replace("~",e.replace(/\*/g,"").replace(/\/$/,""));r[d]=m}else r[c]=m});let i=Ue(o,["compilerOptions","paths"],r,{formattingOptions:{tabSize:1,insertSpaces:!1}}),a=Me(o,i);M.writeFileSync(n,a,"utf8")}}catch(o){console.warn(`Warning: Could not update tsconfig.json paths: ${o}`)}}var oe=(t,e)=>{let n=e.replace(/\*/g,"").replace(/[^/]$/,"$&/");["~/","~lib/","~server/","~components/","~ui/","~hooks/"].forEach(s=>{let r=s.replace("~",n.slice(0,-1));ee(t,s,r)}),Fe(t,n)};import $e from"gradient-string";var He={blue:"#add7ff",cyan:"#89ddff",green:"#5de4c7",magenta:"#fae4fc",red:"#d0679d",yellow:"#fffac2"},ne=()=>{let t=$e(Object.values(He)),e=_();(e==="yarn"||e==="pnpm")&&console.log(""),console.log(t.multiline(vt))};import Ge from"chalk";import{execa as qe}from"execa";import Ve from"ora";var se=async({pkgManager:t,projectDir:e,biome:n})=>{l.info(`Formatting project with ${n?"prettier":"biome"}...`);let o=Ve(`Running format command
`).start();n&&await qe(t,["run","lint"],{cwd:e}),o.succeed(`${Ge.green("Successfully formatted project")}`)};import We from"chalk";import{execa as re}from"execa";import ie from"ora";var yt=async(t,e,n)=>{let{onDataHandle:o,args:s=["install"],stdout:r="pipe"}=n,i=ie(`Running ${e} install...`).start(),a=re(e,s,{cwd:t,stdout:r});return await new Promise((c,m)=>{o&&a.stdout?.on("data",o(i)),a.on("error",d=>m(d)),a.on("close",()=>c())}),i},Be=async(t,e)=>{switch(t){case"npm":return await re(t,["install"],{cwd:e,stderr:"inherit"}),null;case"pnpm":return yt(e,t,{onDataHandle:n=>o=>{let s=o.toString();s.includes("Progress")&&(n.text=s.includes("|")?s.split(" | ")[1]??"":s)}});case"yarn":return yt(e,t,{onDataHandle:n=>o=>{n.text=o.toString()}});case"bun":return yt(e,t,{stdout:"ignore"})}},ae=async({projectDir:t})=>{l.info("Installing dependencies...");let e=_();(await Be(e,t)??ie()).succeed(We.green(`Successfully installed dependencies!
`))};import{execSync as Je}from"child_process";import Ke from"https";var ce=t=>{let e=$();e.includes("beta")?(l.warn(" You are using a beta version of create-imr-app."),l.warn(" Please report any bugs you encounter.")):e.includes("next")?(l.warn(" You are running create-imr-app with the @next tag which is no longer maintained."),l.warn(" Please run the CLI with @latest instead.")):e!==t&&(l.warn(" You are using an outdated version of create-imr-app."),l.warn(" Your version:",`${e}.`,"Latest version in the npm registry:",t),l.warn(" Please run the CLI with @latest to get the latest updates.")),console.log("")};function Ye(){return new Promise((t,e)=>{Ke.get("https://registry.npmjs.org/-/package/create-imr-app/dist-tags",n=>{if(n.statusCode===200){let o="";n.on("data",s=>o+=s),n.on("end",()=>{t(JSON.parse(o).latest)})}else e()}).on("error",()=>{e()})})}var le=()=>Ye().catch(()=>{try{return Je("npm view create-imr-app version").toString().trim()}catch{return null}});var Xe=async()=>{let t=await le(),e=_();ne(),t&&ce(t);let{appName:n,packages:o,flags:{noGit:s,noInstall:r,importAlias:i,appRouter:a},databaseProvider:c,framework:m}=await Ft(),d={next:Ot(o,c),"tanstack-star":zt(o,c)}[m];d||(l.error(`Unsupported framework: ${m}`),process.exit(1));let[S,k]=Z(n),h=await Yt({projectName:k,scopedAppName:S,packages:d,databaseProvider:c,importAlias:i,framework:m,noInstall:r,appRouter:a}),x=me.readJSONSync(pe.join(h,"package.json"));if(x.name=S,x.imrMetadata={initVersion:$()},e!=="bun"){let{stdout:R}=await Qe(e,["-v"],{cwd:h});x.packageManager=`${e}@${R.trim()}`}me.writeJSONSync(pe.join(h,"package.json"),x,{spaces:2}),i!=="~/"&&oe(h,i),r||(await ae({projectDir:h}),await se({pkgManager:e,projectDir:h,biome:o.includes("biome")})),s||await Xt(h),await Zt({projectName:k,packages:d,appRouter:a,noInstall:r,projectDir:h,databaseProvider:c}),process.exit(0)};Xe().catch(t=>{l.error("Aborting installation..."),t instanceof Error?l.error(t):(l.error("An unknown error has occurred. Please open an issue on github with the below:"),console.log(t)),process.exit(1)});