create-better-t-stack 3.7.1 → 3.7.3-canary.53fc0031
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.d.ts +108 -250
- package/dist/index.js +1 -1
- package/dist/{src-BmyCNYPk.js → src-B1ogWZqk.js} +205 -368
- package/package.json +3 -3
- package/templates/api/orpc/server/package.json.hbs +0 -3
- package/templates/api/trpc/server/package.json.hbs +1 -4
- package/templates/auth/better-auth/convex/native/base/lib/auth-client.ts.hbs +0 -2
- package/templates/auth/better-auth/server/base/package.json.hbs +1 -4
- package/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs +6 -2
- package/templates/auth/better-auth/web/react/tanstack-router/src/components/sign-in-form.tsx +117 -121
- package/templates/auth/better-auth/web/react/tanstack-router/src/components/sign-up-form.tsx +141 -145
- package/templates/auth/better-auth/web/react/tanstack-start/src/components/sign-in-form.tsx +117 -121
- package/templates/auth/better-auth/web/react/tanstack-start/src/components/sign-up-form.tsx +141 -145
- package/templates/auth/better-auth/web/solid/src/components/sign-in-form.tsx +3 -11
- package/templates/auth/better-auth/web/solid/src/components/sign-up-form.tsx +4 -14
- package/templates/backend/convex/packages/backend/convex/healthCheck.ts +2 -2
- package/templates/backend/convex/packages/backend/package.json.hbs +1 -2
- package/templates/backend/server/base/package.json.hbs +1 -3
- package/templates/db/base/package.json.hbs +1 -4
- package/templates/examples/ai/native/bare/polyfills.js +3 -7
- package/templates/examples/ai/native/unistyles/polyfills.js +3 -6
- package/templates/examples/ai/native/uniwind/polyfills.js +3 -7
- package/templates/examples/todo/server/drizzle/postgres/src/schema/todo.ts +1 -1
- package/templates/frontend/native/bare/package.json.hbs +1 -2
- package/templates/frontend/native/unistyles/package.json.hbs +1 -2
- package/templates/frontend/native/uniwind/package.json.hbs +1 -2
- package/templates/frontend/nuxt/package.json.hbs +1 -3
- package/templates/frontend/react/next/package.json.hbs +1 -3
- package/templates/frontend/react/react-router/package.json.hbs +1 -3
- package/templates/frontend/react/react-router/src/components/mode-toggle.tsx +3 -9
- package/templates/frontend/react/tanstack-router/package.json.hbs +1 -3
- package/templates/frontend/react/tanstack-router/src/components/mode-toggle.tsx +3 -9
- package/templates/frontend/react/tanstack-start/package.json.hbs +1 -3
- package/templates/frontend/react/web-base/src/components/ui/button.tsx +13 -16
- package/templates/frontend/react/web-base/src/components/ui/card.tsx +13 -30
- package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx +8 -11
- package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx +37 -66
- package/templates/frontend/react/web-base/src/components/ui/input.tsx +5 -5
- package/templates/frontend/react/web-base/src/components/ui/label.tsx +7 -10
- package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx +3 -3
- package/templates/frontend/react/web-base/src/lib/utils.ts +3 -3
- package/templates/frontend/solid/package.json.hbs +1 -3
- package/templates/frontend/svelte/package.json.hbs +1 -3
- package/templates/frontend/svelte/src/app.d.ts +7 -7
- package/templates/frontend/svelte/src/lib/index.ts +1 -0
- package/templates/frontend/svelte/vite.config.ts +4 -4
|
@@ -3,11 +3,12 @@ import { autocompleteMultiselect, cancel, confirm, group, groupMultiselect, intr
|
|
|
3
3
|
import { createRouterClient, os } from "@orpc/server";
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import { createCli } from "trpc-cli";
|
|
6
|
-
import z
|
|
6
|
+
import z from "zod";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import consola, { consola as consola$1 } from "consola";
|
|
9
9
|
import fs from "fs-extra";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { APISchema, AddonsSchema, AuthSchema, BackendSchema, DatabaseSchema, DatabaseSetupSchema, DirectoryConflictSchema, ExamplesSchema, FrontendSchema, ORMSchema, PackageManagerSchema, PaymentsSchema, ProjectNameSchema, RuntimeSchema, ServerDeploySchema, TemplateSchema, WebDeploySchema } from "@create-better-t-stack/types";
|
|
11
12
|
import gradient from "gradient-string";
|
|
12
13
|
import * as JSONC from "jsonc-parser";
|
|
13
14
|
import { $, execa } from "execa";
|
|
@@ -62,20 +63,21 @@ function getDefaultConfig() {
|
|
|
62
63
|
}
|
|
63
64
|
const DEFAULT_CONFIG = getDefaultConfig();
|
|
64
65
|
const dependencyVersionMap = {
|
|
66
|
+
typescript: "^5",
|
|
65
67
|
"better-auth": "^1.4.5",
|
|
66
68
|
"@better-auth/expo": "^1.4.5",
|
|
67
69
|
"@clerk/nextjs": "^6.31.5",
|
|
68
70
|
"@clerk/clerk-react": "^5.45.0",
|
|
69
71
|
"@clerk/tanstack-react-start": "^0.26.3",
|
|
70
72
|
"@clerk/clerk-expo": "^2.14.25",
|
|
71
|
-
"drizzle-orm": "^0.
|
|
72
|
-
"drizzle-kit": "^0.31.
|
|
73
|
+
"drizzle-orm": "^0.45.0",
|
|
74
|
+
"drizzle-kit": "^0.31.8",
|
|
73
75
|
"@planetscale/database": "^1.19.0",
|
|
74
76
|
"@libsql/client": "^0.14.0",
|
|
75
77
|
libsql: "^0.5.22",
|
|
76
78
|
"@neondatabase/serverless": "^1.0.2",
|
|
77
|
-
pg: "^8.
|
|
78
|
-
"@types/pg": "^8.
|
|
79
|
+
pg: "^8.16.3",
|
|
80
|
+
"@types/pg": "^8.15.6",
|
|
79
81
|
"@types/ws": "^8.18.1",
|
|
80
82
|
ws: "^8.18.3",
|
|
81
83
|
mysql2: "^3.14.0",
|
|
@@ -98,7 +100,7 @@ const dependencyVersionMap = {
|
|
|
98
100
|
"lint-staged": "^16.1.2",
|
|
99
101
|
tsx: "^4.19.2",
|
|
100
102
|
"@types/node": "^22.13.11",
|
|
101
|
-
"@types/bun": "^1.
|
|
103
|
+
"@types/bun": "^1.3.4",
|
|
102
104
|
"@elysiajs/node": "^1.3.1",
|
|
103
105
|
"@elysiajs/cors": "^1.3.3",
|
|
104
106
|
"@elysiajs/trpc": "^1.1.0",
|
|
@@ -128,7 +130,7 @@ const dependencyVersionMap = {
|
|
|
128
130
|
"@trpc/tanstack-react-query": "^11.5.0",
|
|
129
131
|
"@trpc/server": "^11.5.0",
|
|
130
132
|
"@trpc/client": "^11.5.0",
|
|
131
|
-
next: "
|
|
133
|
+
next: "^16.0.7",
|
|
132
134
|
convex: "^1.29.3",
|
|
133
135
|
"@convex-dev/react-query": "^0.1.0",
|
|
134
136
|
"convex-svelte": "^0.0.12",
|
|
@@ -153,7 +155,7 @@ const dependencyVersionMap = {
|
|
|
153
155
|
alchemy: "^0.77.0",
|
|
154
156
|
dotenv: "^17.2.2",
|
|
155
157
|
tsdown: "^0.16.5",
|
|
156
|
-
zod: "^4.1.
|
|
158
|
+
zod: "^4.1.13",
|
|
157
159
|
srvx: "0.8.15",
|
|
158
160
|
"@polar-sh/better-auth": "^1.1.3",
|
|
159
161
|
"@polar-sh/sdk": "^0.34.16"
|
|
@@ -184,121 +186,6 @@ const ADDON_COMPATIBILITY = {
|
|
|
184
186
|
none: []
|
|
185
187
|
};
|
|
186
188
|
|
|
187
|
-
//#endregion
|
|
188
|
-
//#region src/types.ts
|
|
189
|
-
const DatabaseSchema = z.enum([
|
|
190
|
-
"none",
|
|
191
|
-
"sqlite",
|
|
192
|
-
"postgres",
|
|
193
|
-
"mysql",
|
|
194
|
-
"mongodb"
|
|
195
|
-
]).describe("Database type");
|
|
196
|
-
const ORMSchema = z.enum([
|
|
197
|
-
"drizzle",
|
|
198
|
-
"prisma",
|
|
199
|
-
"mongoose",
|
|
200
|
-
"none"
|
|
201
|
-
]).describe("ORM type");
|
|
202
|
-
const BackendSchema = z.enum([
|
|
203
|
-
"hono",
|
|
204
|
-
"express",
|
|
205
|
-
"fastify",
|
|
206
|
-
"elysia",
|
|
207
|
-
"convex",
|
|
208
|
-
"self",
|
|
209
|
-
"none"
|
|
210
|
-
]).describe("Backend framework");
|
|
211
|
-
const RuntimeSchema = z.enum([
|
|
212
|
-
"bun",
|
|
213
|
-
"node",
|
|
214
|
-
"workers",
|
|
215
|
-
"none"
|
|
216
|
-
]).describe("Runtime environment");
|
|
217
|
-
const FrontendSchema = z.enum([
|
|
218
|
-
"tanstack-router",
|
|
219
|
-
"react-router",
|
|
220
|
-
"tanstack-start",
|
|
221
|
-
"next",
|
|
222
|
-
"nuxt",
|
|
223
|
-
"native-bare",
|
|
224
|
-
"native-uniwind",
|
|
225
|
-
"native-unistyles",
|
|
226
|
-
"svelte",
|
|
227
|
-
"solid",
|
|
228
|
-
"none"
|
|
229
|
-
]).describe("Frontend framework");
|
|
230
|
-
const AddonsSchema = z.enum([
|
|
231
|
-
"pwa",
|
|
232
|
-
"tauri",
|
|
233
|
-
"starlight",
|
|
234
|
-
"biome",
|
|
235
|
-
"husky",
|
|
236
|
-
"ruler",
|
|
237
|
-
"turborepo",
|
|
238
|
-
"fumadocs",
|
|
239
|
-
"ultracite",
|
|
240
|
-
"oxlint",
|
|
241
|
-
"none"
|
|
242
|
-
]).describe("Additional addons");
|
|
243
|
-
const ExamplesSchema = z.enum([
|
|
244
|
-
"todo",
|
|
245
|
-
"ai",
|
|
246
|
-
"none"
|
|
247
|
-
]).describe("Example templates to include");
|
|
248
|
-
const PackageManagerSchema = z.enum([
|
|
249
|
-
"npm",
|
|
250
|
-
"pnpm",
|
|
251
|
-
"bun"
|
|
252
|
-
]).describe("Package manager");
|
|
253
|
-
const DatabaseSetupSchema = z.enum([
|
|
254
|
-
"turso",
|
|
255
|
-
"neon",
|
|
256
|
-
"prisma-postgres",
|
|
257
|
-
"planetscale",
|
|
258
|
-
"mongodb-atlas",
|
|
259
|
-
"supabase",
|
|
260
|
-
"d1",
|
|
261
|
-
"docker",
|
|
262
|
-
"none"
|
|
263
|
-
]).describe("Database hosting setup");
|
|
264
|
-
const APISchema = z.enum([
|
|
265
|
-
"trpc",
|
|
266
|
-
"orpc",
|
|
267
|
-
"none"
|
|
268
|
-
]).describe("API type");
|
|
269
|
-
const AuthSchema = z.enum([
|
|
270
|
-
"better-auth",
|
|
271
|
-
"clerk",
|
|
272
|
-
"none"
|
|
273
|
-
]).describe("Authentication provider");
|
|
274
|
-
const PaymentsSchema = z.enum(["polar", "none"]).describe("Payments provider");
|
|
275
|
-
const ProjectNameSchema = z.string().min(1, "Project name cannot be empty").max(255, "Project name must be less than 255 characters").refine((name) => name === "." || !name.startsWith("."), "Project name cannot start with a dot (except for '.')").refine((name) => name === "." || !name.startsWith("-"), "Project name cannot start with a dash").refine((name) => {
|
|
276
|
-
return ![
|
|
277
|
-
"<",
|
|
278
|
-
">",
|
|
279
|
-
":",
|
|
280
|
-
"\"",
|
|
281
|
-
"|",
|
|
282
|
-
"?",
|
|
283
|
-
"*"
|
|
284
|
-
].some((char) => name.includes(char));
|
|
285
|
-
}, "Project name contains invalid characters").refine((name) => name.toLowerCase() !== "node_modules", "Project name is reserved").describe("Project name or path");
|
|
286
|
-
const WebDeploySchema = z.enum(["alchemy", "none"]).describe("Web deployment");
|
|
287
|
-
const ServerDeploySchema = z.enum(["alchemy", "none"]).describe("Server deployment");
|
|
288
|
-
const DirectoryConflictSchema = z.enum([
|
|
289
|
-
"merge",
|
|
290
|
-
"overwrite",
|
|
291
|
-
"increment",
|
|
292
|
-
"error"
|
|
293
|
-
]).describe("How to handle existing directory conflicts");
|
|
294
|
-
const TemplateSchema = z.enum([
|
|
295
|
-
"mern",
|
|
296
|
-
"pern",
|
|
297
|
-
"t3",
|
|
298
|
-
"uniwind",
|
|
299
|
-
"none"
|
|
300
|
-
]).describe("Predefined project template");
|
|
301
|
-
|
|
302
189
|
//#endregion
|
|
303
190
|
//#region src/utils/compatibility.ts
|
|
304
191
|
const WEB_FRAMEWORKS = [
|
|
@@ -1045,7 +932,7 @@ async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
|
|
|
1045
932
|
if (orm !== void 0) return orm;
|
|
1046
933
|
const response = await select({
|
|
1047
934
|
message: "Select ORM",
|
|
1048
|
-
options:
|
|
935
|
+
options: database === "mongodb" ? [ormOptions.prisma, ormOptions.mongoose] : [ormOptions.drizzle, ormOptions.prisma],
|
|
1049
936
|
initialValue: database === "mongodb" ? "prisma" : runtime === "workers" ? "drizzle" : DEFAULT_CONFIG.orm
|
|
1050
937
|
});
|
|
1051
938
|
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
@@ -1165,7 +1052,6 @@ async function getServerDeploymentToAdd(runtime, existingDeployment, backend) {
|
|
|
1165
1052
|
}
|
|
1166
1053
|
}
|
|
1167
1054
|
if (existingDeployment && existingDeployment !== "none") return "none";
|
|
1168
|
-
if (options.length > 0) {}
|
|
1169
1055
|
if (options.length === 0) return "none";
|
|
1170
1056
|
const response = await select({
|
|
1171
1057
|
message: "Select server deployment",
|
|
@@ -1347,7 +1233,7 @@ const getLatestCLIVersion = () => {
|
|
|
1347
1233
|
*/
|
|
1348
1234
|
function isTelemetryEnabled() {
|
|
1349
1235
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1350
|
-
const BTS_TELEMETRY = "
|
|
1236
|
+
const BTS_TELEMETRY = "0";
|
|
1351
1237
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1352
1238
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1353
1239
|
return true;
|
|
@@ -1363,20 +1249,19 @@ async function sendConvexEvent(payload) {
|
|
|
1363
1249
|
headers: { "Content-Type": "application/json" },
|
|
1364
1250
|
body: JSON.stringify(payload)
|
|
1365
1251
|
});
|
|
1366
|
-
} catch
|
|
1252
|
+
} catch {}
|
|
1367
1253
|
}
|
|
1368
1254
|
async function trackProjectCreation(config, disableAnalytics = false) {
|
|
1369
1255
|
if (!isTelemetryEnabled() || disableAnalytics) return;
|
|
1370
|
-
const { projectName, projectDir, relativePath,...safeConfig } = config;
|
|
1256
|
+
const { projectName: _projectName, projectDir: _projectDir, relativePath: _relativePath,...safeConfig } = config;
|
|
1371
1257
|
try {
|
|
1372
1258
|
await sendConvexEvent({
|
|
1373
|
-
event: "project_created",
|
|
1374
1259
|
...safeConfig,
|
|
1375
1260
|
cli_version: getLatestCLIVersion(),
|
|
1376
1261
|
node_version: typeof process !== "undefined" ? process.version : "",
|
|
1377
1262
|
platform: typeof process !== "undefined" ? process.platform : ""
|
|
1378
1263
|
});
|
|
1379
|
-
} catch
|
|
1264
|
+
} catch {}
|
|
1380
1265
|
}
|
|
1381
1266
|
|
|
1382
1267
|
//#endregion
|
|
@@ -1980,6 +1865,7 @@ async function writeBtsConfig(projectConfig) {
|
|
|
1980
1865
|
addons: btsConfig.addons,
|
|
1981
1866
|
examples: btsConfig.examples,
|
|
1982
1867
|
auth: btsConfig.auth,
|
|
1868
|
+
payments: btsConfig.payments,
|
|
1983
1869
|
packageManager: btsConfig.packageManager,
|
|
1984
1870
|
dbSetup: btsConfig.dbSetup,
|
|
1985
1871
|
api: btsConfig.api,
|
|
@@ -2015,7 +1901,7 @@ async function readBtsConfig(projectDir) {
|
|
|
2015
1901
|
return null;
|
|
2016
1902
|
}
|
|
2017
1903
|
return config;
|
|
2018
|
-
} catch
|
|
1904
|
+
} catch {
|
|
2019
1905
|
return null;
|
|
2020
1906
|
}
|
|
2021
1907
|
}
|
|
@@ -2033,7 +1919,7 @@ async function updateBtsConfig(projectDir, updates) {
|
|
|
2033
1919
|
modifiedContent = JSONC.applyEdits(modifiedContent, editResult);
|
|
2034
1920
|
}
|
|
2035
1921
|
await fs.writeFile(configPath, modifiedContent, "utf-8");
|
|
2036
|
-
} catch
|
|
1922
|
+
} catch {}
|
|
2037
1923
|
}
|
|
2038
1924
|
|
|
2039
1925
|
//#endregion
|
|
@@ -2212,7 +2098,7 @@ async function setupRuler(config) {
|
|
|
2212
2098
|
shell: true
|
|
2213
2099
|
});
|
|
2214
2100
|
s.stop("Applied rules with Ruler");
|
|
2215
|
-
} catch
|
|
2101
|
+
} catch {
|
|
2216
2102
|
s.stop(pc.red("Failed to apply rules"));
|
|
2217
2103
|
}
|
|
2218
2104
|
} catch (error) {
|
|
@@ -2636,14 +2522,14 @@ async function detectProjectConfig(projectDir) {
|
|
|
2636
2522
|
serverDeploy: btsConfig.serverDeploy
|
|
2637
2523
|
};
|
|
2638
2524
|
return null;
|
|
2639
|
-
} catch
|
|
2525
|
+
} catch {
|
|
2640
2526
|
return null;
|
|
2641
2527
|
}
|
|
2642
2528
|
}
|
|
2643
2529
|
async function isBetterTStackProject(projectDir) {
|
|
2644
2530
|
try {
|
|
2645
2531
|
return await fs.pathExists(path.join(projectDir, "bts.jsonc"));
|
|
2646
|
-
} catch
|
|
2532
|
+
} catch {
|
|
2647
2533
|
return false;
|
|
2648
2534
|
}
|
|
2649
2535
|
}
|
|
@@ -2686,7 +2572,7 @@ function initializeBiome() {
|
|
|
2686
2572
|
biome,
|
|
2687
2573
|
projectKey
|
|
2688
2574
|
};
|
|
2689
|
-
} catch
|
|
2575
|
+
} catch {
|
|
2690
2576
|
return null;
|
|
2691
2577
|
}
|
|
2692
2578
|
}
|
|
@@ -2721,7 +2607,7 @@ function formatFileWithBiome(filePath, content) {
|
|
|
2721
2607
|
const result = biome.formatContent(projectKey, content, { filePath: path.basename(filePath) });
|
|
2722
2608
|
if (result.diagnostics && result.diagnostics.length > 0) consola.debug(`Biome formatting diagnostics for ${filePath}:`, result.diagnostics);
|
|
2723
2609
|
return result.content;
|
|
2724
|
-
} catch
|
|
2610
|
+
} catch {
|
|
2725
2611
|
return null;
|
|
2726
2612
|
}
|
|
2727
2613
|
}
|
|
@@ -3864,6 +3750,7 @@ async function addDeploymentToProject(input) {
|
|
|
3864
3750
|
async function setupCatalogs(projectDir, options) {
|
|
3865
3751
|
if (options.packageManager === "npm") return;
|
|
3866
3752
|
const packagePaths = [
|
|
3753
|
+
".",
|
|
3867
3754
|
"apps/server",
|
|
3868
3755
|
"apps/web",
|
|
3869
3756
|
"apps/native",
|
|
@@ -3872,7 +3759,8 @@ async function setupCatalogs(projectDir, options) {
|
|
|
3872
3759
|
"packages/api",
|
|
3873
3760
|
"packages/db",
|
|
3874
3761
|
"packages/auth",
|
|
3875
|
-
"packages/backend"
|
|
3762
|
+
"packages/backend",
|
|
3763
|
+
"packages/config"
|
|
3876
3764
|
];
|
|
3877
3765
|
const packagesInfo = [];
|
|
3878
3766
|
for (const pkgPath of packagePaths) {
|
|
@@ -3971,15 +3859,18 @@ async function updatePackageJsonsWithCatalogs(packagesInfo, catalog) {
|
|
|
3971
3859
|
//#endregion
|
|
3972
3860
|
//#region src/helpers/addons/examples-setup.ts
|
|
3973
3861
|
async function setupExamples(config) {
|
|
3974
|
-
const { examples, frontend, backend, projectDir, orm } = config;
|
|
3862
|
+
const { examples, frontend, backend, projectDir, orm, database } = config;
|
|
3975
3863
|
if (backend === "convex" || !examples || examples.length === 0 || examples[0] === "none") return;
|
|
3976
3864
|
const apiDir = path.join(projectDir, "packages/api");
|
|
3977
3865
|
if (await fs.pathExists(apiDir) && backend !== "none") {
|
|
3978
|
-
if (orm === "drizzle")
|
|
3979
|
-
dependencies
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3866
|
+
if (orm === "drizzle") {
|
|
3867
|
+
const dependencies = ["drizzle-orm"];
|
|
3868
|
+
if (database === "postgres") dependencies.push("@types/pg");
|
|
3869
|
+
await addPackageDependency({
|
|
3870
|
+
dependencies,
|
|
3871
|
+
projectDir: apiDir
|
|
3872
|
+
});
|
|
3873
|
+
} else if (orm === "prisma") await addPackageDependency({
|
|
3983
3874
|
dependencies: ["@prisma/client"],
|
|
3984
3875
|
projectDir: apiDir
|
|
3985
3876
|
});
|
|
@@ -4028,15 +3919,6 @@ async function setupExamples(config) {
|
|
|
4028
3919
|
|
|
4029
3920
|
//#endregion
|
|
4030
3921
|
//#region src/helpers/core/api-setup.ts
|
|
4031
|
-
async function addBackendWorkspaceDependency(projectDir, backendPackageName, workspaceVersion) {
|
|
4032
|
-
const pkgJsonPath = path.join(projectDir, "package.json");
|
|
4033
|
-
try {
|
|
4034
|
-
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
4035
|
-
if (!pkgJson.dependencies) pkgJson.dependencies = {};
|
|
4036
|
-
pkgJson.dependencies[backendPackageName] = workspaceVersion;
|
|
4037
|
-
await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
4038
|
-
} catch (_error) {}
|
|
4039
|
-
}
|
|
4040
3922
|
function getFrontendType(frontend) {
|
|
4041
3923
|
const reactBasedFrontends = [
|
|
4042
3924
|
"tanstack-router",
|
|
@@ -4154,7 +4036,7 @@ function getConvexDependencies(frontend) {
|
|
|
4154
4036
|
return deps;
|
|
4155
4037
|
}
|
|
4156
4038
|
async function setupApi(config) {
|
|
4157
|
-
const { api,
|
|
4039
|
+
const { api, frontend, backend, projectDir } = config;
|
|
4158
4040
|
const isConvex = backend === "convex";
|
|
4159
4041
|
const webDir = path.join(projectDir, "apps/web");
|
|
4160
4042
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
@@ -4224,10 +4106,6 @@ async function setupApi(config) {
|
|
|
4224
4106
|
dependencies: convexDeps.native.dependencies,
|
|
4225
4107
|
projectDir: nativeDir
|
|
4226
4108
|
});
|
|
4227
|
-
const backendPackageName = `@${projectName}/backend`;
|
|
4228
|
-
const backendWorkspaceVersion = packageManager === "npm" ? "*" : "workspace:*";
|
|
4229
|
-
if (webDirExists) await addBackendWorkspaceDependency(webDir, backendPackageName, backendWorkspaceVersion);
|
|
4230
|
-
if (nativeDirExists) await addBackendWorkspaceDependency(nativeDir, backendPackageName, backendWorkspaceVersion);
|
|
4231
4109
|
}
|
|
4232
4110
|
}
|
|
4233
4111
|
|
|
@@ -4754,15 +4632,11 @@ async function setupCloudflareD1(config) {
|
|
|
4754
4632
|
const { projectDir, serverDeploy, orm, backend } = config;
|
|
4755
4633
|
if (serverDeploy === "alchemy" && orm === "prisma") {
|
|
4756
4634
|
const targetApp2 = backend === "self" ? "apps/web" : "apps/server";
|
|
4757
|
-
|
|
4758
|
-
const variables = [{
|
|
4635
|
+
await addEnvVariablesToFile(path.join(projectDir, targetApp2, ".env"), [{
|
|
4759
4636
|
key: "DATABASE_URL",
|
|
4760
4637
|
value: `file:${path.join(projectDir, "apps/server", "local.db")}`,
|
|
4761
4638
|
condition: true
|
|
4762
|
-
}];
|
|
4763
|
-
try {
|
|
4764
|
-
await addEnvVariablesToFile(envPath, variables);
|
|
4765
|
-
} catch (_err) {}
|
|
4639
|
+
}]);
|
|
4766
4640
|
await addPackageDependency({
|
|
4767
4641
|
dependencies: ["@prisma/adapter-d1"],
|
|
4768
4642
|
projectDir: path.join(projectDir, backend === "self" ? "apps/web" : "apps/server")
|
|
@@ -4817,7 +4691,7 @@ async function checkAtlasCLI() {
|
|
|
4817
4691
|
if (exists) log.info("MongoDB Atlas CLI found");
|
|
4818
4692
|
else log.warn(pc.yellow("MongoDB Atlas CLI not found"));
|
|
4819
4693
|
return exists;
|
|
4820
|
-
} catch
|
|
4694
|
+
} catch {
|
|
4821
4695
|
log.error(pc.red("Error checking MongoDB Atlas CLI"));
|
|
4822
4696
|
return false;
|
|
4823
4697
|
}
|
|
@@ -4862,7 +4736,7 @@ async function writeEnvFile$3(projectDir, backend, config) {
|
|
|
4862
4736
|
value: config?.connectionString ?? "mongodb://localhost:27017/mydb",
|
|
4863
4737
|
condition: true
|
|
4864
4738
|
}]);
|
|
4865
|
-
} catch
|
|
4739
|
+
} catch {
|
|
4866
4740
|
consola.error("Failed to update environment configuration");
|
|
4867
4741
|
}
|
|
4868
4742
|
}
|
|
@@ -4999,7 +4873,7 @@ async function createNeonProject(projectName, regionId, packageManager) {
|
|
|
4999
4873
|
}
|
|
5000
4874
|
consola$1.error(pc.red("Failed to extract connection information from response"));
|
|
5001
4875
|
return null;
|
|
5002
|
-
} catch
|
|
4876
|
+
} catch {
|
|
5003
4877
|
consola$1.error(pc.red("Failed to create Neon project"));
|
|
5004
4878
|
}
|
|
5005
4879
|
}
|
|
@@ -5247,7 +5121,7 @@ async function writeEnvFile$1(projectDir, backend, config) {
|
|
|
5247
5121
|
condition: true
|
|
5248
5122
|
});
|
|
5249
5123
|
await addEnvVariablesToFile(envPath, variables);
|
|
5250
|
-
} catch
|
|
5124
|
+
} catch {
|
|
5251
5125
|
consola$1.error("Failed to update environment configuration");
|
|
5252
5126
|
}
|
|
5253
5127
|
}
|
|
@@ -5474,7 +5348,7 @@ async function loginToTurso() {
|
|
|
5474
5348
|
await $`turso auth login`;
|
|
5475
5349
|
s.stop("Logged into Turso");
|
|
5476
5350
|
return true;
|
|
5477
|
-
} catch
|
|
5351
|
+
} catch {
|
|
5478
5352
|
s.stop(pc.red("Failed to log in to Turso"));
|
|
5479
5353
|
}
|
|
5480
5354
|
}
|
|
@@ -5562,7 +5436,7 @@ async function createTursoDatabase(dbName, groupName) {
|
|
|
5562
5436
|
dbUrl: dbUrl.trim(),
|
|
5563
5437
|
authToken: authToken.trim()
|
|
5564
5438
|
};
|
|
5565
|
-
} catch
|
|
5439
|
+
} catch {
|
|
5566
5440
|
s.stop(pc.red("Failed to retrieve database connection details"));
|
|
5567
5441
|
}
|
|
5568
5442
|
}
|
|
@@ -5688,7 +5562,6 @@ async function setupDatabase(config, cliInput) {
|
|
|
5688
5562
|
}
|
|
5689
5563
|
return;
|
|
5690
5564
|
}
|
|
5691
|
-
const s = spinner();
|
|
5692
5565
|
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5693
5566
|
const webDir = path.join(projectDir, "apps/web");
|
|
5694
5567
|
const webDirExists = await fs.pathExists(webDir);
|
|
@@ -5791,7 +5664,6 @@ async function setupDatabase(config, cliInput) {
|
|
|
5791
5664
|
if (dbSetup === "planetscale") await setupPlanetScale(config);
|
|
5792
5665
|
} else if (database === "mongodb" && dbSetup === "mongodb-atlas") await setupMongoDBAtlas(config, cliInput);
|
|
5793
5666
|
} catch (error) {
|
|
5794
|
-
s.stop(pc.red("Failed to set up database"));
|
|
5795
5667
|
if (error instanceof Error) consola.error(pc.red(error.message));
|
|
5796
5668
|
}
|
|
5797
5669
|
}
|
|
@@ -6438,93 +6310,113 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend)
|
|
|
6438
6310
|
//#endregion
|
|
6439
6311
|
//#region src/helpers/core/workspace-setup.ts
|
|
6440
6312
|
async function setupWorkspaceDependencies(projectDir, options) {
|
|
6441
|
-
const projectName = options
|
|
6442
|
-
const workspaceVersion =
|
|
6313
|
+
const { projectName, packageManager, database, auth, api, runtime, backend } = options;
|
|
6314
|
+
const workspaceVersion = packageManager === "npm" ? "*" : "workspace:*";
|
|
6443
6315
|
const commonDeps = ["dotenv", "zod"];
|
|
6444
|
-
const commonDevDeps = [];
|
|
6445
|
-
const
|
|
6446
|
-
const
|
|
6447
|
-
|
|
6448
|
-
const
|
|
6449
|
-
|
|
6316
|
+
const commonDevDeps = ["typescript"];
|
|
6317
|
+
const configDir = path.join(projectDir, "packages/config");
|
|
6318
|
+
const dbDir = path.join(projectDir, "packages/db");
|
|
6319
|
+
const authDir = path.join(projectDir, "packages/auth");
|
|
6320
|
+
const apiDir = path.join(projectDir, "packages/api");
|
|
6321
|
+
const backendDir = path.join(projectDir, "packages/backend");
|
|
6322
|
+
const serverDir = path.join(projectDir, "apps/server");
|
|
6323
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
6324
|
+
const nativeDir = path.join(projectDir, "apps/native");
|
|
6325
|
+
const [configExists, dbExists, authExists, apiExists, backendExists, serverExists, webExists, nativeExists] = await Promise.all([
|
|
6326
|
+
fs.pathExists(configDir),
|
|
6327
|
+
fs.pathExists(dbDir),
|
|
6328
|
+
fs.pathExists(authDir),
|
|
6329
|
+
fs.pathExists(apiDir),
|
|
6330
|
+
fs.pathExists(backendDir),
|
|
6331
|
+
fs.pathExists(serverDir),
|
|
6332
|
+
fs.pathExists(webDir),
|
|
6333
|
+
fs.pathExists(nativeDir)
|
|
6334
|
+
]);
|
|
6335
|
+
const configDep = configExists ? { [`@${projectName}/config`]: workspaceVersion } : {};
|
|
6336
|
+
if (dbExists) await addPackageDependency({
|
|
6450
6337
|
dependencies: commonDeps,
|
|
6451
6338
|
devDependencies: commonDevDeps,
|
|
6452
6339
|
customDevDependencies: configDep,
|
|
6453
|
-
projectDir:
|
|
6340
|
+
projectDir: dbDir
|
|
6454
6341
|
});
|
|
6455
|
-
|
|
6456
|
-
if (await fs.pathExists(authPackageDir)) {
|
|
6342
|
+
if (authExists) {
|
|
6457
6343
|
const authDeps = {};
|
|
6458
|
-
if (
|
|
6344
|
+
if (database !== "none" && dbExists) authDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6459
6345
|
await addPackageDependency({
|
|
6460
6346
|
dependencies: commonDeps,
|
|
6461
6347
|
devDependencies: commonDevDeps,
|
|
6462
6348
|
customDependencies: authDeps,
|
|
6463
6349
|
customDevDependencies: configDep,
|
|
6464
|
-
projectDir:
|
|
6350
|
+
projectDir: authDir
|
|
6465
6351
|
});
|
|
6466
6352
|
}
|
|
6467
|
-
|
|
6468
|
-
if (await fs.pathExists(apiPackageDir)) {
|
|
6353
|
+
if (apiExists) {
|
|
6469
6354
|
const apiDeps = {};
|
|
6470
|
-
if (
|
|
6471
|
-
if (
|
|
6355
|
+
if (auth !== "none" && authExists) apiDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6356
|
+
if (database !== "none" && dbExists) apiDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6472
6357
|
await addPackageDependency({
|
|
6473
6358
|
dependencies: commonDeps,
|
|
6474
6359
|
devDependencies: commonDevDeps,
|
|
6475
6360
|
customDependencies: apiDeps,
|
|
6476
6361
|
customDevDependencies: configDep,
|
|
6477
|
-
projectDir:
|
|
6362
|
+
projectDir: apiDir
|
|
6478
6363
|
});
|
|
6479
6364
|
}
|
|
6480
|
-
|
|
6481
|
-
|
|
6365
|
+
if (backendExists) await addPackageDependency({
|
|
6366
|
+
dependencies: commonDeps,
|
|
6367
|
+
devDependencies: commonDevDeps,
|
|
6368
|
+
customDevDependencies: configDep,
|
|
6369
|
+
projectDir: backendDir
|
|
6370
|
+
});
|
|
6371
|
+
if (serverExists) {
|
|
6482
6372
|
const serverDeps = {};
|
|
6483
|
-
if (
|
|
6484
|
-
if (
|
|
6485
|
-
if (
|
|
6373
|
+
if (api !== "none" && apiExists) serverDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6374
|
+
if (auth !== "none" && authExists) serverDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6375
|
+
if (database !== "none" && dbExists) serverDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6486
6376
|
await addPackageDependency({
|
|
6487
6377
|
dependencies: commonDeps,
|
|
6488
6378
|
devDependencies: [...commonDevDeps, "tsdown"],
|
|
6489
6379
|
customDependencies: serverDeps,
|
|
6490
6380
|
customDevDependencies: configDep,
|
|
6491
|
-
projectDir:
|
|
6381
|
+
projectDir: serverDir
|
|
6492
6382
|
});
|
|
6493
6383
|
}
|
|
6494
|
-
|
|
6495
|
-
if (await fs.pathExists(webPackageDir)) {
|
|
6384
|
+
if (webExists) {
|
|
6496
6385
|
const webDeps = {};
|
|
6497
|
-
if (
|
|
6498
|
-
if (
|
|
6499
|
-
if (
|
|
6386
|
+
if (api !== "none" && apiExists) webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6387
|
+
if (auth !== "none" && authExists) webDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6388
|
+
if (backend === "convex" && backendExists) webDeps[`@${projectName}/backend`] = workspaceVersion;
|
|
6389
|
+
await addPackageDependency({
|
|
6390
|
+
dependencies: commonDeps,
|
|
6391
|
+
devDependencies: commonDevDeps,
|
|
6500
6392
|
customDependencies: webDeps,
|
|
6501
6393
|
customDevDependencies: configDep,
|
|
6502
|
-
projectDir:
|
|
6394
|
+
projectDir: webDir
|
|
6503
6395
|
});
|
|
6504
6396
|
}
|
|
6505
|
-
|
|
6506
|
-
if (await fs.pathExists(nativePackageDir)) {
|
|
6397
|
+
if (nativeExists) {
|
|
6507
6398
|
const nativeDeps = {};
|
|
6508
|
-
if (
|
|
6509
|
-
if (
|
|
6399
|
+
if (api !== "none" && apiExists) nativeDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6400
|
+
if (backend === "convex" && backendExists) nativeDeps[`@${projectName}/backend`] = workspaceVersion;
|
|
6401
|
+
await addPackageDependency({
|
|
6402
|
+
dependencies: commonDeps,
|
|
6403
|
+
devDependencies: commonDevDeps,
|
|
6510
6404
|
customDependencies: nativeDeps,
|
|
6511
6405
|
customDevDependencies: configDep,
|
|
6512
|
-
projectDir:
|
|
6406
|
+
projectDir: nativeDir
|
|
6513
6407
|
});
|
|
6514
6408
|
}
|
|
6515
|
-
const runtimeDevDeps = getRuntimeDevDeps(
|
|
6409
|
+
const runtimeDevDeps = getRuntimeDevDeps(runtime, backend);
|
|
6516
6410
|
await addPackageDependency({
|
|
6517
6411
|
dependencies: commonDeps,
|
|
6518
6412
|
devDependencies: [...commonDevDeps, ...runtimeDevDeps],
|
|
6519
6413
|
projectDir
|
|
6520
6414
|
});
|
|
6521
6415
|
}
|
|
6522
|
-
function getRuntimeDevDeps(
|
|
6523
|
-
const { runtime, backend } = options;
|
|
6416
|
+
function getRuntimeDevDeps(runtime, backend) {
|
|
6524
6417
|
if (runtime === "none" && backend === "self") return ["@types/node"];
|
|
6525
|
-
if (runtime === "node") return ["@types/node"];
|
|
6418
|
+
if (runtime === "node" || runtime === "workers") return ["@types/node"];
|
|
6526
6419
|
if (runtime === "bun") return ["@types/bun"];
|
|
6527
|
-
if (runtime === "workers") return ["@types/node"];
|
|
6528
6420
|
return [];
|
|
6529
6421
|
}
|
|
6530
6422
|
|
|
@@ -6533,185 +6425,130 @@ function getRuntimeDevDeps(options) {
|
|
|
6533
6425
|
async function updatePackageConfigurations(projectDir, options) {
|
|
6534
6426
|
await updateRootPackageJson(projectDir, options);
|
|
6535
6427
|
if (options.backend === "convex") await updateConvexPackageJson(projectDir, options);
|
|
6536
|
-
else if (options.backend
|
|
6428
|
+
else if (options.backend !== "none") {
|
|
6537
6429
|
await updateDbPackageJson(projectDir, options);
|
|
6538
6430
|
await updateAuthPackageJson(projectDir, options);
|
|
6539
6431
|
await updateApiPackageJson(projectDir, options);
|
|
6540
|
-
await
|
|
6541
|
-
} else if (options.backend !== "none") {
|
|
6542
|
-
await updateServerPackageJson(projectDir, options);
|
|
6543
|
-
await updateAuthPackageJson(projectDir, options);
|
|
6544
|
-
await updateApiPackageJson(projectDir, options);
|
|
6545
|
-
await setupWorkspaceDependencies(projectDir, options);
|
|
6432
|
+
if (options.backend !== "self") await updateServerPackageJson(projectDir, options);
|
|
6546
6433
|
}
|
|
6434
|
+
await setupWorkspaceDependencies(projectDir, options);
|
|
6547
6435
|
}
|
|
6548
6436
|
async function updateRootPackageJson(projectDir, options) {
|
|
6549
6437
|
const rootPackageJsonPath = path.join(projectDir, "package.json");
|
|
6550
6438
|
if (!await fs.pathExists(rootPackageJsonPath)) return;
|
|
6551
6439
|
const packageJson = await fs.readJson(rootPackageJsonPath);
|
|
6552
6440
|
packageJson.name = options.projectName;
|
|
6553
|
-
|
|
6441
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
6442
|
+
packageJson.workspaces = packageJson.workspaces || [];
|
|
6554
6443
|
const scripts = packageJson.scripts;
|
|
6555
|
-
const
|
|
6556
|
-
const
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
scripts["
|
|
6572
|
-
scripts["
|
|
6573
|
-
if (
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
if (
|
|
6579
|
-
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6580
|
-
scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6581
|
-
} else if (options.orm === "drizzle") {
|
|
6582
|
-
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6583
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6584
|
-
}
|
|
6585
|
-
}
|
|
6586
|
-
if (options.dbSetup === "docker") {
|
|
6587
|
-
scripts["db:start"] = `turbo -F ${dbPackageName} db:start`;
|
|
6588
|
-
scripts["db:watch"] = `turbo -F ${dbPackageName} db:watch`;
|
|
6589
|
-
scripts["db:stop"] = `turbo -F ${dbPackageName} db:stop`;
|
|
6590
|
-
scripts["db:down"] = `turbo -F ${dbPackageName} db:down`;
|
|
6591
|
-
}
|
|
6592
|
-
} else if (options.packageManager === "pnpm") {
|
|
6593
|
-
scripts.dev = devScript;
|
|
6594
|
-
scripts.build = "pnpm -r build";
|
|
6595
|
-
scripts["check-types"] = "pnpm -r check-types";
|
|
6596
|
-
scripts["dev:native"] = "pnpm --filter native dev";
|
|
6597
|
-
scripts["dev:web"] = "pnpm --filter web dev";
|
|
6598
|
-
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6599
|
-
if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
|
|
6600
|
-
if (needsDbScripts) {
|
|
6601
|
-
scripts["db:push"] = `pnpm --filter ${dbPackageName} db:push`;
|
|
6602
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${dbPackageName} db:studio`;
|
|
6603
|
-
if (options.orm === "prisma") {
|
|
6604
|
-
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6605
|
-
scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6606
|
-
} else if (options.orm === "drizzle") {
|
|
6607
|
-
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6608
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6609
|
-
}
|
|
6610
|
-
}
|
|
6611
|
-
if (options.dbSetup === "docker") {
|
|
6612
|
-
scripts["db:start"] = `pnpm --filter ${dbPackageName} db:start`;
|
|
6613
|
-
scripts["db:watch"] = `pnpm --filter ${dbPackageName} db:watch`;
|
|
6614
|
-
scripts["db:stop"] = `pnpm --filter ${dbPackageName} db:stop`;
|
|
6615
|
-
scripts["db:down"] = `pnpm --filter ${dbPackageName} db:down`;
|
|
6616
|
-
}
|
|
6617
|
-
} else if (options.packageManager === "npm") {
|
|
6618
|
-
scripts.dev = devScript;
|
|
6619
|
-
scripts.build = "npm run build --workspaces";
|
|
6620
|
-
scripts["check-types"] = "npm run check-types --workspaces";
|
|
6621
|
-
scripts["dev:native"] = "npm run dev --workspace native";
|
|
6622
|
-
scripts["dev:web"] = "npm run dev --workspace web";
|
|
6623
|
-
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6624
|
-
if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
|
|
6625
|
-
if (needsDbScripts) {
|
|
6626
|
-
scripts["db:push"] = `npm run db:push --workspace ${dbPackageName}`;
|
|
6627
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${dbPackageName}`;
|
|
6628
|
-
if (options.orm === "prisma") {
|
|
6629
|
-
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6630
|
-
scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6631
|
-
} else if (options.orm === "drizzle") {
|
|
6632
|
-
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6633
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6634
|
-
}
|
|
6635
|
-
}
|
|
6636
|
-
if (options.dbSetup === "docker") {
|
|
6637
|
-
scripts["db:start"] = `npm run db:start --workspace ${dbPackageName}`;
|
|
6638
|
-
scripts["db:watch"] = `npm run db:watch --workspace ${dbPackageName}`;
|
|
6639
|
-
scripts["db:stop"] = `npm run db:stop --workspace ${dbPackageName}`;
|
|
6640
|
-
scripts["db:down"] = `npm run db:down --workspace ${dbPackageName}`;
|
|
6641
|
-
}
|
|
6642
|
-
} else if (options.packageManager === "bun") {
|
|
6643
|
-
scripts.dev = devScript;
|
|
6644
|
-
scripts.build = "bun run --filter '*' build";
|
|
6645
|
-
scripts["check-types"] = "bun run --filter '*' check-types";
|
|
6646
|
-
scripts["dev:native"] = "bun run --filter native dev";
|
|
6647
|
-
scripts["dev:web"] = "bun run --filter web dev";
|
|
6648
|
-
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6649
|
-
if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
|
|
6650
|
-
if (needsDbScripts) {
|
|
6651
|
-
scripts["db:push"] = `bun run --filter ${dbPackageName} db:push`;
|
|
6652
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${dbPackageName} db:studio`;
|
|
6653
|
-
if (options.orm === "prisma") {
|
|
6654
|
-
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6655
|
-
scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6656
|
-
} else if (options.orm === "drizzle") {
|
|
6657
|
-
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6658
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6659
|
-
}
|
|
6660
|
-
}
|
|
6661
|
-
if (options.dbSetup === "docker") {
|
|
6662
|
-
scripts["db:start"] = `bun run --filter ${dbPackageName} db:start`;
|
|
6663
|
-
scripts["db:watch"] = `bun run --filter ${dbPackageName} db:watch`;
|
|
6664
|
-
scripts["db:stop"] = `bun run --filter ${dbPackageName} db:stop`;
|
|
6665
|
-
scripts["db:down"] = `bun run --filter ${dbPackageName} db:down`;
|
|
6444
|
+
const workspaces = packageJson.workspaces;
|
|
6445
|
+
const { projectName, packageManager, backend, database, orm, dbSetup, serverDeploy, addons } = options;
|
|
6446
|
+
const backendPackageName = backend === "convex" ? `@${projectName}/backend` : "server";
|
|
6447
|
+
const dbPackageName = `@${projectName}/db`;
|
|
6448
|
+
const hasTurborepo = addons.includes("turborepo");
|
|
6449
|
+
const needsDbScripts = backend !== "convex" && database !== "none" && orm !== "none" && orm !== "mongoose";
|
|
6450
|
+
const isD1Alchemy = dbSetup === "d1" && serverDeploy === "alchemy";
|
|
6451
|
+
const pmConfig = getPackageManagerConfig(packageManager, hasTurborepo);
|
|
6452
|
+
scripts.dev = pmConfig.dev;
|
|
6453
|
+
scripts.build = pmConfig.build;
|
|
6454
|
+
scripts["check-types"] = pmConfig.checkTypes;
|
|
6455
|
+
scripts["dev:native"] = pmConfig.filter("native", "dev");
|
|
6456
|
+
scripts["dev:web"] = pmConfig.filter("web", "dev");
|
|
6457
|
+
if (backend !== "self" && backend !== "none") scripts["dev:server"] = pmConfig.filter(backendPackageName, "dev");
|
|
6458
|
+
if (backend === "convex") scripts["dev:setup"] = pmConfig.filter(backendPackageName, "dev:setup");
|
|
6459
|
+
if (needsDbScripts) {
|
|
6460
|
+
scripts["db:push"] = pmConfig.filter(dbPackageName, "db:push");
|
|
6461
|
+
if (!isD1Alchemy) scripts["db:studio"] = pmConfig.filter(dbPackageName, "db:studio");
|
|
6462
|
+
if (orm === "prisma") {
|
|
6463
|
+
scripts["db:generate"] = pmConfig.filter(dbPackageName, "db:generate");
|
|
6464
|
+
scripts["db:migrate"] = pmConfig.filter(dbPackageName, "db:migrate");
|
|
6465
|
+
} else if (orm === "drizzle") {
|
|
6466
|
+
scripts["db:generate"] = pmConfig.filter(dbPackageName, "db:generate");
|
|
6467
|
+
if (!isD1Alchemy) scripts["db:migrate"] = pmConfig.filter(dbPackageName, "db:migrate");
|
|
6666
6468
|
}
|
|
6667
6469
|
}
|
|
6470
|
+
if (dbSetup === "docker") {
|
|
6471
|
+
scripts["db:start"] = pmConfig.filter(dbPackageName, "db:start");
|
|
6472
|
+
scripts["db:watch"] = pmConfig.filter(dbPackageName, "db:watch");
|
|
6473
|
+
scripts["db:stop"] = pmConfig.filter(dbPackageName, "db:stop");
|
|
6474
|
+
scripts["db:down"] = pmConfig.filter(dbPackageName, "db:down");
|
|
6475
|
+
}
|
|
6668
6476
|
try {
|
|
6669
|
-
const { stdout } = await execa(
|
|
6670
|
-
packageJson.packageManager = `${
|
|
6671
|
-
} catch
|
|
6672
|
-
log.warn(`Could not determine ${
|
|
6477
|
+
const { stdout } = await execa(packageManager, ["-v"], { cwd: projectDir });
|
|
6478
|
+
packageJson.packageManager = `${packageManager}@${stdout.trim()}`;
|
|
6479
|
+
} catch {
|
|
6480
|
+
log.warn(`Could not determine ${packageManager} version.`);
|
|
6673
6481
|
}
|
|
6674
|
-
if (
|
|
6675
|
-
const workspaces = packageJson.workspaces;
|
|
6676
|
-
if (options.backend === "convex") {
|
|
6482
|
+
if (backend === "convex") {
|
|
6677
6483
|
if (!workspaces.includes("packages/*")) workspaces.push("packages/*");
|
|
6678
|
-
if ((options.frontend.length > 0 ||
|
|
6484
|
+
if ((options.frontend.length > 0 || addons.includes("starlight")) && !workspaces.includes("apps/*")) workspaces.push("apps/*");
|
|
6679
6485
|
} else {
|
|
6680
6486
|
if (!workspaces.includes("apps/*")) workspaces.push("apps/*");
|
|
6681
6487
|
if (!workspaces.includes("packages/*")) workspaces.push("packages/*");
|
|
6682
6488
|
}
|
|
6683
6489
|
await fs.writeJson(rootPackageJsonPath, packageJson, { spaces: 2 });
|
|
6684
6490
|
}
|
|
6685
|
-
|
|
6491
|
+
function getPackageManagerConfig(packageManager, hasTurborepo) {
|
|
6492
|
+
if (hasTurborepo) return {
|
|
6493
|
+
dev: "turbo dev",
|
|
6494
|
+
build: "turbo build",
|
|
6495
|
+
checkTypes: "turbo check-types",
|
|
6496
|
+
filter: (workspace, script) => `turbo -F ${workspace} ${script}`
|
|
6497
|
+
};
|
|
6498
|
+
switch (packageManager) {
|
|
6499
|
+
case "pnpm": return {
|
|
6500
|
+
dev: "pnpm -r dev",
|
|
6501
|
+
build: "pnpm -r build",
|
|
6502
|
+
checkTypes: "pnpm -r check-types",
|
|
6503
|
+
filter: (workspace, script) => `pnpm --filter ${workspace} ${script}`
|
|
6504
|
+
};
|
|
6505
|
+
case "npm": return {
|
|
6506
|
+
dev: "npm run dev --workspaces",
|
|
6507
|
+
build: "npm run build --workspaces",
|
|
6508
|
+
checkTypes: "npm run check-types --workspaces",
|
|
6509
|
+
filter: (workspace, script) => `npm run ${script} --workspace ${workspace}`
|
|
6510
|
+
};
|
|
6511
|
+
case "bun": return {
|
|
6512
|
+
dev: "bun run --filter '*' dev",
|
|
6513
|
+
build: "bun run --filter '*' build",
|
|
6514
|
+
checkTypes: "bun run --filter '*' check-types",
|
|
6515
|
+
filter: (workspace, script) => `bun run --filter ${workspace} ${script}`
|
|
6516
|
+
};
|
|
6517
|
+
}
|
|
6518
|
+
}
|
|
6519
|
+
async function updateServerPackageJson(projectDir, _options) {
|
|
6686
6520
|
const serverPackageJsonPath = path.join(projectDir, "apps/server/package.json");
|
|
6687
6521
|
if (!await fs.pathExists(serverPackageJsonPath)) return;
|
|
6688
6522
|
const serverPackageJson = await fs.readJson(serverPackageJsonPath);
|
|
6689
|
-
|
|
6523
|
+
serverPackageJson.scripts = serverPackageJson.scripts || {};
|
|
6690
6524
|
await fs.writeJson(serverPackageJsonPath, serverPackageJson, { spaces: 2 });
|
|
6691
|
-
await updateDbPackageJson(projectDir, options);
|
|
6692
6525
|
}
|
|
6693
6526
|
async function updateDbPackageJson(projectDir, options) {
|
|
6694
6527
|
const dbPackageJsonPath = path.join(projectDir, "packages/db/package.json");
|
|
6695
6528
|
if (!await fs.pathExists(dbPackageJsonPath)) return;
|
|
6696
6529
|
const dbPackageJson = await fs.readJson(dbPackageJsonPath);
|
|
6697
6530
|
dbPackageJson.name = `@${options.projectName}/db`;
|
|
6698
|
-
|
|
6531
|
+
dbPackageJson.scripts = dbPackageJson.scripts || {};
|
|
6699
6532
|
const scripts = dbPackageJson.scripts;
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6533
|
+
const { database, orm, dbSetup, serverDeploy } = options;
|
|
6534
|
+
const isD1Alchemy = dbSetup === "d1" && serverDeploy === "alchemy";
|
|
6535
|
+
if (database !== "none") {
|
|
6536
|
+
if (database === "sqlite" && orm === "drizzle" && dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
|
|
6537
|
+
if (orm === "prisma") {
|
|
6703
6538
|
scripts["db:push"] = "prisma db push";
|
|
6704
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = "prisma studio";
|
|
6705
6539
|
scripts["db:generate"] = "prisma generate";
|
|
6706
6540
|
scripts["db:migrate"] = "prisma migrate dev";
|
|
6707
|
-
|
|
6541
|
+
if (!isD1Alchemy) scripts["db:studio"] = "prisma studio";
|
|
6542
|
+
} else if (orm === "drizzle") {
|
|
6708
6543
|
scripts["db:push"] = "drizzle-kit push";
|
|
6709
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = "drizzle-kit studio";
|
|
6710
6544
|
scripts["db:generate"] = "drizzle-kit generate";
|
|
6711
|
-
if (!
|
|
6545
|
+
if (!isD1Alchemy) {
|
|
6546
|
+
scripts["db:studio"] = "drizzle-kit studio";
|
|
6547
|
+
scripts["db:migrate"] = "drizzle-kit migrate";
|
|
6548
|
+
}
|
|
6712
6549
|
}
|
|
6713
6550
|
}
|
|
6714
|
-
if (
|
|
6551
|
+
if (dbSetup === "docker") {
|
|
6715
6552
|
scripts["db:start"] = "docker compose up -d";
|
|
6716
6553
|
scripts["db:watch"] = "docker compose up";
|
|
6717
6554
|
scripts["db:stop"] = "docker compose stop";
|
|
@@ -6738,7 +6575,7 @@ async function updateConvexPackageJson(projectDir, options) {
|
|
|
6738
6575
|
if (!await fs.pathExists(convexPackageJsonPath)) return;
|
|
6739
6576
|
const convexPackageJson = await fs.readJson(convexPackageJsonPath);
|
|
6740
6577
|
convexPackageJson.name = `@${options.projectName}/backend`;
|
|
6741
|
-
|
|
6578
|
+
convexPackageJson.scripts = convexPackageJson.scripts || {};
|
|
6742
6579
|
await fs.writeJson(convexPackageJsonPath, convexPackageJson, { spaces: 2 });
|
|
6743
6580
|
}
|
|
6744
6581
|
|
|
@@ -7101,21 +6938,21 @@ const router = os.router({
|
|
|
7101
6938
|
description: "Create a new Better-T-Stack project",
|
|
7102
6939
|
default: true,
|
|
7103
6940
|
negateBooleans: true
|
|
7104
|
-
}).input(z
|
|
6941
|
+
}).input(z.tuple([ProjectNameSchema.optional(), z.object({
|
|
7105
6942
|
template: TemplateSchema.optional().describe("Use a predefined template"),
|
|
7106
|
-
yes: z
|
|
7107
|
-
yolo: z
|
|
7108
|
-
verbose: z
|
|
6943
|
+
yes: z.boolean().optional().default(false).describe("Use default configuration"),
|
|
6944
|
+
yolo: z.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
|
|
6945
|
+
verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
|
|
7109
6946
|
database: DatabaseSchema.optional(),
|
|
7110
6947
|
orm: ORMSchema.optional(),
|
|
7111
6948
|
auth: AuthSchema.optional(),
|
|
7112
6949
|
payments: PaymentsSchema.optional(),
|
|
7113
|
-
frontend: z
|
|
7114
|
-
addons: z
|
|
7115
|
-
examples: z
|
|
7116
|
-
git: z
|
|
6950
|
+
frontend: z.array(FrontendSchema).optional(),
|
|
6951
|
+
addons: z.array(AddonsSchema).optional(),
|
|
6952
|
+
examples: z.array(ExamplesSchema).optional(),
|
|
6953
|
+
git: z.boolean().optional(),
|
|
7117
6954
|
packageManager: PackageManagerSchema.optional(),
|
|
7118
|
-
install: z
|
|
6955
|
+
install: z.boolean().optional(),
|
|
7119
6956
|
dbSetup: DatabaseSetupSchema.optional(),
|
|
7120
6957
|
backend: BackendSchema.optional(),
|
|
7121
6958
|
runtime: RuntimeSchema.optional(),
|
|
@@ -7123,9 +6960,9 @@ const router = os.router({
|
|
|
7123
6960
|
webDeploy: WebDeploySchema.optional(),
|
|
7124
6961
|
serverDeploy: ServerDeploySchema.optional(),
|
|
7125
6962
|
directoryConflict: DirectoryConflictSchema.optional(),
|
|
7126
|
-
renderTitle: z
|
|
7127
|
-
disableAnalytics: z
|
|
7128
|
-
manualDb: z
|
|
6963
|
+
renderTitle: z.boolean().optional(),
|
|
6964
|
+
disableAnalytics: z.boolean().optional().default(false).describe("Disable analytics"),
|
|
6965
|
+
manualDb: z.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup")
|
|
7129
6966
|
})])).handler(async ({ input }) => {
|
|
7130
6967
|
const [projectName, options] = input;
|
|
7131
6968
|
const result = await createProjectHandler({
|
|
@@ -7134,12 +6971,12 @@ const router = os.router({
|
|
|
7134
6971
|
});
|
|
7135
6972
|
if (options.verbose) return result;
|
|
7136
6973
|
}),
|
|
7137
|
-
add: os.meta({ description: "Add addons or deployment configurations to an existing Better-T-Stack project" }).input(z
|
|
7138
|
-
addons: z
|
|
6974
|
+
add: os.meta({ description: "Add addons or deployment configurations to an existing Better-T-Stack project" }).input(z.tuple([z.object({
|
|
6975
|
+
addons: z.array(AddonsSchema).optional().default([]),
|
|
7139
6976
|
webDeploy: WebDeploySchema.optional(),
|
|
7140
6977
|
serverDeploy: ServerDeploySchema.optional(),
|
|
7141
|
-
projectDir: z
|
|
7142
|
-
install: z
|
|
6978
|
+
projectDir: z.string().optional(),
|
|
6979
|
+
install: z.boolean().optional().default(false).describe("Install dependencies after adding addons or deployment"),
|
|
7143
6980
|
packageManager: PackageManagerSchema.optional()
|
|
7144
6981
|
})])).handler(async ({ input }) => {
|
|
7145
6982
|
const [options] = input;
|