create-better-t-stack 2.50.0-canary.08568a05 → 2.50.0-canary.5b25d7db
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/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-DfbhNFZ9.js → src-Vtq3I-LI.js} +165 -119
- package/package.json +1 -1
- package/templates/api/orpc/fullstack/next/src/app/api/rpc/[[...rest]]/route.ts.hbs +45 -16
- package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +1 -1
- package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +2 -2
- package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +1 -1
- package/templates/api/orpc/web/svelte/src/lib/orpc.ts.hbs +1 -1
- package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +2 -2
- package/templates/auth/better-auth/server/base/src/index.ts.hbs +5 -5
- package/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs +2 -0
- package/templates/auth/better-auth/web/react/next/src/app/dashboard/page.tsx.hbs +31 -0
- package/templates/db/drizzle/mysql/drizzle.config.ts.hbs +5 -1
- package/templates/db/drizzle/postgres/drizzle.config.ts.hbs +5 -1
- package/templates/db/drizzle/sqlite/drizzle.config.ts.hbs +5 -1
- package/templates/db/prisma/mongodb/prisma.config.ts.hbs +5 -1
- package/templates/db/prisma/mysql/prisma.config.ts.hbs +5 -1
- package/templates/db/prisma/postgres/prisma.config.ts.hbs +5 -1
- package/templates/db/prisma/sqlite/prisma.config.ts.hbs +5 -1
- package/templates/frontend/native/nativewind/tsconfig.json.hbs +1 -6
- package/templates/frontend/native/unistyles/tsconfig.json.hbs +1 -6
- package/templates/frontend/nuxt/tsconfig.json.hbs +0 -4
- package/templates/frontend/react/next/tsconfig.json.hbs +0 -7
- package/templates/frontend/react/react-router/tsconfig.json.hbs +1 -6
- package/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs +1 -1
- package/templates/frontend/react/tanstack-router/tsconfig.json.hbs +1 -6
- package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +1 -1
- package/templates/frontend/react/tanstack-start/tsconfig.json.hbs +1 -6
- package/templates/frontend/solid/tsconfig.json.hbs +1 -6
- package/templates/frontend/svelte/tsconfig.json.hbs +1 -6
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -125,7 +125,7 @@ const dependencyVersionMap = {
|
|
|
125
125
|
"@trpc/tanstack-react-query": "^11.5.0",
|
|
126
126
|
"@trpc/server": "^11.5.0",
|
|
127
127
|
"@trpc/client": "^11.5.0",
|
|
128
|
-
|
|
128
|
+
next: "15.5.4",
|
|
129
129
|
convex: "^1.27.0",
|
|
130
130
|
"@convex-dev/react-query": "^0.0.0-alpha.8",
|
|
131
131
|
"convex-svelte": "^0.0.11",
|
|
@@ -699,7 +699,7 @@ async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
|
699
699
|
if (hasFullstackFrontend) backendOptions.push({
|
|
700
700
|
value: "self",
|
|
701
701
|
label: "Self (Fullstack)",
|
|
702
|
-
hint: "Use frontend's built-in
|
|
702
|
+
hint: "Use frontend's built-in api routes"
|
|
703
703
|
});
|
|
704
704
|
backendOptions.push({
|
|
705
705
|
value: "hono",
|
|
@@ -4120,6 +4120,10 @@ async function setupExamples(config) {
|
|
|
4120
4120
|
dependencies: ["ai", "@ai-sdk/google"],
|
|
4121
4121
|
projectDir: apiDir$1
|
|
4122
4122
|
});
|
|
4123
|
+
if (backend === "self" && webClientDirExists) await addPackageDependency({
|
|
4124
|
+
dependencies: ["ai", "@ai-sdk/google"],
|
|
4125
|
+
projectDir: webClientDir
|
|
4126
|
+
});
|
|
4123
4127
|
}
|
|
4124
4128
|
}
|
|
4125
4129
|
|
|
@@ -4251,6 +4255,10 @@ async function setupApi(config) {
|
|
|
4251
4255
|
dependencies: apiDeps.server.dependencies,
|
|
4252
4256
|
projectDir: apiPackageDir
|
|
4253
4257
|
});
|
|
4258
|
+
if (backend === "self" && webDirExists) await addPackageDependency({
|
|
4259
|
+
dependencies: apiDeps.server.dependencies,
|
|
4260
|
+
projectDir: webDir
|
|
4261
|
+
});
|
|
4254
4262
|
const frameworkDeps = [];
|
|
4255
4263
|
if (backend === "hono") frameworkDeps.push("hono");
|
|
4256
4264
|
else if (backend === "elysia") frameworkDeps.push("elysia");
|
|
@@ -4484,6 +4492,34 @@ function generateAuthSecret(length = 32) {
|
|
|
4484
4492
|
|
|
4485
4493
|
//#endregion
|
|
4486
4494
|
//#region src/helpers/core/env-setup.ts
|
|
4495
|
+
function getClientServerVar(frontend, backend) {
|
|
4496
|
+
const hasNextJs = frontend.includes("next");
|
|
4497
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
4498
|
+
const hasSvelte = frontend.includes("svelte");
|
|
4499
|
+
if (backend === "self") return {
|
|
4500
|
+
key: "",
|
|
4501
|
+
value: "",
|
|
4502
|
+
write: false
|
|
4503
|
+
};
|
|
4504
|
+
let key = "VITE_SERVER_URL";
|
|
4505
|
+
if (hasNextJs) key = "NEXT_PUBLIC_SERVER_URL";
|
|
4506
|
+
else if (hasNuxt) key = "NUXT_PUBLIC_SERVER_URL";
|
|
4507
|
+
else if (hasSvelte) key = "PUBLIC_SERVER_URL";
|
|
4508
|
+
return {
|
|
4509
|
+
key,
|
|
4510
|
+
value: "http://localhost:3000",
|
|
4511
|
+
write: true
|
|
4512
|
+
};
|
|
4513
|
+
}
|
|
4514
|
+
function getConvexVar(frontend) {
|
|
4515
|
+
const hasNextJs = frontend.includes("next");
|
|
4516
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
4517
|
+
const hasSvelte = frontend.includes("svelte");
|
|
4518
|
+
if (hasNextJs) return "NEXT_PUBLIC_CONVEX_URL";
|
|
4519
|
+
if (hasNuxt) return "NUXT_PUBLIC_CONVEX_URL";
|
|
4520
|
+
if (hasSvelte) return "PUBLIC_CONVEX_URL";
|
|
4521
|
+
return "VITE_CONVEX_URL";
|
|
4522
|
+
}
|
|
4487
4523
|
async function addEnvVariablesToFile(filePath, variables) {
|
|
4488
4524
|
await fs.ensureDir(path.dirname(filePath));
|
|
4489
4525
|
let envContent = "";
|
|
@@ -4542,22 +4578,13 @@ async function setupEnvironmentVariables(config) {
|
|
|
4542
4578
|
if (hasReactRouter || hasTanStackRouter || hasTanStackStart || hasNextJs || hasNuxt || hasSolid || hasSvelte) {
|
|
4543
4579
|
const clientDir = path.join(projectDir, "apps/web");
|
|
4544
4580
|
if (await fs.pathExists(clientDir)) {
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
else if (hasNuxt) envVarName = "NUXT_PUBLIC_SERVER_URL";
|
|
4549
|
-
else if (hasSvelte) envVarName = "PUBLIC_SERVER_URL";
|
|
4550
|
-
if (backend === "convex") {
|
|
4551
|
-
if (hasNextJs) envVarName = "NEXT_PUBLIC_CONVEX_URL";
|
|
4552
|
-
else if (hasNuxt) envVarName = "NUXT_PUBLIC_CONVEX_URL";
|
|
4553
|
-
else if (hasSvelte) envVarName = "PUBLIC_CONVEX_URL";
|
|
4554
|
-
else envVarName = "VITE_CONVEX_URL";
|
|
4555
|
-
serverUrl = "https://<YOUR_CONVEX_URL>";
|
|
4556
|
-
}
|
|
4581
|
+
const baseVar = getClientServerVar(frontend, backend);
|
|
4582
|
+
const envVarName = backend === "convex" ? getConvexVar(frontend) : baseVar.key;
|
|
4583
|
+
const serverUrl = backend === "convex" ? "https://<YOUR_CONVEX_URL>" : baseVar.value;
|
|
4557
4584
|
const clientVars = [{
|
|
4558
4585
|
key: envVarName,
|
|
4559
4586
|
value: serverUrl,
|
|
4560
|
-
condition: backend
|
|
4587
|
+
condition: backend === "convex" ? true : baseVar.write
|
|
4561
4588
|
}];
|
|
4562
4589
|
if (backend === "convex" && auth === "clerk") {
|
|
4563
4590
|
if (hasNextJs) clientVars.push({
|
|
@@ -4649,7 +4676,8 @@ async function setupEnvironmentVariables(config) {
|
|
|
4649
4676
|
}
|
|
4650
4677
|
const serverDir = path.join(projectDir, "apps/server");
|
|
4651
4678
|
let corsOrigin = "http://localhost:3001";
|
|
4652
|
-
if (
|
|
4679
|
+
if (backend === "self") corsOrigin = "http://localhost:3001";
|
|
4680
|
+
else if (hasReactRouter || hasSvelte) corsOrigin = "http://localhost:5173";
|
|
4653
4681
|
let databaseUrl = null;
|
|
4654
4682
|
if (database !== "none" && dbSetup === "none") switch (database) {
|
|
4655
4683
|
case "postgres":
|
|
@@ -4663,7 +4691,10 @@ async function setupEnvironmentVariables(config) {
|
|
|
4663
4691
|
break;
|
|
4664
4692
|
case "sqlite":
|
|
4665
4693
|
if (config.runtime === "workers") databaseUrl = "http://127.0.0.1:8080";
|
|
4666
|
-
else
|
|
4694
|
+
else {
|
|
4695
|
+
const dbAppDir = backend === "self" ? "apps/web" : "apps/server";
|
|
4696
|
+
databaseUrl = `file:${path.join(config.projectDir, dbAppDir, "local.db")}`;
|
|
4697
|
+
}
|
|
4667
4698
|
break;
|
|
4668
4699
|
}
|
|
4669
4700
|
const serverVars = [
|
|
@@ -4674,7 +4705,7 @@ async function setupEnvironmentVariables(config) {
|
|
|
4674
4705
|
},
|
|
4675
4706
|
{
|
|
4676
4707
|
key: "BETTER_AUTH_URL",
|
|
4677
|
-
value: "http://localhost:3000",
|
|
4708
|
+
value: backend === "self" ? "http://localhost:3001" : "http://localhost:3000",
|
|
4678
4709
|
condition: !!auth
|
|
4679
4710
|
},
|
|
4680
4711
|
{
|
|
@@ -4742,9 +4773,10 @@ async function setupEnvironmentVariables(config) {
|
|
|
4742
4773
|
//#endregion
|
|
4743
4774
|
//#region src/helpers/database-providers/d1-setup.ts
|
|
4744
4775
|
async function setupCloudflareD1(config) {
|
|
4745
|
-
const { projectDir, serverDeploy, orm } = config;
|
|
4776
|
+
const { projectDir, serverDeploy, orm, backend } = config;
|
|
4746
4777
|
if (serverDeploy === "wrangler") {
|
|
4747
|
-
const
|
|
4778
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
4779
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4748
4780
|
const variables = [
|
|
4749
4781
|
{
|
|
4750
4782
|
key: "CLOUDFLARE_ACCOUNT_ID",
|
|
@@ -4767,7 +4799,8 @@ async function setupCloudflareD1(config) {
|
|
|
4767
4799
|
} catch (_err) {}
|
|
4768
4800
|
}
|
|
4769
4801
|
if ((serverDeploy === "wrangler" || serverDeploy === "alchemy") && orm === "prisma") {
|
|
4770
|
-
const
|
|
4802
|
+
const targetApp2 = backend === "self" ? "apps/web" : "apps/server";
|
|
4803
|
+
const envPath = path.join(projectDir, targetApp2, ".env");
|
|
4771
4804
|
const variables = [{
|
|
4772
4805
|
key: "DATABASE_URL",
|
|
4773
4806
|
value: `file:${path.join(projectDir, "apps/server", "local.db")}`,
|
|
@@ -4776,7 +4809,7 @@ async function setupCloudflareD1(config) {
|
|
|
4776
4809
|
try {
|
|
4777
4810
|
await addEnvVariablesToFile(envPath, variables);
|
|
4778
4811
|
} catch (_err) {}
|
|
4779
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
4812
|
+
const serverDir = path.join(projectDir, backend === "self" ? "apps/web" : "apps/server");
|
|
4780
4813
|
await addPackageDependency({
|
|
4781
4814
|
dependencies: ["@prisma/adapter-d1"],
|
|
4782
4815
|
projectDir: serverDir
|
|
@@ -4869,9 +4902,10 @@ async function initMongoDBAtlas(serverDir) {
|
|
|
4869
4902
|
return null;
|
|
4870
4903
|
}
|
|
4871
4904
|
}
|
|
4872
|
-
async function writeEnvFile$3(projectDir, config) {
|
|
4905
|
+
async function writeEnvFile$3(projectDir, backend, config) {
|
|
4873
4906
|
try {
|
|
4874
|
-
const
|
|
4907
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
4908
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4875
4909
|
const variables = [{
|
|
4876
4910
|
key: "DATABASE_URL",
|
|
4877
4911
|
value: config?.connectionString ?? "mongodb://localhost:27017/mydb",
|
|
@@ -4900,16 +4934,16 @@ ${pc.green("MongoDB Atlas Manual Setup Instructions:")}
|
|
|
4900
4934
|
`);
|
|
4901
4935
|
}
|
|
4902
4936
|
async function setupMongoDBAtlas(config, cliInput) {
|
|
4903
|
-
const { projectDir } = config;
|
|
4937
|
+
const { projectDir, backend } = config;
|
|
4904
4938
|
const manualDb = cliInput?.manualDb ?? false;
|
|
4905
4939
|
const mainSpinner = spinner();
|
|
4906
4940
|
mainSpinner.start("Setting up MongoDB Atlas...");
|
|
4907
|
-
const serverDir = path.join(projectDir, "
|
|
4941
|
+
const serverDir = path.join(projectDir, "packages/db");
|
|
4908
4942
|
try {
|
|
4909
4943
|
await fs.ensureDir(serverDir);
|
|
4910
4944
|
if (manualDb) {
|
|
4911
4945
|
mainSpinner.stop("MongoDB Atlas manual setup selected");
|
|
4912
|
-
await writeEnvFile$3(projectDir);
|
|
4946
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4913
4947
|
displayManualSetupInstructions$3();
|
|
4914
4948
|
return;
|
|
4915
4949
|
}
|
|
@@ -4929,25 +4963,25 @@ async function setupMongoDBAtlas(config, cliInput) {
|
|
|
4929
4963
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
4930
4964
|
if (mode === "manual") {
|
|
4931
4965
|
mainSpinner.stop("MongoDB Atlas manual setup selected");
|
|
4932
|
-
await writeEnvFile$3(projectDir);
|
|
4966
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4933
4967
|
displayManualSetupInstructions$3();
|
|
4934
4968
|
return;
|
|
4935
4969
|
}
|
|
4936
4970
|
mainSpinner.stop("MongoDB Atlas setup ready");
|
|
4937
4971
|
const config$1 = await initMongoDBAtlas(serverDir);
|
|
4938
4972
|
if (config$1) {
|
|
4939
|
-
await writeEnvFile$3(projectDir, config$1);
|
|
4973
|
+
await writeEnvFile$3(projectDir, backend, config$1);
|
|
4940
4974
|
log.success(pc.green("MongoDB Atlas setup complete! Connection saved to .env file."));
|
|
4941
4975
|
} else {
|
|
4942
4976
|
log.warn(pc.yellow("Falling back to local MongoDB configuration"));
|
|
4943
|
-
await writeEnvFile$3(projectDir);
|
|
4977
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4944
4978
|
displayManualSetupInstructions$3();
|
|
4945
4979
|
}
|
|
4946
4980
|
} catch (error) {
|
|
4947
4981
|
mainSpinner.stop(pc.red("MongoDB Atlas setup failed"));
|
|
4948
4982
|
consola.error(pc.red(`Error during MongoDB Atlas setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
4949
4983
|
try {
|
|
4950
|
-
await writeEnvFile$3(projectDir);
|
|
4984
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4951
4985
|
displayManualSetupInstructions$3();
|
|
4952
4986
|
} catch {}
|
|
4953
4987
|
}
|
|
@@ -5004,7 +5038,7 @@ async function executeNeonCommand(packageManager, commandArgsString, spinnerText
|
|
|
5004
5038
|
}
|
|
5005
5039
|
async function createNeonProject(projectName, regionId, packageManager) {
|
|
5006
5040
|
try {
|
|
5007
|
-
const commandArgsString = `neonctl projects create --name ${projectName} --region-id ${regionId} --output json`;
|
|
5041
|
+
const commandArgsString = `neonctl@latest projects create --name ${projectName} --region-id ${regionId} --output json`;
|
|
5008
5042
|
const { stdout } = await executeNeonCommand(packageManager, commandArgsString, `Creating Neon project "${projectName}"...`);
|
|
5009
5043
|
const response = JSON.parse(stdout);
|
|
5010
5044
|
if (response.project && response.connection_uris && response.connection_uris.length > 0) {
|
|
@@ -5024,8 +5058,9 @@ async function createNeonProject(projectName, regionId, packageManager) {
|
|
|
5024
5058
|
consola$1.error(pc.red("Failed to create Neon project"));
|
|
5025
5059
|
}
|
|
5026
5060
|
}
|
|
5027
|
-
async function writeEnvFile$2(projectDir, config) {
|
|
5028
|
-
const
|
|
5061
|
+
async function writeEnvFile$2(projectDir, backend, config) {
|
|
5062
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5063
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5029
5064
|
const variables = [{
|
|
5030
5065
|
key: "DATABASE_URL",
|
|
5031
5066
|
value: config?.connectionString ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
@@ -5034,16 +5069,17 @@ async function writeEnvFile$2(projectDir, config) {
|
|
|
5034
5069
|
await addEnvVariablesToFile(envPath, variables);
|
|
5035
5070
|
return true;
|
|
5036
5071
|
}
|
|
5037
|
-
async function setupWithNeonDb(projectDir, packageManager) {
|
|
5072
|
+
async function setupWithNeonDb(projectDir, packageManager, backend) {
|
|
5038
5073
|
try {
|
|
5039
5074
|
const s = spinner();
|
|
5040
5075
|
s.start("Creating Neon database using neondb...");
|
|
5041
|
-
const
|
|
5042
|
-
|
|
5043
|
-
|
|
5076
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5077
|
+
const targetDir = path.join(projectDir, targetApp);
|
|
5078
|
+
await fs.ensureDir(targetDir);
|
|
5079
|
+
const packageCmd = getPackageExecutionCommand(packageManager, "neondb@latest --yes");
|
|
5044
5080
|
await execa(packageCmd, {
|
|
5045
5081
|
shell: true,
|
|
5046
|
-
cwd:
|
|
5082
|
+
cwd: targetDir
|
|
5047
5083
|
});
|
|
5048
5084
|
s.stop(pc.green("Neon database created successfully!"));
|
|
5049
5085
|
return true;
|
|
@@ -5052,23 +5088,23 @@ async function setupWithNeonDb(projectDir, packageManager) {
|
|
|
5052
5088
|
throw error;
|
|
5053
5089
|
}
|
|
5054
5090
|
}
|
|
5055
|
-
function displayManualSetupInstructions$2() {
|
|
5091
|
+
function displayManualSetupInstructions$2(target) {
|
|
5056
5092
|
log.info(`Manual Neon PostgreSQL Setup Instructions:
|
|
5057
5093
|
|
|
5058
5094
|
1. Visit https://neon.tech and create an account
|
|
5059
5095
|
2. Create a new project from the dashboard
|
|
5060
5096
|
3. Get your connection string
|
|
5061
|
-
4. Add the database URL to the .env file in
|
|
5097
|
+
4. Add the database URL to the .env file in ${target}/.env
|
|
5062
5098
|
|
|
5063
5099
|
DATABASE_URL="your_connection_string"`);
|
|
5064
5100
|
}
|
|
5065
5101
|
async function setupNeonPostgres(config, cliInput) {
|
|
5066
|
-
const { packageManager, projectDir } = config;
|
|
5102
|
+
const { packageManager, projectDir, backend } = config;
|
|
5067
5103
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5068
5104
|
try {
|
|
5069
5105
|
if (manualDb) {
|
|
5070
|
-
await writeEnvFile$2(projectDir);
|
|
5071
|
-
displayManualSetupInstructions$2();
|
|
5106
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5107
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
5072
5108
|
return;
|
|
5073
5109
|
}
|
|
5074
5110
|
const mode = await select({
|
|
@@ -5086,8 +5122,8 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
5086
5122
|
});
|
|
5087
5123
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5088
5124
|
if (mode === "manual") {
|
|
5089
|
-
await writeEnvFile$2(projectDir);
|
|
5090
|
-
displayManualSetupInstructions$2();
|
|
5125
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5126
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
5091
5127
|
return;
|
|
5092
5128
|
}
|
|
5093
5129
|
const setupMethod = await select({
|
|
@@ -5104,7 +5140,7 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
5104
5140
|
initialValue: "neondb"
|
|
5105
5141
|
});
|
|
5106
5142
|
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
5107
|
-
if (setupMethod === "neondb") await setupWithNeonDb(projectDir, packageManager);
|
|
5143
|
+
if (setupMethod === "neondb") await setupWithNeonDb(projectDir, packageManager, backend);
|
|
5108
5144
|
else {
|
|
5109
5145
|
const suggestedProjectName = path.basename(projectDir);
|
|
5110
5146
|
const projectName = await text({
|
|
@@ -5122,22 +5158,22 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
5122
5158
|
if (!neonConfig) throw new Error("Failed to create project - couldn't get connection information");
|
|
5123
5159
|
const finalSpinner = spinner();
|
|
5124
5160
|
finalSpinner.start("Configuring database connection");
|
|
5125
|
-
await
|
|
5126
|
-
await writeEnvFile$2(projectDir, neonConfig);
|
|
5161
|
+
await writeEnvFile$2(projectDir, backend, neonConfig);
|
|
5127
5162
|
finalSpinner.stop("Neon database configured!");
|
|
5128
5163
|
}
|
|
5129
5164
|
} catch (error) {
|
|
5130
5165
|
if (error instanceof Error) consola$1.error(pc.red(error.message));
|
|
5131
|
-
await writeEnvFile$2(projectDir);
|
|
5132
|
-
displayManualSetupInstructions$2();
|
|
5166
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5167
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
5133
5168
|
}
|
|
5134
5169
|
}
|
|
5135
5170
|
|
|
5136
5171
|
//#endregion
|
|
5137
5172
|
//#region src/helpers/database-providers/planetscale-setup.ts
|
|
5138
5173
|
async function setupPlanetScale(config) {
|
|
5139
|
-
const { projectDir, database, orm } = config;
|
|
5140
|
-
const
|
|
5174
|
+
const { projectDir, database, orm, backend } = config;
|
|
5175
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5176
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5141
5177
|
if (database === "mysql" && orm === "drizzle") {
|
|
5142
5178
|
const variables = [
|
|
5143
5179
|
{
|
|
@@ -5161,7 +5197,7 @@ async function setupPlanetScale(config) {
|
|
|
5161
5197
|
condition: true
|
|
5162
5198
|
}
|
|
5163
5199
|
];
|
|
5164
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5200
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
5165
5201
|
await addEnvVariablesToFile(envPath, variables);
|
|
5166
5202
|
}
|
|
5167
5203
|
if (database === "postgres" && orm === "prisma") {
|
|
@@ -5170,7 +5206,7 @@ async function setupPlanetScale(config) {
|
|
|
5170
5206
|
value: "postgresql://username:password@host/database?sslaccept=strict",
|
|
5171
5207
|
condition: true
|
|
5172
5208
|
}];
|
|
5173
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5209
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
5174
5210
|
await addEnvVariablesToFile(envPath, variables);
|
|
5175
5211
|
}
|
|
5176
5212
|
if (database === "postgres" && orm === "drizzle") {
|
|
@@ -5179,7 +5215,7 @@ async function setupPlanetScale(config) {
|
|
|
5179
5215
|
value: "postgresql://username:password@host/database?sslmode=verify-full",
|
|
5180
5216
|
condition: true
|
|
5181
5217
|
}];
|
|
5182
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5218
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
5183
5219
|
await addEnvVariablesToFile(envPath, variables);
|
|
5184
5220
|
}
|
|
5185
5221
|
if (database === "mysql" && orm === "prisma") {
|
|
@@ -5188,7 +5224,7 @@ async function setupPlanetScale(config) {
|
|
|
5188
5224
|
value: "mysql://username:password@host/database?sslaccept=strict",
|
|
5189
5225
|
condition: true
|
|
5190
5226
|
}];
|
|
5191
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5227
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
5192
5228
|
await addEnvVariablesToFile(envPath, variables);
|
|
5193
5229
|
}
|
|
5194
5230
|
}
|
|
@@ -5258,7 +5294,7 @@ async function initPrismaDatabase(serverDir, packageManager) {
|
|
|
5258
5294
|
try {
|
|
5259
5295
|
const prismaDir = path.join(serverDir, "prisma");
|
|
5260
5296
|
await fs.ensureDir(prismaDir);
|
|
5261
|
-
log.info("Starting Prisma PostgreSQL setup.
|
|
5297
|
+
log.info("Starting Prisma PostgreSQL setup.");
|
|
5262
5298
|
const prismaInitCommand = getPackageExecutionCommand(packageManager, "prisma init --db");
|
|
5263
5299
|
await execa(prismaInitCommand, {
|
|
5264
5300
|
cwd: serverDir,
|
|
@@ -5280,9 +5316,10 @@ async function initPrismaDatabase(serverDir, packageManager) {
|
|
|
5280
5316
|
return null;
|
|
5281
5317
|
}
|
|
5282
5318
|
}
|
|
5283
|
-
async function writeEnvFile$1(projectDir, config) {
|
|
5319
|
+
async function writeEnvFile$1(projectDir, backend, config) {
|
|
5284
5320
|
try {
|
|
5285
|
-
const
|
|
5321
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5322
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5286
5323
|
const variables = [{
|
|
5287
5324
|
key: "DATABASE_URL",
|
|
5288
5325
|
value: config?.databaseUrl ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
@@ -5298,23 +5335,23 @@ async function writeEnvFile$1(projectDir, config) {
|
|
|
5298
5335
|
consola$1.error("Failed to update environment configuration");
|
|
5299
5336
|
}
|
|
5300
5337
|
}
|
|
5301
|
-
async function addDotenvImportToPrismaConfig(projectDir) {
|
|
5338
|
+
async function addDotenvImportToPrismaConfig(projectDir, backend) {
|
|
5302
5339
|
try {
|
|
5303
5340
|
const prismaConfigPath = path.join(projectDir, "packages/db/prisma.config.ts");
|
|
5304
5341
|
let content = await fs.readFile(prismaConfigPath, "utf8");
|
|
5305
|
-
content = `import dotenv from "dotenv";\ndotenv.config({ path: "../../apps/server/.env" });\n${content}`;
|
|
5342
|
+
content = `import dotenv from "dotenv";\ndotenv.config({ path: "${backend === "self" ? "../../apps/web/.env" : "../../apps/server/.env"}" });\n${content}`;
|
|
5306
5343
|
await fs.writeFile(prismaConfigPath, content);
|
|
5307
5344
|
} catch (_error) {
|
|
5308
5345
|
consola$1.error("Failed to update prisma.config.ts");
|
|
5309
5346
|
}
|
|
5310
5347
|
}
|
|
5311
|
-
function displayManualSetupInstructions$1() {
|
|
5348
|
+
function displayManualSetupInstructions$1(target) {
|
|
5312
5349
|
log.info(`Manual Prisma PostgreSQL Setup Instructions:
|
|
5313
5350
|
|
|
5314
5351
|
1. Visit https://console.prisma.io and create an account
|
|
5315
5352
|
2. Create a new PostgreSQL database from the dashboard
|
|
5316
5353
|
3. Get your database URL
|
|
5317
|
-
4. Add the database URL to the .env file in
|
|
5354
|
+
4. Add the database URL to the .env file in ${target}/.env
|
|
5318
5355
|
|
|
5319
5356
|
DATABASE_URL="your_database_url"`);
|
|
5320
5357
|
}
|
|
@@ -5332,14 +5369,14 @@ async function addPrismaAccelerateExtension(projectDir) {
|
|
|
5332
5369
|
}
|
|
5333
5370
|
}
|
|
5334
5371
|
async function setupPrismaPostgres(config, cliInput) {
|
|
5335
|
-
const { packageManager, projectDir, orm } = config;
|
|
5372
|
+
const { packageManager, projectDir, orm, backend } = config;
|
|
5336
5373
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5337
|
-
const
|
|
5374
|
+
const dbDir = path.join(projectDir, "packages/db");
|
|
5338
5375
|
try {
|
|
5339
|
-
await fs.ensureDir(
|
|
5376
|
+
await fs.ensureDir(dbDir);
|
|
5340
5377
|
if (manualDb) {
|
|
5341
|
-
await writeEnvFile$1(projectDir);
|
|
5342
|
-
displayManualSetupInstructions$1();
|
|
5378
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5379
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5343
5380
|
return;
|
|
5344
5381
|
}
|
|
5345
5382
|
const mode = await select({
|
|
@@ -5357,8 +5394,8 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5357
5394
|
});
|
|
5358
5395
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5359
5396
|
if (mode === "manual") {
|
|
5360
|
-
await writeEnvFile$1(projectDir);
|
|
5361
|
-
displayManualSetupInstructions$1();
|
|
5397
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5398
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5362
5399
|
return;
|
|
5363
5400
|
}
|
|
5364
5401
|
const setupOptions = [{
|
|
@@ -5378,26 +5415,26 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5378
5415
|
});
|
|
5379
5416
|
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
5380
5417
|
let prismaConfig = null;
|
|
5381
|
-
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(
|
|
5382
|
-
else prismaConfig = await initPrismaDatabase(
|
|
5418
|
+
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(dbDir, packageManager, orm);
|
|
5419
|
+
else prismaConfig = await initPrismaDatabase(dbDir, packageManager);
|
|
5383
5420
|
if (prismaConfig) {
|
|
5384
|
-
await writeEnvFile$1(projectDir, prismaConfig);
|
|
5421
|
+
await writeEnvFile$1(projectDir, backend, prismaConfig);
|
|
5385
5422
|
if (orm === "prisma") {
|
|
5386
|
-
await addDotenvImportToPrismaConfig(projectDir);
|
|
5423
|
+
await addDotenvImportToPrismaConfig(projectDir, backend);
|
|
5387
5424
|
await addPrismaAccelerateExtension(projectDir);
|
|
5388
5425
|
}
|
|
5389
5426
|
const connectionType = orm === "drizzle" ? "direct connection" : "Prisma Accelerate";
|
|
5390
5427
|
log.success(pc.green(`Prisma Postgres database configured successfully with ${connectionType}!`));
|
|
5391
5428
|
if (prismaConfig.claimUrl) log.info(pc.blue(`Claim URL saved to .env: ${prismaConfig.claimUrl}`));
|
|
5392
5429
|
} else {
|
|
5393
|
-
await writeEnvFile$1(projectDir);
|
|
5394
|
-
displayManualSetupInstructions$1();
|
|
5430
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5431
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5395
5432
|
}
|
|
5396
5433
|
} catch (error) {
|
|
5397
5434
|
consola$1.error(pc.red(`Error during Prisma Postgres setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
5398
5435
|
try {
|
|
5399
|
-
await writeEnvFile$1(projectDir);
|
|
5400
|
-
displayManualSetupInstructions$1();
|
|
5436
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5437
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5401
5438
|
} catch {}
|
|
5402
5439
|
log.info("Setup completed with manual configuration required.");
|
|
5403
5440
|
}
|
|
@@ -5405,9 +5442,10 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5405
5442
|
|
|
5406
5443
|
//#endregion
|
|
5407
5444
|
//#region src/helpers/database-providers/supabase-setup.ts
|
|
5408
|
-
async function writeSupabaseEnvFile(projectDir, databaseUrl) {
|
|
5445
|
+
async function writeSupabaseEnvFile(projectDir, backend, databaseUrl) {
|
|
5409
5446
|
try {
|
|
5410
|
-
const
|
|
5447
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5448
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5411
5449
|
const dbUrlToUse = databaseUrl || "postgresql://postgres:postgres@127.0.0.1:54322/postgres";
|
|
5412
5450
|
await addEnvVariablesToFile(envPath, [{
|
|
5413
5451
|
key: "DATABASE_URL",
|
|
@@ -5493,14 +5531,14 @@ ${pc.dim(output)}` : ""}
|
|
|
5493
5531
|
${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
|
|
5494
5532
|
}
|
|
5495
5533
|
async function setupSupabase(config, cliInput) {
|
|
5496
|
-
const { projectDir, packageManager } = config;
|
|
5534
|
+
const { projectDir, packageManager, backend } = config;
|
|
5497
5535
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5498
5536
|
const serverDir = path.join(projectDir, "packages", "db");
|
|
5499
5537
|
try {
|
|
5500
5538
|
await fs.ensureDir(serverDir);
|
|
5501
5539
|
if (manualDb) {
|
|
5502
5540
|
displayManualSupabaseInstructions();
|
|
5503
|
-
await writeSupabaseEnvFile(projectDir, "");
|
|
5541
|
+
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
5504
5542
|
return;
|
|
5505
5543
|
}
|
|
5506
5544
|
const mode = await select({
|
|
@@ -5519,7 +5557,7 @@ async function setupSupabase(config, cliInput) {
|
|
|
5519
5557
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5520
5558
|
if (mode === "manual") {
|
|
5521
5559
|
displayManualSupabaseInstructions();
|
|
5522
|
-
await writeSupabaseEnvFile(projectDir, "");
|
|
5560
|
+
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
5523
5561
|
return;
|
|
5524
5562
|
}
|
|
5525
5563
|
if (!await initializeSupabase(serverDir, packageManager)) {
|
|
@@ -5532,7 +5570,7 @@ async function setupSupabase(config, cliInput) {
|
|
|
5532
5570
|
return;
|
|
5533
5571
|
}
|
|
5534
5572
|
const dbUrl = extractDbUrl(supabaseOutput);
|
|
5535
|
-
if (dbUrl) if (await writeSupabaseEnvFile(projectDir, dbUrl)) log.success(pc.green("Supabase local development setup ready!"));
|
|
5573
|
+
if (dbUrl) if (await writeSupabaseEnvFile(projectDir, backend, dbUrl)) log.success(pc.green("Supabase local development setup ready!"));
|
|
5536
5574
|
else {
|
|
5537
5575
|
log.error(pc.red("Supabase setup completed, but failed to update .env automatically."));
|
|
5538
5576
|
displayManualSupabaseInstructions(supabaseOutput);
|
|
@@ -5660,8 +5698,9 @@ async function createTursoDatabase(dbName, groupName) {
|
|
|
5660
5698
|
s.stop(pc.red("Failed to retrieve database connection details"));
|
|
5661
5699
|
}
|
|
5662
5700
|
}
|
|
5663
|
-
async function writeEnvFile(projectDir, config) {
|
|
5664
|
-
const
|
|
5701
|
+
async function writeEnvFile(projectDir, backend, config) {
|
|
5702
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5703
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5665
5704
|
const variables = [{
|
|
5666
5705
|
key: "DATABASE_URL",
|
|
5667
5706
|
value: config?.dbUrl ?? "",
|
|
@@ -5685,12 +5724,12 @@ DATABASE_URL=your_database_url
|
|
|
5685
5724
|
DATABASE_AUTH_TOKEN=your_auth_token`);
|
|
5686
5725
|
}
|
|
5687
5726
|
async function setupTurso(config, cliInput) {
|
|
5688
|
-
const { orm, projectDir } = config;
|
|
5727
|
+
const { orm, projectDir, backend } = config;
|
|
5689
5728
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5690
5729
|
const setupSpinner = spinner();
|
|
5691
5730
|
try {
|
|
5692
5731
|
if (manualDb) {
|
|
5693
|
-
await writeEnvFile(projectDir);
|
|
5732
|
+
await writeEnvFile(projectDir, backend);
|
|
5694
5733
|
displayManualSetupInstructions();
|
|
5695
5734
|
return;
|
|
5696
5735
|
}
|
|
@@ -5709,7 +5748,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5709
5748
|
});
|
|
5710
5749
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5711
5750
|
if (mode === "manual") {
|
|
5712
|
-
await writeEnvFile(projectDir);
|
|
5751
|
+
await writeEnvFile(projectDir, backend);
|
|
5713
5752
|
displayManualSetupInstructions();
|
|
5714
5753
|
return;
|
|
5715
5754
|
}
|
|
@@ -5719,7 +5758,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5719
5758
|
if (platform === "win32") {
|
|
5720
5759
|
if (setupSpinner) setupSpinner.stop(pc.yellow("Turso setup not supported on Windows"));
|
|
5721
5760
|
log.warn(pc.yellow("Automatic Turso setup is not supported on Windows."));
|
|
5722
|
-
await writeEnvFile(projectDir);
|
|
5761
|
+
await writeEnvFile(projectDir, backend);
|
|
5723
5762
|
displayManualSetupInstructions();
|
|
5724
5763
|
return;
|
|
5725
5764
|
}
|
|
@@ -5731,7 +5770,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5731
5770
|
});
|
|
5732
5771
|
if (isCancel(shouldInstall)) return exitCancelled("Operation cancelled");
|
|
5733
5772
|
if (!shouldInstall) {
|
|
5734
|
-
await writeEnvFile(projectDir);
|
|
5773
|
+
await writeEnvFile(projectDir, backend);
|
|
5735
5774
|
displayManualSetupInstructions();
|
|
5736
5775
|
return;
|
|
5737
5776
|
}
|
|
@@ -5753,7 +5792,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5753
5792
|
dbName = dbNameResponse;
|
|
5754
5793
|
try {
|
|
5755
5794
|
const config$1 = await createTursoDatabase(dbName, selectedGroup);
|
|
5756
|
-
await writeEnvFile(projectDir, config$1);
|
|
5795
|
+
await writeEnvFile(projectDir, backend, config$1);
|
|
5757
5796
|
success = true;
|
|
5758
5797
|
} catch (error) {
|
|
5759
5798
|
if (error instanceof Error && error.message === "DATABASE_EXISTS") {
|
|
@@ -5766,7 +5805,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5766
5805
|
} catch (error) {
|
|
5767
5806
|
if (setupSpinner) setupSpinner.stop(pc.red("Turso CLI availability check failed"));
|
|
5768
5807
|
consola.error(pc.red(`Error during Turso setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
5769
|
-
await writeEnvFile(projectDir);
|
|
5808
|
+
await writeEnvFile(projectDir, backend);
|
|
5770
5809
|
displayManualSetupInstructions();
|
|
5771
5810
|
log.success("Setup completed with manual configuration required.");
|
|
5772
5811
|
}
|
|
@@ -5788,26 +5827,34 @@ async function setupDatabase(config, cliInput) {
|
|
|
5788
5827
|
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5789
5828
|
if (!await fs.pathExists(dbPackageDir)) return;
|
|
5790
5829
|
try {
|
|
5791
|
-
if (orm === "prisma")
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5830
|
+
if (orm === "prisma") {
|
|
5831
|
+
if (database === "mysql" && dbSetup === "planetscale") await addPackageDependency({
|
|
5832
|
+
dependencies: [
|
|
5833
|
+
"@prisma/client",
|
|
5834
|
+
"@prisma/adapter-planetscale",
|
|
5835
|
+
"@planetscale/database"
|
|
5836
|
+
],
|
|
5837
|
+
devDependencies: ["prisma"],
|
|
5838
|
+
projectDir: dbPackageDir
|
|
5839
|
+
});
|
|
5840
|
+
else if (database === "sqlite" && dbSetup === "turso") await addPackageDependency({
|
|
5841
|
+
dependencies: ["@prisma/client", "@prisma/adapter-libsql"],
|
|
5842
|
+
devDependencies: ["prisma"],
|
|
5843
|
+
projectDir: dbPackageDir
|
|
5844
|
+
});
|
|
5845
|
+
else await addPackageDependency({
|
|
5846
|
+
dependencies: ["@prisma/client"],
|
|
5847
|
+
devDependencies: ["prisma"],
|
|
5848
|
+
projectDir: dbPackageDir
|
|
5849
|
+
});
|
|
5850
|
+
if (backend === "self") {
|
|
5851
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
5852
|
+
if (await fs.pathExists(webDir)) await addPackageDependency({
|
|
5853
|
+
dependencies: ["@prisma/client"],
|
|
5854
|
+
projectDir: webDir
|
|
5855
|
+
});
|
|
5856
|
+
}
|
|
5857
|
+
} else if (orm === "drizzle") {
|
|
5811
5858
|
if (database === "sqlite") await addPackageDependency({
|
|
5812
5859
|
dependencies: [
|
|
5813
5860
|
"drizzle-orm",
|
|
@@ -6261,15 +6308,14 @@ async function initializeGit(projectDir, useGit) {
|
|
|
6261
6308
|
async function setupPayments(config) {
|
|
6262
6309
|
const { payments, projectDir, frontend } = config;
|
|
6263
6310
|
if (!payments || payments === "none") return;
|
|
6264
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
6265
6311
|
const clientDir = path.join(projectDir, "apps/web");
|
|
6266
|
-
const
|
|
6312
|
+
const authDir = path.join(projectDir, "packages/auth");
|
|
6267
6313
|
const clientDirExists = await fs.pathExists(clientDir);
|
|
6268
|
-
|
|
6314
|
+
const authDirExists = await fs.pathExists(authDir);
|
|
6269
6315
|
if (payments === "polar") {
|
|
6270
|
-
await addPackageDependency({
|
|
6316
|
+
if (authDirExists) await addPackageDependency({
|
|
6271
6317
|
dependencies: ["@polar-sh/better-auth", "@polar-sh/sdk"],
|
|
6272
|
-
projectDir:
|
|
6318
|
+
projectDir: authDir
|
|
6273
6319
|
});
|
|
6274
6320
|
if (clientDirExists) {
|
|
6275
6321
|
if (frontend.some((f) => [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "2.50.0-canary.
|
|
3
|
+
"version": "2.50.0-canary.5b25d7db",
|
|
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,21 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { createContext } from "@{{projectName}}/api/context";
|
|
2
|
+
import { appRouter } from "@{{projectName}}/api/routers/index";
|
|
3
|
+
import { OpenAPIHandler } from "@orpc/openapi/fetch";
|
|
4
|
+
import { OpenAPIReferencePlugin } from "@orpc/openapi/plugins";
|
|
5
|
+
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
|
|
6
|
+
import { RPCHandler } from "@orpc/server/fetch";
|
|
7
|
+
import { onError } from "@orpc/server";
|
|
8
|
+
import { NextRequest } from "next/server";
|
|
4
9
|
|
|
5
|
-
const
|
|
10
|
+
const rpcHandler = new RPCHandler(appRouter, {
|
|
11
|
+
interceptors: [
|
|
12
|
+
onError((error) => {
|
|
13
|
+
console.error(error);
|
|
14
|
+
}),
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
const apiHandler = new OpenAPIHandler(appRouter, {
|
|
18
|
+
plugins: [
|
|
19
|
+
new OpenAPIReferencePlugin({
|
|
20
|
+
schemaConverters: [new ZodToJsonSchemaConverter()],
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
interceptors: [
|
|
24
|
+
onError((error) => {
|
|
25
|
+
console.error(error);
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
28
|
+
});
|
|
6
29
|
|
|
7
|
-
async function handleRequest(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
30
|
+
async function handleRequest(req: NextRequest) {
|
|
31
|
+
const rpcResult = await rpcHandler.handle(req, {
|
|
32
|
+
prefix: "/api/rpc",
|
|
33
|
+
context: await createContext(req),
|
|
34
|
+
});
|
|
35
|
+
if (rpcResult.response) return rpcResult.response;
|
|
12
36
|
|
|
13
|
-
|
|
37
|
+
const apiResult = await apiHandler.handle(req, {
|
|
38
|
+
prefix: "/api/rpc/api",
|
|
39
|
+
context: await createContext(req),
|
|
40
|
+
});
|
|
41
|
+
if (apiResult.response) return apiResult.response;
|
|
42
|
+
|
|
43
|
+
return new Response("Not found", { status: 404 });
|
|
14
44
|
}
|
|
15
45
|
|
|
16
|
-
export const
|
|
17
|
-
export const
|
|
18
|
-
export const
|
|
19
|
-
export const
|
|
20
|
-
export const
|
|
21
|
-
export const DELETE = handleRequest
|
|
46
|
+
export const GET = handleRequest;
|
|
47
|
+
export const POST = handleRequest;
|
|
48
|
+
export const PUT = handleRequest;
|
|
49
|
+
export const PATCH = handleRequest;
|
|
50
|
+
export const DELETE = handleRequest;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineNuxtPlugin, useRuntimeConfig } from '#app'
|
|
2
|
-
import type { AppRouterClient } from "@{{projectName}}/api/
|
|
2
|
+
import type { AppRouterClient } from "@{{projectName}}/api/routers/index";
|
|
3
3
|
import { createORPCClient } from '@orpc/client'
|
|
4
4
|
import { RPCLink } from '@orpc/client/fetch'
|
|
5
5
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
@@ -3,7 +3,7 @@ import { RPCLink } from "@orpc/client/fetch";
|
|
|
3
3
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
4
4
|
import { QueryCache, QueryClient } from "@tanstack/react-query";
|
|
5
5
|
import { toast } from "sonner";
|
|
6
|
-
import type { AppRouterClient } from "@{{projectName}}/api/
|
|
6
|
+
import type { AppRouterClient } from "@{{projectName}}/api/routers/index";
|
|
7
7
|
|
|
8
8
|
export const queryClient = new QueryClient({
|
|
9
9
|
queryCache: new QueryCache({
|
|
@@ -22,7 +22,7 @@ export const queryClient = new QueryClient({
|
|
|
22
22
|
|
|
23
23
|
export const link = new RPCLink({
|
|
24
24
|
{{#if (and (eq backend "self") (includes frontend "next"))}}
|
|
25
|
-
url: "/api/rpc
|
|
25
|
+
url: `${typeof window !== "undefined" ? window.location.origin : "http://localhost:3001"}/api/rpc`,
|
|
26
26
|
{{else if (includes frontend "next")}}
|
|
27
27
|
url: `${process.env.NEXT_PUBLIC_SERVER_URL}/rpc`,
|
|
28
28
|
{{else}}
|
|
@@ -2,7 +2,7 @@ import { createORPCClient } from "@orpc/client";
|
|
|
2
2
|
import { RPCLink } from "@orpc/client/fetch";
|
|
3
3
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
4
4
|
import { QueryCache, QueryClient } from "@tanstack/solid-query";
|
|
5
|
-
import type { AppRouterClient } from "@{{projectName}}/api/
|
|
5
|
+
import type { AppRouterClient } from "@{{projectName}}/api/routers/index";
|
|
6
6
|
|
|
7
7
|
export const queryClient = new QueryClient({
|
|
8
8
|
queryCache: new QueryCache({
|
|
@@ -3,7 +3,7 @@ import { createORPCClient } from "@orpc/client";
|
|
|
3
3
|
import { RPCLink } from "@orpc/client/fetch";
|
|
4
4
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
5
5
|
import { QueryCache, QueryClient } from "@tanstack/svelte-query";
|
|
6
|
-
import type { AppRouterClient } from "@{{projectName}}/api/
|
|
6
|
+
import type { AppRouterClient } from "@{{projectName}}/api/routers/index";
|
|
7
7
|
|
|
8
8
|
export const queryClient = new QueryClient({
|
|
9
9
|
queryCache: new QueryCache({
|
|
@@ -49,13 +49,13 @@ export const trpc = createTRPCOptionsProxy<AppRouter>({
|
|
|
49
49
|
|
|
50
50
|
{{else if (includes frontend 'tanstack-start')}}
|
|
51
51
|
import { createTRPCContext } from "@trpc/tanstack-react-query";
|
|
52
|
-
import type { AppRouter } from "@{{projectName}}/api/
|
|
52
|
+
import type { AppRouter } from "@{{projectName}}/api/routers/index";
|
|
53
53
|
|
|
54
54
|
export const { TRPCProvider, useTRPC, useTRPCClient } =
|
|
55
55
|
createTRPCContext<AppRouter>();
|
|
56
56
|
|
|
57
57
|
{{else}}
|
|
58
|
-
import type { AppRouter } from "@{{projectName}}/api/
|
|
58
|
+
import type { AppRouter } from "@{{projectName}}/api/routers/index";
|
|
59
59
|
import { QueryCache, QueryClient } from "@tanstack/react-query";
|
|
60
60
|
import { createTRPCClient, httpBatchLink } from "@trpc/client";
|
|
61
61
|
import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query";
|
|
@@ -6,7 +6,7 @@ import { expo } from "@better-auth/expo";
|
|
|
6
6
|
{{/if}}
|
|
7
7
|
{{#if (eq payments "polar")}}
|
|
8
8
|
import { polar, checkout, portal } from "@polar-sh/better-auth";
|
|
9
|
-
import { polarClient } from "./payments";
|
|
9
|
+
import { polarClient } from "./lib/payments";
|
|
10
10
|
{{/if}}
|
|
11
11
|
import prisma from "@{{projectName}}/db";
|
|
12
12
|
|
|
@@ -74,7 +74,7 @@ import { expo } from "@better-auth/expo";
|
|
|
74
74
|
{{/if}}
|
|
75
75
|
{{#if (eq payments "polar")}}
|
|
76
76
|
import { polar, checkout, portal } from "@polar-sh/better-auth";
|
|
77
|
-
import { polarClient } from "./payments";
|
|
77
|
+
import { polarClient } from "./lib/payments";
|
|
78
78
|
{{/if}}
|
|
79
79
|
import { db } from "@{{projectName}}/db";
|
|
80
80
|
import * as schema from "@{{projectName}}/db/schema/auth";
|
|
@@ -142,7 +142,7 @@ import { expo } from "@better-auth/expo";
|
|
|
142
142
|
{{/if}}
|
|
143
143
|
{{#if (eq payments "polar")}}
|
|
144
144
|
import { polar, checkout, portal } from "@polar-sh/better-auth";
|
|
145
|
-
import { polarClient } from "./payments";
|
|
145
|
+
import { polarClient } from "./lib/payments";
|
|
146
146
|
{{/if}}
|
|
147
147
|
import { db } from "@{{projectName}}/db";
|
|
148
148
|
import * as schema from "@{{projectName}}/db/schema/auth";
|
|
@@ -224,7 +224,7 @@ import { expo } from "@better-auth/expo";
|
|
|
224
224
|
{{/if}}
|
|
225
225
|
{{#if (eq payments "polar")}}
|
|
226
226
|
import { polar, checkout, portal } from "@polar-sh/better-auth";
|
|
227
|
-
import { polarClient } from "./payments";
|
|
227
|
+
import { polarClient } from "./lib/payments";
|
|
228
228
|
{{/if}}
|
|
229
229
|
import { client } from "@{{projectName}}/db";
|
|
230
230
|
|
|
@@ -285,7 +285,7 @@ import { expo } from "@better-auth/expo";
|
|
|
285
285
|
{{/if}}
|
|
286
286
|
{{#if (eq payments "polar")}}
|
|
287
287
|
import { polar, checkout, portal } from "@polar-sh/better-auth";
|
|
288
|
-
import { polarClient } from "./payments";
|
|
288
|
+
import { polarClient } from "./lib/payments";
|
|
289
289
|
{{/if}}
|
|
290
290
|
|
|
291
291
|
export const auth = betterAuth<BetterAuthOptions>({
|
|
@@ -4,12 +4,14 @@ import { polarClient } from "@polar-sh/better-auth";
|
|
|
4
4
|
{{/if}}
|
|
5
5
|
|
|
6
6
|
export const authClient = createAuthClient({
|
|
7
|
+
{{#unless (eq backend "self")}}
|
|
7
8
|
baseURL:
|
|
8
9
|
{{#if (includes frontend "next")}}
|
|
9
10
|
process.env.NEXT_PUBLIC_SERVER_URL,
|
|
10
11
|
{{else}}
|
|
11
12
|
import.meta.env.VITE_SERVER_URL,
|
|
12
13
|
{{/if}}
|
|
14
|
+
{{/unless}}
|
|
13
15
|
{{#if (eq payments "polar")}}
|
|
14
16
|
plugins: [polarClient()]
|
|
15
17
|
{{/if}}
|
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
{{#if (eq backend "self")}}
|
|
2
|
+
import { redirect } from "next/navigation";
|
|
3
|
+
import Dashboard from "./dashboard";
|
|
4
|
+
import { headers } from "next/headers";
|
|
5
|
+
import { auth } from "@{{projectName}}/auth";
|
|
6
|
+
|
|
7
|
+
export default async function DashboardPage() {
|
|
8
|
+
const session = await auth.api.getSession({
|
|
9
|
+
headers: await headers(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (!session?.user) {
|
|
13
|
+
redirect("/login");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
{{#if (eq payments "polar")}}
|
|
17
|
+
const { data: customerState } = await auth.api.customer.state({
|
|
18
|
+
headers: await headers(),
|
|
19
|
+
});
|
|
20
|
+
{{/if}}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div>
|
|
24
|
+
<h1>Dashboard</h1>
|
|
25
|
+
<p>Welcome {session.user.name}</p>
|
|
26
|
+
<Dashboard session={session} {{#if (eq payments "polar")}}customerState={customerState}{{/if}} />
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
{{else}}
|
|
1
31
|
import { authClient } from "@/lib/auth-client";
|
|
2
32
|
import { redirect } from "next/navigation";
|
|
3
33
|
import Dashboard from "./dashboard";
|
|
@@ -35,3 +65,4 @@ export default async function DashboardPage() {
|
|
|
35
65
|
</div>
|
|
36
66
|
);
|
|
37
67
|
}
|
|
68
|
+
{{/if}}
|
|
@@ -2,7 +2,11 @@ import { defineConfig } from "drizzle-kit";
|
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
|
|
4
4
|
dotenv.config({
|
|
5
|
-
|
|
5
|
+
{{#if (eq backend "self")}}
|
|
6
|
+
path: "../../apps/web/.env",
|
|
7
|
+
{{else}}
|
|
8
|
+
path: "../../apps/server/.env",
|
|
9
|
+
{{/if}}
|
|
6
10
|
});
|
|
7
11
|
|
|
8
12
|
export default defineConfig({
|
|
@@ -2,7 +2,11 @@ import { defineConfig } from "drizzle-kit";
|
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
|
|
4
4
|
dotenv.config({
|
|
5
|
-
|
|
5
|
+
{{#if (eq backend "self")}}
|
|
6
|
+
path: "../../apps/web/.env",
|
|
7
|
+
{{else}}
|
|
8
|
+
path: "../../apps/server/.env",
|
|
9
|
+
{{/if}}
|
|
6
10
|
});
|
|
7
11
|
|
|
8
12
|
export default defineConfig({
|
|
@@ -2,7 +2,11 @@ import { defineConfig } from "drizzle-kit";
|
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
|
|
4
4
|
dotenv.config({
|
|
5
|
-
|
|
5
|
+
{{#if (eq backend "self")}}
|
|
6
|
+
path: "../../apps/web/.env",
|
|
7
|
+
{{else}}
|
|
8
|
+
path: "../../apps/server/.env",
|
|
9
|
+
{{/if}}
|
|
6
10
|
});
|
|
7
11
|
|
|
8
12
|
export default defineConfig({
|
|
@@ -3,7 +3,11 @@ import type { PrismaConfig } from "prisma";
|
|
|
3
3
|
import dotenv from "dotenv";
|
|
4
4
|
|
|
5
5
|
dotenv.config({
|
|
6
|
-
|
|
6
|
+
{{#if (eq backend "self")}}
|
|
7
|
+
path: "../../apps/web/.env",
|
|
8
|
+
{{else}}
|
|
9
|
+
path: "../../apps/server/.env",
|
|
10
|
+
{{/if}}
|
|
7
11
|
});
|
|
8
12
|
|
|
9
13
|
export default {
|
|
@@ -3,7 +3,11 @@ import type { PrismaConfig } from "prisma";
|
|
|
3
3
|
import dotenv from "dotenv";
|
|
4
4
|
|
|
5
5
|
dotenv.config({
|
|
6
|
-
|
|
6
|
+
{{#if (eq backend "self")}}
|
|
7
|
+
path: "../../apps/web/.env",
|
|
8
|
+
{{else}}
|
|
9
|
+
path: "../../apps/server/.env",
|
|
10
|
+
{{/if}}
|
|
7
11
|
});
|
|
8
12
|
|
|
9
13
|
export default {
|
|
@@ -4,7 +4,11 @@ import type { PrismaConfig } from "prisma";
|
|
|
4
4
|
import dotenv from "dotenv";
|
|
5
5
|
|
|
6
6
|
dotenv.config({
|
|
7
|
-
|
|
7
|
+
{{#if (eq backend "self")}}
|
|
8
|
+
path: "../../apps/web/.env",
|
|
9
|
+
{{else}}
|
|
10
|
+
path: "../../apps/server/.env",
|
|
11
|
+
{{/if}}
|
|
8
12
|
});
|
|
9
13
|
{{/unless}}
|
|
10
14
|
|
|
@@ -3,7 +3,11 @@ import type { PrismaConfig } from "prisma";
|
|
|
3
3
|
import dotenv from "dotenv";
|
|
4
4
|
|
|
5
5
|
dotenv.config({
|
|
6
|
-
|
|
6
|
+
{{#if (eq backend "self")}}
|
|
7
|
+
path: "../../apps/web/.env",
|
|
8
|
+
{{else}}
|
|
9
|
+
path: "../../apps/server/.env",
|
|
10
|
+
{{/if}}
|
|
7
11
|
});
|
|
8
12
|
|
|
9
13
|
export default {
|
|
@@ -8,10 +8,5 @@
|
|
|
8
8
|
"@/*": ["*"]
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
|
|
12
|
-
{{#unless (or (eq backend "convex") (eq backend "none"))}}
|
|
13
|
-
"references": [{
|
|
14
|
-
"path": "../server"
|
|
15
|
-
}]
|
|
16
|
-
{{/unless}}
|
|
11
|
+
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
|
|
17
12
|
}
|
|
@@ -8,7 +8,7 @@ import type { QueryClient } from "@tanstack/react-query";
|
|
|
8
8
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
|
9
9
|
import { useState } from "react";
|
|
10
10
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
11
|
-
import type { AppRouterClient } from "@{{projectName}}/api/
|
|
11
|
+
import type { AppRouterClient } from "@{{projectName}}/api/routers/index";
|
|
12
12
|
import { createORPCClient } from "@orpc/client";
|
|
13
13
|
{{/if}}
|
|
14
14
|
{{#if (eq api "trpc")}}
|
|
@@ -66,7 +66,7 @@ export interface RouterAppContext {
|
|
|
66
66
|
{{else}}
|
|
67
67
|
{{#if (eq api "trpc")}}
|
|
68
68
|
import type { TRPCOptionsProxy } from "@trpc/tanstack-react-query";
|
|
69
|
-
import type { AppRouter } from "@{{projectName}}/api/
|
|
69
|
+
import type { AppRouter } from "@{{projectName}}/api/routers/index";
|
|
70
70
|
export interface RouterAppContext {
|
|
71
71
|
trpc: TRPCOptionsProxy<AppRouter>;
|
|
72
72
|
queryClient: QueryClient;
|
|
@@ -10,12 +10,7 @@
|
|
|
10
10
|
"sourceMap": true,
|
|
11
11
|
"strict": true,
|
|
12
12
|
"moduleResolution": "bundler"
|
|
13
|
-
}
|
|
14
|
-
{{#unless (or (eq backend "convex") (eq backend "none"))}}
|
|
15
|
-
"references": [{
|
|
16
|
-
"path": "../server"
|
|
17
|
-
}]
|
|
18
|
-
{{/unless}}
|
|
13
|
+
}
|
|
19
14
|
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
|
20
15
|
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
|
21
16
|
//
|