create-better-t-stack 2.13.3 → 2.13.4
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 +8 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import e from"node:path";import{cancel as t,confirm as n,group as r,intro as i,i
|
|
|
3
3
|
`)&&(r+=`
|
|
4
4
|
`),r+=a),i&&await h.writeFile(t,r.trimEnd());let s=t.replace(/\.env$/,`.env.example`),c=``;await h.pathExists(s)&&(c=await h.readFile(s,`utf8`));let l=!1,u=``;for(let e of o){let t=e.split(`=`)[0],n=RegExp(`^${t}=.*$`,`m`);n.test(c)||(u+=`${e}\n`,l=!0)}u&&(c.length>0&&!c.endsWith(`
|
|
5
5
|
`)&&(c+=`
|
|
6
|
-
`),c+=u),(l||!await h.pathExists(s))&&await h.writeFile(s,c.trimEnd())}async function pe(t){let{backend:n,frontend:r,database:i,auth:a,examples:o,dbSetup:s,projectDir:c}=t,l=r.includes(`react-router`),u=r.includes(`tanstack-router`),d=r.includes(`tanstack-start`),f=r.includes(`next`),p=r.includes(`nuxt`),m=r.includes(`svelte`),g=r.includes(`solid`),_=l||u||d||f||p||g||m;if(_){let t=e.join(c,`apps/web`);if(await h.pathExists(t)){let r=`VITE_SERVER_URL`,i=`http://localhost:3000`;f?r=`NEXT_PUBLIC_SERVER_URL`:p?r=`NUXT_PUBLIC_SERVER_URL`:m&&(r=`PUBLIC_SERVER_URL`),n===`convex`&&(r=f?`NEXT_PUBLIC_CONVEX_URL`:p?`NUXT_PUBLIC_CONVEX_URL`:m?`PUBLIC_CONVEX_URL`:`VITE_CONVEX_URL`,i=`https://<YOUR_CONVEX_URL>`);let a=[{key:r,value:i,condition:!0}];await F(e.join(t,`.env`),a)}}if(r.includes(`native-nativewind`)||r.includes(`native-unistyles`)){let t=e.join(c,`apps/native`);if(await h.pathExists(t)){let r=`EXPO_PUBLIC_SERVER_URL`,i=`http://localhost:3000`;n===`convex`&&(r=`EXPO_PUBLIC_CONVEX_URL`,i=`https://<YOUR_CONVEX_URL>`);let a=[{key:r,value:i,condition:!0}];await F(e.join(t,`.env`),a)}}if(n===`convex`)return;let v=e.join(c,`apps/server`);if(!await h.pathExists(v))return;let y=e.join(v,`.env`),b=`http://localhost:3001`;(l||m)&&(b=`http://localhost:5173`);let x=null,S=s===`turso`||s===`prisma-postgres`||s===`mongodb-atlas`||s===`neon`||s===`supabase`;if(i!==`none`&&!S)switch(i){case`postgres`:x=`postgresql://postgres:password@localhost:5432/postgres`;break;case`mysql`:x=`mysql://root:password@localhost:3306/mydb`;break;case`mongodb`:x=`mongodb://localhost:27017/mydatabase`;break;case`sqlite`:x=`file:./local.db`;break}let C=[{key:`CORS_ORIGIN`,value:b,condition:!0},{key:`BETTER_AUTH_SECRET`,value:de(),condition:!!a},{key:`BETTER_AUTH_URL`,value:`http://localhost:3000`,condition:!!a},{key:`DATABASE_URL`,value:x,condition:i!==`none`&&!S},{key:`GOOGLE_GENERATIVE_AI_API_KEY`,value:``,condition:o?.includes(`ai`)||!1}];await F(y,C)}async function me(){let e=d();e.start(`Checking for MongoDB Atlas CLI
|
|
6
|
+
`),c+=u),(l||!await h.pathExists(s))&&await h.writeFile(s,c.trimEnd())}async function pe(t){let{backend:n,frontend:r,database:i,auth:a,examples:o,dbSetup:s,projectDir:c}=t,l=r.includes(`react-router`),u=r.includes(`tanstack-router`),d=r.includes(`tanstack-start`),f=r.includes(`next`),p=r.includes(`nuxt`),m=r.includes(`svelte`),g=r.includes(`solid`),_=l||u||d||f||p||g||m;if(_){let t=e.join(c,`apps/web`);if(await h.pathExists(t)){let r=`VITE_SERVER_URL`,i=`http://localhost:3000`;f?r=`NEXT_PUBLIC_SERVER_URL`:p?r=`NUXT_PUBLIC_SERVER_URL`:m&&(r=`PUBLIC_SERVER_URL`),n===`convex`&&(r=f?`NEXT_PUBLIC_CONVEX_URL`:p?`NUXT_PUBLIC_CONVEX_URL`:m?`PUBLIC_CONVEX_URL`:`VITE_CONVEX_URL`,i=`https://<YOUR_CONVEX_URL>`);let a=[{key:r,value:i,condition:!0}];await F(e.join(t,`.env`),a)}}if(r.includes(`native-nativewind`)||r.includes(`native-unistyles`)){let t=e.join(c,`apps/native`);if(await h.pathExists(t)){let r=`EXPO_PUBLIC_SERVER_URL`,i=`http://localhost:3000`;n===`convex`&&(r=`EXPO_PUBLIC_CONVEX_URL`,i=`https://<YOUR_CONVEX_URL>`);let a=[{key:r,value:i,condition:!0}];await F(e.join(t,`.env`),a)}}if(n===`convex`)return;let v=e.join(c,`apps/server`);if(!await h.pathExists(v))return;let y=e.join(v,`.env`),b=`http://localhost:3001`;(l||m)&&(b=`http://localhost:5173`);let x=null,S=s===`turso`||s===`prisma-postgres`||s===`mongodb-atlas`||s===`neon`||s===`supabase`;if(i!==`none`&&!S)switch(i){case`postgres`:x=`postgresql://postgres:password@localhost:5432/postgres`;break;case`mysql`:x=`mysql://root:password@localhost:3306/mydb`;break;case`mongodb`:x=`mongodb://localhost:27017/mydatabase`;break;case`sqlite`:x=`file:./local.db`;break}let C=[{key:`CORS_ORIGIN`,value:b,condition:!0},{key:`BETTER_AUTH_SECRET`,value:de(),condition:!!a},{key:`BETTER_AUTH_URL`,value:`http://localhost:3000`,condition:!!a},{key:`DATABASE_URL`,value:x,condition:i!==`none`&&!S},{key:`GOOGLE_GENERATIVE_AI_API_KEY`,value:``,condition:o?.includes(`ai`)||!1}];await F(y,C)}async function me(){let e=d();e.start(`Checking for MongoDB Atlas CLI...`);try{let t=await P(`atlas`);return e.stop(t?`MongoDB Atlas CLI found`:g.yellow(`MongoDB Atlas CLI not found`)),t}catch{return e.stop(g.red(`Error checking MongoDB Atlas CLI`)),!1}}async function he(e){try{let n=await me();if(!n)return p.error(g.red(`MongoDB Atlas CLI not found.`)),o.info(g.yellow(`Please install it from: https://www.mongodb.com/docs/atlas/cli/current/install-atlas-cli/`)),null;o.info(g.blue(`Running MongoDB Atlas setup...`)),await x(`atlas`,[`deployments`,`setup`],{cwd:e,stdio:`inherit`}),o.info(g.green(`MongoDB Atlas deployment ready`));let r=await f({message:`Enter your MongoDB connection string:`,placeholder:`mongodb+srv://username:password@cluster.mongodb.net/database`,validate(e){if(!e)return`Please enter a connection string`;if(!e.startsWith(`mongodb`))return`URL should start with mongodb:// or mongodb+srv://`}});return a(r)?(t(`MongoDB setup cancelled`),null):{connectionString:r}}catch(e){return e instanceof Error&&p.error(g.red(e.message)),null}}async function I(t,n){try{let r=e.join(t,`apps/server`,`.env`),i=[{key:`DATABASE_URL`,value:n?.connectionString??`mongodb://localhost:27017/mydb`,condition:!0}];await F(r,i)}catch{p.error(`Failed to update environment configuration`)}}function L(){o.info(`
|
|
7
7
|
${g.green(`MongoDB Atlas Manual Setup Instructions:`)}
|
|
8
8
|
|
|
9
9
|
1. Install Atlas CLI:
|
|
@@ -17,8 +17,8 @@ ${g.green(`MongoDB Atlas Manual Setup Instructions:`)}
|
|
|
17
17
|
|
|
18
18
|
4. Add the connection string to your .env file:
|
|
19
19
|
${g.dim(`DATABASE_URL="your_connection_string"`)}
|
|
20
|
-
`)}async function ge(t){let{projectDir:n}=t,r=d();r.start(`Setting up MongoDB Atlas
|
|
21
|
-
It looks like: prisma+postgres://accelerate.prisma-data.net/?api_key=...`));let u=await l({message:`Paste your Prisma Postgres database URL:`,validate(e){if(!e)return`Please enter a database URL`;if(!e.startsWith(`prisma+postgres://`))return`URL should start with prisma+postgres://`}});return a(u)?(t(`Database setup cancelled`),null):{databaseUrl:u}}catch(e){return i.stop(g.red(`
|
|
20
|
+
`)}async function ge(t){let{projectDir:n}=t,r=d();r.start(`Setting up MongoDB Atlas...`);let i=e.join(n,`apps/server`);try{await h.ensureDir(i),r.stop(`MongoDB Atlas setup ready`);let e=await he(i);e?(await I(n,e),o.success(g.green(`MongoDB Atlas setup complete! Connection saved to .env file.`))):(o.warn(g.yellow(`Falling back to local MongoDB configuration`)),await I(n),L())}catch(e){r.stop(g.red(`MongoDB Atlas setup failed`)),p.error(g.red(`Error during MongoDB Atlas setup: ${e instanceof Error?e.message:String(e)}`));try{await I(n),L()}catch{}}}async function _e(n,r){let i=d();try{i.start(`Initializing Prisma PostgreSQL...`);let s=e.join(n,`prisma`);await h.ensureDir(s),i.stop(`Prisma PostgreSQL initialized. Follow the prompts below:`);let c=N(r,`prisma init --db`);await x(c,{cwd:n,stdio:`inherit`,shell:!0}),o.info(g.yellow(`Please copy the Prisma Postgres URL from the output above.
|
|
21
|
+
It looks like: prisma+postgres://accelerate.prisma-data.net/?api_key=...`));let u=await l({message:`Paste your Prisma Postgres database URL:`,validate(e){if(!e)return`Please enter a database URL`;if(!e.startsWith(`prisma+postgres://`))return`URL should start with prisma+postgres://`}});return a(u)?(t(`Database setup cancelled`),null):{databaseUrl:u}}catch(e){return i.stop(g.red(`Prisma PostgreSQL initialization failed`)),e instanceof Error&&m.error(e.message),null}}async function R(t,n){try{let r=e.join(t,`apps/server`,`.env`),i=[{key:`DATABASE_URL`,value:n?.databaseUrl??`postgresql://postgres:postgres@localhost:5432/mydb?schema=public`,condition:!0}];await F(r,i)}catch{m.error(`Failed to update environment configuration`)}}function z(){o.info(`Manual Prisma PostgreSQL Setup Instructions:
|
|
22
22
|
|
|
23
23
|
1. Visit https://console.prisma.io and create an account
|
|
24
24
|
2. Create a new PostgreSQL database from the dashboard
|
|
@@ -32,7 +32,7 @@ import { withAccelerate } from "@prisma/extension-accelerate";
|
|
|
32
32
|
const prisma = new PrismaClient().$extends(withAccelerate());
|
|
33
33
|
|
|
34
34
|
export default prisma;
|
|
35
|
-
`;await h.writeFile(n,r.trim());let i=e.join(t,`src/db/index.ts`);if(await h.pathExists(i)){let e=await h.readFile(i,`utf8`);e.includes(`@prisma/extension-accelerate`)||(e=`import { withAccelerate } from "@prisma/extension-accelerate";\n${e}`,e=e.replace(`export const db = new PrismaClient();`,`export const db = new PrismaClient().$extends(withAccelerate());`),await h.writeFile(i,e))}return!0}catch{return o.warn(g.yellow(`Could not add Prisma Accelerate extension automatically`)),!1}}async function ye(t){let{packageManager:n,projectDir:r}=t,i=e.join(r,`apps/server`),a=d();a.start(`Setting up Prisma PostgreSQL
|
|
35
|
+
`;await h.writeFile(n,r.trim());let i=e.join(t,`src/db/index.ts`);if(await h.pathExists(i)){let e=await h.readFile(i,`utf8`);e.includes(`@prisma/extension-accelerate`)||(e=`import { withAccelerate } from "@prisma/extension-accelerate";\n${e}`,e=e.replace(`export const db = new PrismaClient();`,`export const db = new PrismaClient().$extends(withAccelerate());`),await h.writeFile(i,e))}return!0}catch{return o.warn(g.yellow(`Could not add Prisma Accelerate extension automatically`)),!1}}async function ye(t){let{packageManager:n,projectDir:r}=t,i=e.join(r,`apps/server`),a=d();a.start(`Setting up Prisma PostgreSQL...`);try{await h.ensureDir(i),a.stop(`Prisma PostgreSQL setup ready`);let e=await _e(i,n);if(e)await R(r,e),await ve(i),o.success(g.green(`Prisma PostgreSQL database configured successfully!`)),o.info(g.cyan('NOTE: Make sure to uncomment `import "dotenv/config";` in `apps/server/src/prisma.config.ts` to load environment variables.'));else{let e=d();e.start(`Setting up fallback configuration...`),await R(r),e.stop(`Fallback configuration ready`),z()}}catch(e){a.stop(g.red(`Prisma PostgreSQL setup failed`)),m.error(g.red(`Error during Prisma PostgreSQL setup: ${e instanceof Error?e.message:String(e)}`));try{await R(r),z()}catch{}o.info(`Setup completed with manual configuration required.`)}}async function be(t,n){try{let r=e.join(t,`apps/server`,`.env`),i=n||`postgresql://postgres:postgres@127.0.0.1:54322/postgres`,a=[{key:`DATABASE_URL`,value:i,condition:!0},{key:`DIRECT_URL`,value:i,condition:!0}];return await F(r,a),!0}catch(e){return m.error(g.red(`Failed to update .env file for Supabase.`)),e instanceof Error&&m.error(e.message),!1}}function xe(e){let t=e.match(/DB URL:\s*(postgresql:\/\/[^\s]+)/),n=t?.[1];return n||null}async function Se(e,t){o.info(`Initializing Supabase project...`);try{let n=N(t,`supabase init`);return await x(n,{cwd:e,stdio:`inherit`,shell:!0}),o.success(`Supabase project initialized`),!0}catch(e){return m.error(g.red(`Failed to initialize Supabase project.`)),e instanceof Error?m.error(e.message):m.error(String(e)),e instanceof Error&&e.message.includes(`ENOENT`)&&(o.error(g.red(`Supabase CLI not found. Please install it globally or ensure it's in your PATH.`)),o.info(`You can install it using: npm install -g supabase`)),!1}}async function Ce(e,t){o.info(`Starting Supabase services (this may take a moment)...`);let n=N(t,`supabase start`);try{let t=x(n,{cwd:e,shell:!0}),r=``;return t.stdout&&t.stdout.on(`data`,e=>{let t=e.toString();process.stdout.write(t),r+=t}),t.stderr&&t.stderr.pipe(process.stderr),await t,await new Promise(e=>setTimeout(e,100)),r}catch(e){m.error(g.red(`Failed to start Supabase services.`));let t=e;return t?.message?(m.error(`Error details: ${t.message}`),t.message.includes(`Docker is not running`)&&o.error(g.red(`Docker is not running. Please start Docker and try again.`))):m.error(String(e)),null}}function B(e){o.info(`"Manual Supabase Setup Instructions:"
|
|
36
36
|
1. Ensure Docker is installed and running.
|
|
37
37
|
2. Install the Supabase CLI (e.g., \`npm install -g supabase\`).
|
|
38
38
|
3. Run \`supabase init\` in your project's \`apps/server\` directory.
|
|
@@ -41,8 +41,8 @@ export default prisma;
|
|
|
41
41
|
${g.bold("Relevant output from `supabase start`:")}
|
|
42
42
|
${g.dim(e)}`:``}
|
|
43
43
|
6. Add the DB URL to the .env file in \`apps/server/.env\` as \`DATABASE_URL\`:
|
|
44
|
-
${g.gray(`DATABASE_URL="your_supabase_db_url"`)}`)}async function we(t){let{projectDir:n,packageManager:r}=t,i=e.join(n,`apps`,`server`);try{await h.ensureDir(i);let e=await Se(i,r);if(!e){B();return}let t=await Ce(i,r);if(!t){B();return}let a=xe(t);if(a){let e=await be(n,a);e?o.success(g.green(`Supabase local development setup
|
|
45
|
-
`);if(n.length<=1)return e.stop(`No Turso groups found`),[];let r=n.slice(1).map(e=>{let[t,n,r,i]=e.trim().split(/\s{2,}/);return{name:t,locations:n,version:r,status:i}});return e.stop(`Found ${r.length} Turso groups`),r}catch(t){return e.stop(g.red(`Error fetching Turso groups`)),console.error(`Error fetching Turso groups:`,t),[]}}async function Ae(){let e=await ke();if(e.length===0)return null;if(e.length===1)return o.info(`Using the only available group: ${g.blue(e[0].name)}`),e[0].name;let n=e.map(e=>({value:e.name,label:`${e.name} (${e.locations})`})),r=await u({message:`Select a Turso database group:`,options:n});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function je(e,t){let n=d();try{n.start(`Creating Turso database "${e}"${t?` in group "${t}"`:``}...`),t?await b`turso db create ${e} --group ${t}`:await b`turso db create ${e}`,n.stop(`
|
|
44
|
+
${g.gray(`DATABASE_URL="your_supabase_db_url"`)}`)}async function we(t){let{projectDir:n,packageManager:r}=t,i=e.join(n,`apps`,`server`);try{await h.ensureDir(i);let e=await Se(i,r);if(!e){B();return}let t=await Ce(i,r);if(!t){B();return}let a=xe(t);if(a){let e=await be(n,a);e?o.success(g.green(`Supabase local development setup ready!`)):(o.error(g.red(`Supabase setup completed, but failed to update .env automatically.`)),B(t))}else o.error(g.yellow(`Supabase started, but could not extract DB URL automatically.`)),B(t)}catch(e){e instanceof Error?m.error(g.red(`Error during Supabase setup: ${e.message}`)):m.error(g.red(`An unknown error occurred during Supabase setup: ${String(e)}`)),B()}}async function Te(){return P(`turso`)}async function Ee(){try{let e=await b`turso auth whoami`;return!e.stdout.includes(`You are not logged in`)}catch{return!1}}async function De(){let e=d();try{return e.start(`Logging in to Turso...`),await b`turso auth login`,e.stop(`Logged into Turso`),!0}catch{e.stop(g.red(`Failed to log in to Turso`))}}async function Oe(e){let t=d();try{if(t.start(`Installing Turso CLI...`),e)await b`brew install tursodatabase/tap/turso`;else{let{stdout:e}=await b`curl -sSfL https://get.tur.so/install.sh`;await b`bash -c '${e}'`}return t.stop(`Turso CLI installed`),!0}catch(e){if(e instanceof Error&&e.message.includes(`User force closed`))throw t.stop(`Turso CLI installation cancelled`),o.warn(g.yellow(`Turso CLI installation cancelled by user`)),Error(`Installation cancelled`);t.stop(g.red(`Failed to install Turso CLI`))}}async function ke(){let e=d();try{e.start(`Fetching Turso groups...`);let{stdout:t}=await b`turso group list`,n=t.trim().split(`
|
|
45
|
+
`);if(n.length<=1)return e.stop(`No Turso groups found`),[];let r=n.slice(1).map(e=>{let[t,n,r,i]=e.trim().split(/\s{2,}/);return{name:t,locations:n,version:r,status:i}});return e.stop(`Found ${r.length} Turso groups`),r}catch(t){return e.stop(g.red(`Error fetching Turso groups`)),console.error(`Error fetching Turso groups:`,t),[]}}async function Ae(){let e=await ke();if(e.length===0)return null;if(e.length===1)return o.info(`Using the only available group: ${g.blue(e[0].name)}`),e[0].name;let n=e.map(e=>({value:e.name,label:`${e.name} (${e.locations})`})),r=await u({message:`Select a Turso database group:`,options:n});return a(r)&&(t(g.red(`Operation cancelled`)),process.exit(0)),r}async function je(e,t){let n=d();try{n.start(`Creating Turso database "${e}"${t?` in group "${t}"`:``}...`),t?await b`turso db create ${e} --group ${t}`:await b`turso db create ${e}`,n.stop(`Turso database "${e}" created`)}catch(t){if(n.stop(g.red(`Failed to create database "${e}"`)),t instanceof Error&&t.message.includes(`already exists`))throw Error(`DATABASE_EXISTS`)}n.start(`Retrieving database connection details...`);try{let{stdout:t}=await b`turso db show ${e} --url`,{stdout:r}=await b`turso db tokens create ${e}`;return n.stop(`Database connection details retrieved`),{dbUrl:t.trim(),authToken:r.trim()}}catch{n.stop(g.red(`Failed to retrieve database connection details`))}}async function V(t,n){let r=e.join(t,`apps/server`,`.env`),i=[{key:`DATABASE_URL`,value:n?.dbUrl??``,condition:!0},{key:`DATABASE_AUTH_TOKEN`,value:n?.authToken??``,condition:!0}];await F(r,i)}function H(){o.info(`Manual Turso Setup Instructions:
|
|
46
46
|
|
|
47
47
|
1. Visit https://turso.tech and create an account
|
|
48
48
|
2. Create a new database from the dashboard
|
|
@@ -50,14 +50,14 @@ ${g.dim(e)}`:``}
|
|
|
50
50
|
4. Add these credentials to the .env file in apps/server/.env
|
|
51
51
|
|
|
52
52
|
DATABASE_URL=your_database_url
|
|
53
|
-
DATABASE_AUTH_TOKEN=your_auth_token`)}async function Me(r){let{orm:i,projectDir:s}=r,c=i===`drizzle`,l=d();l.start(`
|
|
53
|
+
DATABASE_AUTH_TOKEN=your_auth_token`)}async function Me(r){let{orm:i,projectDir:s}=r,c=i===`drizzle`,l=d();l.start(`Checking Turso CLI availability...`);try{let r=S.platform(),i=r===`darwin`,c=r===`linux`,u=r===`win32`;if(u){l.stop(g.yellow(`Turso setup not supported on Windows`)),o.warn(g.yellow(`Automatic Turso setup is not supported on Windows.`)),await V(s),H();return}l.stop(`Turso CLI availability checked`);let d=await Te();if(!d){let e=await n({message:`Would you like to install Turso CLI?`,initialValue:!0});if(a(e)&&(t(g.red(`Operation cancelled`)),process.exit(0)),!e){await V(s),H();return}await Oe(i)}let p=await Ee();p||await De();let m=await Ae(),h=!1,_=``,v=e.basename(s);for(;!h;){let e=await f({message:`Enter a name for your database:`,defaultValue:v,initialValue:v,placeholder:v});a(e)&&(t(g.red(`Operation cancelled`)),process.exit(0)),_=e;try{let e=await je(_,m);await V(s,e),h=!0}catch(e){if(e instanceof Error&&e.message===`DATABASE_EXISTS`)o.warn(g.yellow(`Database "${g.red(_)}" already exists`)),v=`${_}-${Math.floor(Math.random()*1e3)}`;else throw e}}o.success(`Turso database setup completed successfully!`)}catch(e){l.stop(g.red(`Turso CLI availability check failed`)),p.error(g.red(`Error during Turso setup: ${e instanceof Error?e.message:String(e)}`)),await V(s),H(),o.success(`Setup completed with manual configuration required.`)}}const U=[{label:`AWS US East (N. Virginia)`,value:`aws-us-east-1`},{label:`AWS US East (Ohio)`,value:`aws-us-east-2`},{label:`AWS US West (Oregon)`,value:`aws-us-west-2`},{label:`AWS Europe (Frankfurt)`,value:`aws-eu-central-1`},{label:`AWS Asia Pacific (Singapore)`,value:`aws-ap-southeast-1`},{label:`AWS Asia Pacific (Sydney)`,value:`aws-ap-southeast-2`},{label:`Azure East US 2 region (Virginia)`,value:`azure-eastus2`}];async function W(e,t,n){let r=d();try{let i=N(e,t);n&&r.start(n);let a=await x(i,{shell:!0});return n&&r.stop(g.green(n.replace(`...`,``).replace(`ing `,`ed `).trim())),a}catch(e){throw r&&r.stop(g.red(`Failed: ${n||`Command execution`}`)),e}}async function Ne(e){try{let t=`neonctl projects list`,n=await W(e,t);return!n.stdout.includes(`not authenticated`)&&!n.stdout.includes(`error`)}catch{return!1}}async function Pe(e){try{return await W(e,`neonctl auth`,`Authenticating with Neon...`),!0}catch{m.error(g.red(`Failed to authenticate with Neon`))}}async function Fe(e,t,n){try{let r=`neonctl projects create --name ${e} --region-id ${t} --output json`,{stdout:i}=await W(n,r,`Creating Neon project "${e}"...`),a=JSON.parse(i);if(a.project&&a.connection_uris&&a.connection_uris.length>0){let e=a.project.id,t=a.connection_uris[0].connection_uri,n=a.connection_uris[0].connection_parameters;return{connectionString:t,projectId:e,dbName:n.database,roleName:n.role}}return m.error(g.red(`Failed to extract connection information from response`)),null}catch{m.error(g.red(`Failed to create Neon project`))}}async function G(t,n){let r=e.join(t,`apps/server`,`.env`),i=[{key:`DATABASE_URL`,value:n?.connectionString??`postgresql://postgres:postgres@localhost:5432/mydb?schema=public`,condition:!0}];return await F(r,i),!0}function Ie(){o.info(`Manual Neon PostgreSQL Setup Instructions:
|
|
54
54
|
|
|
55
55
|
1. Visit https://neon.tech and create an account
|
|
56
56
|
2. Create a new project from the dashboard
|
|
57
57
|
3. Get your connection string
|
|
58
58
|
4. Add the database URL to the .env file in apps/server/.env
|
|
59
59
|
|
|
60
|
-
DATABASE_URL="your_connection_string"`)}async function Le(n){let{packageManager:r,projectDir:i}=n,s=d();s.start(`
|
|
60
|
+
DATABASE_URL="your_connection_string"`)}async function Le(n){let{packageManager:r,projectDir:i}=n,s=d();s.start(`Checking Neon authentication...`);try{let n=await Ne(r);s.stop(`Neon authentication checked`),n||(o.info(`Please authenticate with Neon to continue:`),await Pe(r));let c=e.basename(i),l=await f({message:`Enter a name for your Neon project:`,defaultValue:c,initialValue:c}),p=await u({message:`Select a region for your Neon project:`,options:U,initialValue:U[0].value});(a(l)||a(p))&&(t(g.red(`Operation cancelled`)),process.exit(0));let m=await Fe(l,p,r);if(!m)throw Error(`Failed to create project - couldn't get connection information`);let _=d();_.start(`Configuring database connection`),await h.ensureDir(e.join(i,`apps/server`)),await G(i,m),_.stop(`Neon database configured!`)}catch(e){s.stop(g.red(`Neon authentication check failed`)),e instanceof Error&&m.error(g.red(e.message)),await G(i),Ie()}}async function Re(t){let{database:n,orm:r,dbSetup:i,backend:a,projectDir:o}=t;if(a===`convex`||n===`none`){if(a!==`convex`){let t=e.join(o,`apps/server`),n=e.join(t,`src/db`);await h.pathExists(n)&&await h.remove(n)}return}let s=d(),c=e.join(o,`apps/server`);if(await h.pathExists(c))try{r===`prisma`?await M({dependencies:[`@prisma/client`],devDependencies:[`prisma`],projectDir:c}):r===`drizzle`?n===`sqlite`?await M({dependencies:[`drizzle-orm`,`@libsql/client`],devDependencies:[`drizzle-kit`],projectDir:c}):n===`postgres`?await M({dependencies:[`drizzle-orm`,`pg`],devDependencies:[`drizzle-kit`,`@types/pg`],projectDir:c}):n===`mysql`&&await M({dependencies:[`drizzle-orm`,`mysql2`],devDependencies:[`drizzle-kit`],projectDir:c}):r===`mongoose`&&await M({dependencies:[`mongoose`],devDependencies:[],projectDir:c}),n===`sqlite`&&i===`turso`?await Me(t):n===`postgres`?r===`prisma`&&i===`prisma-postgres`?await ye(t):i===`neon`?await Le(t):i===`supabase`&&await we(t):n===`mongodb`&&i===`mongodb-atlas`&&await ge(t)}catch(e){s.stop(g.red(`Failed to set up database`)),e instanceof Error&&p.error(g.red(e.message))}}async function ze(t){let{examples:n,frontend:r,backend:i,projectDir:a}=t;if(!(i===`convex`||!n||n.length===0||n[0]===`none`)&&n.includes(`ai`)){let t=e.join(a,`apps/web`),n=e.join(a,`apps/server`),o=await h.pathExists(t),s=await h.pathExists(n),c=r.includes(`nuxt`),l=r.includes(`svelte`),u=r.includes(`react-router`)||r.includes(`tanstack-router`)||r.includes(`next`)||r.includes(`tanstack-start`);if(o){let e=[`ai`];c?e.push(`@ai-sdk/vue`):l?e.push(`@ai-sdk/svelte`):u&&e.push(`@ai-sdk/react`),await M({dependencies:e,projectDir:t})}s&&i!==`none`&&await M({dependencies:[`ai`,`@ai-sdk/google`],projectDir:n})}}async function Be(t){let{runtime:n,backend:r,projectDir:i}=t;if(r===`convex`||r===`next`||n===`none`)return;let a=e.join(i,`apps/server`);await h.pathExists(a)&&(n===`bun`?await Ve(a,r):n===`node`&&await He(a,r))}async function Ve(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts={...i.scripts,dev:`bun run --hot src/index.ts`,start:`bun run dist/src/index.js`},await h.writeJson(r,i,{spaces:2}),await M({devDependencies:[`@types/bun`],projectDir:t})}async function He(t,n){let r=e.join(t,`package.json`);if(!await h.pathExists(r))return;let i=await h.readJson(r);i.scripts={...i.scripts,dev:`tsx watch src/index.ts`,start:`node dist/src/index.js`},await h.writeJson(r,i,{spaces:2}),await M({devDependencies:[`tsx`,`@types/node`],projectDir:t}),n===`hono`?await M({dependencies:[`@hono/node-server`],projectDir:t}):n===`elysia`&&await M({dependencies:[`@elysiajs/node`],projectDir:t})}async function Ue(t,n){let r=e.join(t,`README.md`),i=We(n);try{await h.writeFile(r,i)}catch(e){p.error(`Failed to create README.md file:`,e)}}function We(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`,api:u=`trpc`}=e,d=l===`convex`,f=c.includes(`react-router`),p=c.includes(`tanstack-router`),m=c.includes(`native-nativewind`)||c.includes(`native-unistyles`),h=c.includes(`next`),g=c.includes(`tanstack-start`),_=c.includes(`svelte`),v=c.includes(`solid`),y=c.includes(`nuxt`),b=n===`npm`?`npm run`:n,x=`3001`;return(f||_)&&(x=`5173`),`# ${t}
|
|
61
61
|
|
|
62
62
|
This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack that combines ${p?`React, TanStack Router`:f?`React, React Router`:h?`Next.js`:g?`React, TanStack Start`:_?`SvelteKit`:y?`Nuxt`:v?`SolidJS`:``}, ${l[0].toUpperCase()+l.slice(1)}${d?``:`, ${u.toUpperCase()}`}, and more.
|
|
63
63
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.4",
|
|
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",
|