create-better-t-stack 3.4.1 → 3.4.2-canary.281ca96d
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 +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.js +1 -1
- package/dist/{src-_EdtPnBT.js → src-CFkY2F0Q.js} +97 -462
- package/package.json +1 -1
- package/templates/api/orpc/server/package.json.hbs +1 -5
- package/templates/api/orpc/server/tsconfig.json.hbs +1 -4
- package/templates/api/trpc/server/package.json.hbs +1 -5
- package/templates/api/trpc/server/tsconfig.json.hbs +1 -4
- package/templates/auth/better-auth/server/base/package.json.hbs +1 -5
- package/templates/auth/better-auth/server/base/tsconfig.json.hbs +1 -4
- package/templates/db/base/package.json.hbs +1 -5
- package/templates/db/base/tsconfig.json.hbs +1 -4
- package/templates/db/drizzle/sqlite/drizzle.config.ts.hbs +0 -7
- package/templates/db/prisma/mongodb/prisma/schema/schema.prisma.hbs +1 -1
- package/templates/db/prisma/mysql/prisma/schema/schema.prisma.hbs +8 -12
- package/templates/db/prisma/mysql/prisma.config.ts.hbs +17 -14
- package/templates/db/prisma/mysql/src/index.ts.hbs +20 -6
- package/templates/db/prisma/postgres/prisma/schema/schema.prisma.hbs +1 -5
- package/templates/db/prisma/postgres/prisma.config.ts.hbs +12 -9
- package/templates/db/prisma/postgres/src/index.ts.hbs +26 -4
- package/templates/db/prisma/sqlite/prisma/schema/schema.prisma.hbs +1 -12
- package/templates/db/prisma/sqlite/prisma.config.ts.hbs +12 -9
- package/templates/db/prisma/sqlite/src/index.ts.hbs +10 -14
- package/templates/deploy/alchemy/alchemy.run.ts.hbs +67 -5
- package/templates/examples/ai/web/react/next/src/app/ai/page.tsx.hbs +2 -2
- package/templates/extras/_npmrc.hbs +2 -2
- package/templates/frontend/native/uniwind/app/(drawer)/_layout.tsx.hbs +21 -13
- package/templates/frontend/react/next/next.config.ts.hbs +5 -2
- package/templates/frontend/react/next/tsconfig.json.hbs +0 -3
- package/templates/frontend/react/tanstack-start/package.json.hbs +4 -4
- package/templates/packages/config/tsconfig.base.json.hbs +1 -1
- package/templates/api/orpc/server/tsdown.config.ts.hbs +0 -7
- package/templates/api/trpc/server/tsdown.config.ts.hbs +0 -7
- package/templates/auth/better-auth/server/base/tsdown.config.ts.hbs +0 -7
- package/templates/db/base/tsdown.config.ts.hbs +0 -7
- package/templates/deploy/wrangler/server/wrangler.jsonc.hbs +0 -39
- package/templates/deploy/wrangler/web/nuxt/wrangler.jsonc.hbs +0 -51
- package/templates/deploy/wrangler/web/react/next/open-next.config.ts +0 -6
- package/templates/deploy/wrangler/web/react/next/wrangler.jsonc.hbs +0 -22
- package/templates/deploy/wrangler/web/react/react-router/wrangler.jsonc.hbs +0 -8
- package/templates/deploy/wrangler/web/react/tanstack-router/wrangler.jsonc.hbs +0 -8
- package/templates/deploy/wrangler/web/react/tanstack-start/wrangler.jsonc.hbs +0 -20
- package/templates/deploy/wrangler/web/solid/wrangler.jsonc.hbs +0 -8
- package/templates/deploy/wrangler/web/svelte/wrangler.jsonc.hbs +0 -51
|
@@ -72,18 +72,22 @@ const dependencyVersionMap = {
|
|
|
72
72
|
"drizzle-kit": "^0.31.2",
|
|
73
73
|
"@planetscale/database": "^1.19.0",
|
|
74
74
|
"@libsql/client": "^0.14.0",
|
|
75
|
+
libsql: "^0.5.22",
|
|
75
76
|
"@neondatabase/serverless": "^1.0.1",
|
|
76
77
|
pg: "^8.14.1",
|
|
77
78
|
"@types/pg": "^8.11.11",
|
|
78
79
|
"@types/ws": "^8.18.1",
|
|
79
80
|
ws: "^8.18.3",
|
|
80
81
|
mysql2: "^3.14.0",
|
|
81
|
-
"@prisma/client": "
|
|
82
|
-
prisma: "
|
|
83
|
-
"@prisma/adapter-d1": "
|
|
84
|
-
"@prisma/
|
|
85
|
-
"@prisma/adapter-
|
|
86
|
-
"@prisma/adapter-
|
|
82
|
+
"@prisma/client": "dev",
|
|
83
|
+
prisma: "dev",
|
|
84
|
+
"@prisma/adapter-d1": "dev",
|
|
85
|
+
"@prisma/adapter-neon": "dev",
|
|
86
|
+
"@prisma/adapter-mariadb": "dev",
|
|
87
|
+
"@prisma/adapter-libsql": "dev",
|
|
88
|
+
"@prisma/adapter-better-sqlite3": "dev",
|
|
89
|
+
"@prisma/adapter-pg": "dev",
|
|
90
|
+
"@prisma/adapter-planetscale": "dev",
|
|
87
91
|
mongoose: "^8.14.0",
|
|
88
92
|
"vite-plugin-pwa": "^1.0.1",
|
|
89
93
|
"@vite-pwa/assets-generator": "^1.0.0",
|
|
@@ -148,7 +152,7 @@ const dependencyVersionMap = {
|
|
|
148
152
|
"@cloudflare/workers-types": "^4.20250822.0",
|
|
149
153
|
alchemy: "^0.77.0",
|
|
150
154
|
dotenv: "^17.2.2",
|
|
151
|
-
tsdown: "^0.
|
|
155
|
+
tsdown: "^0.16.5",
|
|
152
156
|
zod: "^4.1.11",
|
|
153
157
|
srvx: "0.8.15",
|
|
154
158
|
"@polar-sh/better-auth": "^1.1.3",
|
|
@@ -279,16 +283,8 @@ const ProjectNameSchema = z.string().min(1, "Project name cannot be empty").max(
|
|
|
279
283
|
"*"
|
|
280
284
|
].some((char) => name.includes(char));
|
|
281
285
|
}, "Project name contains invalid characters").refine((name) => name.toLowerCase() !== "node_modules", "Project name is reserved").describe("Project name or path");
|
|
282
|
-
const WebDeploySchema = z.enum([
|
|
283
|
-
|
|
284
|
-
"alchemy",
|
|
285
|
-
"none"
|
|
286
|
-
]).describe("Web deployment");
|
|
287
|
-
const ServerDeploySchema = z.enum([
|
|
288
|
-
"wrangler",
|
|
289
|
-
"alchemy",
|
|
290
|
-
"none"
|
|
291
|
-
]).describe("Server deployment");
|
|
286
|
+
const WebDeploySchema = z.enum(["alchemy", "none"]).describe("Web deployment");
|
|
287
|
+
const ServerDeploySchema = z.enum(["alchemy", "none"]).describe("Server deployment");
|
|
292
288
|
const DirectoryConflictSchema = z.enum([
|
|
293
289
|
"merge",
|
|
294
290
|
"overwrite",
|
|
@@ -1132,10 +1128,6 @@ async function getRuntimeChoice(runtime, backend) {
|
|
|
1132
1128
|
//#endregion
|
|
1133
1129
|
//#region src/prompts/server-deploy.ts
|
|
1134
1130
|
function getDeploymentDisplay$1(deployment) {
|
|
1135
|
-
if (deployment === "wrangler") return {
|
|
1136
|
-
label: "Wrangler",
|
|
1137
|
-
hint: "Deploy to Cloudflare Workers using Wrangler"
|
|
1138
|
-
};
|
|
1139
1131
|
if (deployment === "alchemy") return {
|
|
1140
1132
|
label: "Alchemy",
|
|
1141
1133
|
hint: "Deploy to Cloudflare Workers using Alchemy"
|
|
@@ -1145,40 +1137,17 @@ function getDeploymentDisplay$1(deployment) {
|
|
|
1145
1137
|
hint: `Add ${deployment} deployment`
|
|
1146
1138
|
};
|
|
1147
1139
|
}
|
|
1148
|
-
async function getServerDeploymentChoice(deployment, runtime, backend,
|
|
1140
|
+
async function getServerDeploymentChoice(deployment, runtime, backend, _webDeploy) {
|
|
1149
1141
|
if (deployment !== void 0) return deployment;
|
|
1150
1142
|
if (backend === "none" || backend === "convex") return "none";
|
|
1151
1143
|
if (backend !== "hono") return "none";
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
["alchemy", "wrangler"].forEach((deploy) => {
|
|
1155
|
-
const { label, hint } = getDeploymentDisplay$1(deploy);
|
|
1156
|
-
options.unshift({
|
|
1157
|
-
value: deploy,
|
|
1158
|
-
label,
|
|
1159
|
-
hint
|
|
1160
|
-
});
|
|
1161
|
-
});
|
|
1162
|
-
const response = await select({
|
|
1163
|
-
message: "Select server deployment",
|
|
1164
|
-
options,
|
|
1165
|
-
initialValue: webDeploy === "alchemy" ? "alchemy" : runtime === "workers" ? "wrangler" : DEFAULT_CONFIG.serverDeploy
|
|
1166
|
-
});
|
|
1167
|
-
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
1168
|
-
return response;
|
|
1144
|
+
if (runtime === "workers") return "alchemy";
|
|
1145
|
+
return "none";
|
|
1169
1146
|
}
|
|
1170
1147
|
async function getServerDeploymentToAdd(runtime, existingDeployment, backend) {
|
|
1171
1148
|
if (backend !== "hono") return "none";
|
|
1172
1149
|
const options = [];
|
|
1173
1150
|
if (runtime === "workers") {
|
|
1174
|
-
if (existingDeployment !== "wrangler") {
|
|
1175
|
-
const { label, hint } = getDeploymentDisplay$1("wrangler");
|
|
1176
|
-
options.push({
|
|
1177
|
-
value: "wrangler",
|
|
1178
|
-
label,
|
|
1179
|
-
hint
|
|
1180
|
-
});
|
|
1181
|
-
}
|
|
1182
1151
|
if (existingDeployment !== "alchemy") {
|
|
1183
1152
|
const { label, hint } = getDeploymentDisplay$1("alchemy");
|
|
1184
1153
|
options.push({
|
|
@@ -1194,7 +1163,7 @@ async function getServerDeploymentToAdd(runtime, existingDeployment, backend) {
|
|
|
1194
1163
|
const response = await select({
|
|
1195
1164
|
message: "Select server deployment",
|
|
1196
1165
|
options,
|
|
1197
|
-
initialValue:
|
|
1166
|
+
initialValue: DEFAULT_CONFIG.serverDeploy
|
|
1198
1167
|
});
|
|
1199
1168
|
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
1200
1169
|
return response;
|
|
@@ -1206,10 +1175,6 @@ function hasWebFrontend(frontends) {
|
|
|
1206
1175
|
return frontends.some((f) => WEB_FRAMEWORKS.includes(f));
|
|
1207
1176
|
}
|
|
1208
1177
|
function getDeploymentDisplay(deployment) {
|
|
1209
|
-
if (deployment === "wrangler") return {
|
|
1210
|
-
label: "Wrangler",
|
|
1211
|
-
hint: "Deploy to Cloudflare Workers using Wrangler"
|
|
1212
|
-
};
|
|
1213
1178
|
if (deployment === "alchemy") return {
|
|
1214
1179
|
label: "Alchemy",
|
|
1215
1180
|
hint: "Deploy to Cloudflare Workers using Alchemy"
|
|
@@ -1224,11 +1189,7 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
|
|
|
1224
1189
|
if (!hasWebFrontend(frontend)) return "none";
|
|
1225
1190
|
const response = await select({
|
|
1226
1191
|
message: "Select web deployment",
|
|
1227
|
-
options: [
|
|
1228
|
-
"wrangler",
|
|
1229
|
-
"alchemy",
|
|
1230
|
-
"none"
|
|
1231
|
-
].map((deploy) => {
|
|
1192
|
+
options: ["alchemy", "none"].map((deploy) => {
|
|
1232
1193
|
const { label, hint } = getDeploymentDisplay(deploy);
|
|
1233
1194
|
return {
|
|
1234
1195
|
value: deploy,
|
|
@@ -1244,14 +1205,6 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
|
|
|
1244
1205
|
async function getDeploymentToAdd(frontend, existingDeployment) {
|
|
1245
1206
|
if (!hasWebFrontend(frontend)) return "none";
|
|
1246
1207
|
const options = [];
|
|
1247
|
-
if (existingDeployment !== "wrangler") {
|
|
1248
|
-
const { label, hint } = getDeploymentDisplay("wrangler");
|
|
1249
|
-
options.push({
|
|
1250
|
-
value: "wrangler",
|
|
1251
|
-
label,
|
|
1252
|
-
hint
|
|
1253
|
-
});
|
|
1254
|
-
}
|
|
1255
1208
|
if (existingDeployment !== "alchemy") {
|
|
1256
1209
|
const { label, hint } = getDeploymentDisplay("alchemy");
|
|
1257
1210
|
options.push({
|
|
@@ -1387,7 +1340,7 @@ const getLatestCLIVersion = () => {
|
|
|
1387
1340
|
*/
|
|
1388
1341
|
function isTelemetryEnabled() {
|
|
1389
1342
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1390
|
-
const BTS_TELEMETRY = "
|
|
1343
|
+
const BTS_TELEMETRY = "0";
|
|
1391
1344
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1392
1345
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1393
1346
|
return true;
|
|
@@ -1395,8 +1348,8 @@ function isTelemetryEnabled() {
|
|
|
1395
1348
|
|
|
1396
1349
|
//#endregion
|
|
1397
1350
|
//#region src/utils/analytics.ts
|
|
1398
|
-
const POSTHOG_API_KEY = "
|
|
1399
|
-
const POSTHOG_HOST = "
|
|
1351
|
+
const POSTHOG_API_KEY = "random";
|
|
1352
|
+
const POSTHOG_HOST = "random";
|
|
1400
1353
|
function generateSessionId() {
|
|
1401
1354
|
const rand = Math.random().toString(36).slice(2);
|
|
1402
1355
|
return `cli_${Date.now().toString(36)}${rand}`;
|
|
@@ -1815,8 +1768,8 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1815
1768
|
validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
|
|
1816
1769
|
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
1817
1770
|
validateWorkersCompatibility(providedFlags, options, config);
|
|
1818
|
-
if (config.runtime === "workers" && config.serverDeploy === "none") exitWithError("Cloudflare Workers runtime requires a server deployment. Please choose '
|
|
1819
|
-
if (providedFlags.has("serverDeploy") &&
|
|
1771
|
+
if (config.runtime === "workers" && config.serverDeploy === "none") exitWithError("Cloudflare Workers runtime requires a server deployment. Please choose 'alchemy' for --server-deploy.");
|
|
1772
|
+
if (providedFlags.has("serverDeploy") && config.serverDeploy === "alchemy" && config.runtime !== "workers") exitWithError(`Server deployment '${config.serverDeploy}' requires '--runtime workers'. Please use '--runtime workers' or choose a different server deployment.`);
|
|
1820
1773
|
if (config.addons && config.addons.length > 0) {
|
|
1821
1774
|
validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth);
|
|
1822
1775
|
config.addons = [...new Set(config.addons)];
|
|
@@ -3227,14 +3180,14 @@ async function setupDeploymentTemplates(projectDir, context) {
|
|
|
3227
3180
|
if (await fs.pathExists(alchemyTemplateSrc)) {
|
|
3228
3181
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3229
3182
|
await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, isBackendSelf && await fs.pathExists(webAppDir) ? webAppDir : projectDir, context);
|
|
3230
|
-
await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
|
|
3183
|
+
if (!isBackendSelf) await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
|
|
3231
3184
|
}
|
|
3232
3185
|
} else {
|
|
3233
3186
|
if (context.webDeploy === "alchemy") {
|
|
3234
3187
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3235
3188
|
if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(webAppDir)) {
|
|
3236
3189
|
await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, webAppDir, context);
|
|
3237
|
-
await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
|
|
3190
|
+
if (!isBackendSelf) await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
|
|
3238
3191
|
}
|
|
3239
3192
|
}
|
|
3240
3193
|
if (context.serverDeploy === "alchemy" && !isBackendSelf) {
|
|
@@ -3338,54 +3291,13 @@ async function addAddonsToProject(input) {
|
|
|
3338
3291
|
//#region src/helpers/deployment/server-deploy-setup.ts
|
|
3339
3292
|
async function setupServerDeploy(config) {
|
|
3340
3293
|
const { serverDeploy, webDeploy, projectDir } = config;
|
|
3341
|
-
const { packageManager } = config;
|
|
3342
3294
|
if (serverDeploy === "none") return;
|
|
3343
3295
|
if (serverDeploy === "alchemy" && webDeploy === "alchemy") return;
|
|
3344
3296
|
const serverDir = path.join(projectDir, "apps/server");
|
|
3345
3297
|
if (!await fs.pathExists(serverDir)) return;
|
|
3346
|
-
if (serverDeploy === "
|
|
3347
|
-
await setupWorkersServerDeploy(serverDir, packageManager);
|
|
3348
|
-
await generateCloudflareWorkerTypes({
|
|
3349
|
-
serverDir,
|
|
3350
|
-
packageManager
|
|
3351
|
-
});
|
|
3352
|
-
} else if (serverDeploy === "alchemy") await setupAlchemyServerDeploy(serverDir, packageManager, projectDir);
|
|
3298
|
+
if (serverDeploy === "alchemy") await setupAlchemyServerDeploy(serverDir, projectDir);
|
|
3353
3299
|
}
|
|
3354
|
-
async function
|
|
3355
|
-
const packageJsonPath = path.join(serverDir, "package.json");
|
|
3356
|
-
if (!await fs.pathExists(packageJsonPath)) return;
|
|
3357
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
3358
|
-
packageJson.scripts = {
|
|
3359
|
-
...packageJson.scripts,
|
|
3360
|
-
dev: "wrangler dev --port=3000",
|
|
3361
|
-
start: "wrangler dev",
|
|
3362
|
-
deploy: "wrangler deploy",
|
|
3363
|
-
build: "wrangler deploy --dry-run",
|
|
3364
|
-
"cf-typegen": "wrangler types --env-interface CloudflareBindings"
|
|
3365
|
-
};
|
|
3366
|
-
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
3367
|
-
await addPackageDependency({
|
|
3368
|
-
devDependencies: ["wrangler", "@types/node"],
|
|
3369
|
-
projectDir: serverDir
|
|
3370
|
-
});
|
|
3371
|
-
}
|
|
3372
|
-
async function generateCloudflareWorkerTypes({ serverDir, packageManager }) {
|
|
3373
|
-
if (!await fs.pathExists(serverDir)) return;
|
|
3374
|
-
const s = spinner();
|
|
3375
|
-
try {
|
|
3376
|
-
s.start("Generating Cloudflare Workers types...");
|
|
3377
|
-
await execa(getPackageExecutionCommand(packageManager, "wrangler types --env-interface CloudflareBindings"), {
|
|
3378
|
-
cwd: serverDir,
|
|
3379
|
-
shell: true
|
|
3380
|
-
});
|
|
3381
|
-
s.stop("Cloudflare Workers types generated successfully!");
|
|
3382
|
-
} catch {
|
|
3383
|
-
s.stop(pc.yellow("Failed to generate Cloudflare Workers types"));
|
|
3384
|
-
const managerCmd = `${packageManager} run`;
|
|
3385
|
-
log.warn(`Note: You can manually run 'cd apps/server && ${managerCmd} cf-typegen' in the project directory later`);
|
|
3386
|
-
}
|
|
3387
|
-
}
|
|
3388
|
-
async function setupAlchemyServerDeploy(serverDir, _packageManager, projectDir) {
|
|
3300
|
+
async function setupAlchemyServerDeploy(serverDir, projectDir) {
|
|
3389
3301
|
if (!await fs.pathExists(serverDir)) return;
|
|
3390
3302
|
await addPackageDependency({
|
|
3391
3303
|
devDependencies: [
|
|
@@ -3720,7 +3632,7 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
|
3720
3632
|
await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
|
|
3721
3633
|
}
|
|
3722
3634
|
const serverDir = path.join(projectDir, "apps/server");
|
|
3723
|
-
if (await fs.pathExists(serverDir)) await setupAlchemyServerDeploy(serverDir,
|
|
3635
|
+
if (await fs.pathExists(serverDir)) await setupAlchemyServerDeploy(serverDir, projectDir);
|
|
3724
3636
|
const frontend = config.frontend;
|
|
3725
3637
|
const isNext = frontend.includes("next");
|
|
3726
3638
|
const isNuxt = frontend.includes("nuxt");
|
|
@@ -3738,219 +3650,13 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
|
3738
3650
|
else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3739
3651
|
}
|
|
3740
3652
|
|
|
3741
|
-
//#endregion
|
|
3742
|
-
//#region src/helpers/deployment/workers/workers-next-setup.ts
|
|
3743
|
-
async function setupNextWorkersDeploy(projectDir, _packageManager) {
|
|
3744
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
3745
|
-
if (!await fs.pathExists(webAppDir)) return;
|
|
3746
|
-
await addPackageDependency({
|
|
3747
|
-
dependencies: ["@opennextjs/cloudflare"],
|
|
3748
|
-
devDependencies: ["wrangler"],
|
|
3749
|
-
projectDir: webAppDir
|
|
3750
|
-
});
|
|
3751
|
-
const packageJsonPath = path.join(webAppDir, "package.json");
|
|
3752
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
3753
|
-
const pkg = await fs.readJson(packageJsonPath);
|
|
3754
|
-
pkg.scripts = {
|
|
3755
|
-
...pkg.scripts,
|
|
3756
|
-
preview: "opennextjs-cloudflare build && opennextjs-cloudflare preview",
|
|
3757
|
-
deploy: "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
|
|
3758
|
-
upload: "opennextjs-cloudflare build && opennextjs-cloudflare upload",
|
|
3759
|
-
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
|
|
3760
|
-
};
|
|
3761
|
-
await fs.writeJson(packageJsonPath, pkg, { spaces: 2 });
|
|
3762
|
-
}
|
|
3763
|
-
}
|
|
3764
|
-
|
|
3765
|
-
//#endregion
|
|
3766
|
-
//#region src/helpers/deployment/workers/workers-nuxt-setup.ts
|
|
3767
|
-
async function setupNuxtWorkersDeploy(projectDir, packageManager) {
|
|
3768
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
3769
|
-
if (!await fs.pathExists(webAppDir)) return;
|
|
3770
|
-
await addPackageDependency({
|
|
3771
|
-
devDependencies: ["nitro-cloudflare-dev", "wrangler"],
|
|
3772
|
-
projectDir: webAppDir
|
|
3773
|
-
});
|
|
3774
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3775
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3776
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3777
|
-
pkg.scripts = {
|
|
3778
|
-
...pkg.scripts,
|
|
3779
|
-
deploy: `${packageManager} run build && wrangler deploy`,
|
|
3780
|
-
"cf-typegen": "wrangler types"
|
|
3781
|
-
};
|
|
3782
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3783
|
-
}
|
|
3784
|
-
const nuxtConfigPath = path.join(webAppDir, "nuxt.config.ts");
|
|
3785
|
-
if (!await fs.pathExists(nuxtConfigPath)) return;
|
|
3786
|
-
const sourceFile = tsProject.addSourceFileAtPathIfExists(nuxtConfigPath);
|
|
3787
|
-
if (!sourceFile) return;
|
|
3788
|
-
const defineCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((expr) => {
|
|
3789
|
-
const expression = expr.getExpression();
|
|
3790
|
-
return Node.isIdentifier(expression) && expression.getText() === "defineNuxtConfig";
|
|
3791
|
-
});
|
|
3792
|
-
if (!defineCall) return;
|
|
3793
|
-
const configObj = defineCall.getArguments()[0];
|
|
3794
|
-
if (!configObj) return;
|
|
3795
|
-
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3796
|
-
const compatProp = configObj.getProperty("compatibilityDate");
|
|
3797
|
-
if (compatProp && compatProp.getKind() === SyntaxKind.PropertyAssignment) compatProp.setInitializer(`'${today}'`);
|
|
3798
|
-
else configObj.addPropertyAssignment({
|
|
3799
|
-
name: "compatibilityDate",
|
|
3800
|
-
initializer: `'${today}'`
|
|
3801
|
-
});
|
|
3802
|
-
const nitroInitializer = `{
|
|
3803
|
-
preset: "cloudflare_module",
|
|
3804
|
-
cloudflare: {
|
|
3805
|
-
deployConfig: true,
|
|
3806
|
-
nodeCompat: true
|
|
3807
|
-
}
|
|
3808
|
-
}`;
|
|
3809
|
-
const nitroProp = configObj.getProperty("nitro");
|
|
3810
|
-
if (nitroProp && nitroProp.getKind() === SyntaxKind.PropertyAssignment) nitroProp.setInitializer(nitroInitializer);
|
|
3811
|
-
else configObj.addPropertyAssignment({
|
|
3812
|
-
name: "nitro",
|
|
3813
|
-
initializer: nitroInitializer
|
|
3814
|
-
});
|
|
3815
|
-
const modulesProp = configObj.getProperty("modules");
|
|
3816
|
-
if (modulesProp && modulesProp.getKind() === SyntaxKind.PropertyAssignment) {
|
|
3817
|
-
const arrayExpr = modulesProp.getFirstDescendantByKind(SyntaxKind.ArrayLiteralExpression);
|
|
3818
|
-
if (arrayExpr) {
|
|
3819
|
-
if (!arrayExpr.getElements().some((el) => el.getText().replace(/['"`]/g, "") === "nitro-cloudflare-dev")) arrayExpr.addElement("'nitro-cloudflare-dev'");
|
|
3820
|
-
}
|
|
3821
|
-
} else configObj.addPropertyAssignment({
|
|
3822
|
-
name: "modules",
|
|
3823
|
-
initializer: "['nitro-cloudflare-dev']"
|
|
3824
|
-
});
|
|
3825
|
-
await tsProject.save();
|
|
3826
|
-
}
|
|
3827
|
-
|
|
3828
|
-
//#endregion
|
|
3829
|
-
//#region src/helpers/deployment/workers/workers-svelte-setup.ts
|
|
3830
|
-
async function setupSvelteWorkersDeploy(projectDir, packageManager) {
|
|
3831
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
3832
|
-
if (!await fs.pathExists(webAppDir)) return;
|
|
3833
|
-
await addPackageDependency({
|
|
3834
|
-
devDependencies: ["@sveltejs/adapter-cloudflare", "wrangler"],
|
|
3835
|
-
projectDir: webAppDir
|
|
3836
|
-
});
|
|
3837
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3838
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3839
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3840
|
-
pkg.scripts = {
|
|
3841
|
-
...pkg.scripts,
|
|
3842
|
-
deploy: `${packageManager} run build && wrangler deploy`,
|
|
3843
|
-
"cf-typegen": "wrangler types ./src/worker-configuration.d.ts"
|
|
3844
|
-
};
|
|
3845
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3846
|
-
}
|
|
3847
|
-
const possibleConfigFiles = [path.join(webAppDir, "svelte.config.js"), path.join(webAppDir, "svelte.config.ts")];
|
|
3848
|
-
const existingConfigPath = (await Promise.all(possibleConfigFiles.map(async (p) => await fs.pathExists(p) ? p : ""))).find((p) => p);
|
|
3849
|
-
if (existingConfigPath) {
|
|
3850
|
-
const sourceFile = tsProject.addSourceFileAtPathIfExists(existingConfigPath);
|
|
3851
|
-
if (!sourceFile) return;
|
|
3852
|
-
const adapterImport = sourceFile.getImportDeclarations().find((imp) => ["@sveltejs/adapter-auto", "@sveltejs/adapter-node"].includes(imp.getModuleSpecifierValue()));
|
|
3853
|
-
if (adapterImport) adapterImport.setModuleSpecifier("@sveltejs/adapter-cloudflare");
|
|
3854
|
-
else if (!sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === "@sveltejs/adapter-cloudflare")) sourceFile.insertImportDeclaration(0, {
|
|
3855
|
-
defaultImport: "adapter",
|
|
3856
|
-
moduleSpecifier: "@sveltejs/adapter-cloudflare"
|
|
3857
|
-
});
|
|
3858
|
-
await tsProject.save();
|
|
3859
|
-
}
|
|
3860
|
-
}
|
|
3861
|
-
|
|
3862
|
-
//#endregion
|
|
3863
|
-
//#region src/helpers/deployment/workers/workers-tanstack-start-setup.ts
|
|
3864
|
-
async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
3865
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
3866
|
-
if (!await fs.pathExists(webAppDir)) return;
|
|
3867
|
-
await addPackageDependency({
|
|
3868
|
-
devDependencies: ["wrangler", "@cloudflare/vite-plugin"],
|
|
3869
|
-
projectDir: webAppDir
|
|
3870
|
-
});
|
|
3871
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3872
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3873
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3874
|
-
pkg.scripts = {
|
|
3875
|
-
...pkg.scripts,
|
|
3876
|
-
deploy: `${packageManager} run build && wrangler deploy`,
|
|
3877
|
-
"cf-typegen": "wrangler types --env-interface Env"
|
|
3878
|
-
};
|
|
3879
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3880
|
-
}
|
|
3881
|
-
const viteConfigPath = path.join(webAppDir, "vite.config.ts");
|
|
3882
|
-
if (!await fs.pathExists(viteConfigPath)) return;
|
|
3883
|
-
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
|
|
3884
|
-
if (!sourceFile) return;
|
|
3885
|
-
const cfImport = sourceFile.getImportDeclaration("@cloudflare/vite-plugin");
|
|
3886
|
-
if (!cfImport) sourceFile.addImportDeclaration({
|
|
3887
|
-
moduleSpecifier: "@cloudflare/vite-plugin",
|
|
3888
|
-
namedImports: [{ name: "cloudflare" }]
|
|
3889
|
-
});
|
|
3890
|
-
else if (!cfImport.getNamedImports().some((ni) => ni.getName() === "cloudflare")) cfImport.addNamedImport({ name: "cloudflare" });
|
|
3891
|
-
const reactImport = sourceFile.getImportDeclaration("@vitejs/plugin-react");
|
|
3892
|
-
let reactPluginIdentifier = "viteReact";
|
|
3893
|
-
if (!reactImport) sourceFile.addImportDeclaration({
|
|
3894
|
-
moduleSpecifier: "@vitejs/plugin-react",
|
|
3895
|
-
defaultImport: "viteReact"
|
|
3896
|
-
});
|
|
3897
|
-
else {
|
|
3898
|
-
const defaultImport = reactImport.getDefaultImport();
|
|
3899
|
-
if (defaultImport) reactPluginIdentifier = defaultImport.getText();
|
|
3900
|
-
else reactImport.setDefaultImport("viteReact");
|
|
3901
|
-
}
|
|
3902
|
-
const defineCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((expr) => {
|
|
3903
|
-
const expression = expr.getExpression();
|
|
3904
|
-
return Node.isIdentifier(expression) && expression.getText() === "defineConfig";
|
|
3905
|
-
});
|
|
3906
|
-
if (!defineCall) return;
|
|
3907
|
-
const configObj = defineCall.getArguments()[0];
|
|
3908
|
-
if (!configObj) return;
|
|
3909
|
-
const pluginsArray = ensureArrayProperty(configObj, "plugins");
|
|
3910
|
-
if (!pluginsArray.getElements().some((el) => el.getText().includes("cloudflare("))) pluginsArray.insertElement(0, "cloudflare({ viteEnvironment: { name: 'ssr' } })");
|
|
3911
|
-
if (!pluginsArray.getElements().some((el) => Node.isCallExpression(el) && el.getExpression().getText() === reactPluginIdentifier)) {
|
|
3912
|
-
const nextIndex = pluginsArray.getElements().findIndex((el) => el.getText().includes("tanstackStart(")) + 1;
|
|
3913
|
-
if (nextIndex > 0) pluginsArray.insertElement(nextIndex, `${reactPluginIdentifier}()`);
|
|
3914
|
-
else pluginsArray.addElement(`${reactPluginIdentifier}()`);
|
|
3915
|
-
}
|
|
3916
|
-
await tsProject.save();
|
|
3917
|
-
}
|
|
3918
|
-
|
|
3919
|
-
//#endregion
|
|
3920
|
-
//#region src/helpers/deployment/workers/workers-vite-setup.ts
|
|
3921
|
-
async function setupWorkersVitePlugin(projectDir) {
|
|
3922
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
3923
|
-
const viteConfigPath = path.join(webAppDir, "vite.config.ts");
|
|
3924
|
-
if (!await fs.pathExists(viteConfigPath)) throw new Error("vite.config.ts not found in web app directory");
|
|
3925
|
-
await addPackageDependency({
|
|
3926
|
-
devDependencies: ["@cloudflare/vite-plugin", "wrangler"],
|
|
3927
|
-
projectDir: webAppDir
|
|
3928
|
-
});
|
|
3929
|
-
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
|
|
3930
|
-
if (!sourceFile) throw new Error("vite.config.ts not found in web app directory");
|
|
3931
|
-
if (!sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === "@cloudflare/vite-plugin")) sourceFile.insertImportDeclaration(0, {
|
|
3932
|
-
namedImports: ["cloudflare"],
|
|
3933
|
-
moduleSpecifier: "@cloudflare/vite-plugin"
|
|
3934
|
-
});
|
|
3935
|
-
const defineCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((expr) => {
|
|
3936
|
-
const expression = expr.getExpression();
|
|
3937
|
-
return Node.isIdentifier(expression) && expression.getText() === "defineConfig";
|
|
3938
|
-
});
|
|
3939
|
-
if (!defineCall) throw new Error("Could not find defineConfig call in vite config");
|
|
3940
|
-
const configObject = defineCall.getArguments()[0];
|
|
3941
|
-
if (!configObject) throw new Error("defineConfig argument is not an object literal");
|
|
3942
|
-
const pluginsArray = ensureArrayProperty(configObject, "plugins");
|
|
3943
|
-
if (!pluginsArray.getElements().some((el) => el.getText().includes("cloudflare("))) pluginsArray.addElement("cloudflare()");
|
|
3944
|
-
await tsProject.save();
|
|
3945
|
-
}
|
|
3946
|
-
|
|
3947
3653
|
//#endregion
|
|
3948
3654
|
//#region src/helpers/deployment/web-deploy-setup.ts
|
|
3949
3655
|
async function setupWebDeploy(config) {
|
|
3950
3656
|
const { webDeploy, serverDeploy, frontend, projectDir } = config;
|
|
3951
3657
|
const { packageManager } = config;
|
|
3952
3658
|
if (webDeploy === "none") return;
|
|
3953
|
-
if (webDeploy !== "
|
|
3659
|
+
if (webDeploy !== "alchemy") return;
|
|
3954
3660
|
if (webDeploy === "alchemy" && serverDeploy === "alchemy") {
|
|
3955
3661
|
await setupCombinedAlchemyDeploy(projectDir, packageManager, config);
|
|
3956
3662
|
await addAlchemyPackagesDependencies(projectDir);
|
|
@@ -3963,37 +3669,14 @@ async function setupWebDeploy(config) {
|
|
|
3963
3669
|
const isTanstackStart = frontend.includes("tanstack-start");
|
|
3964
3670
|
const isReactRouter = frontend.includes("react-router");
|
|
3965
3671
|
const isSolid = frontend.includes("solid");
|
|
3966
|
-
if (
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
else if (isNuxt) await setupNuxtAlchemyDeploy(projectDir, packageManager);
|
|
3975
|
-
else if (isSvelte) await setupSvelteAlchemyDeploy(projectDir, packageManager);
|
|
3976
|
-
else if (isTanstackStart) await setupTanStackStartAlchemyDeploy(projectDir, packageManager);
|
|
3977
|
-
else if (isTanstackRouter) await setupTanStackRouterAlchemyDeploy(projectDir, packageManager);
|
|
3978
|
-
else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager);
|
|
3979
|
-
else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager);
|
|
3980
|
-
await addAlchemyPackagesDependencies(projectDir);
|
|
3981
|
-
}
|
|
3982
|
-
}
|
|
3983
|
-
async function setupWorkersWebDeploy(projectDir, pkgManager) {
|
|
3984
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
3985
|
-
if (!await fs.pathExists(webAppDir)) return;
|
|
3986
|
-
const packageJsonPath = path.join(webAppDir, "package.json");
|
|
3987
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
3988
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
3989
|
-
packageJson.scripts = {
|
|
3990
|
-
...packageJson.scripts,
|
|
3991
|
-
"wrangler:dev": "wrangler dev --port=3001",
|
|
3992
|
-
deploy: `${pkgManager} run build && wrangler deploy`
|
|
3993
|
-
};
|
|
3994
|
-
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
3995
|
-
}
|
|
3996
|
-
await setupWorkersVitePlugin(projectDir);
|
|
3672
|
+
if (isNext) await setupNextAlchemyDeploy(projectDir, packageManager);
|
|
3673
|
+
else if (isNuxt) await setupNuxtAlchemyDeploy(projectDir, packageManager);
|
|
3674
|
+
else if (isSvelte) await setupSvelteAlchemyDeploy(projectDir, packageManager);
|
|
3675
|
+
else if (isTanstackStart) await setupTanStackStartAlchemyDeploy(projectDir, packageManager);
|
|
3676
|
+
else if (isTanstackRouter) await setupTanStackRouterAlchemyDeploy(projectDir, packageManager);
|
|
3677
|
+
else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager);
|
|
3678
|
+
else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager);
|
|
3679
|
+
await addAlchemyPackagesDependencies(projectDir);
|
|
3997
3680
|
}
|
|
3998
3681
|
async function addAlchemyPackagesDependencies(projectDir) {
|
|
3999
3682
|
await addPackageDependency({
|
|
@@ -4854,7 +4537,7 @@ ${hasWeb ? "# npx convex env set SITE_URL http://localhost:3001\n" : ""}
|
|
|
4854
4537
|
databaseUrl = "mongodb://localhost:27017/mydatabase";
|
|
4855
4538
|
break;
|
|
4856
4539
|
case "sqlite":
|
|
4857
|
-
if (config.runtime === "workers" || webDeploy === "
|
|
4540
|
+
if (config.runtime === "workers" || webDeploy === "alchemy" || serverDeploy === "alchemy") databaseUrl = "http://127.0.0.1:8080";
|
|
4858
4541
|
else {
|
|
4859
4542
|
const dbAppDir = backend === "self" ? "apps/web" : "apps/server";
|
|
4860
4543
|
databaseUrl = `file:${path.join(config.projectDir, dbAppDir, "local.db")}`;
|
|
@@ -4936,31 +4619,7 @@ ${hasWeb ? "# npx convex env set SITE_URL http://localhost:3001\n" : ""}
|
|
|
4936
4619
|
//#region src/helpers/database-providers/d1-setup.ts
|
|
4937
4620
|
async function setupCloudflareD1(config) {
|
|
4938
4621
|
const { projectDir, serverDeploy, orm, backend } = config;
|
|
4939
|
-
if (serverDeploy === "
|
|
4940
|
-
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
4941
|
-
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4942
|
-
const variables = [
|
|
4943
|
-
{
|
|
4944
|
-
key: "CLOUDFLARE_ACCOUNT_ID",
|
|
4945
|
-
value: "",
|
|
4946
|
-
condition: true
|
|
4947
|
-
},
|
|
4948
|
-
{
|
|
4949
|
-
key: "CLOUDFLARE_DATABASE_ID",
|
|
4950
|
-
value: "",
|
|
4951
|
-
condition: true
|
|
4952
|
-
},
|
|
4953
|
-
{
|
|
4954
|
-
key: "CLOUDFLARE_D1_TOKEN",
|
|
4955
|
-
value: "",
|
|
4956
|
-
condition: true
|
|
4957
|
-
}
|
|
4958
|
-
];
|
|
4959
|
-
try {
|
|
4960
|
-
await addEnvVariablesToFile(envPath, variables);
|
|
4961
|
-
} catch (_err) {}
|
|
4962
|
-
}
|
|
4963
|
-
if ((serverDeploy === "wrangler" || serverDeploy === "alchemy") && orm === "prisma") {
|
|
4622
|
+
if (serverDeploy === "alchemy" && orm === "prisma") {
|
|
4964
4623
|
const targetApp2 = backend === "self" ? "apps/web" : "apps/server";
|
|
4965
4624
|
const envPath = path.join(projectDir, targetApp2, ".env");
|
|
4966
4625
|
const variables = [{
|
|
@@ -5407,7 +5066,7 @@ const AVAILABLE_REGIONS = [
|
|
|
5407
5066
|
label: "US West (N. California)"
|
|
5408
5067
|
}
|
|
5409
5068
|
];
|
|
5410
|
-
async function setupWithCreateDb(serverDir, packageManager
|
|
5069
|
+
async function setupWithCreateDb(serverDir, packageManager) {
|
|
5411
5070
|
try {
|
|
5412
5071
|
log.info("Starting Prisma Postgres setup with create-db.");
|
|
5413
5072
|
const selectedRegion = await select({
|
|
@@ -5432,7 +5091,7 @@ async function setupWithCreateDb(serverDir, packageManager, orm) {
|
|
|
5432
5091
|
return null;
|
|
5433
5092
|
}
|
|
5434
5093
|
return {
|
|
5435
|
-
databaseUrl:
|
|
5094
|
+
databaseUrl: createDbResponse.connectionString,
|
|
5436
5095
|
claimUrl: createDbResponse.claimUrl
|
|
5437
5096
|
};
|
|
5438
5097
|
} catch (error) {
|
|
@@ -5450,12 +5109,12 @@ async function initPrismaDatabase(serverDir, packageManager) {
|
|
|
5450
5109
|
stdio: "inherit",
|
|
5451
5110
|
shell: true
|
|
5452
5111
|
});
|
|
5453
|
-
log.info(pc.yellow("Please copy the Prisma Postgres URL
|
|
5112
|
+
log.info(pc.yellow("Please copy the Prisma Postgres URL.\nIt looks like: postgresql://user:password@host:5432/db?sslmode=require"));
|
|
5454
5113
|
const databaseUrl = await text({
|
|
5455
5114
|
message: "Paste your Prisma Postgres database URL:",
|
|
5456
5115
|
validate(value) {
|
|
5457
5116
|
if (!value) return "Please enter a database URL";
|
|
5458
|
-
if (!value.startsWith("
|
|
5117
|
+
if (!value.startsWith("postgresql://")) return "URL should start with postgresql://";
|
|
5459
5118
|
}
|
|
5460
5119
|
});
|
|
5461
5120
|
if (isCancel(databaseUrl)) return null;
|
|
@@ -5504,18 +5163,6 @@ function displayManualSetupInstructions$1(target) {
|
|
|
5504
5163
|
|
|
5505
5164
|
DATABASE_URL="your_database_url"`);
|
|
5506
5165
|
}
|
|
5507
|
-
async function addPrismaAccelerateExtension(projectDir) {
|
|
5508
|
-
try {
|
|
5509
|
-
await addPackageDependency({
|
|
5510
|
-
dependencies: ["@prisma/extension-accelerate"],
|
|
5511
|
-
projectDir: path.join(projectDir, "packages/db")
|
|
5512
|
-
});
|
|
5513
|
-
return true;
|
|
5514
|
-
} catch (_error) {
|
|
5515
|
-
log.warn(pc.yellow("Could not add Prisma Accelerate extension automatically"));
|
|
5516
|
-
return false;
|
|
5517
|
-
}
|
|
5518
|
-
}
|
|
5519
5166
|
async function setupPrismaPostgres(config, cliInput) {
|
|
5520
5167
|
const { packageManager, projectDir, orm, backend } = config;
|
|
5521
5168
|
const manualDb = cliInput?.manualDb ?? false;
|
|
@@ -5563,16 +5210,12 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5563
5210
|
});
|
|
5564
5211
|
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
5565
5212
|
let prismaConfig = null;
|
|
5566
|
-
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(dbDir, packageManager
|
|
5213
|
+
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(dbDir, packageManager);
|
|
5567
5214
|
else prismaConfig = await initPrismaDatabase(dbDir, packageManager);
|
|
5568
5215
|
if (prismaConfig) {
|
|
5569
5216
|
await writeEnvFile$1(projectDir, backend, prismaConfig);
|
|
5570
|
-
if (orm === "prisma")
|
|
5571
|
-
|
|
5572
|
-
await addPrismaAccelerateExtension(projectDir);
|
|
5573
|
-
}
|
|
5574
|
-
const connectionType = orm === "drizzle" ? "direct connection" : "Prisma Accelerate";
|
|
5575
|
-
log.success(pc.green(`Prisma Postgres database configured successfully with ${connectionType}!`));
|
|
5217
|
+
if (orm === "prisma") await addDotenvImportToPrismaConfig(projectDir, backend);
|
|
5218
|
+
log.success(pc.green("Prisma Postgres database configured successfully!"));
|
|
5576
5219
|
if (prismaConfig.claimUrl) log.info(pc.blue(`Claim URL saved to .env: ${prismaConfig.claimUrl}`));
|
|
5577
5220
|
} else {
|
|
5578
5221
|
await writeEnvFile$1(projectDir, backend);
|
|
@@ -5968,40 +5611,57 @@ async function setupDatabase(config, cliInput) {
|
|
|
5968
5611
|
}
|
|
5969
5612
|
const s = spinner();
|
|
5970
5613
|
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5614
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
5971
5615
|
if (!await fs.pathExists(dbPackageDir)) return;
|
|
5972
5616
|
try {
|
|
5973
5617
|
if (orm === "prisma") {
|
|
5974
|
-
if (database === "
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
"@prisma/adapter-planetscale",
|
|
5978
|
-
"@planetscale/database"
|
|
5979
|
-
],
|
|
5980
|
-
devDependencies: ["prisma"],
|
|
5618
|
+
if (database === "mongodb") await addPackageDependency({
|
|
5619
|
+
customDependencies: { "@prisma/client": "6.19.0" },
|
|
5620
|
+
customDevDependencies: { prisma: "6.19.0" },
|
|
5981
5621
|
projectDir: dbPackageDir
|
|
5982
5622
|
});
|
|
5983
|
-
else
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5623
|
+
else {
|
|
5624
|
+
const prismaDependencies = ["@prisma/client"];
|
|
5625
|
+
const prismaDevDependencies = ["prisma"];
|
|
5626
|
+
if (database === "mysql" && dbSetup === "planetscale") prismaDependencies.push("@prisma/adapter-planetscale", "@planetscale/database");
|
|
5627
|
+
else if (database === "mysql") prismaDependencies.push("@prisma/adapter-mariadb");
|
|
5628
|
+
else if (database === "sqlite") prismaDependencies.push("@prisma/adapter-libsql");
|
|
5629
|
+
else if (database === "postgres") if (dbSetup === "neon") prismaDependencies.push("@prisma/adapter-neon");
|
|
5630
|
+
else {
|
|
5631
|
+
prismaDependencies.push("@prisma/adapter-pg");
|
|
5632
|
+
prismaDependencies.push("pg");
|
|
5633
|
+
prismaDevDependencies.push("@types/pg");
|
|
5634
|
+
}
|
|
5635
|
+
await addPackageDependency({
|
|
5636
|
+
dependencies: prismaDependencies,
|
|
5637
|
+
devDependencies: prismaDevDependencies,
|
|
5638
|
+
projectDir: dbPackageDir
|
|
5639
|
+
});
|
|
5640
|
+
}
|
|
5641
|
+
if (await fs.pathExists(webDir)) if (database === "mongodb") await addPackageDependency({
|
|
5642
|
+
customDependencies: { "@prisma/client": "6.19.0" },
|
|
5643
|
+
projectDir: webDir
|
|
5987
5644
|
});
|
|
5988
5645
|
else await addPackageDependency({
|
|
5989
|
-
dependencies: ["@prisma/client"],
|
|
5990
|
-
devDependencies: ["prisma"],
|
|
5991
|
-
projectDir: dbPackageDir
|
|
5992
|
-
});
|
|
5993
|
-
const webDir = path.join(projectDir, "apps/web");
|
|
5994
|
-
if (await fs.pathExists(webDir)) await addPackageDependency({
|
|
5995
5646
|
dependencies: ["@prisma/client"],
|
|
5996
5647
|
projectDir: webDir
|
|
5997
5648
|
});
|
|
5998
5649
|
} else if (orm === "drizzle") {
|
|
5999
|
-
if (database === "sqlite")
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
5650
|
+
if (database === "sqlite") {
|
|
5651
|
+
await addPackageDependency({
|
|
5652
|
+
dependencies: [
|
|
5653
|
+
"drizzle-orm",
|
|
5654
|
+
"@libsql/client",
|
|
5655
|
+
"libsql"
|
|
5656
|
+
],
|
|
5657
|
+
devDependencies: ["drizzle-kit"],
|
|
5658
|
+
projectDir: dbPackageDir
|
|
5659
|
+
});
|
|
5660
|
+
await addPackageDependency({
|
|
5661
|
+
dependencies: ["@libsql/client", "libsql"],
|
|
5662
|
+
projectDir: webDir
|
|
5663
|
+
});
|
|
5664
|
+
} else if (database === "postgres") if (dbSetup === "neon") await addPackageDependency({
|
|
6005
5665
|
dependencies: [
|
|
6006
5666
|
"drizzle-orm",
|
|
6007
5667
|
"@neondatabase/serverless",
|
|
@@ -6320,7 +5980,7 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
6320
5980
|
else if (addon === "turborepo") addonsList.push("- **Turborepo** - Optimized monorepo build system");
|
|
6321
5981
|
return addonsList.join("\n");
|
|
6322
5982
|
}
|
|
6323
|
-
function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup,
|
|
5983
|
+
function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup, _serverDeploy, backend) {
|
|
6324
5984
|
if (database === "none") return "";
|
|
6325
5985
|
const isBackendSelf = backend === "self";
|
|
6326
5986
|
const envPath = isBackendSelf ? "apps/web/.env" : "apps/server/.env";
|
|
@@ -6329,7 +5989,7 @@ function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSet
|
|
|
6329
5989
|
if (database === "sqlite") setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
6330
5990
|
|
|
6331
5991
|
1. Start the local SQLite database:
|
|
6332
|
-
${dbSetup === "d1" ?
|
|
5992
|
+
${dbSetup === "d1" ? "D1 local development and migrations are handled automatically by Alchemy during dev and deploy." : `\`\`\`bash
|
|
6333
5993
|
cd ${dbLocalPath} && ${packageManagerRunCmd} db:local
|
|
6334
5994
|
\`\`\`
|
|
6335
5995
|
`}
|
|
@@ -6427,11 +6087,6 @@ function generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeplo
|
|
|
6427
6087
|
if (serverDeploy === "alchemy" && webDeploy !== "alchemy") lines.push(`- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`, `- Server destroy: cd apps/server && ${packageManagerRunCmd} destroy`);
|
|
6428
6088
|
if (webDeploy === "alchemy" && serverDeploy === "alchemy") lines.push(`- Dev: ${packageManagerRunCmd} dev`, `- Deploy: ${packageManagerRunCmd} deploy`, `- Destroy: ${packageManagerRunCmd} destroy`);
|
|
6429
6089
|
}
|
|
6430
|
-
if (webDeploy === "wrangler" || serverDeploy === "wrangler") {
|
|
6431
|
-
lines.push("\n## Deployment (Cloudflare Wrangler)");
|
|
6432
|
-
if (webDeploy === "wrangler") lines.push(`- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`);
|
|
6433
|
-
if (serverDeploy === "wrangler") lines.push(`- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`);
|
|
6434
|
-
}
|
|
6435
6090
|
return lines.length ? `\n${lines.join("\n")}\n` : "";
|
|
6436
6091
|
}
|
|
6437
6092
|
|
|
@@ -6555,7 +6210,6 @@ async function displayPostInstallInstructions(config) {
|
|
|
6555
6210
|
const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
|
|
6556
6211
|
const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
|
|
6557
6212
|
const polarInstructions = config.payments === "polar" && config.auth === "better-auth" ? getPolarInstructions(backend) : "";
|
|
6558
|
-
const wranglerDeployInstructions = getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
|
|
6559
6213
|
const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
|
|
6560
6214
|
const hasWeb = frontend?.some((f) => [
|
|
6561
6215
|
"tanstack-router",
|
|
@@ -6575,7 +6229,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6575
6229
|
let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
|
|
6576
6230
|
let stepCounter = 2;
|
|
6577
6231
|
if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${packageManager} install\n`;
|
|
6578
|
-
if (database === "sqlite" && dbSetup === "none" && (serverDeploy === "
|
|
6232
|
+
if (database === "sqlite" && dbSetup === "none" && (serverDeploy === "alchemy" || webDeploy === "alchemy")) output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} db:local\n${pc.dim(" (starts local SQLite server for Workers compatibility)")}\n`;
|
|
6579
6233
|
if (isConvex) {
|
|
6580
6234
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup\n${pc.dim(" (this will guide you through Convex project setup)")}\n`;
|
|
6581
6235
|
output += `${pc.cyan(`${stepCounter++}.`)} Copy environment variables from\n${pc.white(" packages/backend/.env.local")} to ${pc.white("apps/*/.env")}\n`;
|
|
@@ -6586,7 +6240,6 @@ async function displayPostInstallInstructions(config) {
|
|
|
6586
6240
|
if (runtime === "workers") {
|
|
6587
6241
|
if (dbSetup === "d1") output += `${pc.yellow("IMPORTANT:")} Complete D1 database setup first\n (see Database commands below)\n`;
|
|
6588
6242
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n`;
|
|
6589
|
-
if (serverDeploy === "wrangler") output += `${pc.cyan(`${stepCounter++}.`)} cd apps/server && ${runCmd} cf-typegen\n`;
|
|
6590
6243
|
}
|
|
6591
6244
|
}
|
|
6592
6245
|
output += `${pc.bold("Your project will be available at:")}\n`;
|
|
@@ -6604,7 +6257,6 @@ async function displayPostInstallInstructions(config) {
|
|
|
6604
6257
|
if (tauriInstructions) output += `\n${tauriInstructions.trim()}\n`;
|
|
6605
6258
|
if (lintingInstructions) output += `\n${lintingInstructions.trim()}\n`;
|
|
6606
6259
|
if (pwaInstructions) output += `\n${pwaInstructions.trim()}\n`;
|
|
6607
|
-
if (wranglerDeployInstructions) output += `\n${wranglerDeployInstructions.trim()}\n`;
|
|
6608
6260
|
if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
|
|
6609
6261
|
if (starlightInstructions) output += `\n${starlightInstructions.trim()}\n`;
|
|
6610
6262
|
if (clerkInstructions) output += `\n${clerkInstructions.trim()}\n`;
|
|
@@ -6627,7 +6279,7 @@ function getNativeInstructions(isConvex, isBackendSelf, _frontend) {
|
|
|
6627
6279
|
function getLintingInstructions(runCmd) {
|
|
6628
6280
|
return `${pc.bold("Linting and formatting:")}\n${pc.cyan("•")} Format and lint fix: ${`${runCmd} check`}\n`;
|
|
6629
6281
|
}
|
|
6630
|
-
async function getDatabaseInstructions(database, orm, runCmd,
|
|
6282
|
+
async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup, serverDeploy, _backend) {
|
|
6631
6283
|
const instructions = [];
|
|
6632
6284
|
if (dbSetup === "docker") {
|
|
6633
6285
|
const dockerStatus = await getDockerStatus(database);
|
|
@@ -6636,17 +6288,6 @@ async function getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup,
|
|
|
6636
6288
|
instructions.push("");
|
|
6637
6289
|
}
|
|
6638
6290
|
}
|
|
6639
|
-
if (serverDeploy === "wrangler" && dbSetup === "d1") {
|
|
6640
|
-
if (orm === "prisma" && runtime === "workers") instructions.push(`\n${pc.yellow("WARNING:")} Prisma + D1 on Workers with Wrangler has migration issues.\n Consider using Alchemy deploy instead of Wrangler for D1 projects.\n`);
|
|
6641
|
-
const packageManager = runCmd === "npm run" ? "npm" : runCmd || "npm";
|
|
6642
|
-
instructions.push(`${pc.cyan("1.")} Login to Cloudflare: ${pc.white(`${packageManager} wrangler login`)}`);
|
|
6643
|
-
instructions.push(`${pc.cyan("2.")} Create D1 database: ${pc.white(`${packageManager} wrangler d1 create your-database-name`)}`);
|
|
6644
|
-
const wranglerPath = backend === "self" ? "apps/web" : "apps/server";
|
|
6645
|
-
instructions.push(`${pc.cyan("3.")} Update ${wranglerPath}/wrangler.jsonc with database_id and database_name`);
|
|
6646
|
-
instructions.push(`${pc.cyan("4.")} Generate migrations: ${pc.white(`cd ${wranglerPath} && ${runCmd} db:generate`)}`);
|
|
6647
|
-
instructions.push(`${pc.cyan("5.")} Apply migrations locally: ${pc.white(`${packageManager} wrangler d1 migrations apply YOUR_DB_NAME --local`)}`);
|
|
6648
|
-
instructions.push(`${pc.cyan("6.")} Apply migrations to production: ${pc.white(`${packageManager} wrangler d1 migrations apply YOUR_DB_NAME`)}`);
|
|
6649
|
-
}
|
|
6650
6291
|
if (dbSetup === "d1" && serverDeploy === "alchemy") {
|
|
6651
6292
|
if (orm === "drizzle") instructions.push(`${pc.yellow("NOTE:")} D1 migrations are automatically handled by Alchemy`);
|
|
6652
6293
|
else if (orm === "prisma") {
|
|
@@ -6661,7 +6302,10 @@ async function getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup,
|
|
|
6661
6302
|
if (orm === "prisma") {
|
|
6662
6303
|
if (database === "mongodb" && dbSetup === "docker") instructions.push(`${pc.yellow("WARNING:")} Prisma + MongoDB + Docker combination\n may not work.`);
|
|
6663
6304
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6664
|
-
if (!(dbSetup === "d1" && serverDeploy === "alchemy"))
|
|
6305
|
+
if (!(dbSetup === "d1" && serverDeploy === "alchemy")) {
|
|
6306
|
+
instructions.push(`${pc.cyan("•")} Generate Prisma Client: ${`${runCmd} db:generate`}`);
|
|
6307
|
+
instructions.push(`${pc.cyan("•")} Apply schema: ${`${runCmd} db:push`}`);
|
|
6308
|
+
}
|
|
6665
6309
|
if (!(dbSetup === "d1" && serverDeploy === "alchemy")) instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
|
|
6666
6310
|
} else if (orm === "drizzle") {
|
|
6667
6311
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
@@ -6687,15 +6331,6 @@ function getNoOrmWarning() {
|
|
|
6687
6331
|
function getBunWebNativeWarning() {
|
|
6688
6332
|
return `\n${pc.yellow("WARNING:")} 'bun' might cause issues with web + native apps in a monorepo.\n Use 'pnpm' if problems arise.`;
|
|
6689
6333
|
}
|
|
6690
|
-
function getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy, backend) {
|
|
6691
|
-
const instructions = [];
|
|
6692
|
-
if (webDeploy === "wrangler") {
|
|
6693
|
-
const deployPath = backend === "self" ? "apps/web" : "apps/web";
|
|
6694
|
-
instructions.push(`${pc.bold("Deploy web to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd ${deployPath} && ${runCmd} deploy`}`);
|
|
6695
|
-
}
|
|
6696
|
-
if (serverDeploy === "wrangler" && backend !== "self") instructions.push(`${pc.bold("Deploy server to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} deploy`}`);
|
|
6697
|
-
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
6698
|
-
}
|
|
6699
6334
|
function getClerkInstructions() {
|
|
6700
6335
|
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`;
|
|
6701
6336
|
}
|
|
@@ -6706,7 +6341,7 @@ function getPolarInstructions(backend) {
|
|
|
6706
6341
|
function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend) {
|
|
6707
6342
|
const instructions = [];
|
|
6708
6343
|
const isBackendSelf = backend === "self";
|
|
6709
|
-
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`}`);
|
|
6344
|
+
if (webDeploy === "alchemy" && serverDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd} alchemy dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/web && ${runCmd} destroy`}`);
|
|
6710
6345
|
else if (serverDeploy === "alchemy" && webDeploy !== "alchemy" && !isBackendSelf) 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`}`);
|
|
6711
6346
|
else if (webDeploy === "alchemy" && (serverDeploy === "alchemy" || isBackendSelf)) 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`}`);
|
|
6712
6347
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
@@ -6718,7 +6353,7 @@ async function setupWorkspaceDependencies(projectDir, options) {
|
|
|
6718
6353
|
const projectName = options.projectName;
|
|
6719
6354
|
const workspaceVersion = options.packageManager === "npm" ? "*" : "workspace:*";
|
|
6720
6355
|
const commonDeps = ["dotenv", "zod"];
|
|
6721
|
-
const commonDevDeps = [
|
|
6356
|
+
const commonDevDeps = [];
|
|
6722
6357
|
const configPackageDir = path.join(projectDir, "packages/config");
|
|
6723
6358
|
const configDep = {};
|
|
6724
6359
|
if (await fs.pathExists(configPackageDir)) configDep[`@${projectName}/config`] = workspaceVersion;
|
|
@@ -6762,7 +6397,7 @@ async function setupWorkspaceDependencies(projectDir, options) {
|
|
|
6762
6397
|
if (options.database !== "none" && await fs.pathExists(dbPackageDir)) serverDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6763
6398
|
await addPackageDependency({
|
|
6764
6399
|
dependencies: commonDeps,
|
|
6765
|
-
devDependencies: commonDevDeps,
|
|
6400
|
+
devDependencies: [...commonDevDeps, "tsdown"],
|
|
6766
6401
|
customDependencies: serverDeps,
|
|
6767
6402
|
customDevDependencies: configDep,
|
|
6768
6403
|
projectDir: serverPackageDir
|