create-better-t-stack 2.50.1-canary.58bbe5f6 → 2.50.1-canary.7ebd503f
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-CulfT5QB.js → src-DG05Vcnx.js} +127 -163
- package/package.json +1 -1
- package/templates/addons/ruler/.ruler/bts.md.hbs +14 -24
- package/templates/api/orpc/server/package.json.hbs +3 -1
- package/templates/api/orpc/server/tsconfig.json.hbs +8 -8
- package/templates/api/trpc/server/package.json.hbs +3 -1
- package/templates/api/trpc/server/tsconfig.json.hbs +11 -8
- package/templates/auth/better-auth/server/base/package.json.hbs +4 -1
- package/templates/auth/better-auth/server/base/tsconfig.json.hbs +11 -8
- package/templates/backend/server/base/tsconfig.json.hbs +15 -1
- package/templates/base/tsconfig.base.json.hbs +21 -32
- package/templates/db/base/package.json.hbs +3 -1
- package/templates/db/base/tsconfig.json.hbs +11 -8
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -347,16 +347,21 @@ function ensureSingleWebAndNative(frontends) {
|
|
|
347
347
|
if (web.length > 1) exitWithError("Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid");
|
|
348
348
|
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles");
|
|
349
349
|
}
|
|
350
|
-
const FULLSTACK_FRONTENDS$1 = [
|
|
350
|
+
const FULLSTACK_FRONTENDS$1 = [
|
|
351
|
+
"next",
|
|
352
|
+
"nuxt",
|
|
353
|
+
"svelte",
|
|
354
|
+
"tanstack-start"
|
|
355
|
+
];
|
|
351
356
|
function validateSelfBackendCompatibility(providedFlags, options, config) {
|
|
352
357
|
const backend = config.backend || options.backend;
|
|
353
358
|
const frontends = config.frontend || options.frontend || [];
|
|
354
359
|
if (backend === "self") {
|
|
355
|
-
if (!frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f))) exitWithError("Backend 'self' (fullstack)
|
|
360
|
+
if (!frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f))) exitWithError("Backend 'self' (fullstack) requires a fullstack-capable frontend. Please use --frontend with one of: next, nuxt, svelte, tanstack-start");
|
|
356
361
|
if (frontends.length > 1) exitWithError("Backend 'self' (fullstack) can only be used with a single frontend framework.");
|
|
357
362
|
}
|
|
358
363
|
const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f));
|
|
359
|
-
if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack)
|
|
364
|
+
if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack) is only compatible with fullstack-capable frontends: next, nuxt, svelte, tanstack-start. Please choose a different backend or use a fullstack frontend.");
|
|
360
365
|
}
|
|
361
366
|
function validateWorkersCompatibility(providedFlags, options, config) {
|
|
362
367
|
if (providedFlags.has("runtime") && options.runtime === "workers" && config.backend && config.backend !== "hono") exitWithError(`Cloudflare Workers runtime (--runtime workers) is only supported with Hono backend (--backend hono). Current backend: ${config.backend}. Please use '--backend hono' or choose a different runtime.`);
|
|
@@ -679,7 +684,12 @@ async function getAuthChoice(auth, hasDatabase, backend, frontend) {
|
|
|
679
684
|
|
|
680
685
|
//#endregion
|
|
681
686
|
//#region src/prompts/backend.ts
|
|
682
|
-
const FULLSTACK_FRONTENDS = [
|
|
687
|
+
const FULLSTACK_FRONTENDS = [
|
|
688
|
+
"next",
|
|
689
|
+
"nuxt",
|
|
690
|
+
"svelte",
|
|
691
|
+
"tanstack-start"
|
|
692
|
+
];
|
|
683
693
|
async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
684
694
|
if (backendFramework !== void 0) return backendFramework;
|
|
685
695
|
const hasIncompatibleFrontend = frontends?.some((f) => f === "solid");
|
|
@@ -3145,29 +3155,25 @@ async function setupDockerComposeTemplates(projectDir, context) {
|
|
|
3145
3155
|
if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir, dbPackageDir, context);
|
|
3146
3156
|
}
|
|
3147
3157
|
async function setupDeploymentTemplates(projectDir, context) {
|
|
3148
|
-
|
|
3149
|
-
if (context.webDeploy === "alchemy" || context.serverDeploy === "alchemy") {
|
|
3158
|
+
if (context.webDeploy === "alchemy" || context.serverDeploy === "alchemy") if (context.webDeploy === "alchemy" && context.serverDeploy === "alchemy") {
|
|
3150
3159
|
const alchemyTemplateSrc = path.join(PKG_ROOT, "templates/deploy/alchemy");
|
|
3151
|
-
if (
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
3169
|
-
await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
|
|
3170
|
-
}
|
|
3160
|
+
if (await fs.pathExists(alchemyTemplateSrc)) {
|
|
3161
|
+
await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, projectDir, context);
|
|
3162
|
+
const serverAppDir = path.join(projectDir, "apps/server");
|
|
3163
|
+
if (await fs.pathExists(serverAppDir)) await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
3164
|
+
}
|
|
3165
|
+
} else {
|
|
3166
|
+
if (context.webDeploy === "alchemy") {
|
|
3167
|
+
const alchemyTemplateSrc = path.join(PKG_ROOT, "templates/deploy/alchemy");
|
|
3168
|
+
const webAppDir = path.join(projectDir, "apps/web");
|
|
3169
|
+
if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(webAppDir)) await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, webAppDir, context);
|
|
3170
|
+
}
|
|
3171
|
+
if (context.serverDeploy === "alchemy") {
|
|
3172
|
+
const alchemyTemplateSrc = path.join(PKG_ROOT, "templates/deploy/alchemy");
|
|
3173
|
+
const serverAppDir = path.join(projectDir, "apps/server");
|
|
3174
|
+
if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(serverAppDir)) {
|
|
3175
|
+
await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
3176
|
+
await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
3171
3177
|
}
|
|
3172
3178
|
}
|
|
3173
3179
|
}
|
|
@@ -3190,7 +3196,7 @@ async function setupDeploymentTemplates(projectDir, context) {
|
|
|
3190
3196
|
}
|
|
3191
3197
|
}
|
|
3192
3198
|
}
|
|
3193
|
-
if (context.serverDeploy !== "none" && context.serverDeploy !== "alchemy"
|
|
3199
|
+
if (context.serverDeploy !== "none" && context.serverDeploy !== "alchemy") {
|
|
3194
3200
|
const serverAppDir = path.join(projectDir, "apps/server");
|
|
3195
3201
|
if (await fs.pathExists(serverAppDir)) {
|
|
3196
3202
|
const deployTemplateSrc = path.join(PKG_ROOT, `templates/deploy/${context.serverDeploy}/server`);
|
|
@@ -3198,18 +3204,6 @@ async function setupDeploymentTemplates(projectDir, context) {
|
|
|
3198
3204
|
}
|
|
3199
3205
|
}
|
|
3200
3206
|
}
|
|
3201
|
-
async function addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc) {
|
|
3202
|
-
for (const packageName of [
|
|
3203
|
-
"packages/api",
|
|
3204
|
-
"packages/auth",
|
|
3205
|
-
"packages/db"
|
|
3206
|
-
]) {
|
|
3207
|
-
const packageDir = path.join(projectDir, packageName);
|
|
3208
|
-
if (await fs.pathExists(packageDir)) await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, packageDir, context);
|
|
3209
|
-
}
|
|
3210
|
-
const serverAppDir = path.join(projectDir, "apps/server");
|
|
3211
|
-
if (await fs.pathExists(serverAppDir)) await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
3212
|
-
}
|
|
3213
3207
|
|
|
3214
3208
|
//#endregion
|
|
3215
3209
|
//#region src/helpers/core/add-addons.ts
|
|
@@ -3275,7 +3269,7 @@ async function setupServerDeploy(config) {
|
|
|
3275
3269
|
serverDir,
|
|
3276
3270
|
packageManager
|
|
3277
3271
|
});
|
|
3278
|
-
} else if (serverDeploy === "alchemy") await setupAlchemyServerDeploy(serverDir, packageManager
|
|
3272
|
+
} else if (serverDeploy === "alchemy") await setupAlchemyServerDeploy(serverDir, packageManager);
|
|
3279
3273
|
}
|
|
3280
3274
|
async function setupWorkersServerDeploy(serverDir, _packageManager) {
|
|
3281
3275
|
const packageJsonPath = path.join(serverDir, "package.json");
|
|
@@ -3312,7 +3306,7 @@ async function generateCloudflareWorkerTypes({ serverDir, packageManager }) {
|
|
|
3312
3306
|
log.warn(`Note: You can manually run 'cd apps/server && ${managerCmd} cf-typegen' in the project directory later`);
|
|
3313
3307
|
}
|
|
3314
3308
|
}
|
|
3315
|
-
async function setupAlchemyServerDeploy(serverDir, _packageManager
|
|
3309
|
+
async function setupAlchemyServerDeploy(serverDir, _packageManager) {
|
|
3316
3310
|
if (!await fs.pathExists(serverDir)) return;
|
|
3317
3311
|
await addPackageDependency({
|
|
3318
3312
|
devDependencies: [
|
|
@@ -3323,7 +3317,6 @@ async function setupAlchemyServerDeploy(serverDir, _packageManager, projectDir)
|
|
|
3323
3317
|
],
|
|
3324
3318
|
projectDir: serverDir
|
|
3325
3319
|
});
|
|
3326
|
-
if (projectDir) await addAlchemyPackagesDependencies$1(projectDir);
|
|
3327
3320
|
const packageJsonPath = path.join(serverDir, "package.json");
|
|
3328
3321
|
if (await fs.pathExists(packageJsonPath)) {
|
|
3329
3322
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
@@ -3336,19 +3329,6 @@ async function setupAlchemyServerDeploy(serverDir, _packageManager, projectDir)
|
|
|
3336
3329
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
3337
3330
|
}
|
|
3338
3331
|
}
|
|
3339
|
-
async function addAlchemyPackagesDependencies$1(projectDir) {
|
|
3340
|
-
for (const packageName of [
|
|
3341
|
-
"packages/api",
|
|
3342
|
-
"packages/auth",
|
|
3343
|
-
"packages/db"
|
|
3344
|
-
]) {
|
|
3345
|
-
const packageDir = path.join(projectDir, packageName);
|
|
3346
|
-
if (await fs.pathExists(packageDir)) await addPackageDependency({
|
|
3347
|
-
devDependencies: ["@cloudflare/workers-types"],
|
|
3348
|
-
projectDir: packageDir
|
|
3349
|
-
});
|
|
3350
|
-
}
|
|
3351
|
-
}
|
|
3352
3332
|
|
|
3353
3333
|
//#endregion
|
|
3354
3334
|
//#region src/helpers/deployment/alchemy/alchemy-next-setup.ts
|
|
@@ -3654,7 +3634,7 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
|
3654
3634
|
await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
|
|
3655
3635
|
}
|
|
3656
3636
|
const serverDir = path.join(projectDir, "apps/server");
|
|
3657
|
-
if (await fs.pathExists(serverDir)) await setupAlchemyServerDeploy(serverDir, packageManager
|
|
3637
|
+
if (await fs.pathExists(serverDir)) await setupAlchemyServerDeploy(serverDir, packageManager);
|
|
3658
3638
|
const frontend = config.frontend;
|
|
3659
3639
|
const isNext = frontend.includes("next");
|
|
3660
3640
|
const isNuxt = frontend.includes("nuxt");
|
|
@@ -3887,7 +3867,6 @@ async function setupWebDeploy(config) {
|
|
|
3887
3867
|
if (webDeploy !== "wrangler" && webDeploy !== "alchemy") return;
|
|
3888
3868
|
if (webDeploy === "alchemy" && serverDeploy === "alchemy") {
|
|
3889
3869
|
await setupCombinedAlchemyDeploy(projectDir, packageManager, config);
|
|
3890
|
-
await addAlchemyPackagesDependencies(projectDir);
|
|
3891
3870
|
return;
|
|
3892
3871
|
}
|
|
3893
3872
|
const isNext = frontend.includes("next");
|
|
@@ -3911,7 +3890,6 @@ async function setupWebDeploy(config) {
|
|
|
3911
3890
|
else if (isTanstackRouter) await setupTanStackRouterAlchemyDeploy(projectDir, packageManager);
|
|
3912
3891
|
else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager);
|
|
3913
3892
|
else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager);
|
|
3914
|
-
await addAlchemyPackagesDependencies(projectDir);
|
|
3915
3893
|
}
|
|
3916
3894
|
}
|
|
3917
3895
|
async function setupWorkersWebDeploy(projectDir, pkgManager) {
|
|
@@ -3929,19 +3907,6 @@ async function setupWorkersWebDeploy(projectDir, pkgManager) {
|
|
|
3929
3907
|
}
|
|
3930
3908
|
await setupWorkersVitePlugin(projectDir);
|
|
3931
3909
|
}
|
|
3932
|
-
async function addAlchemyPackagesDependencies(projectDir) {
|
|
3933
|
-
for (const packageName of [
|
|
3934
|
-
"packages/api",
|
|
3935
|
-
"packages/auth",
|
|
3936
|
-
"packages/db"
|
|
3937
|
-
]) {
|
|
3938
|
-
const packageDir = path.join(projectDir, packageName);
|
|
3939
|
-
if (await fs.pathExists(packageDir)) await addPackageDependency({
|
|
3940
|
-
devDependencies: ["@cloudflare/workers-types"],
|
|
3941
|
-
projectDir: packageDir
|
|
3942
|
-
});
|
|
3943
|
-
}
|
|
3944
|
-
}
|
|
3945
3910
|
|
|
3946
3911
|
//#endregion
|
|
3947
3912
|
//#region src/helpers/core/add-deployment.ts
|
|
@@ -4267,7 +4232,7 @@ function getConvexDependencies(frontend) {
|
|
|
4267
4232
|
return deps;
|
|
4268
4233
|
}
|
|
4269
4234
|
async function setupApi(config) {
|
|
4270
|
-
const { api, projectName, frontend, backend, packageManager, projectDir } = config;
|
|
4235
|
+
const { api, projectName, frontend, backend, packageManager, projectDir, auth } = config;
|
|
4271
4236
|
const isConvex = backend === "convex";
|
|
4272
4237
|
const webDir = path.join(projectDir, "apps/web");
|
|
4273
4238
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
@@ -4288,14 +4253,40 @@ async function setupApi(config) {
|
|
|
4288
4253
|
dependencies: apiDeps.server.dependencies,
|
|
4289
4254
|
projectDir: webDir
|
|
4290
4255
|
});
|
|
4291
|
-
|
|
4292
|
-
|
|
4256
|
+
const frameworkDeps = [];
|
|
4257
|
+
if (backend === "hono") frameworkDeps.push("hono");
|
|
4258
|
+
else if (backend === "elysia") frameworkDeps.push("elysia");
|
|
4259
|
+
else if (backend === "express") frameworkDeps.push("express", "@types/express");
|
|
4260
|
+
else if (backend === "fastify") frameworkDeps.push("fastify");
|
|
4261
|
+
else if (backend === "self") {
|
|
4293
4262
|
if (frontend.includes("next")) frameworkDeps.push("next");
|
|
4294
|
-
|
|
4295
|
-
|
|
4263
|
+
}
|
|
4264
|
+
if (frameworkDeps.length > 0) await addPackageDependency({
|
|
4265
|
+
dependencies: frameworkDeps,
|
|
4266
|
+
projectDir: apiPackageDir
|
|
4267
|
+
});
|
|
4268
|
+
if (api === "trpc") {
|
|
4269
|
+
if (backend === "hono") await addPackageDependency({
|
|
4270
|
+
dependencies: ["@hono/trpc-server"],
|
|
4271
|
+
projectDir: apiPackageDir
|
|
4272
|
+
});
|
|
4273
|
+
else if (backend === "elysia") await addPackageDependency({
|
|
4274
|
+
dependencies: ["@elysiajs/trpc"],
|
|
4275
|
+
projectDir: apiPackageDir
|
|
4276
|
+
});
|
|
4277
|
+
else if (backend === "express") await addPackageDependency({
|
|
4278
|
+
dependencies: ["@trpc/server"],
|
|
4279
|
+
projectDir: apiPackageDir
|
|
4280
|
+
});
|
|
4281
|
+
else if (backend === "fastify") await addPackageDependency({
|
|
4282
|
+
dependencies: ["@trpc/server"],
|
|
4296
4283
|
projectDir: apiPackageDir
|
|
4297
4284
|
});
|
|
4298
4285
|
}
|
|
4286
|
+
if (auth === "better-auth") await addPackageDependency({
|
|
4287
|
+
dependencies: ["better-auth"],
|
|
4288
|
+
projectDir: apiPackageDir
|
|
4289
|
+
});
|
|
4299
4290
|
}
|
|
4300
4291
|
if (webDirExists && apiDeps.web) await addPackageDependency({
|
|
4301
4292
|
dependencies: apiDeps.web.dependencies,
|
|
@@ -4347,23 +4338,34 @@ async function setupBackendDependencies(config) {
|
|
|
4347
4338
|
const devDependencies = [];
|
|
4348
4339
|
if (framework === "hono") {
|
|
4349
4340
|
dependencies.push("hono");
|
|
4350
|
-
if (
|
|
4341
|
+
if (api === "trpc") dependencies.push("@hono/trpc-server");
|
|
4342
|
+
if (runtime === "node") {
|
|
4343
|
+
dependencies.push("@hono/node-server");
|
|
4344
|
+
devDependencies.push("tsx", "@types/node");
|
|
4345
|
+
}
|
|
4351
4346
|
} else if (framework === "elysia") {
|
|
4352
4347
|
dependencies.push("elysia", "@elysiajs/cors");
|
|
4353
|
-
if (
|
|
4348
|
+
if (api === "trpc") dependencies.push("@elysiajs/trpc");
|
|
4349
|
+
if (runtime === "node") {
|
|
4350
|
+
dependencies.push("@elysiajs/node");
|
|
4351
|
+
devDependencies.push("tsx", "@types/node");
|
|
4352
|
+
}
|
|
4354
4353
|
} else if (framework === "express") {
|
|
4355
4354
|
dependencies.push("express", "cors");
|
|
4356
4355
|
devDependencies.push("@types/express", "@types/cors");
|
|
4357
|
-
|
|
4356
|
+
if (runtime === "node") devDependencies.push("tsx", "@types/node");
|
|
4357
|
+
} else if (framework === "fastify") {
|
|
4358
|
+
dependencies.push("fastify", "@fastify/cors");
|
|
4359
|
+
if (runtime === "node") devDependencies.push("tsx", "@types/node");
|
|
4360
|
+
}
|
|
4358
4361
|
if (api === "trpc") {
|
|
4359
|
-
dependencies.push("@trpc/server");
|
|
4360
|
-
if (framework === "
|
|
4361
|
-
else if (
|
|
4362
|
+
if (framework === "express") dependencies.push("@trpc/server");
|
|
4363
|
+
else if (framework === "fastify") dependencies.push("@trpc/server");
|
|
4364
|
+
else if (runtime === "workers") dependencies.push("@trpc/server");
|
|
4362
4365
|
} else if (api === "orpc") dependencies.push("@orpc/server", "@orpc/openapi", "@orpc/zod");
|
|
4363
4366
|
if (auth === "better-auth") dependencies.push("better-auth");
|
|
4364
4367
|
if (examples.includes("ai")) dependencies.push("ai", "@ai-sdk/google");
|
|
4365
|
-
if (runtime === "
|
|
4366
|
-
else if (runtime === "bun") devDependencies.push("@types/bun");
|
|
4368
|
+
if (runtime === "bun") devDependencies.push("@types/bun");
|
|
4367
4369
|
if (dependencies.length > 0 || devDependencies.length > 0) await addPackageDependency({
|
|
4368
4370
|
dependencies,
|
|
4369
4371
|
devDependencies,
|
|
@@ -5993,7 +5995,7 @@ This project uses Convex as a backend. You'll need to set up Convex before runni
|
|
|
5993
5995
|
${packageManagerRunCmd} dev:setup
|
|
5994
5996
|
\`\`\`
|
|
5995
5997
|
|
|
5996
|
-
Follow the prompts to create a new Convex project and connect it to your application.${auth === "clerk" ? " See [Convex + Clerk guide](https://docs.convex.dev/auth/clerk) for auth setup." : ""}` : generateDatabaseSetup(database, auth, packageManagerRunCmd, orm, options.dbSetup, options.serverDeploy
|
|
5998
|
+
Follow the prompts to create a new Convex project and connect it to your application.${auth === "clerk" ? " See [Convex + Clerk guide](https://docs.convex.dev/auth/clerk) for auth setup." : ""}` : generateDatabaseSetup(database, auth, packageManagerRunCmd, orm, options.dbSetup, options.serverDeploy)}
|
|
5997
5999
|
|
|
5998
6000
|
Then, run the development server:
|
|
5999
6001
|
|
|
@@ -6046,7 +6048,6 @@ function generateRunningInstructions(frontend, backend, webPort, hasNative, isCo
|
|
|
6046
6048
|
const instructions = [];
|
|
6047
6049
|
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
|
|
6048
6050
|
const isBackendNone = backend === "none";
|
|
6049
|
-
const isBackendSelf = backend === "self";
|
|
6050
6051
|
if (!hasFrontendNone) {
|
|
6051
6052
|
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
6052
6053
|
const hasReactRouter = frontend.includes("react-router");
|
|
@@ -6055,19 +6056,17 @@ function generateRunningInstructions(frontend, backend, webPort, hasNative, isCo
|
|
|
6055
6056
|
const hasSvelte = frontend.includes("svelte");
|
|
6056
6057
|
const hasNuxt = frontend.includes("nuxt");
|
|
6057
6058
|
const hasSolid = frontend.includes("solid");
|
|
6058
|
-
if (hasTanstackRouter || hasReactRouter || hasNext || hasTanstackStart || hasSvelte || hasNuxt || hasSolid)
|
|
6059
|
-
else instructions.push(`Open [http://localhost:${webPort}](http://localhost:${webPort}) in your browser to see the web application.`);
|
|
6059
|
+
if (hasTanstackRouter || hasReactRouter || hasNext || hasTanstackStart || hasSvelte || hasNuxt || hasSolid) instructions.push(`Open [http://localhost:${webPort}](http://localhost:${webPort}) in your browser to see the web application.`);
|
|
6060
6060
|
}
|
|
6061
6061
|
if (hasNative) instructions.push("Use the Expo Go app to run the mobile application.");
|
|
6062
6062
|
if (isConvex) instructions.push("Your app will connect to the Convex cloud backend automatically.");
|
|
6063
|
-
else if (!isBackendNone
|
|
6063
|
+
else if (!isBackendNone) instructions.push("The API is running at [http://localhost:3000](http://localhost:3000).");
|
|
6064
6064
|
return instructions.join("\n");
|
|
6065
6065
|
}
|
|
6066
6066
|
function generateProjectStructure(projectName, frontend, backend, addons, isConvex, api, auth) {
|
|
6067
6067
|
const structure = [`${projectName}/`, "├── apps/"];
|
|
6068
6068
|
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
|
|
6069
6069
|
const isBackendNone = backend === "none";
|
|
6070
|
-
const isBackendSelf = backend === "self";
|
|
6071
6070
|
if (!hasFrontendNone) {
|
|
6072
6071
|
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
6073
6072
|
const hasReactRouter = frontend.includes("react-router");
|
|
@@ -6085,32 +6084,21 @@ function generateProjectStructure(projectName, frontend, backend, addons, isConv
|
|
|
6085
6084
|
else if (hasSvelte) frontendType = "SvelteKit";
|
|
6086
6085
|
else if (hasNuxt) frontendType = "Nuxt";
|
|
6087
6086
|
else if (hasSolid) frontendType = "SolidJS";
|
|
6088
|
-
|
|
6089
|
-
else structure.push(`│ ├── web/ # Frontend application (${frontendType})`);
|
|
6087
|
+
structure.push(`│ ├── web/ # Frontend application (${frontendType})`);
|
|
6090
6088
|
}
|
|
6091
6089
|
}
|
|
6092
|
-
if (frontend.includes("native-nativewind") || frontend.includes("native-unistyles"))
|
|
6093
|
-
|
|
6094
|
-
if (
|
|
6095
|
-
|
|
6096
|
-
|
|
6090
|
+
if (frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) structure.push("│ ├── native/ # Mobile application (React Native, Expo)");
|
|
6091
|
+
if (addons.includes("starlight")) structure.push("│ ├── docs/ # Documentation site (Astro Starlight)");
|
|
6092
|
+
if (isConvex) {
|
|
6093
|
+
structure.push("├── packages/");
|
|
6094
|
+
structure.push("│ └── backend/ # Convex backend functions and schema");
|
|
6095
|
+
if (auth === "clerk") structure.push("│ ├── convex/ # Convex functions and schema", "│ └── .env.local # Convex environment variables");
|
|
6096
|
+
} else if (!isBackendNone) {
|
|
6097
6097
|
const backendName = backend[0].toUpperCase() + backend.slice(1);
|
|
6098
6098
|
const apiName = api !== "none" ? api.toUpperCase() : "";
|
|
6099
6099
|
const backendDesc = apiName ? `${backendName}, ${apiName}` : backendName;
|
|
6100
6100
|
structure.push(`│ └── server/ # Backend API (${backendDesc})`);
|
|
6101
6101
|
}
|
|
6102
|
-
if (isConvex || !isBackendNone) {
|
|
6103
|
-
structure.push("├── packages/");
|
|
6104
|
-
if (isConvex) {
|
|
6105
|
-
structure.push("│ ├── backend/ # Convex backend functions and schema");
|
|
6106
|
-
if (auth === "clerk") structure.push("│ │ ├── convex/ # Convex functions and schema", "│ │ └── .env.local # Convex environment variables");
|
|
6107
|
-
}
|
|
6108
|
-
if (!isConvex) {
|
|
6109
|
-
structure.push("│ ├── api/ # API layer / business logic");
|
|
6110
|
-
if (auth !== "none") structure.push("│ ├── auth/ # Authentication configuration & logic");
|
|
6111
|
-
if (api !== "none" || auth !== "none") structure.push("│ └── db/ # Database schema & queries");
|
|
6112
|
-
}
|
|
6113
|
-
}
|
|
6114
6102
|
return structure.join("\n");
|
|
6115
6103
|
}
|
|
6116
6104
|
function generateFeaturesList(database, auth, addons, orm, runtime, frontend, backend, api) {
|
|
@@ -6168,36 +6156,33 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
6168
6156
|
else if (addon === "turborepo") addonsList.push("- **Turborepo** - Optimized monorepo build system");
|
|
6169
6157
|
return addonsList.join("\n");
|
|
6170
6158
|
}
|
|
6171
|
-
function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup, serverDeploy
|
|
6159
|
+
function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup, serverDeploy) {
|
|
6172
6160
|
if (database === "none") return "";
|
|
6173
|
-
const isBackendSelf = backend === "self";
|
|
6174
|
-
const envPath = isBackendSelf ? "apps/web/.env" : "apps/server/.env";
|
|
6175
|
-
const dbLocalPath = isBackendSelf ? "apps/web" : "apps/server";
|
|
6176
6161
|
let setup = "## Database Setup\n\n";
|
|
6177
6162
|
if (database === "sqlite") setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
6178
6163
|
|
|
6179
6164
|
1. Start the local SQLite database:
|
|
6180
6165
|
${dbSetup === "d1" ? serverDeploy === "alchemy" ? "D1 local development and migrations are handled automatically by Alchemy during dev and deploy." : "Local development for a Cloudflare D1 database will already be running as part of the `wrangler dev` command." : `\`\`\`bash
|
|
6181
|
-
cd
|
|
6166
|
+
cd apps/server && ${packageManagerRunCmd} db:local
|
|
6182
6167
|
\`\`\`
|
|
6183
6168
|
`}
|
|
6184
6169
|
|
|
6185
|
-
2. Update your \`.env\` file in the
|
|
6170
|
+
2. Update your \`.env\` file in the \`apps/server\` directory with the appropriate connection details if needed.
|
|
6186
6171
|
`;
|
|
6187
6172
|
else if (database === "postgres") setup += `This project uses PostgreSQL${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
6188
6173
|
|
|
6189
6174
|
1. Make sure you have a PostgreSQL database set up.
|
|
6190
|
-
2. Update your
|
|
6175
|
+
2. Update your \`apps/server/.env\` file with your PostgreSQL connection details.
|
|
6191
6176
|
`;
|
|
6192
6177
|
else if (database === "mysql") setup += `This project uses MySQL${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
6193
6178
|
|
|
6194
6179
|
1. Make sure you have a MySQL database set up.
|
|
6195
|
-
2. Update your
|
|
6180
|
+
2. Update your \`apps/server/.env\` file with your MySQL connection details.
|
|
6196
6181
|
`;
|
|
6197
6182
|
else if (database === "mongodb") setup += `This project uses MongoDB ${orm === "mongoose" ? "with Mongoose" : orm === "prisma" ? "with Prisma ORM" : `with ${orm}`}.
|
|
6198
6183
|
|
|
6199
6184
|
1. Make sure you have MongoDB set up.
|
|
6200
|
-
2. Update your
|
|
6185
|
+
2. Update your \`apps/server/.env\` file with your MongoDB connection URI.
|
|
6201
6186
|
`;
|
|
6202
6187
|
setup += `
|
|
6203
6188
|
3. ${orm === "prisma" ? `Generate the Prisma client and push the schema:
|
|
@@ -6216,14 +6201,13 @@ ${packageManagerRunCmd} db:push
|
|
|
6216
6201
|
function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNative, addons, backend) {
|
|
6217
6202
|
const isConvex = backend === "convex";
|
|
6218
6203
|
const isBackendNone = backend === "none";
|
|
6219
|
-
const isBackendSelf = backend === "self";
|
|
6220
6204
|
let scripts = `- \`${packageManagerRunCmd} dev\`: Start all applications in development mode
|
|
6221
6205
|
- \`${packageManagerRunCmd} build\`: Build all applications`;
|
|
6222
|
-
|
|
6206
|
+
scripts += `
|
|
6223
6207
|
- \`${packageManagerRunCmd} dev:web\`: Start only the web application`;
|
|
6224
6208
|
if (isConvex) scripts += `
|
|
6225
6209
|
- \`${packageManagerRunCmd} dev:setup\`: Setup and configure your Convex project`;
|
|
6226
|
-
else if (!isBackendNone
|
|
6210
|
+
else if (!isBackendNone) scripts += `
|
|
6227
6211
|
- \`${packageManagerRunCmd} dev:server\`: Start only the server`;
|
|
6228
6212
|
scripts += `
|
|
6229
6213
|
- \`${packageManagerRunCmd} check-types\`: Check TypeScript types across all apps`;
|
|
@@ -6234,7 +6218,7 @@ function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNati
|
|
|
6234
6218
|
- \`${packageManagerRunCmd} db:push\`: Push schema changes to database
|
|
6235
6219
|
- \`${packageManagerRunCmd} db:studio\`: Open database studio UI`;
|
|
6236
6220
|
if (database === "sqlite" && orm === "drizzle") scripts += `
|
|
6237
|
-
- \`cd
|
|
6221
|
+
- \`cd apps/server && ${packageManagerRunCmd} db:local\`: Start the local SQLite database`;
|
|
6238
6222
|
}
|
|
6239
6223
|
if (addons.includes("biome")) scripts += `
|
|
6240
6224
|
- \`${packageManagerRunCmd} check\`: Run Biome formatting and linting`;
|
|
@@ -6391,20 +6375,19 @@ async function getDockerStatus(database) {
|
|
|
6391
6375
|
async function displayPostInstallInstructions(config) {
|
|
6392
6376
|
const { api, database, relativePath, packageManager, depsInstalled, orm, addons, runtime, frontend, backend, dbSetup, webDeploy, serverDeploy } = config;
|
|
6393
6377
|
const isConvex = backend === "convex";
|
|
6394
|
-
const isBackendSelf = backend === "self";
|
|
6395
6378
|
const runCmd = packageManager === "npm" ? "npm run" : packageManager === "pnpm" ? "pnpm run" : "bun run";
|
|
6396
6379
|
const cdCmd = `cd ${relativePath}`;
|
|
6397
6380
|
const hasHuskyOrBiome = addons?.includes("husky") || addons?.includes("biome");
|
|
6398
|
-
const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy
|
|
6381
|
+
const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy) : "";
|
|
6399
6382
|
const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd) : "";
|
|
6400
6383
|
const lintingInstructions = hasHuskyOrBiome ? getLintingInstructions(runCmd) : "";
|
|
6401
6384
|
const nativeInstructions = frontend?.includes("native-nativewind") || frontend?.includes("native-unistyles") ? getNativeInstructions(isConvex) : "";
|
|
6402
6385
|
const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
|
|
6403
6386
|
const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
|
|
6404
6387
|
const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
|
|
6405
|
-
const polarInstructions = config.payments === "polar" && config.auth === "better-auth" ? getPolarInstructions(
|
|
6406
|
-
const wranglerDeployInstructions = getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy
|
|
6407
|
-
const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy
|
|
6388
|
+
const polarInstructions = config.payments === "polar" && config.auth === "better-auth" ? getPolarInstructions() : "";
|
|
6389
|
+
const wranglerDeployInstructions = getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy);
|
|
6390
|
+
const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy);
|
|
6408
6391
|
const hasWeb = frontend?.some((f) => [
|
|
6409
6392
|
"tanstack-router",
|
|
6410
6393
|
"react-router",
|
|
@@ -6428,8 +6411,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6428
6411
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup\n${pc.dim(" (this will guide you through Convex project setup)")}\n`;
|
|
6429
6412
|
output += `${pc.cyan(`${stepCounter++}.`)} Copy environment variables from\n${pc.white(" packages/backend/.env.local")} to ${pc.white("apps/*/.env")}\n`;
|
|
6430
6413
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n\n`;
|
|
6431
|
-
} else
|
|
6432
|
-
else {
|
|
6414
|
+
} else {
|
|
6433
6415
|
if (runtime !== "workers") output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n`;
|
|
6434
6416
|
if (runtime === "workers") {
|
|
6435
6417
|
if (dbSetup === "d1") output += `${pc.yellow("IMPORTANT:")} Complete D1 database setup first\n (see Database commands below)\n`;
|
|
@@ -6440,11 +6422,11 @@ async function displayPostInstallInstructions(config) {
|
|
|
6440
6422
|
output += `${pc.bold("Your project will be available at:")}\n`;
|
|
6441
6423
|
if (hasWeb) output += `${pc.cyan("•")} Frontend: http://localhost:${webPort}\n`;
|
|
6442
6424
|
else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
|
|
6443
|
-
if (!isConvex
|
|
6425
|
+
if (!isConvex) {
|
|
6444
6426
|
output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
|
|
6445
|
-
if (api === "orpc") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api\n`;
|
|
6427
|
+
if (api === "orpc") if (backend === "self") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/rpc/api\n`;
|
|
6428
|
+
else output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api\n`;
|
|
6446
6429
|
}
|
|
6447
|
-
if (isBackendSelf && api === "orpc") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:${webPort}/rpc/api\n`;
|
|
6448
6430
|
if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
|
|
6449
6431
|
if (addons?.includes("fumadocs")) output += `${pc.cyan("•")} Fumadocs: http://localhost:4000\n`;
|
|
6450
6432
|
if (nativeInstructions) output += `\n${nativeInstructions.trim()}\n`;
|
|
@@ -6476,7 +6458,7 @@ function getNativeInstructions(isConvex) {
|
|
|
6476
6458
|
function getLintingInstructions(runCmd) {
|
|
6477
6459
|
return `${pc.bold("Linting and formatting:")}\n${pc.cyan("•")} Format and lint fix: ${`${runCmd} check`}\n`;
|
|
6478
6460
|
}
|
|
6479
|
-
async function getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy
|
|
6461
|
+
async function getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy) {
|
|
6480
6462
|
const instructions = [];
|
|
6481
6463
|
if (dbSetup === "docker") {
|
|
6482
6464
|
const dockerStatus = await getDockerStatus(database);
|
|
@@ -6490,9 +6472,8 @@ async function getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup,
|
|
|
6490
6472
|
const packageManager = runCmd === "npm run" ? "npm" : runCmd || "npm";
|
|
6491
6473
|
instructions.push(`${pc.cyan("1.")} Login to Cloudflare: ${pc.white(`${packageManager} wrangler login`)}`);
|
|
6492
6474
|
instructions.push(`${pc.cyan("2.")} Create D1 database: ${pc.white(`${packageManager} wrangler d1 create your-database-name`)}`);
|
|
6493
|
-
|
|
6494
|
-
instructions.push(`${pc.cyan("
|
|
6495
|
-
instructions.push(`${pc.cyan("4.")} Generate migrations: ${pc.white(`cd ${wranglerPath} && ${runCmd} db:generate`)}`);
|
|
6475
|
+
instructions.push(`${pc.cyan("3.")} Update apps/server/wrangler.jsonc with database_id and database_name`);
|
|
6476
|
+
instructions.push(`${pc.cyan("4.")} Generate migrations: ${pc.white(`cd apps/server && ${runCmd} db:generate`)}`);
|
|
6496
6477
|
instructions.push(`${pc.cyan("5.")} Apply migrations locally: ${pc.white(`${packageManager} wrangler d1 migrations apply YOUR_DB_NAME --local`)}`);
|
|
6497
6478
|
instructions.push(`${pc.cyan("6.")} Apply migrations to production: ${pc.white(`${packageManager} wrangler d1 migrations apply YOUR_DB_NAME`)}`);
|
|
6498
6479
|
}
|
|
@@ -6516,10 +6497,7 @@ async function getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup,
|
|
|
6516
6497
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6517
6498
|
if (dbSetup !== "d1") instructions.push(`${pc.cyan("•")} Apply schema: ${`${runCmd} db:push`}`);
|
|
6518
6499
|
if (!(dbSetup === "d1" && serverDeploy === "alchemy")) instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
|
|
6519
|
-
if (database === "sqlite" && dbSetup !== "d1") {
|
|
6520
|
-
const dbLocalPath = backend === "self" ? "apps/web" : "apps/server";
|
|
6521
|
-
instructions.push(`${pc.cyan("•")} Start local DB (if needed): ${`cd ${dbLocalPath} && ${runCmd} db:local`}`);
|
|
6522
|
-
}
|
|
6500
|
+
if (database === "sqlite" && dbSetup !== "d1") instructions.push(`${pc.cyan("•")} Start local DB (if needed): ${`cd apps/server && ${runCmd} db:local`}`);
|
|
6523
6501
|
} else if (orm === "mongoose") {
|
|
6524
6502
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6525
6503
|
} else if (orm === "none") instructions.push(`${pc.yellow("NOTE:")} Manual database schema setup\n required.`);
|
|
@@ -6540,28 +6518,23 @@ function getNoOrmWarning() {
|
|
|
6540
6518
|
function getBunWebNativeWarning() {
|
|
6541
6519
|
return `\n${pc.yellow("WARNING:")} 'bun' might cause issues with web + native apps in a monorepo.\n Use 'pnpm' if problems arise.`;
|
|
6542
6520
|
}
|
|
6543
|
-
function getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy
|
|
6521
|
+
function getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy) {
|
|
6544
6522
|
const instructions = [];
|
|
6545
|
-
if (webDeploy === "wrangler") {
|
|
6546
|
-
|
|
6547
|
-
instructions.push(`${pc.bold("Deploy web to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd ${deployPath} && ${runCmd} run deploy`}`);
|
|
6548
|
-
}
|
|
6549
|
-
if (serverDeploy === "wrangler" && backend !== "self") instructions.push(`${pc.bold("Deploy server to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} run deploy`}`);
|
|
6523
|
+
if (webDeploy === "wrangler") instructions.push(`${pc.bold("Deploy web to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} run deploy`}`);
|
|
6524
|
+
if (serverDeploy === "wrangler") instructions.push(`${pc.bold("Deploy server to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} run deploy`}`);
|
|
6550
6525
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
6551
6526
|
}
|
|
6552
6527
|
function getClerkInstructions() {
|
|
6553
6528
|
return `${pc.bold("Clerk Authentication Setup:")}\n${pc.cyan("•")} Follow the guide: ${pc.underline("https://docs.convex.dev/auth/clerk")}\n${pc.cyan("•")} Set CLERK_JWT_ISSUER_DOMAIN in Convex Dashboard\n${pc.cyan("•")} Set CLERK_PUBLISHABLE_KEY in apps/*/.env`;
|
|
6554
6529
|
}
|
|
6555
|
-
function getPolarInstructions(
|
|
6556
|
-
|
|
6557
|
-
return `${pc.bold("Polar Payments Setup:")}\n${pc.cyan("•")} Get access token & product ID from ${pc.underline("https://sandbox.polar.sh/")}\n${pc.cyan("•")} Set POLAR_ACCESS_TOKEN in ${envPath}`;
|
|
6530
|
+
function getPolarInstructions() {
|
|
6531
|
+
return `${pc.bold("Polar Payments Setup:")}\n${pc.cyan("•")} Get access token & product ID from ${pc.underline("https://sandbox.polar.sh/")}\n${pc.cyan("•")} Set POLAR_ACCESS_TOKEN in apps/server/.env`;
|
|
6558
6532
|
}
|
|
6559
|
-
function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy
|
|
6533
|
+
function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy) {
|
|
6560
6534
|
const instructions = [];
|
|
6561
|
-
const isBackendSelf = backend === "self";
|
|
6562
6535
|
if (webDeploy === "alchemy" && serverDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/web && ${runCmd} destroy`}`);
|
|
6563
|
-
else if (serverDeploy === "alchemy" && webDeploy !== "alchemy"
|
|
6564
|
-
else if (webDeploy === "alchemy" &&
|
|
6536
|
+
else if (serverDeploy === "alchemy" && webDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy server with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/server && ${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/server && ${runCmd} destroy`}`);
|
|
6537
|
+
else if (webDeploy === "alchemy" && serverDeploy === "alchemy") instructions.push(`${pc.bold("Deploy with Alchemy:")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
|
|
6565
6538
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
6566
6539
|
}
|
|
6567
6540
|
|
|
@@ -6617,21 +6590,12 @@ async function setupWorkspaceDependencies(projectDir, options) {
|
|
|
6617
6590
|
projectDir: webPackageDir
|
|
6618
6591
|
});
|
|
6619
6592
|
}
|
|
6620
|
-
const runtimeDevDeps = getRuntimeDevDeps(options);
|
|
6621
6593
|
await addPackageDependency({
|
|
6622
6594
|
dependencies: commonDeps,
|
|
6623
|
-
devDependencies:
|
|
6595
|
+
devDependencies: commonDevDeps,
|
|
6624
6596
|
projectDir
|
|
6625
6597
|
});
|
|
6626
6598
|
}
|
|
6627
|
-
function getRuntimeDevDeps(options) {
|
|
6628
|
-
const { runtime, backend } = options;
|
|
6629
|
-
if (runtime === "none" && backend === "self") return ["@types/node"];
|
|
6630
|
-
if (runtime === "node") return ["@types/node"];
|
|
6631
|
-
if (runtime === "bun") return ["@types/bun"];
|
|
6632
|
-
if (runtime === "workers") return ["@types/node"];
|
|
6633
|
-
return [];
|
|
6634
|
-
}
|
|
6635
6599
|
|
|
6636
6600
|
//#endregion
|
|
6637
6601
|
//#region src/helpers/core/project-config.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "2.50.1-canary.
|
|
3
|
+
"version": "2.50.1-canary.7ebd503f",
|
|
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",
|
|
@@ -8,14 +8,14 @@ This is a monorepo with the following structure:
|
|
|
8
8
|
|
|
9
9
|
{{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "tanstack-start")
|
|
10
10
|
(includes frontend "next") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
11
|
-
- **`apps/web/`** -
|
|
11
|
+
- **`apps/web/`** - Frontend application{{#if (includes frontend "tanstack-router")}} (React with TanStack Router){{else
|
|
12
12
|
if (includes frontend "react-router")}} (React with React Router){{else if (includes frontend "next")}} (Next.js){{else
|
|
13
13
|
if (includes frontend "nuxt")}} (Nuxt.js){{else if (includes frontend "svelte")}} (SvelteKit){{else if (includes
|
|
14
14
|
frontend "solid")}} (SolidStart){{/if}}
|
|
15
15
|
{{/if}}
|
|
16
16
|
|
|
17
17
|
{{#if (ne backend "convex")}}
|
|
18
|
-
{{#if (
|
|
18
|
+
{{#if (ne backend "none")}}
|
|
19
19
|
- **`apps/server/`** - Backend server{{#if (eq backend "hono")}} (Hono){{else if (eq backend "express")}}
|
|
20
20
|
(Express){{else if (eq backend "fastify")}} (Fastify){{else if (eq backend "elysia")}} (Elysia){{else if (eq backend
|
|
21
21
|
"next")}} (Next.js API){{/if}}
|
|
@@ -24,18 +24,6 @@ frontend "solid")}} (SolidStart){{/if}}
|
|
|
24
24
|
- **`packages/backend/`** - Convex backend functions
|
|
25
25
|
{{/if}}
|
|
26
26
|
|
|
27
|
-
{{#if (or (ne backend "none") (ne backend "convex"))}}
|
|
28
|
-
{{#if (ne api "none")}}
|
|
29
|
-
- **`packages/api/`** - Shared API logic and types
|
|
30
|
-
{{/if}}
|
|
31
|
-
{{#if (and (ne auth "none") (ne backend "convex"))}}
|
|
32
|
-
- **`packages/auth/`** - Authentication logic and utilities
|
|
33
|
-
{{/if}}
|
|
34
|
-
{{#if (and (ne database "none") (ne orm "none") (ne backend "convex"))}}
|
|
35
|
-
- **`packages/db/`** - Database schema and utilities
|
|
36
|
-
{{/if}}
|
|
37
|
-
{{/if}}
|
|
38
|
-
|
|
39
27
|
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
|
40
28
|
- **`apps/native/`** - React Native mobile app{{#if (includes frontend "native-nativewind")}} (with NativeWind){{else if
|
|
41
29
|
(includes frontend "native-unistyles")}} (with Unistyles){{/if}}
|
|
@@ -44,13 +32,15 @@ frontend "solid")}} (SolidStart){{/if}}
|
|
|
44
32
|
## Available Scripts
|
|
45
33
|
|
|
46
34
|
- `{{packageManager}} run dev` - Start all apps in development mode
|
|
47
|
-
{{#if (
|
|
48
|
-
(includes frontend "next") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))
|
|
35
|
+
{{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "tanstack-start")
|
|
36
|
+
(includes frontend "next") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
49
37
|
- `{{packageManager}} run dev:web` - Start only the web app
|
|
50
38
|
{{/if}}
|
|
51
|
-
{{#if (
|
|
39
|
+
{{#if (ne backend "none")}}
|
|
40
|
+
{{#if (ne backend "convex")}}
|
|
52
41
|
- `{{packageManager}} run dev:server` - Start only the server
|
|
53
42
|
{{/if}}
|
|
43
|
+
{{/if}}
|
|
54
44
|
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
|
55
45
|
- `{{packageManager}} run dev:native` - Start only the native app
|
|
56
46
|
{{/if}}
|
|
@@ -58,7 +48,7 @@ frontend "solid")}} (SolidStart){{/if}}
|
|
|
58
48
|
{{#if (and (ne database "none") (ne orm "none") (ne backend "convex"))}}
|
|
59
49
|
## Database Commands
|
|
60
50
|
|
|
61
|
-
All database operations should be run from the
|
|
51
|
+
All database operations should be run from the server workspace:
|
|
62
52
|
|
|
63
53
|
- `{{packageManager}} run db:push` - Push schema changes to database
|
|
64
54
|
- `{{packageManager}} run db:studio` - Open database studio
|
|
@@ -67,11 +57,11 @@ All database operations should be run from the {{#if (eq backend "self")}}web{{e
|
|
|
67
57
|
- `{{packageManager}} run db:migrate` - Run database migrations
|
|
68
58
|
|
|
69
59
|
{{#if (eq orm "drizzle")}}
|
|
70
|
-
Database schema files are located in
|
|
60
|
+
Database schema files are located in `apps/server/src/db/schema/`
|
|
71
61
|
{{else if (eq orm "prisma")}}
|
|
72
|
-
Database schema is located in
|
|
62
|
+
Database schema is located in `apps/server/prisma/schema.prisma`
|
|
73
63
|
{{else if (eq orm "mongoose")}}
|
|
74
|
-
Database models are located in
|
|
64
|
+
Database models are located in `apps/server/src/db/models/`
|
|
75
65
|
{{/if}}
|
|
76
66
|
{{/if}}
|
|
77
67
|
|
|
@@ -79,10 +69,10 @@ Database models are located in {{#if (eq backend "self")}}`apps/web/src/db/model
|
|
|
79
69
|
## API Structure
|
|
80
70
|
|
|
81
71
|
{{#if (eq api "trpc")}}
|
|
82
|
-
- tRPC routers are in
|
|
72
|
+
- tRPC routers are in `apps/server/src/routers/`
|
|
83
73
|
- Client-side tRPC utils are in `apps/web/src/utils/trpc.ts`
|
|
84
74
|
{{else if (eq api "orpc")}}
|
|
85
|
-
- oRPC endpoints are in
|
|
75
|
+
- oRPC endpoints are in `apps/server/src/api/`
|
|
86
76
|
- Client-side API utils are in `apps/web/src/utils/api.ts`
|
|
87
77
|
{{/if}}
|
|
88
78
|
{{/if}}
|
|
@@ -92,7 +82,7 @@ Database models are located in {{#if (eq backend "self")}}`apps/web/src/db/model
|
|
|
92
82
|
|
|
93
83
|
Authentication is enabled in this project:
|
|
94
84
|
{{#if (ne backend "convex")}}
|
|
95
|
-
- Server auth logic is in
|
|
85
|
+
- Server auth logic is in `apps/server/src/lib/auth.ts`
|
|
96
86
|
{{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "tanstack-start")
|
|
97
87
|
(includes frontend "next") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
98
88
|
- Web app auth client is in `apps/web/src/lib/auth-client.ts`
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"types": [
|
|
7
|
+
"bun"
|
|
8
|
+
],
|
|
9
|
+
}
|
|
10
10
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"declarationMap": true,
|
|
6
|
+
"sourceMap": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"composite": true,
|
|
9
|
+
"types": [
|
|
10
|
+
"bun"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
10
13
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"declarationMap": true,
|
|
6
|
+
"sourceMap": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"composite": true,
|
|
9
|
+
"types": [
|
|
10
|
+
"bun"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
10
13
|
}
|
|
@@ -5,8 +5,22 @@
|
|
|
5
5
|
"outDir": "dist",
|
|
6
6
|
"baseUrl": ".",
|
|
7
7
|
"paths": {
|
|
8
|
-
"@/*": ["./src/*"]
|
|
8
|
+
"@/*": ["./src/*"]{{#if (eq orm "prisma")}},
|
|
9
|
+
"prisma": ["node_modules/prisma"]{{/if}}
|
|
9
10
|
},
|
|
11
|
+
"types": [
|
|
12
|
+
{{#if (eq runtime "node")}}
|
|
13
|
+
"node"
|
|
14
|
+
{{else if (eq runtime "bun")}}
|
|
15
|
+
"bun"
|
|
16
|
+
{{else if (eq runtime "workers")}}
|
|
17
|
+
"node"
|
|
18
|
+
{{else}}
|
|
19
|
+
"node",
|
|
20
|
+
"bun"
|
|
21
|
+
{{/if}}{{#if (eq serverDeploy "alchemy")}},
|
|
22
|
+
"@cloudflare/workers-types"{{/if}}
|
|
23
|
+
],
|
|
10
24
|
"jsx": "react-jsx"{{#if (eq backend "hono")}},
|
|
11
25
|
"jsxImportSource": "hono/jsx"{{/if}}
|
|
12
26
|
}
|
|
@@ -1,34 +1,23 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{{else if (eq runtime "bun")}}
|
|
24
|
-
"bun"
|
|
25
|
-
{{else if (eq runtime "workers")}}
|
|
26
|
-
"node"
|
|
27
|
-
{{else}}
|
|
28
|
-
"node",
|
|
29
|
-
"bun"
|
|
30
|
-
{{/if}}{{#if (eq serverDeploy "alchemy")}},
|
|
31
|
-
"@cloudflare/workers-types"{{/if}}
|
|
32
|
-
]
|
|
33
|
-
}
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"lib": [
|
|
8
|
+
"ESNext"
|
|
9
|
+
],
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"allowSyntheticDefaultImports": true,
|
|
15
|
+
"esModuleInterop": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"isolatedModules": true,
|
|
18
|
+
"noUncheckedIndexedAccess": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true
|
|
22
|
+
}
|
|
34
23
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"declarationMap": true,
|
|
6
|
+
"sourceMap": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"composite": true,
|
|
9
|
+
"types": [
|
|
10
|
+
"bun"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
10
13
|
}
|