create-better-t-stack 3.46.1 → 3.47.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/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { D as setProcessMode, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as types_exports, y as getLatestCLIVersion } from "./src-_HMF_A8q.mjs";
2
+ import { D as setProcessMode, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as types_exports, y as getLatestCLIVersion } from "./src-CC7QNkfh.mjs";
3
3
  import { lineByLineConsoleLogger } from "trpc-cli";
4
4
  import z from "zod";
5
5
  import { McpServer } from "@modelcontextprotocol/server";
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { C as DirectoryConflictError, E as ValidationError, S as DatabaseSetupError, T as UserCancelledError, _ as ProjectLauncherSchema, a as TEMPLATE_COUNT, b as CLIError, 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 ProjectCreationError, x as CompatibilityError } from "./src-_HMF_A8q.mjs";
2
+ import { C as DirectoryConflictError, E as ValidationError, S as DatabaseSetupError, T as UserCancelledError, _ as ProjectLauncherSchema, a as TEMPLATE_COUNT, b as CLIError, 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 ProjectCreationError, x as CompatibilityError } from "./src-CC7QNkfh.mjs";
3
3
  export { CLIError, CompatibilityError, DatabaseSetupError, DirectoryConflictError, EMBEDDED_TEMPLATES, GeneratorError, ProjectCreationError, ProjectLauncherSchema, Result, SchemaNameSchema, TEMPLATE_COUNT, UserCancelledError, ValidationError, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generate, getSchemaResult, router, sponsors };
@@ -8078,19 +8078,21 @@ async function setupPrismaPostgres(config, cliInput) {
8078
8078
  }
8079
8079
  //#endregion
8080
8080
  //#region src/helpers/database-providers/supabase-setup.ts
8081
+ const SUPABASE_CLI_PACKAGE = "supabase@2.121.0";
8082
+ const supabaseEnv = { SUPABASE_EXPERIMENTAL_STACK: "0" };
8083
+ const statusSchema = z$1.object({ DB_URL: z$1.url().refine((value) => ["postgres:", "postgresql:"].includes(new URL(value).protocol)) });
8084
+ /** Save a verified database URL in the app that consumes the database. */
8081
8085
  async function writeSupabaseEnvFile(projectDir, backend, databaseUrl) {
8082
8086
  return Result.tryPromise({
8083
8087
  try: async () => {
8084
8088
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
8085
- const envPath = path.join(projectDir, targetApp, ".env");
8086
- const dbUrlToUse = databaseUrl || "postgresql://postgres:postgres@127.0.0.1:54322/postgres";
8087
- await addEnvVariablesToFile(envPath, [{
8089
+ await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
8088
8090
  key: "DATABASE_URL",
8089
- value: dbUrlToUse,
8091
+ value: databaseUrl,
8090
8092
  condition: true
8091
8093
  }, {
8092
8094
  key: "DIRECT_URL",
8093
- value: dbUrlToUse,
8095
+ value: databaseUrl,
8094
8096
  condition: true
8095
8097
  }]);
8096
8098
  },
@@ -8101,28 +8103,38 @@ async function writeSupabaseEnvFile(projectDir, backend, databaseUrl) {
8101
8103
  })
8102
8104
  });
8103
8105
  }
8104
- function extractDbUrl(statusEnv) {
8105
- return statusEnv.match(/^DB_URL="(postgresql:\/\/[^"]+)"$/m)?.[1] ?? null;
8106
- }
8106
+ /** Read Docker status with cancellation and a bounded wait. */
8107
8107
  async function readSupabaseStatus(serverDir, packageManager) {
8108
- const statusArgs = getPackageExecutionArgs(packageManager, "supabase status --agent no -o env");
8109
- const result = await Result.tryPromise({
8108
+ const statusArgs = getPackageExecutionArgs(packageManager, `${SUPABASE_CLI_PACKAGE} status --agent no --output json`);
8109
+ return Result.tryPromise({
8110
8110
  try: async () => {
8111
- const { stdout } = await execa(statusArgs[0], statusArgs.slice(1), { cwd: serverDir });
8112
- return stdout;
8111
+ const { stdout } = await execa(statusArgs[0], statusArgs.slice(1), {
8112
+ cwd: serverDir,
8113
+ env: supabaseEnv,
8114
+ cancelSignal: getInterruptSignal(),
8115
+ timeout: 12e4
8116
+ });
8117
+ return statusSchema.parse(JSON.parse(stdout)).DB_URL;
8113
8118
  },
8114
- catch: () => ""
8119
+ catch: (e) => new DatabaseSetupError({
8120
+ provider: "supabase",
8121
+ message: "Could not read the Supabase database URL. Run Supabase status and configure DATABASE_URL and DIRECT_URL manually.",
8122
+ cause: e
8123
+ })
8115
8124
  });
8116
- return result.isOk() ? result.value : "";
8117
8125
  }
8126
+ /** Initialize missing configuration without overwriting an existing project. */
8118
8127
  async function initializeSupabase(serverDir, packageManager) {
8119
8128
  cliLog.info("Initializing Supabase project...");
8120
8129
  return Result.tryPromise({
8121
8130
  try: async () => {
8122
- const supabaseInitArgs = getPackageExecutionArgs(packageManager, "supabase init");
8131
+ if (await fs.pathExists(path.join(serverDir, "supabase/config.toml"))) return;
8132
+ const supabaseInitArgs = getPackageExecutionArgs(packageManager, `${SUPABASE_CLI_PACKAGE} init --agent no`);
8123
8133
  await execa(supabaseInitArgs[0], supabaseInitArgs.slice(1), {
8124
8134
  cwd: serverDir,
8125
- stdio: "inherit"
8135
+ stdio: "inherit",
8136
+ env: supabaseEnv,
8137
+ cancelSignal: getInterruptSignal()
8126
8138
  });
8127
8139
  cliLog.success("Supabase project initialized");
8128
8140
  },
@@ -8130,18 +8142,23 @@ async function initializeSupabase(serverDir, packageManager) {
8130
8142
  const error = e;
8131
8143
  return new DatabaseSetupError({
8132
8144
  provider: "supabase",
8133
- message: error.message?.includes("ENOENT") ? "Supabase CLI not found. Please install it globally (npm install -g supabase) or ensure it's in your PATH." : `Failed to initialize Supabase project: ${error.message ?? String(e)}`,
8145
+ message: error.message?.includes("ENOENT") ? "Could not run the Supabase CLI. Ensure your selected package manager is installed and available in PATH." : `Failed to initialize Supabase project: ${error.message ?? String(e)}`,
8134
8146
  cause: e
8135
8147
  });
8136
8148
  }
8137
8149
  });
8138
8150
  }
8151
+ /** Start the standard Docker runtime and stream its progress to the CLI. */
8139
8152
  async function startSupabase(serverDir, packageManager) {
8140
8153
  cliLog.info("Starting Supabase services (this may take a moment)...");
8141
- const supabaseStartArgs = getPackageExecutionArgs(packageManager, "supabase start --agent no");
8154
+ const supabaseStartArgs = getPackageExecutionArgs(packageManager, `${SUPABASE_CLI_PACKAGE} start --agent no`);
8142
8155
  return Result.tryPromise({
8143
8156
  try: async () => {
8144
- const subprocess = execa(supabaseStartArgs[0], supabaseStartArgs.slice(1), { cwd: serverDir });
8157
+ const subprocess = execa(supabaseStartArgs[0], supabaseStartArgs.slice(1), {
8158
+ cwd: serverDir,
8159
+ env: supabaseEnv,
8160
+ cancelSignal: getInterruptSignal()
8161
+ });
8145
8162
  let stdoutData = "";
8146
8163
  if (subprocess.stdout) subprocess.stdout.on("data", (data) => {
8147
8164
  const text = data.toString();
@@ -8150,7 +8167,6 @@ async function startSupabase(serverDir, packageManager) {
8150
8167
  });
8151
8168
  if (subprocess.stderr) subprocess.stderr.pipe(process.stderr);
8152
8169
  await subprocess;
8153
- await new Promise((resolve) => setTimeout(resolve, 100));
8154
8170
  return stdoutData;
8155
8171
  },
8156
8172
  catch: (e) => {
@@ -8163,18 +8179,21 @@ async function startSupabase(serverDir, packageManager) {
8163
8179
  }
8164
8180
  });
8165
8181
  }
8166
- function displayManualSupabaseInstructions(targetApp, output) {
8182
+ /** Print pinned setup commands without changing configuration or credentials. */
8183
+ function displayManualSupabaseInstructions(targetApp, packageManager, output) {
8184
+ const command = getPackageExecutionCommand(packageManager, SUPABASE_CLI_PACKAGE);
8167
8185
  cliLog.info(`"Manual Supabase Setup Instructions:"
8168
- 1. Ensure Docker is installed and running.
8169
- 2. Install the Supabase CLI (e.g., \`npm install -g supabase\`).
8170
- 3. Run \`supabase init\` in your project's \`packages/db\` directory.
8171
- 4. Run \`supabase start\` in your project's \`packages/db\` directory.
8172
- 5. Copy the database URL from the output.${output ? `
8186
+ 1. Open your project's \`packages/db\` directory.
8187
+ 2. Run \`${command} init\` if \`supabase/config.toml\` does not exist.
8188
+ 3. Ensure Docker or a Docker-compatible container runtime is installed and running.
8189
+ 4. Run \`${command} start\`.
8190
+ 5. Run \`${command} status --output json\` and copy \`DB_URL\`.${output ? `
8173
8191
  ${pc.bold("Relevant output from `supabase start`:")}
8174
8192
  ${pc.dim(output)}` : ""}
8175
- 6. Add the database URL to the .env file in \`${targetApp}/.env\` as \`DATABASE_URL\`:
8176
- ${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
8193
+ 6. Add the database URL to the .env file in \`${targetApp}/.env\` as \`DATABASE_URL\` and \`DIRECT_URL\`:
8194
+ ${pc.gray("DATABASE_URL=\"your_supabase_db_url\"\nDIRECT_URL=\"your_supabase_db_url\"")}`);
8177
8195
  }
8196
+ /** Configure local Supabase, preserving credentials until automatic setup succeeds. */
8178
8197
  async function setupSupabase(config, cliInput) {
8179
8198
  const { projectDir, packageManager, backend } = config;
8180
8199
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
@@ -8193,8 +8212,8 @@ async function setupSupabase(config, cliInput) {
8193
8212
  });
8194
8213
  if (ensureDirResult.isErr()) return ensureDirResult;
8195
8214
  if (setupMode === "manual") {
8196
- displayManualSupabaseInstructions(targetApp);
8197
- return writeSupabaseEnvFile(projectDir, backend, "");
8215
+ displayManualSupabaseInstructions(targetApp, packageManager);
8216
+ return Result.ok();
8198
8217
  }
8199
8218
  let mode = setupMode;
8200
8219
  if (!mode) {
@@ -8218,35 +8237,35 @@ async function setupSupabase(config, cliInput) {
8218
8237
  }
8219
8238
  }
8220
8239
  if (mode === "manual") {
8221
- displayManualSupabaseInstructions(targetApp);
8222
- return writeSupabaseEnvFile(projectDir, backend, "");
8240
+ displayManualSupabaseInstructions(targetApp, packageManager);
8241
+ return Result.ok();
8223
8242
  }
8224
8243
  const initResult = await initializeSupabase(serverDir, packageManager);
8225
8244
  if (initResult.isErr()) {
8226
8245
  cliLog.error(pc.red(initResult.error.message));
8227
- displayManualSupabaseInstructions(targetApp);
8228
- return writeSupabaseEnvFile(projectDir, backend, "");
8246
+ displayManualSupabaseInstructions(targetApp, packageManager);
8247
+ return initResult;
8229
8248
  }
8230
8249
  const startResult = await startSupabase(serverDir, packageManager);
8231
8250
  if (startResult.isErr()) {
8232
8251
  cliLog.error(pc.red(startResult.error.message));
8233
- displayManualSupabaseInstructions(targetApp);
8234
- return writeSupabaseEnvFile(projectDir, backend, "");
8252
+ displayManualSupabaseInstructions(targetApp, packageManager);
8253
+ return startResult;
8235
8254
  }
8236
8255
  const supabaseOutput = startResult.value;
8237
- const dbUrl = extractDbUrl(await readSupabaseStatus(serverDir, packageManager));
8238
- if (dbUrl) {
8239
- const envResult = await writeSupabaseEnvFile(projectDir, backend, dbUrl);
8256
+ const statusResult = await readSupabaseStatus(serverDir, packageManager);
8257
+ if (statusResult.isOk()) {
8258
+ const envResult = await writeSupabaseEnvFile(projectDir, backend, statusResult.value);
8240
8259
  if (envResult.isOk()) cliLog.success(pc.green("Supabase local development setup ready!"));
8241
8260
  else {
8242
8261
  cliLog.error(pc.red("Supabase setup completed, but failed to update .env automatically."));
8243
- displayManualSupabaseInstructions(targetApp, supabaseOutput);
8262
+ displayManualSupabaseInstructions(targetApp, packageManager, supabaseOutput);
8244
8263
  }
8245
8264
  return envResult;
8246
8265
  }
8247
8266
  cliLog.error(pc.yellow("Supabase started, but could not extract DB URL automatically."));
8248
- displayManualSupabaseInstructions(targetApp, supabaseOutput);
8249
- return databaseSetupError("supabase", "Could not extract database URL from Supabase output. Please configure manually.");
8267
+ displayManualSupabaseInstructions(targetApp, packageManager, supabaseOutput);
8268
+ return statusResult;
8250
8269
  }
8251
8270
  //#endregion
8252
8271
  //#region src/helpers/database-providers/turso-setup.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.46.1",
3
+ "version": "3.47.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.46.1",
74
- "@better-t-stack/types": "^3.46.1",
73
+ "@better-t-stack/template-generator": "^3.47.0",
74
+ "@better-t-stack/types": "^3.47.0",
75
75
  "@clack/core": "^1.5.0",
76
76
  "@clack/prompts": "^1.8.0",
77
77
  "@modelcontextprotocol/server": "2.0.0",