create-better-t-stack 3.26.1 → 3.27.0
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/README.md +8 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-Kus6HC8q.mjs → src-CiY2JajO.mjs} +34 -14
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -217,6 +217,12 @@ Create a Cloudflare Workers project:
|
|
|
217
217
|
npx create-better-t-stack --backend hono --runtime workers --database sqlite --orm drizzle --db-setup d1
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
+
Create a self-hosted fullstack project on Cloudflare with D1:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npx create-better-t-stack --backend self --frontend next --api trpc --database sqlite --orm drizzle --db-setup d1 --web-deploy cloudflare
|
|
224
|
+
```
|
|
225
|
+
|
|
220
226
|
Create a minimal API-only project:
|
|
221
227
|
|
|
222
228
|
```bash
|
|
@@ -232,7 +238,8 @@ npx create-better-t-stack --frontend none --backend hono --api trpc --database n
|
|
|
232
238
|
- **Database 'none'**: Disables database setup and requires ORM to be `none`.
|
|
233
239
|
- **ORM 'none'**: Can be used when you want to handle database operations manually or use a different ORM.
|
|
234
240
|
- **Runtime 'none'**: Only available with Convex backend, backend `none`, or backend `self`.
|
|
235
|
-
- **Cloudflare Workers runtime**: Only compatible with Hono backend
|
|
241
|
+
- **Cloudflare Workers runtime**: Only compatible with Hono backend. If a database is used, MongoDB is not supported.
|
|
242
|
+
- **Cloudflare D1 setup**: Requires `sqlite` and either `--runtime workers --server-deploy cloudflare` or `--backend self --web-deploy cloudflare`. For `backend self`, D1 is supported on `next`, `tanstack-start`, `nuxt`, and `astro`.
|
|
236
243
|
- **Addons 'none'**: Skips all addons.
|
|
237
244
|
- **Examples 'none'**: Skips all example implementations (todo, AI chat).
|
|
238
245
|
- **Nuxt, Svelte, SolidJS, and Astro** frontends are only compatible with oRPC API layer
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { _ as types_exports, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-
|
|
2
|
+
import { _ as types_exports, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-CiY2JajO.mjs";
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-
|
|
2
|
+
import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-CiY2JajO.mjs";
|
|
3
3
|
export { CLIError, CompatibilityError, DatabaseSetupError, DirectoryConflictError, EMBEDDED_TEMPLATES, GeneratorError, ProjectCreationError, Result, SchemaNameSchema, TEMPLATE_COUNT, UserCancelledError, ValidationError, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generate, getSchemaResult, router, sponsors };
|
|
@@ -3392,7 +3392,7 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
|
|
|
3392
3392
|
label: "Turso",
|
|
3393
3393
|
hint: "SQLite for Production. Powered by libSQL"
|
|
3394
3394
|
},
|
|
3395
|
-
...runtime === "workers" ? [{
|
|
3395
|
+
...runtime === "workers" || backend === "self" ? [{
|
|
3396
3396
|
value: "d1",
|
|
3397
3397
|
label: "Cloudflare D1",
|
|
3398
3398
|
hint: "Cloudflare's managed, serverless database with SQLite's SQL semantics"
|
|
@@ -3832,9 +3832,10 @@ function getDeploymentDisplay(deployment) {
|
|
|
3832
3832
|
hint: `Add ${deployment} deployment`
|
|
3833
3833
|
};
|
|
3834
3834
|
}
|
|
3835
|
-
async function getDeploymentChoice(deployment, _runtime,
|
|
3835
|
+
async function getDeploymentChoice(deployment, _runtime, backend, frontend = [], dbSetup) {
|
|
3836
3836
|
if (deployment !== void 0) return deployment;
|
|
3837
3837
|
if (!hasWebFrontend(frontend)) return "none";
|
|
3838
|
+
if (backend === "self" && dbSetup === "d1") return "cloudflare";
|
|
3838
3839
|
const response = await navigableSelect({
|
|
3839
3840
|
message: "Select web deployment",
|
|
3840
3841
|
options: ["cloudflare", "none"].map((deploy) => {
|
|
@@ -3888,7 +3889,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
3888
3889
|
addons: ({ results }) => getAddonsChoice(flags.addons, results.frontend, results.auth),
|
|
3889
3890
|
examples: ({ results }) => getExamplesChoice(flags.examples, results.database, results.frontend, results.backend, results.api),
|
|
3890
3891
|
dbSetup: ({ results }) => getDBSetupChoice(results.database ?? "none", flags.dbSetup, results.orm, results.backend, results.runtime),
|
|
3891
|
-
webDeploy: ({ results }) => getDeploymentChoice(flags.webDeploy, results.runtime, results.backend, results.frontend),
|
|
3892
|
+
webDeploy: ({ results }) => getDeploymentChoice(flags.webDeploy, results.runtime, results.backend, results.frontend, results.dbSetup),
|
|
3892
3893
|
serverDeploy: ({ results }) => getServerDeploymentChoice(flags.serverDeploy, results.runtime, results.backend, results.webDeploy),
|
|
3893
3894
|
git: () => getGitChoice(flags.git),
|
|
3894
3895
|
packageManager: () => getPackageManagerChoice(flags.packageManager),
|
|
@@ -4305,6 +4306,18 @@ function validateArrayOptions(options) {
|
|
|
4305
4306
|
function validationErr(message) {
|
|
4306
4307
|
return Result.err(new ValidationError({ message }));
|
|
4307
4308
|
}
|
|
4309
|
+
function hasResolvedWorkersD1Target(config) {
|
|
4310
|
+
return config.backend === "hono" && config.runtime === "workers" && config.serverDeploy === "cloudflare";
|
|
4311
|
+
}
|
|
4312
|
+
function hasResolvedSelfCloudflareD1Target(config) {
|
|
4313
|
+
return config.backend === "self" && config.runtime === "none" && config.webDeploy === "cloudflare";
|
|
4314
|
+
}
|
|
4315
|
+
function canResolveWorkersD1Target(config) {
|
|
4316
|
+
return (config.backend === void 0 || config.backend === "hono") && (config.runtime === void 0 || config.runtime === "workers") && (config.serverDeploy === void 0 || config.serverDeploy === "cloudflare");
|
|
4317
|
+
}
|
|
4318
|
+
function canResolveSelfCloudflareD1Target(config) {
|
|
4319
|
+
return (config.backend === void 0 || config.backend === "self") && (config.runtime === void 0 || config.runtime === "none") && (config.webDeploy === void 0 || config.webDeploy === "cloudflare");
|
|
4320
|
+
}
|
|
4308
4321
|
function validateDatabaseOrmAuth(cfg, flags) {
|
|
4309
4322
|
const db = cfg.database;
|
|
4310
4323
|
const orm = cfg.orm;
|
|
@@ -4343,8 +4356,7 @@ function validateDatabaseSetup(config, providedFlags) {
|
|
|
4343
4356
|
},
|
|
4344
4357
|
d1: {
|
|
4345
4358
|
database: "sqlite",
|
|
4346
|
-
|
|
4347
|
-
errorMessage: "Cloudflare D1 setup requires SQLite database and Cloudflare Workers runtime."
|
|
4359
|
+
errorMessage: "Cloudflare D1 setup requires SQLite database."
|
|
4348
4360
|
},
|
|
4349
4361
|
docker: { errorMessage: "Docker setup is not compatible with SQLite database or Cloudflare Workers runtime." },
|
|
4350
4362
|
none: { errorMessage: "" }
|
|
@@ -4355,6 +4367,13 @@ function validateDatabaseSetup(config, providedFlags) {
|
|
|
4355
4367
|
if (database !== "postgres" && database !== "mysql") return validationErr(validation.errorMessage);
|
|
4356
4368
|
} else if (validation.database && database !== validation.database) return validationErr(validation.errorMessage);
|
|
4357
4369
|
if (validation.runtime && runtime !== validation.runtime) return validationErr(validation.errorMessage);
|
|
4370
|
+
if (dbSetup === "d1") {
|
|
4371
|
+
const isWorkersTarget = hasResolvedWorkersD1Target(config);
|
|
4372
|
+
const isSelfCloudflareTarget = hasResolvedSelfCloudflareD1Target(config);
|
|
4373
|
+
const canResolveWorkersTarget = canResolveWorkersD1Target(config);
|
|
4374
|
+
const canResolveSelfCloudflareTarget = canResolveSelfCloudflareD1Target(config);
|
|
4375
|
+
if (!isWorkersTarget && !isSelfCloudflareTarget && !canResolveWorkersTarget && !canResolveSelfCloudflareTarget) return validationErr("Cloudflare D1 setup requires SQLite database and either Cloudflare Workers runtime with server deployment or backend 'self' with Cloudflare web deployment.");
|
|
4376
|
+
}
|
|
4358
4377
|
if (dbSetup === "docker") {
|
|
4359
4378
|
if (database === "sqlite") return validationErr("Docker setup is not compatible with SQLite database. SQLite is file-based and doesn't require Docker. Please use '--database postgres', '--database mysql', '--database mongodb', or choose a different setup.");
|
|
4360
4379
|
if (runtime === "workers") return validationErr("Docker setup is not compatible with Cloudflare Workers runtime. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.");
|
|
@@ -4612,8 +4631,8 @@ async function addEnvVariablesToFile(envPath, variables) {
|
|
|
4612
4631
|
//#endregion
|
|
4613
4632
|
//#region src/helpers/database-providers/d1-setup.ts
|
|
4614
4633
|
async function setupCloudflareD1(config) {
|
|
4615
|
-
const { projectDir, serverDeploy, orm, backend } = config;
|
|
4616
|
-
if (!(serverDeploy === "cloudflare" &&
|
|
4634
|
+
const { projectDir, serverDeploy, webDeploy, orm, backend } = config;
|
|
4635
|
+
if (!(orm === "prisma" && (serverDeploy === "cloudflare" || backend === "self" && webDeploy === "cloudflare"))) return Result.ok(void 0);
|
|
4617
4636
|
return Result.tryPromise({
|
|
4618
4637
|
try: async () => {
|
|
4619
4638
|
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
@@ -5995,7 +6014,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
5995
6014
|
const hasHusky = addons?.includes("husky");
|
|
5996
6015
|
const hasLefthook = addons?.includes("lefthook");
|
|
5997
6016
|
const hasGitHooksOrLinting = addons?.includes("husky") || addons?.includes("biome") || addons?.includes("lefthook") || addons?.includes("oxlint");
|
|
5998
|
-
const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy, backend) : "";
|
|
6017
|
+
const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, webDeploy, serverDeploy, backend) : "";
|
|
5999
6018
|
const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd, frontend) : "";
|
|
6000
6019
|
const electrobunInstructions = addons?.includes("electrobun") ? getElectrobunInstructions(runCmd, frontend) : "";
|
|
6001
6020
|
const huskyInstructions = hasHusky ? getHuskyInstructions(runCmd) : "";
|
|
@@ -6088,8 +6107,9 @@ function getLefthookInstructions(packageManager) {
|
|
|
6088
6107
|
const cmd = packageManager === "npm" ? "npx" : packageManager;
|
|
6089
6108
|
return `${pc.bold("Git hooks with Lefthook:")}\n${pc.cyan("•")} Install hooks: ${cmd} lefthook install\n`;
|
|
6090
6109
|
}
|
|
6091
|
-
async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup, serverDeploy,
|
|
6110
|
+
async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup, webDeploy, serverDeploy, backend) {
|
|
6092
6111
|
const instructions = [];
|
|
6112
|
+
const isD1Alchemy = dbSetup === "d1" && (serverDeploy === "cloudflare" || backend === "self" && webDeploy === "cloudflare");
|
|
6093
6113
|
if (dbSetup === "docker") {
|
|
6094
6114
|
const dockerStatus = await getDockerStatus(database);
|
|
6095
6115
|
if (dockerStatus.message) {
|
|
@@ -6097,7 +6117,7 @@ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup,
|
|
|
6097
6117
|
instructions.push("");
|
|
6098
6118
|
}
|
|
6099
6119
|
}
|
|
6100
|
-
if (
|
|
6120
|
+
if (isD1Alchemy) {
|
|
6101
6121
|
if (orm === "drizzle") instructions.push(`${pc.cyan("•")} Generate migrations: ${`${runCmd} db:generate`}`);
|
|
6102
6122
|
else if (orm === "prisma") {
|
|
6103
6123
|
instructions.push(`${pc.cyan("•")} Generate Prisma client: ${`${runCmd} db:generate`}`);
|
|
@@ -6112,15 +6132,15 @@ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup,
|
|
|
6112
6132
|
if (orm === "prisma") {
|
|
6113
6133
|
if (database === "mongodb" && dbSetup === "docker") instructions.push(`${pc.yellow("WARNING:")} Prisma + MongoDB + Docker combination\n may not work.`);
|
|
6114
6134
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6115
|
-
if (!
|
|
6135
|
+
if (!isD1Alchemy) {
|
|
6116
6136
|
instructions.push(`${pc.cyan("•")} Generate Prisma Client: ${`${runCmd} db:generate`}`);
|
|
6117
6137
|
instructions.push(`${pc.cyan("•")} Apply schema: ${`${runCmd} db:push`}`);
|
|
6118
6138
|
}
|
|
6119
|
-
if (!
|
|
6139
|
+
if (!isD1Alchemy) instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
|
|
6120
6140
|
} else if (orm === "drizzle") {
|
|
6121
6141
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6122
|
-
if (
|
|
6123
|
-
if (!
|
|
6142
|
+
if (!isD1Alchemy) instructions.push(`${pc.cyan("•")} Apply schema: ${`${runCmd} db:push`}`);
|
|
6143
|
+
if (!isD1Alchemy) instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
|
|
6124
6144
|
} else if (orm === "mongoose") {
|
|
6125
6145
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6126
6146
|
} else if (orm === "none") instructions.push(`${pc.yellow("NOTE:")} Manual database schema setup\n required.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.27.0",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"better-auth",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"prepublishOnly": "npm run build"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@better-t-stack/template-generator": "^3.
|
|
74
|
-
"@better-t-stack/types": "^3.
|
|
73
|
+
"@better-t-stack/template-generator": "^3.27.0",
|
|
74
|
+
"@better-t-stack/types": "^3.27.0",
|
|
75
75
|
"@clack/core": "^1.1.0",
|
|
76
76
|
"@clack/prompts": "^1.1.0",
|
|
77
77
|
"@modelcontextprotocol/sdk": "1.27.1",
|