create-better-t-stack 3.11.0 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-Dt3mZKp0.mjs +24 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +40 -60
- package/dist/index.mjs +2 -2
- package/dist/{src-XVvJUQ_h.mjs → src-DBVnwTkj.mjs} +668 -631
- package/package.json +2 -2
- package/templates/addons/turborepo/turbo.json.hbs +13 -0
- package/templates/api/orpc/native/utils/orpc.ts.hbs +21 -20
- package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +3 -5
- package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +73 -67
- package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +15 -14
- package/templates/api/trpc/native/utils/trpc.ts.hbs +8 -7
- package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +59 -57
- package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +3 -5
- package/templates/auth/better-auth/convex/backend/convex/privateData.ts.hbs +13 -12
- package/templates/auth/better-auth/convex/native/base/lib/auth-client.ts.hbs +10 -9
- package/templates/auth/better-auth/convex/web/react/next/src/lib/auth-client.ts.hbs +2 -2
- package/templates/auth/better-auth/convex/web/react/next/src/lib/auth-server.ts.hbs +11 -9
- package/templates/auth/better-auth/convex/web/react/tanstack-router/src/lib/auth-client.ts.hbs +5 -4
- package/templates/auth/better-auth/convex/web/react/tanstack-start/src/lib/auth-server.ts.hbs +8 -7
- package/templates/auth/better-auth/native/base/lib/auth-client.ts.hbs +9 -8
- package/templates/auth/better-auth/server/base/src/index.ts.hbs +239 -235
- package/templates/auth/better-auth/web/nuxt/app/plugins/auth-client.ts.hbs +2 -3
- package/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs +9 -11
- package/templates/auth/better-auth/web/solid/src/lib/auth-client.ts.hbs +3 -2
- package/templates/backend/server/elysia/src/index.ts.hbs +71 -71
- package/templates/backend/server/express/src/index.ts.hbs +57 -57
- package/templates/backend/server/fastify/src/index.ts.hbs +107 -107
- package/templates/backend/server/hono/src/index.ts.hbs +75 -85
- package/templates/base/tsconfig.json.hbs +3 -0
- package/templates/db/drizzle/mysql/src/index.ts.hbs +23 -30
- package/templates/db/drizzle/postgres/src/index.ts.hbs +6 -13
- package/templates/db/drizzle/sqlite/src/index.ts.hbs +11 -18
- package/templates/db/mongoose/mongodb/src/index.ts.hbs +3 -2
- package/templates/db/prisma/mongodb/prisma/schema/schema.prisma.hbs +1 -1
- package/templates/db/prisma/mysql/prisma/schema/schema.prisma.hbs +1 -1
- package/templates/db/prisma/mysql/prisma.config.ts.hbs +16 -16
- package/templates/db/prisma/mysql/src/index.ts.hbs +16 -15
- package/templates/db/prisma/postgres/prisma/schema/schema.prisma.hbs +1 -1
- package/templates/db/prisma/postgres/src/index.ts.hbs +10 -9
- package/templates/db/prisma/sqlite/prisma/schema/schema.prisma.hbs +1 -1
- package/templates/db/prisma/sqlite/src/index.ts.hbs +4 -7
- package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +2 -1
- package/templates/examples/ai/native/unistyles/app/(drawer)/ai.tsx.hbs +2 -1
- package/templates/examples/ai/native/uniwind/app/(drawer)/ai.tsx.hbs +2 -1
- package/templates/examples/ai/web/nuxt/app/pages/ai.vue.hbs +1 -3
- package/templates/examples/ai/web/react/next/src/app/ai/page.tsx.hbs +4 -3
- package/templates/examples/ai/web/react/react-router/src/routes/ai.tsx.hbs +2 -1
- package/templates/examples/ai/web/react/tanstack-router/src/routes/ai.tsx.hbs +4 -1
- package/templates/examples/ai/web/react/tanstack-start/src/routes/ai.tsx.hbs +4 -1
- package/templates/frontend/native/bare/app/_layout.tsx.hbs +4 -2
- package/templates/frontend/native/unistyles/app/_layout.tsx.hbs +4 -2
- package/templates/frontend/native/uniwind/app/_layout.tsx.hbs +4 -3
- package/templates/frontend/nuxt/nuxt.config.ts.hbs +6 -3
- package/templates/frontend/react/next/next.config.ts.hbs +9 -8
- package/templates/frontend/react/next/src/components/providers.tsx.hbs +4 -1
- package/templates/frontend/react/next/tsconfig.json.hbs +2 -2
- package/templates/frontend/react/react-router/src/root.tsx.hbs +3 -4
- package/templates/frontend/react/tanstack-router/src/main.tsx.hbs +3 -2
- package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +100 -108
- package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +25 -7
- package/templates/packages/config/tsconfig.base.json.hbs +1 -1
- package/templates/{deploy/alchemy → packages/env}/env.d.ts.hbs +6 -4
- package/templates/packages/env/package.json.hbs +7 -0
- package/templates/packages/env/src/native.ts.hbs +21 -0
- package/templates/packages/env/src/server.ts.hbs +38 -0
- package/templates/packages/env/src/web.ts.hbs +89 -0
- package/templates/packages/env/tsconfig.json.hbs +3 -0
- package/templates/{deploy/alchemy → packages/infra}/alchemy.run.ts.hbs +86 -82
- package/templates/packages/infra/package.json.hbs +10 -0
- package/templates/payments/polar/server/base/src/lib/payments.ts.hbs +3 -2
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { t as __reExport } from "./chunk-Dt3mZKp0.mjs";
|
|
2
3
|
import { autocompleteMultiselect, cancel, confirm, group, groupMultiselect, intro, isCancel, log, multiselect, outro, select, spinner, text } from "@clack/prompts";
|
|
3
4
|
import { createRouterClient, os } from "@orpc/server";
|
|
4
5
|
import pc from "picocolors";
|
|
5
6
|
import { createCli } from "trpc-cli";
|
|
6
7
|
import z from "zod";
|
|
7
|
-
import path from "node:path";
|
|
8
8
|
import consola, { consola as consola$1 } from "consola";
|
|
9
9
|
import fs from "fs-extra";
|
|
10
|
+
import path from "node:path";
|
|
10
11
|
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 "@better-t-stack/types";
|
|
12
12
|
import gradient from "gradient-string";
|
|
13
13
|
import * as JSONC from "jsonc-parser";
|
|
14
14
|
import { $, execa } from "execa";
|
|
@@ -64,8 +64,8 @@ function getDefaultConfig() {
|
|
|
64
64
|
const DEFAULT_CONFIG = getDefaultConfig();
|
|
65
65
|
const dependencyVersionMap = {
|
|
66
66
|
typescript: "^5",
|
|
67
|
-
"better-auth": "^1.4.
|
|
68
|
-
"@better-auth/expo": "^1.4.
|
|
67
|
+
"better-auth": "^1.4.9",
|
|
68
|
+
"@better-auth/expo": "^1.4.9",
|
|
69
69
|
"@clerk/nextjs": "^6.31.5",
|
|
70
70
|
"@clerk/clerk-react": "^5.45.0",
|
|
71
71
|
"@clerk/tanstack-react-start": "^0.26.3",
|
|
@@ -138,13 +138,14 @@ const dependencyVersionMap = {
|
|
|
138
138
|
"convex-svelte": "^0.0.12",
|
|
139
139
|
"convex-nuxt": "0.1.5",
|
|
140
140
|
"convex-vue": "^0.1.5",
|
|
141
|
-
"@convex-dev/better-auth": "^0.10.
|
|
141
|
+
"@convex-dev/better-auth": "^0.10.9",
|
|
142
142
|
"@tanstack/svelte-query": "^5.85.3",
|
|
143
143
|
"@tanstack/svelte-query-devtools": "^5.85.3",
|
|
144
144
|
"@tanstack/vue-query-devtools": "^5.90.2",
|
|
145
145
|
"@tanstack/vue-query": "^5.90.2",
|
|
146
146
|
"@tanstack/react-query-devtools": "^5.91.1",
|
|
147
147
|
"@tanstack/react-query": "^5.90.12",
|
|
148
|
+
"@tanstack/react-router-ssr-query": "^1.142.7",
|
|
148
149
|
"@tanstack/solid-query": "^5.87.4",
|
|
149
150
|
"@tanstack/solid-query-devtools": "^5.87.4",
|
|
150
151
|
"@tanstack/solid-router-devtools": "^1.131.44",
|
|
@@ -154,10 +155,13 @@ const dependencyVersionMap = {
|
|
|
154
155
|
"nitro-cloudflare-dev": "^0.2.2",
|
|
155
156
|
"@sveltejs/adapter-cloudflare": "^7.2.4",
|
|
156
157
|
"@cloudflare/workers-types": "^4.20251213.0",
|
|
157
|
-
alchemy: "^0.
|
|
158
|
+
alchemy: "^0.82.1",
|
|
158
159
|
dotenv: "^17.2.2",
|
|
159
160
|
tsdown: "^0.16.5",
|
|
160
161
|
zod: "^4.1.13",
|
|
162
|
+
"@t3-oss/env-core": "^0.13.1",
|
|
163
|
+
"@t3-oss/env-nextjs": "^0.13.1",
|
|
164
|
+
"@t3-oss/env-nuxt": "^0.13.1",
|
|
161
165
|
srvx: "0.8.15",
|
|
162
166
|
"@polar-sh/better-auth": "^1.1.3",
|
|
163
167
|
"@polar-sh/sdk": "^0.34.16"
|
|
@@ -190,6 +194,12 @@ const ADDON_COMPATIBILITY = {
|
|
|
190
194
|
none: []
|
|
191
195
|
};
|
|
192
196
|
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/types.ts
|
|
199
|
+
var types_exports = {};
|
|
200
|
+
import * as import__better_t_stack_types from "@better-t-stack/types";
|
|
201
|
+
__reExport(types_exports, import__better_t_stack_types);
|
|
202
|
+
|
|
193
203
|
//#endregion
|
|
194
204
|
//#region src/utils/compatibility.ts
|
|
195
205
|
const WEB_FRAMEWORKS = [
|
|
@@ -204,24 +214,18 @@ const WEB_FRAMEWORKS = [
|
|
|
204
214
|
|
|
205
215
|
//#endregion
|
|
206
216
|
//#region src/utils/errors.ts
|
|
207
|
-
function isProgrammatic() {
|
|
208
|
-
return process.env.BTS_PROGRAMMATIC === "1";
|
|
209
|
-
}
|
|
210
217
|
function exitWithError(message) {
|
|
211
218
|
consola.error(pc.red(message));
|
|
212
|
-
|
|
213
|
-
process.exit(1);
|
|
219
|
+
throw new Error(message);
|
|
214
220
|
}
|
|
215
221
|
function exitCancelled(message = "Operation cancelled") {
|
|
216
222
|
cancel(pc.red(message));
|
|
217
|
-
|
|
218
|
-
process.exit(0);
|
|
223
|
+
throw new Error(message);
|
|
219
224
|
}
|
|
220
225
|
function handleError(error, fallbackMessage) {
|
|
221
226
|
const message = error instanceof Error ? error.message : fallbackMessage || String(error);
|
|
222
227
|
consola.error(pc.red(message));
|
|
223
|
-
|
|
224
|
-
process.exit(1);
|
|
228
|
+
throw new Error(message);
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
//#endregion
|
|
@@ -434,7 +438,7 @@ const ADDON_GROUPS = {
|
|
|
434
438
|
};
|
|
435
439
|
async function getAddonsChoice(addons, frontends, auth) {
|
|
436
440
|
if (addons !== void 0) return addons;
|
|
437
|
-
const allAddons = AddonsSchema.options.filter((addon) => addon !== "none");
|
|
441
|
+
const allAddons = types_exports.AddonsSchema.options.filter((addon) => addon !== "none");
|
|
438
442
|
const groupedOptions = {
|
|
439
443
|
Documentation: [],
|
|
440
444
|
Linting: [],
|
|
@@ -480,7 +484,7 @@ async function getAddonsToAdd(frontend, existingAddons = [], auth) {
|
|
|
480
484
|
Other: []
|
|
481
485
|
};
|
|
482
486
|
const frontendArray = frontend || [];
|
|
483
|
-
const compatibleAddons = getCompatibleAddons(AddonsSchema.options.filter((addon) => addon !== "none"), frontendArray, existingAddons, auth);
|
|
487
|
+
const compatibleAddons = getCompatibleAddons(types_exports.AddonsSchema.options.filter((addon) => addon !== "none"), frontendArray, existingAddons, auth);
|
|
484
488
|
for (const addon of compatibleAddons) {
|
|
485
489
|
const { label, hint } = getAddonDisplay(addon);
|
|
486
490
|
const option = {
|
|
@@ -1057,8 +1061,8 @@ async function getRuntimeChoice(runtime, backend) {
|
|
|
1057
1061
|
//#endregion
|
|
1058
1062
|
//#region src/prompts/server-deploy.ts
|
|
1059
1063
|
function getDeploymentDisplay$1(deployment) {
|
|
1060
|
-
if (deployment === "
|
|
1061
|
-
label: "
|
|
1064
|
+
if (deployment === "cloudflare") return {
|
|
1065
|
+
label: "Cloudflare",
|
|
1062
1066
|
hint: "Deploy to Cloudflare Workers using Alchemy"
|
|
1063
1067
|
};
|
|
1064
1068
|
return {
|
|
@@ -1070,17 +1074,17 @@ async function getServerDeploymentChoice(deployment, runtime, backend, _webDeplo
|
|
|
1070
1074
|
if (deployment !== void 0) return deployment;
|
|
1071
1075
|
if (backend === "none" || backend === "convex") return "none";
|
|
1072
1076
|
if (backend !== "hono") return "none";
|
|
1073
|
-
if (runtime === "workers") return "
|
|
1077
|
+
if (runtime === "workers") return "cloudflare";
|
|
1074
1078
|
return "none";
|
|
1075
1079
|
}
|
|
1076
1080
|
async function getServerDeploymentToAdd(runtime, existingDeployment, backend) {
|
|
1077
1081
|
if (backend !== "hono") return "none";
|
|
1078
1082
|
const options = [];
|
|
1079
1083
|
if (runtime === "workers") {
|
|
1080
|
-
if (existingDeployment !== "
|
|
1081
|
-
const { label, hint } = getDeploymentDisplay$1("
|
|
1084
|
+
if (existingDeployment !== "cloudflare") {
|
|
1085
|
+
const { label, hint } = getDeploymentDisplay$1("cloudflare");
|
|
1082
1086
|
options.push({
|
|
1083
|
-
value: "
|
|
1087
|
+
value: "cloudflare",
|
|
1084
1088
|
label,
|
|
1085
1089
|
hint
|
|
1086
1090
|
});
|
|
@@ -1103,8 +1107,8 @@ function hasWebFrontend(frontends) {
|
|
|
1103
1107
|
return frontends.some((f) => WEB_FRAMEWORKS.includes(f));
|
|
1104
1108
|
}
|
|
1105
1109
|
function getDeploymentDisplay(deployment) {
|
|
1106
|
-
if (deployment === "
|
|
1107
|
-
label: "
|
|
1110
|
+
if (deployment === "cloudflare") return {
|
|
1111
|
+
label: "Cloudflare",
|
|
1108
1112
|
hint: "Deploy to Cloudflare Workers using Alchemy"
|
|
1109
1113
|
};
|
|
1110
1114
|
return {
|
|
@@ -1117,7 +1121,7 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
|
|
|
1117
1121
|
if (!hasWebFrontend(frontend)) return "none";
|
|
1118
1122
|
const response = await select({
|
|
1119
1123
|
message: "Select web deployment",
|
|
1120
|
-
options: ["
|
|
1124
|
+
options: ["cloudflare", "none"].map((deploy) => {
|
|
1121
1125
|
const { label, hint } = getDeploymentDisplay(deploy);
|
|
1122
1126
|
return {
|
|
1123
1127
|
value: deploy,
|
|
@@ -1133,10 +1137,10 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
|
|
|
1133
1137
|
async function getDeploymentToAdd(frontend, existingDeployment) {
|
|
1134
1138
|
if (!hasWebFrontend(frontend)) return "none";
|
|
1135
1139
|
const options = [];
|
|
1136
|
-
if (existingDeployment !== "
|
|
1137
|
-
const { label, hint } = getDeploymentDisplay("
|
|
1140
|
+
if (existingDeployment !== "cloudflare") {
|
|
1141
|
+
const { label, hint } = getDeploymentDisplay("cloudflare");
|
|
1138
1142
|
options.push({
|
|
1139
|
-
value: "
|
|
1143
|
+
value: "cloudflare",
|
|
1140
1144
|
label,
|
|
1141
1145
|
hint
|
|
1142
1146
|
});
|
|
@@ -1210,7 +1214,7 @@ function isPathWithinCwd(targetPath) {
|
|
|
1210
1214
|
}
|
|
1211
1215
|
function validateDirectoryName(name) {
|
|
1212
1216
|
if (name === ".") return void 0;
|
|
1213
|
-
const result = ProjectNameSchema.safeParse(name);
|
|
1217
|
+
const result = types_exports.ProjectNameSchema.safeParse(name);
|
|
1214
1218
|
if (!result.success) return result.error.issues[0]?.message || "Invalid project name";
|
|
1215
1219
|
}
|
|
1216
1220
|
async function getProjectName(initialName) {
|
|
@@ -1770,7 +1774,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1770
1774
|
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
1771
1775
|
validateWorkersCompatibility(providedFlags, options, config);
|
|
1772
1776
|
if (config.runtime === "workers" && config.serverDeploy === "none") exitWithError("Cloudflare Workers runtime requires a server deployment. Please choose 'alchemy' for --server-deploy.");
|
|
1773
|
-
if (providedFlags.has("serverDeploy") && config.serverDeploy === "
|
|
1777
|
+
if (providedFlags.has("serverDeploy") && config.serverDeploy === "cloudflare" && config.runtime !== "workers") exitWithError(`Server deployment '${config.serverDeploy}' requires '--runtime workers'. Please use '--runtime workers' or choose a different server deployment.`);
|
|
1774
1778
|
if (config.addons && config.addons.length > 0) {
|
|
1775
1779
|
validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth);
|
|
1776
1780
|
config.addons = [...new Set(config.addons)];
|
|
@@ -1795,11 +1799,11 @@ function validateConfigForProgrammaticUse(config) {
|
|
|
1795
1799
|
//#endregion
|
|
1796
1800
|
//#region src/utils/project-name-validation.ts
|
|
1797
1801
|
function validateProjectName(name) {
|
|
1798
|
-
const result = ProjectNameSchema.safeParse(name);
|
|
1802
|
+
const result = types_exports.ProjectNameSchema.safeParse(name);
|
|
1799
1803
|
if (!result.success) exitWithError(`Invalid project name: ${result.error.issues[0]?.message || "Invalid project name"}`);
|
|
1800
1804
|
}
|
|
1801
1805
|
function validateProjectNameThrow(name) {
|
|
1802
|
-
const result = ProjectNameSchema.safeParse(name);
|
|
1806
|
+
const result = types_exports.ProjectNameSchema.safeParse(name);
|
|
1803
1807
|
if (!result.success) throw new Error(`Invalid project name: ${result.error.issues[0]?.message}`);
|
|
1804
1808
|
}
|
|
1805
1809
|
function extractAndValidateProjectName(projectName, projectDirectory, throwOnError = false) {
|
|
@@ -1997,6 +2001,45 @@ function getPackageExecutionCommand(packageManager, commandWithArgs) {
|
|
|
1997
2001
|
default: return `npx ${commandWithArgs}`;
|
|
1998
2002
|
}
|
|
1999
2003
|
}
|
|
2004
|
+
/**
|
|
2005
|
+
* Returns the command and arguments as an array for use with execa's $ template syntax.
|
|
2006
|
+
* This avoids the need for shell: true and provides better escaping.
|
|
2007
|
+
*
|
|
2008
|
+
* @param packageManager - The selected package manager (e.g., 'npm', 'yarn', 'pnpm', 'bun').
|
|
2009
|
+
* @param commandWithArgs - The command to run, including arguments (e.g., "prisma generate").
|
|
2010
|
+
* @returns An array of [command, ...args] (e.g., ["npx", "prisma", "generate"]).
|
|
2011
|
+
*/
|
|
2012
|
+
function getPackageExecutionArgs(packageManager, commandWithArgs) {
|
|
2013
|
+
const args = commandWithArgs.split(" ");
|
|
2014
|
+
switch (packageManager) {
|
|
2015
|
+
case "pnpm": return [
|
|
2016
|
+
"pnpm",
|
|
2017
|
+
"dlx",
|
|
2018
|
+
...args
|
|
2019
|
+
];
|
|
2020
|
+
case "bun": return ["bunx", ...args];
|
|
2021
|
+
default: return ["npx", ...args];
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
/**
|
|
2025
|
+
* Returns just the runner prefix as an array, for when you already have args built.
|
|
2026
|
+
* Use this when you have complex arguments that shouldn't be split by spaces.
|
|
2027
|
+
*
|
|
2028
|
+
* @param packageManager - The selected package manager.
|
|
2029
|
+
* @returns The runner prefix as an array (e.g., ["npx"] or ["pnpm", "dlx"]).
|
|
2030
|
+
*
|
|
2031
|
+
* @example
|
|
2032
|
+
* const prefix = getPackageRunnerPrefix("bun");
|
|
2033
|
+
* const args = ["@tauri-apps/cli@latest", "init", "--app-name=foo"];
|
|
2034
|
+
* await $`${[...prefix, ...args]}`;
|
|
2035
|
+
*/
|
|
2036
|
+
function getPackageRunnerPrefix(packageManager) {
|
|
2037
|
+
switch (packageManager) {
|
|
2038
|
+
case "pnpm": return ["pnpm", "dlx"];
|
|
2039
|
+
case "bun": return ["bunx"];
|
|
2040
|
+
default: return ["npx"];
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2000
2043
|
|
|
2001
2044
|
//#endregion
|
|
2002
2045
|
//#region src/helpers/addons/fumadocs-setup.ts
|
|
@@ -2041,16 +2084,15 @@ async function setupFumadocs(config) {
|
|
|
2041
2084
|
initialValue: "next-mdx"
|
|
2042
2085
|
});
|
|
2043
2086
|
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
2044
|
-
const
|
|
2087
|
+
const args = getPackageExecutionArgs(packageManager, `create-fumadocs-app@latest fumadocs --template ${TEMPLATES$2[template].value} --src --pm ${packageManager} --no-git`);
|
|
2045
2088
|
const appsDir = path.join(projectDir, "apps");
|
|
2046
2089
|
await fs.ensureDir(appsDir);
|
|
2047
2090
|
const s = spinner();
|
|
2048
2091
|
s.start("Running Fumadocs create command...");
|
|
2049
|
-
await
|
|
2092
|
+
await $({
|
|
2050
2093
|
cwd: appsDir,
|
|
2051
|
-
env: { CI: "true" }
|
|
2052
|
-
|
|
2053
|
-
});
|
|
2094
|
+
env: { CI: "true" }
|
|
2095
|
+
})`${args}`;
|
|
2054
2096
|
const fumadocsDir = path.join(projectDir, "apps", "fumadocs");
|
|
2055
2097
|
const packageJsonPath = path.join(fumadocsDir, "package.json");
|
|
2056
2098
|
if (await fs.pathExists(packageJsonPath)) {
|
|
@@ -2083,18 +2125,17 @@ async function setupOxlint(projectDir, packageManager) {
|
|
|
2083
2125
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
2084
2126
|
}
|
|
2085
2127
|
const s = spinner();
|
|
2086
|
-
const
|
|
2128
|
+
const oxlintArgs = getPackageExecutionArgs(packageManager, "oxlint@latest --init");
|
|
2087
2129
|
s.start("Initializing oxlint and oxfmt...");
|
|
2088
|
-
await
|
|
2130
|
+
await $({
|
|
2089
2131
|
cwd: projectDir,
|
|
2090
|
-
env: { CI: "true" }
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
await
|
|
2132
|
+
env: { CI: "true" }
|
|
2133
|
+
})`${oxlintArgs}`;
|
|
2134
|
+
const oxfmtArgs = getPackageExecutionArgs(packageManager, "oxfmt@latest --init");
|
|
2135
|
+
await $({
|
|
2094
2136
|
cwd: projectDir,
|
|
2095
|
-
env: { CI: "true" }
|
|
2096
|
-
|
|
2097
|
-
});
|
|
2137
|
+
env: { CI: "true" }
|
|
2138
|
+
})`${oxfmtArgs}`;
|
|
2098
2139
|
s.stop("oxlint and oxfmt initialized successfully!");
|
|
2099
2140
|
}
|
|
2100
2141
|
|
|
@@ -2159,11 +2200,11 @@ async function setupRuler(config) {
|
|
|
2159
2200
|
const s = spinner();
|
|
2160
2201
|
s.start("Applying rules with Ruler...");
|
|
2161
2202
|
try {
|
|
2162
|
-
|
|
2203
|
+
const rulerApplyArgs = getPackageExecutionArgs(packageManager, `@intellectronica/ruler@latest apply --agents ${selectedEditors.join(",")} --local-only`);
|
|
2204
|
+
await $({
|
|
2163
2205
|
cwd: projectDir,
|
|
2164
|
-
env: { CI: "true" }
|
|
2165
|
-
|
|
2166
|
-
});
|
|
2206
|
+
env: { CI: "true" }
|
|
2207
|
+
})`${rulerApplyArgs}`;
|
|
2167
2208
|
s.stop("Applied rules with Ruler");
|
|
2168
2209
|
} catch {
|
|
2169
2210
|
s.stop(pc.red("Failed to apply rules"));
|
|
@@ -2193,7 +2234,7 @@ async function setupStarlight(config) {
|
|
|
2193
2234
|
const s = spinner();
|
|
2194
2235
|
try {
|
|
2195
2236
|
s.start("Setting up Starlight docs...");
|
|
2196
|
-
const
|
|
2237
|
+
const args = getPackageExecutionArgs(packageManager, `create-astro@latest ${[
|
|
2197
2238
|
"docs",
|
|
2198
2239
|
"--template",
|
|
2199
2240
|
"starlight",
|
|
@@ -2205,11 +2246,10 @@ async function setupStarlight(config) {
|
|
|
2205
2246
|
].join(" ")}`);
|
|
2206
2247
|
const appsDir = path.join(projectDir, "apps");
|
|
2207
2248
|
await fs.ensureDir(appsDir);
|
|
2208
|
-
await
|
|
2249
|
+
await $({
|
|
2209
2250
|
cwd: appsDir,
|
|
2210
|
-
env: { CI: "true" }
|
|
2211
|
-
|
|
2212
|
-
});
|
|
2251
|
+
env: { CI: "true" }
|
|
2252
|
+
})`${args}`;
|
|
2213
2253
|
s.stop("Starlight docs setup successfully!");
|
|
2214
2254
|
} catch (error) {
|
|
2215
2255
|
s.stop(pc.red("Failed to set up Starlight docs"));
|
|
@@ -2249,19 +2289,21 @@ async function setupTauri(config) {
|
|
|
2249
2289
|
const hasNext = frontend.includes("next");
|
|
2250
2290
|
const devUrl = hasReactRouter || hasSvelte ? "http://localhost:5173" : hasNext ? "http://localhost:3001" : "http://localhost:3001";
|
|
2251
2291
|
const frontendDist = hasNuxt ? "../.output/public" : hasSvelte ? "../build" : hasNext ? "../.next" : hasReactRouter ? "../build/client" : "../dist";
|
|
2252
|
-
|
|
2292
|
+
const tauriArgs = [
|
|
2293
|
+
"@tauri-apps/cli@latest",
|
|
2253
2294
|
"init",
|
|
2254
2295
|
`--app-name=${path.basename(projectDir)}`,
|
|
2255
2296
|
`--window-title=${path.basename(projectDir)}`,
|
|
2256
2297
|
`--frontend-dist=${frontendDist}`,
|
|
2257
2298
|
`--dev-url=${devUrl}`,
|
|
2258
|
-
`--before-dev-command
|
|
2259
|
-
`--before-build-command
|
|
2260
|
-
]
|
|
2299
|
+
`--before-dev-command=${packageManager} run dev`,
|
|
2300
|
+
`--before-build-command=${packageManager} run build`
|
|
2301
|
+
];
|
|
2302
|
+
const prefix = getPackageRunnerPrefix(packageManager);
|
|
2303
|
+
await $({
|
|
2261
2304
|
cwd: clientPackageDir,
|
|
2262
|
-
env: { CI: "true" }
|
|
2263
|
-
|
|
2264
|
-
});
|
|
2305
|
+
env: { CI: "true" }
|
|
2306
|
+
})`${[...prefix, ...tauriArgs]}`;
|
|
2265
2307
|
s.stop("Tauri desktop app support configured successfully!");
|
|
2266
2308
|
} catch (error) {
|
|
2267
2309
|
s.stop(pc.red("Failed to set up Tauri"));
|
|
@@ -2299,16 +2341,15 @@ async function setupTui(config) {
|
|
|
2299
2341
|
initialValue: "core"
|
|
2300
2342
|
});
|
|
2301
2343
|
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
2302
|
-
const
|
|
2344
|
+
const args = getPackageExecutionArgs(packageManager, `create-tui@latest --template ${template} --no-git --no-install tui`);
|
|
2303
2345
|
const appsDir = path.join(projectDir, "apps");
|
|
2304
2346
|
await fs.ensureDir(appsDir);
|
|
2305
2347
|
const s = spinner();
|
|
2306
2348
|
s.start("Running OpenTUI create command...");
|
|
2307
|
-
await
|
|
2349
|
+
await $({
|
|
2308
2350
|
cwd: appsDir,
|
|
2309
|
-
env: { CI: "true" }
|
|
2310
|
-
|
|
2311
|
-
});
|
|
2351
|
+
env: { CI: "true" }
|
|
2352
|
+
})`${args}`;
|
|
2312
2353
|
s.stop("OpenTUI setup complete!");
|
|
2313
2354
|
} catch (error) {
|
|
2314
2355
|
log.error(pc.red("Failed to set up OpenTUI"));
|
|
@@ -2409,14 +2450,13 @@ async function setupUltracite(config, hasHusky) {
|
|
|
2409
2450
|
if (agents.length > 0) ultraciteArgs.push("--agents", ...agents);
|
|
2410
2451
|
if (hooks.length > 0) ultraciteArgs.push("--hooks", ...hooks);
|
|
2411
2452
|
if (hasHusky) ultraciteArgs.push("--integrations", "husky", "lint-staged");
|
|
2412
|
-
const
|
|
2453
|
+
const args = getPackageExecutionArgs(packageManager, `ultracite@latest ${ultraciteArgs.join(" ")} --skip-install`);
|
|
2413
2454
|
const s = spinner();
|
|
2414
2455
|
s.start("Running Ultracite init command...");
|
|
2415
|
-
await
|
|
2456
|
+
await $({
|
|
2416
2457
|
cwd: projectDir,
|
|
2417
|
-
env: { CI: "true" }
|
|
2418
|
-
|
|
2419
|
-
});
|
|
2458
|
+
env: { CI: "true" }
|
|
2459
|
+
})`${args}`;
|
|
2420
2460
|
if (hasHusky) await addPackageDependency({
|
|
2421
2461
|
devDependencies: ["husky", "lint-staged"],
|
|
2422
2462
|
projectDir
|
|
@@ -2428,6 +2468,54 @@ async function setupUltracite(config, hasHusky) {
|
|
|
2428
2468
|
}
|
|
2429
2469
|
}
|
|
2430
2470
|
|
|
2471
|
+
//#endregion
|
|
2472
|
+
//#region src/utils/ts-morph.ts
|
|
2473
|
+
const tsProject = new Project({
|
|
2474
|
+
useInMemoryFileSystem: false,
|
|
2475
|
+
skipAddingFilesFromTsConfig: true,
|
|
2476
|
+
manipulationSettings: {
|
|
2477
|
+
quoteKind: QuoteKind.Single,
|
|
2478
|
+
indentationText: IndentationText.TwoSpaces
|
|
2479
|
+
}
|
|
2480
|
+
});
|
|
2481
|
+
function ensureArrayProperty(obj, name) {
|
|
2482
|
+
return obj.getProperty(name)?.getFirstDescendantByKind(SyntaxKind.ArrayLiteralExpression) ?? obj.addPropertyAssignment({
|
|
2483
|
+
name,
|
|
2484
|
+
initializer: "[]"
|
|
2485
|
+
}).getFirstDescendantByKindOrThrow(SyntaxKind.ArrayLiteralExpression);
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
//#endregion
|
|
2489
|
+
//#region src/helpers/addons/vite-pwa-setup.ts
|
|
2490
|
+
async function addPwaToViteConfig(viteConfigPath, projectName) {
|
|
2491
|
+
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
|
|
2492
|
+
if (!sourceFile) throw new Error("vite config not found");
|
|
2493
|
+
if (!sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === "vite-plugin-pwa")) sourceFile.insertImportDeclaration(0, {
|
|
2494
|
+
namedImports: ["VitePWA"],
|
|
2495
|
+
moduleSpecifier: "vite-plugin-pwa"
|
|
2496
|
+
});
|
|
2497
|
+
const defineCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((expr) => {
|
|
2498
|
+
const expression = expr.getExpression();
|
|
2499
|
+
return Node.isIdentifier(expression) && expression.getText() === "defineConfig";
|
|
2500
|
+
});
|
|
2501
|
+
if (!defineCall) throw new Error("Could not find defineConfig call in vite config");
|
|
2502
|
+
const configObject = defineCall.getArguments()[0];
|
|
2503
|
+
if (!configObject) throw new Error("defineConfig argument is not an object literal");
|
|
2504
|
+
const pluginsArray = ensureArrayProperty(configObject, "plugins");
|
|
2505
|
+
if (!pluginsArray.getElements().some((el) => el.getText().startsWith("VitePWA("))) pluginsArray.addElement(`VitePWA({
|
|
2506
|
+
registerType: "autoUpdate",
|
|
2507
|
+
manifest: {
|
|
2508
|
+
name: "${projectName}",
|
|
2509
|
+
short_name: "${projectName}",
|
|
2510
|
+
description: "${projectName} - PWA Application",
|
|
2511
|
+
theme_color: "#0c0c0c",
|
|
2512
|
+
},
|
|
2513
|
+
pwaAssets: { disabled: false, config: true },
|
|
2514
|
+
devOptions: { enabled: true },
|
|
2515
|
+
})`);
|
|
2516
|
+
await tsProject.save();
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2431
2519
|
//#endregion
|
|
2432
2520
|
//#region src/helpers/addons/wxt-setup.ts
|
|
2433
2521
|
const TEMPLATES = {
|
|
@@ -2466,16 +2554,15 @@ async function setupWxt(config) {
|
|
|
2466
2554
|
initialValue: "react"
|
|
2467
2555
|
});
|
|
2468
2556
|
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
2469
|
-
const
|
|
2557
|
+
const args = getPackageExecutionArgs(packageManager, `wxt@latest init extension --template ${template} --pm ${packageManager}`);
|
|
2470
2558
|
const appsDir = path.join(projectDir, "apps");
|
|
2471
2559
|
await fs.ensureDir(appsDir);
|
|
2472
2560
|
const s = spinner();
|
|
2473
2561
|
s.start("Running WXT init command...");
|
|
2474
|
-
await
|
|
2562
|
+
await $({
|
|
2475
2563
|
cwd: appsDir,
|
|
2476
|
-
env: { CI: "true" }
|
|
2477
|
-
|
|
2478
|
-
});
|
|
2564
|
+
env: { CI: "true" }
|
|
2565
|
+
})`${args}`;
|
|
2479
2566
|
const extensionDir = path.join(projectDir, "apps", "extension");
|
|
2480
2567
|
const packageJsonPath = path.join(extensionDir, "package.json");
|
|
2481
2568
|
if (await fs.pathExists(packageJsonPath)) {
|
|
@@ -2491,54 +2578,6 @@ async function setupWxt(config) {
|
|
|
2491
2578
|
}
|
|
2492
2579
|
}
|
|
2493
2580
|
|
|
2494
|
-
//#endregion
|
|
2495
|
-
//#region src/utils/ts-morph.ts
|
|
2496
|
-
const tsProject$1 = new Project({
|
|
2497
|
-
useInMemoryFileSystem: false,
|
|
2498
|
-
skipAddingFilesFromTsConfig: true,
|
|
2499
|
-
manipulationSettings: {
|
|
2500
|
-
quoteKind: QuoteKind.Single,
|
|
2501
|
-
indentationText: IndentationText.TwoSpaces
|
|
2502
|
-
}
|
|
2503
|
-
});
|
|
2504
|
-
function ensureArrayProperty(obj, name) {
|
|
2505
|
-
return obj.getProperty(name)?.getFirstDescendantByKind(SyntaxKind.ArrayLiteralExpression) ?? obj.addPropertyAssignment({
|
|
2506
|
-
name,
|
|
2507
|
-
initializer: "[]"
|
|
2508
|
-
}).getFirstDescendantByKindOrThrow(SyntaxKind.ArrayLiteralExpression);
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
//#endregion
|
|
2512
|
-
//#region src/helpers/addons/vite-pwa-setup.ts
|
|
2513
|
-
async function addPwaToViteConfig(viteConfigPath, projectName) {
|
|
2514
|
-
const sourceFile = tsProject$1.addSourceFileAtPathIfExists(viteConfigPath);
|
|
2515
|
-
if (!sourceFile) throw new Error("vite config not found");
|
|
2516
|
-
if (!sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === "vite-plugin-pwa")) sourceFile.insertImportDeclaration(0, {
|
|
2517
|
-
namedImports: ["VitePWA"],
|
|
2518
|
-
moduleSpecifier: "vite-plugin-pwa"
|
|
2519
|
-
});
|
|
2520
|
-
const defineCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((expr) => {
|
|
2521
|
-
const expression = expr.getExpression();
|
|
2522
|
-
return Node.isIdentifier(expression) && expression.getText() === "defineConfig";
|
|
2523
|
-
});
|
|
2524
|
-
if (!defineCall) throw new Error("Could not find defineConfig call in vite config");
|
|
2525
|
-
const configObject = defineCall.getArguments()[0];
|
|
2526
|
-
if (!configObject) throw new Error("defineConfig argument is not an object literal");
|
|
2527
|
-
const pluginsArray = ensureArrayProperty(configObject, "plugins");
|
|
2528
|
-
if (!pluginsArray.getElements().some((el) => el.getText().startsWith("VitePWA("))) pluginsArray.addElement(`VitePWA({
|
|
2529
|
-
registerType: "autoUpdate",
|
|
2530
|
-
manifest: {
|
|
2531
|
-
name: "${projectName}",
|
|
2532
|
-
short_name: "${projectName}",
|
|
2533
|
-
description: "${projectName} - PWA Application",
|
|
2534
|
-
theme_color: "#0c0c0c",
|
|
2535
|
-
},
|
|
2536
|
-
pwaAssets: { disabled: false, config: true },
|
|
2537
|
-
devOptions: { enabled: true },
|
|
2538
|
-
})`);
|
|
2539
|
-
await tsProject$1.save();
|
|
2540
|
-
}
|
|
2541
|
-
|
|
2542
2581
|
//#endregion
|
|
2543
2582
|
//#region src/helpers/addons/addons-setup.ts
|
|
2544
2583
|
async function setupAddons(config, isAddCommand = false) {
|
|
@@ -2767,38 +2806,6 @@ handlebars.registerHelper("or", (...args) => {
|
|
|
2767
2806
|
});
|
|
2768
2807
|
handlebars.registerHelper("includes", (array, value) => Array.isArray(array) && array.includes(value));
|
|
2769
2808
|
|
|
2770
|
-
//#endregion
|
|
2771
|
-
//#region src/helpers/deployment/alchemy/env-dts-setup.ts
|
|
2772
|
-
const tsProject = new Project({
|
|
2773
|
-
useInMemoryFileSystem: false,
|
|
2774
|
-
skipAddingFilesFromTsConfig: true
|
|
2775
|
-
});
|
|
2776
|
-
function determineImportPath(envDtsPath, projectDir, config) {
|
|
2777
|
-
const { webDeploy, serverDeploy, backend } = config;
|
|
2778
|
-
const isBackendSelf = backend === "self";
|
|
2779
|
-
let alchemyRunPath;
|
|
2780
|
-
if (webDeploy === "alchemy" && (serverDeploy === "alchemy" || isBackendSelf)) if (isBackendSelf) alchemyRunPath = path.join(projectDir, "apps/web/alchemy.run.ts");
|
|
2781
|
-
else alchemyRunPath = path.join(projectDir, "alchemy.run.ts");
|
|
2782
|
-
else if (webDeploy === "alchemy") alchemyRunPath = path.join(projectDir, "apps/web/alchemy.run.ts");
|
|
2783
|
-
else if (serverDeploy === "alchemy") alchemyRunPath = path.join(projectDir, "apps/server/alchemy.run.ts");
|
|
2784
|
-
else alchemyRunPath = path.join(projectDir, "alchemy.run.ts");
|
|
2785
|
-
const relativePath = path.relative(path.dirname(envDtsPath), alchemyRunPath.replace(/\.ts$/, ""));
|
|
2786
|
-
return (relativePath.startsWith(".") ? relativePath : `./${relativePath}`).replace(/\\/g, "/");
|
|
2787
|
-
}
|
|
2788
|
-
async function setupEnvDtsImport(envDtsPath, projectDir, config) {
|
|
2789
|
-
if (!await fs.pathExists(envDtsPath)) return;
|
|
2790
|
-
const importPath = determineImportPath(envDtsPath, projectDir, config);
|
|
2791
|
-
const sourceFile = tsProject.addSourceFileAtPath(envDtsPath);
|
|
2792
|
-
if (!sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === importPath && imp.getNamedImports().some((named) => named.getName() === "server"))) sourceFile.insertImportDeclaration(0, {
|
|
2793
|
-
moduleSpecifier: importPath,
|
|
2794
|
-
namedImports: [{
|
|
2795
|
-
name: "server",
|
|
2796
|
-
isTypeOnly: true
|
|
2797
|
-
}]
|
|
2798
|
-
});
|
|
2799
|
-
await sourceFile.save();
|
|
2800
|
-
}
|
|
2801
|
-
|
|
2802
2809
|
//#endregion
|
|
2803
2810
|
//#region src/helpers/core/template-manager.ts
|
|
2804
2811
|
async function processAndCopyFiles(sourcePattern, baseSourceDir, destDir, context, overwrite = true, ignorePatterns) {
|
|
@@ -2903,7 +2910,7 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2903
2910
|
}
|
|
2904
2911
|
}
|
|
2905
2912
|
}
|
|
2906
|
-
async function setupApiPackage(projectDir, context) {
|
|
2913
|
+
async function setupApiPackage$1(projectDir, context) {
|
|
2907
2914
|
if (context.api === "none") return;
|
|
2908
2915
|
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
2909
2916
|
await fs.ensureDir(apiPackageDir);
|
|
@@ -2916,7 +2923,7 @@ async function setupConfigPackage(projectDir, context) {
|
|
|
2916
2923
|
const configBaseDir = path.join(PKG_ROOT, "templates/packages/config");
|
|
2917
2924
|
if (await fs.pathExists(configBaseDir)) await processAndCopyFiles("**/*", configBaseDir, configPackageDir, context);
|
|
2918
2925
|
}
|
|
2919
|
-
async function setupDbPackage(projectDir, context) {
|
|
2926
|
+
async function setupDbPackage$1(projectDir, context) {
|
|
2920
2927
|
if (context.database === "none" || context.orm === "none") return;
|
|
2921
2928
|
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2922
2929
|
await fs.ensureDir(dbPackageDir);
|
|
@@ -2943,21 +2950,78 @@ async function setupServerApp(projectDir, context) {
|
|
|
2943
2950
|
const frameworkSrcDir = path.join(PKG_ROOT, `templates/backend/server/${context.backend}`);
|
|
2944
2951
|
if (await fs.pathExists(frameworkSrcDir)) await processAndCopyFiles("**/*", frameworkSrcDir, serverAppDir, context, true);
|
|
2945
2952
|
}
|
|
2953
|
+
async function setupEnvPackage$1(projectDir, context) {
|
|
2954
|
+
const hasWebFrontend$1 = context.frontend.some((f) => [
|
|
2955
|
+
"tanstack-router",
|
|
2956
|
+
"react-router",
|
|
2957
|
+
"tanstack-start",
|
|
2958
|
+
"next",
|
|
2959
|
+
"nuxt",
|
|
2960
|
+
"svelte",
|
|
2961
|
+
"solid"
|
|
2962
|
+
].includes(f));
|
|
2963
|
+
const hasNative = context.frontend.some((f) => [
|
|
2964
|
+
"native-bare",
|
|
2965
|
+
"native-uniwind",
|
|
2966
|
+
"native-unistyles"
|
|
2967
|
+
].includes(f));
|
|
2968
|
+
if (!hasWebFrontend$1 && !hasNative && context.backend === "none") return;
|
|
2969
|
+
const envPackageDir = path.join(projectDir, "packages/env");
|
|
2970
|
+
await fs.ensureDir(envPackageDir);
|
|
2971
|
+
const envBaseDir = path.join(PKG_ROOT, "templates/packages/env");
|
|
2972
|
+
const packageJsonSrc = path.join(envBaseDir, "package.json.hbs");
|
|
2973
|
+
if (await fs.pathExists(packageJsonSrc)) await processAndCopyFiles("package.json.hbs", envBaseDir, envPackageDir, context);
|
|
2974
|
+
const tsconfigSrc = path.join(envBaseDir, "tsconfig.json.hbs");
|
|
2975
|
+
if (await fs.pathExists(tsconfigSrc)) await processAndCopyFiles("tsconfig.json.hbs", envBaseDir, envPackageDir, context);
|
|
2976
|
+
const needsServerEnv = context.backend !== "none" && context.backend !== "convex";
|
|
2977
|
+
if (needsServerEnv) {
|
|
2978
|
+
const serverSrc = path.join(envBaseDir, "src/server.ts.hbs");
|
|
2979
|
+
if (await fs.pathExists(serverSrc)) {
|
|
2980
|
+
await fs.ensureDir(path.join(envPackageDir, "src"));
|
|
2981
|
+
await processAndCopyFiles("src/server.ts.hbs", envBaseDir, envPackageDir, context);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
if (hasWebFrontend$1) {
|
|
2985
|
+
const webSrc = path.join(envBaseDir, "src/web.ts.hbs");
|
|
2986
|
+
if (await fs.pathExists(webSrc)) {
|
|
2987
|
+
await fs.ensureDir(path.join(envPackageDir, "src"));
|
|
2988
|
+
await processAndCopyFiles("src/web.ts.hbs", envBaseDir, envPackageDir, context);
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
if (hasNative) {
|
|
2992
|
+
const nativeSrc = path.join(envBaseDir, "src/native.ts.hbs");
|
|
2993
|
+
if (await fs.pathExists(nativeSrc)) {
|
|
2994
|
+
await fs.ensureDir(path.join(envPackageDir, "src"));
|
|
2995
|
+
await processAndCopyFiles("src/native.ts.hbs", envBaseDir, envPackageDir, context);
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
const packageJsonPath = path.join(envPackageDir, "package.json");
|
|
2999
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
3000
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
3001
|
+
const exports = {};
|
|
3002
|
+
if (needsServerEnv) exports["./server"] = "./src/server.ts";
|
|
3003
|
+
if (hasWebFrontend$1) exports["./web"] = "./src/web.ts";
|
|
3004
|
+
if (hasNative) exports["./native"] = "./src/native.ts";
|
|
3005
|
+
packageJson.exports = exports;
|
|
3006
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
2946
3009
|
async function setupBackendFramework(projectDir, context) {
|
|
2947
3010
|
await setupConfigPackage(projectDir, context);
|
|
3011
|
+
await setupEnvPackage$1(projectDir, context);
|
|
2948
3012
|
if (context.backend === "none") return;
|
|
2949
3013
|
if (context.backend === "convex") {
|
|
2950
3014
|
await setupConvexBackend(projectDir, context);
|
|
2951
3015
|
return;
|
|
2952
3016
|
}
|
|
2953
3017
|
if (context.backend === "self") {
|
|
2954
|
-
await setupApiPackage(projectDir, context);
|
|
2955
|
-
await setupDbPackage(projectDir, context);
|
|
3018
|
+
await setupApiPackage$1(projectDir, context);
|
|
3019
|
+
await setupDbPackage$1(projectDir, context);
|
|
2956
3020
|
return;
|
|
2957
3021
|
}
|
|
2958
3022
|
await setupServerApp(projectDir, context);
|
|
2959
|
-
await setupApiPackage(projectDir, context);
|
|
2960
|
-
await setupDbPackage(projectDir, context);
|
|
3023
|
+
await setupApiPackage$1(projectDir, context);
|
|
3024
|
+
await setupDbPackage$1(projectDir, context);
|
|
2961
3025
|
}
|
|
2962
3026
|
async function setupAuthTemplate(projectDir, context) {
|
|
2963
3027
|
if (!context.auth || context.auth === "none") return;
|
|
@@ -3286,35 +3350,22 @@ async function setupDockerComposeTemplates(projectDir, context) {
|
|
|
3286
3350
|
}
|
|
3287
3351
|
async function setupDeploymentTemplates(projectDir, context) {
|
|
3288
3352
|
const isBackendSelf = context.backend === "self";
|
|
3289
|
-
if (context.webDeploy === "
|
|
3290
|
-
const
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
if (!isBackendSelf) await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
|
|
3303
|
-
}
|
|
3304
|
-
}
|
|
3305
|
-
if (context.serverDeploy === "alchemy" && !isBackendSelf) {
|
|
3306
|
-
const serverAppDir = path.join(projectDir, "apps/server");
|
|
3307
|
-
if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(serverAppDir)) {
|
|
3308
|
-
await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
3309
|
-
const envDtsPath = path.join(serverAppDir, "env.d.ts");
|
|
3310
|
-
await processTemplate(path.join(alchemyTemplateSrc, "env.d.ts.hbs"), envDtsPath, context);
|
|
3311
|
-
await setupEnvDtsImport(envDtsPath, projectDir, context);
|
|
3312
|
-
await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
|
|
3313
|
-
}
|
|
3314
|
-
}
|
|
3353
|
+
if (context.webDeploy === "cloudflare" || context.serverDeploy === "cloudflare") {
|
|
3354
|
+
const infraTemplateSrc = path.join(PKG_ROOT, "templates/packages/infra");
|
|
3355
|
+
const infraDir = path.join(projectDir, "packages/infra");
|
|
3356
|
+
if (await fs.pathExists(infraTemplateSrc)) {
|
|
3357
|
+
await fs.ensureDir(infraDir);
|
|
3358
|
+
await processAndCopyFiles("package.json.hbs", infraTemplateSrc, infraDir, context);
|
|
3359
|
+
await processAndCopyFiles("alchemy.run.ts.hbs", infraTemplateSrc, infraDir, context);
|
|
3360
|
+
}
|
|
3361
|
+
if (!isBackendSelf) {
|
|
3362
|
+
const envTemplateSrc = path.join(PKG_ROOT, "templates/packages/env");
|
|
3363
|
+
const envDir = path.join(projectDir, "packages/env");
|
|
3364
|
+
const envDtsTemplatePath = path.join(envTemplateSrc, "env.d.ts.hbs");
|
|
3365
|
+
if (await fs.pathExists(envDtsTemplatePath)) await processTemplate(envDtsTemplatePath, path.join(envDir, "env.d.ts"), context);
|
|
3315
3366
|
}
|
|
3316
3367
|
}
|
|
3317
|
-
if (context.webDeploy !== "none" && context.webDeploy !== "
|
|
3368
|
+
if (context.webDeploy !== "none" && context.webDeploy !== "cloudflare") {
|
|
3318
3369
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3319
3370
|
if (await fs.pathExists(webAppDir)) {
|
|
3320
3371
|
const frontends = context.frontend;
|
|
@@ -3333,7 +3384,7 @@ async function setupDeploymentTemplates(projectDir, context) {
|
|
|
3333
3384
|
}
|
|
3334
3385
|
}
|
|
3335
3386
|
}
|
|
3336
|
-
if (context.serverDeploy !== "none" && context.serverDeploy !== "
|
|
3387
|
+
if (context.serverDeploy !== "none" && context.serverDeploy !== "cloudflare" && !isBackendSelf) {
|
|
3337
3388
|
const serverAppDir = path.join(projectDir, "apps/server");
|
|
3338
3389
|
if (await fs.pathExists(serverAppDir)) {
|
|
3339
3390
|
const deployTemplateSrc = path.join(PKG_ROOT, `templates/deploy/${context.serverDeploy}/server`);
|
|
@@ -3341,26 +3392,6 @@ async function setupDeploymentTemplates(projectDir, context) {
|
|
|
3341
3392
|
}
|
|
3342
3393
|
}
|
|
3343
3394
|
}
|
|
3344
|
-
async function addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc) {
|
|
3345
|
-
for (const packageName of [
|
|
3346
|
-
"packages/api",
|
|
3347
|
-
"packages/auth",
|
|
3348
|
-
"packages/db"
|
|
3349
|
-
]) {
|
|
3350
|
-
const packageDir = path.join(projectDir, packageName);
|
|
3351
|
-
if (await fs.pathExists(packageDir)) {
|
|
3352
|
-
const envDtsPath = path.join(packageDir, "env.d.ts");
|
|
3353
|
-
await processTemplate(path.join(alchemyTemplateSrc, "env.d.ts.hbs"), envDtsPath, context);
|
|
3354
|
-
await setupEnvDtsImport(envDtsPath, projectDir, context);
|
|
3355
|
-
}
|
|
3356
|
-
}
|
|
3357
|
-
const serverAppDir = path.join(projectDir, "apps/server");
|
|
3358
|
-
if (await fs.pathExists(serverAppDir)) {
|
|
3359
|
-
const envDtsPath = path.join(serverAppDir, "env.d.ts");
|
|
3360
|
-
await processTemplate(path.join(alchemyTemplateSrc, "env.d.ts.hbs"), envDtsPath, context);
|
|
3361
|
-
await setupEnvDtsImport(envDtsPath, projectDir, context);
|
|
3362
|
-
}
|
|
3363
|
-
}
|
|
3364
3395
|
|
|
3365
3396
|
//#endregion
|
|
3366
3397
|
//#region src/helpers/core/add-addons.ts
|
|
@@ -3409,50 +3440,9 @@ async function addAddonsToProject(input) {
|
|
|
3409
3440
|
}
|
|
3410
3441
|
}
|
|
3411
3442
|
|
|
3412
|
-
//#endregion
|
|
3413
|
-
//#region src/helpers/deployment/server-deploy-setup.ts
|
|
3414
|
-
async function setupServerDeploy(config) {
|
|
3415
|
-
const { serverDeploy, webDeploy, projectDir } = config;
|
|
3416
|
-
if (serverDeploy === "none") return;
|
|
3417
|
-
if (serverDeploy === "alchemy" && webDeploy === "alchemy") return;
|
|
3418
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
3419
|
-
if (!await fs.pathExists(serverDir)) return;
|
|
3420
|
-
if (serverDeploy === "alchemy") await setupAlchemyServerDeploy(serverDir, projectDir);
|
|
3421
|
-
}
|
|
3422
|
-
async function setupAlchemyServerDeploy(serverDir, projectDir) {
|
|
3423
|
-
if (!await fs.pathExists(serverDir)) return;
|
|
3424
|
-
await addPackageDependency({
|
|
3425
|
-
devDependencies: [
|
|
3426
|
-
"alchemy",
|
|
3427
|
-
"wrangler",
|
|
3428
|
-
"@types/node",
|
|
3429
|
-
"@cloudflare/workers-types"
|
|
3430
|
-
],
|
|
3431
|
-
projectDir: serverDir
|
|
3432
|
-
});
|
|
3433
|
-
if (projectDir) await addAlchemyPackagesDependencies$1(projectDir);
|
|
3434
|
-
const packageJsonPath = path.join(serverDir, "package.json");
|
|
3435
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
3436
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
3437
|
-
packageJson.scripts = {
|
|
3438
|
-
...packageJson.scripts,
|
|
3439
|
-
dev: "alchemy dev",
|
|
3440
|
-
deploy: "alchemy deploy",
|
|
3441
|
-
destroy: "alchemy destroy"
|
|
3442
|
-
};
|
|
3443
|
-
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
3444
|
-
}
|
|
3445
|
-
}
|
|
3446
|
-
async function addAlchemyPackagesDependencies$1(projectDir) {
|
|
3447
|
-
await addPackageDependency({
|
|
3448
|
-
devDependencies: ["@cloudflare/workers-types"],
|
|
3449
|
-
projectDir
|
|
3450
|
-
});
|
|
3451
|
-
}
|
|
3452
|
-
|
|
3453
3443
|
//#endregion
|
|
3454
3444
|
//#region src/helpers/deployment/alchemy/alchemy-next-setup.ts
|
|
3455
|
-
async function setupNextAlchemyDeploy(projectDir, _packageManager,
|
|
3445
|
+
async function setupNextAlchemyDeploy(projectDir, _packageManager, _options) {
|
|
3456
3446
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3457
3447
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3458
3448
|
await addPackageDependency({
|
|
@@ -3464,17 +3454,6 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3464
3454
|
],
|
|
3465
3455
|
projectDir: webAppDir
|
|
3466
3456
|
});
|
|
3467
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3468
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3469
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3470
|
-
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3471
|
-
...pkg.scripts,
|
|
3472
|
-
dev: "alchemy dev",
|
|
3473
|
-
deploy: "alchemy deploy",
|
|
3474
|
-
destroy: "alchemy destroy"
|
|
3475
|
-
};
|
|
3476
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3477
|
-
}
|
|
3478
3457
|
const openNextConfigPath = path.join(webAppDir, "open-next.config.ts");
|
|
3479
3458
|
await fs.writeFile(openNextConfigPath, `import { defineCloudflareConfig } from "@opennextjs/cloudflare";
|
|
3480
3459
|
|
|
@@ -3488,7 +3467,7 @@ export default defineCloudflareConfig({});
|
|
|
3488
3467
|
|
|
3489
3468
|
//#endregion
|
|
3490
3469
|
//#region src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts
|
|
3491
|
-
async function setupNuxtAlchemyDeploy(projectDir, _packageManager,
|
|
3470
|
+
async function setupNuxtAlchemyDeploy(projectDir, _packageManager, _options) {
|
|
3492
3471
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3493
3472
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3494
3473
|
await addPackageDependency({
|
|
@@ -3499,17 +3478,6 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3499
3478
|
],
|
|
3500
3479
|
projectDir: webAppDir
|
|
3501
3480
|
});
|
|
3502
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3503
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3504
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3505
|
-
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3506
|
-
...pkg.scripts,
|
|
3507
|
-
dev: "alchemy dev",
|
|
3508
|
-
deploy: "alchemy deploy",
|
|
3509
|
-
destroy: "alchemy destroy"
|
|
3510
|
-
};
|
|
3511
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3512
|
-
}
|
|
3513
3481
|
const nuxtConfigPath = path.join(webAppDir, "nuxt.config.ts");
|
|
3514
3482
|
if (!await fs.pathExists(nuxtConfigPath)) return;
|
|
3515
3483
|
try {
|
|
@@ -3554,68 +3522,35 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3554
3522
|
|
|
3555
3523
|
//#endregion
|
|
3556
3524
|
//#region src/helpers/deployment/alchemy/alchemy-react-router-setup.ts
|
|
3557
|
-
async function setupReactRouterAlchemyDeploy(projectDir, _packageManager,
|
|
3525
|
+
async function setupReactRouterAlchemyDeploy(projectDir, _packageManager, _options) {
|
|
3558
3526
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3559
3527
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3560
3528
|
await addPackageDependency({
|
|
3561
3529
|
devDependencies: ["alchemy"],
|
|
3562
3530
|
projectDir: webAppDir
|
|
3563
3531
|
});
|
|
3564
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3565
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3566
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3567
|
-
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3568
|
-
...pkg.scripts,
|
|
3569
|
-
dev: "alchemy dev",
|
|
3570
|
-
deploy: "alchemy deploy",
|
|
3571
|
-
destroy: "alchemy destroy"
|
|
3572
|
-
};
|
|
3573
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3574
|
-
}
|
|
3575
3532
|
}
|
|
3576
3533
|
|
|
3577
3534
|
//#endregion
|
|
3578
3535
|
//#region src/helpers/deployment/alchemy/alchemy-solid-setup.ts
|
|
3579
|
-
async function setupSolidAlchemyDeploy(projectDir, _packageManager,
|
|
3536
|
+
async function setupSolidAlchemyDeploy(projectDir, _packageManager, _options) {
|
|
3580
3537
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3581
3538
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3582
3539
|
await addPackageDependency({
|
|
3583
3540
|
devDependencies: ["alchemy"],
|
|
3584
3541
|
projectDir: webAppDir
|
|
3585
3542
|
});
|
|
3586
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3587
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3588
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3589
|
-
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3590
|
-
...pkg.scripts,
|
|
3591
|
-
dev: "alchemy dev",
|
|
3592
|
-
deploy: "alchemy deploy",
|
|
3593
|
-
destroy: "alchemy destroy"
|
|
3594
|
-
};
|
|
3595
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3596
|
-
}
|
|
3597
3543
|
}
|
|
3598
3544
|
|
|
3599
3545
|
//#endregion
|
|
3600
3546
|
//#region src/helpers/deployment/alchemy/alchemy-svelte-setup.ts
|
|
3601
|
-
async function setupSvelteAlchemyDeploy(projectDir, _packageManager,
|
|
3547
|
+
async function setupSvelteAlchemyDeploy(projectDir, _packageManager, _options) {
|
|
3602
3548
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3603
3549
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3604
3550
|
await addPackageDependency({
|
|
3605
3551
|
devDependencies: ["alchemy", "@sveltejs/adapter-cloudflare"],
|
|
3606
3552
|
projectDir: webAppDir
|
|
3607
3553
|
});
|
|
3608
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3609
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3610
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3611
|
-
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3612
|
-
...pkg.scripts,
|
|
3613
|
-
dev: "alchemy dev",
|
|
3614
|
-
deploy: "alchemy deploy",
|
|
3615
|
-
destroy: "alchemy destroy"
|
|
3616
|
-
};
|
|
3617
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3618
|
-
}
|
|
3619
3554
|
const svelteConfigPath = path.join(webAppDir, "svelte.config.js");
|
|
3620
3555
|
if (!await fs.pathExists(svelteConfigPath)) return;
|
|
3621
3556
|
try {
|
|
@@ -3664,46 +3599,24 @@ function updateAdapterInConfig(configObject) {
|
|
|
3664
3599
|
|
|
3665
3600
|
//#endregion
|
|
3666
3601
|
//#region src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts
|
|
3667
|
-
async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager,
|
|
3602
|
+
async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager, _options) {
|
|
3668
3603
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3669
3604
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3670
3605
|
await addPackageDependency({
|
|
3671
3606
|
devDependencies: ["alchemy"],
|
|
3672
3607
|
projectDir: webAppDir
|
|
3673
3608
|
});
|
|
3674
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3675
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3676
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3677
|
-
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3678
|
-
...pkg.scripts,
|
|
3679
|
-
dev: "alchemy dev",
|
|
3680
|
-
deploy: "alchemy deploy",
|
|
3681
|
-
destroy: "alchemy destroy"
|
|
3682
|
-
};
|
|
3683
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3684
|
-
}
|
|
3685
3609
|
}
|
|
3686
3610
|
|
|
3687
3611
|
//#endregion
|
|
3688
3612
|
//#region src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts
|
|
3689
|
-
async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager,
|
|
3613
|
+
async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, _options) {
|
|
3690
3614
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3691
3615
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3692
3616
|
await addPackageDependency({
|
|
3693
3617
|
devDependencies: ["alchemy", "@cloudflare/vite-plugin"],
|
|
3694
3618
|
projectDir: webAppDir
|
|
3695
3619
|
});
|
|
3696
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
3697
|
-
if (await fs.pathExists(pkgPath)) {
|
|
3698
|
-
const pkg = await fs.readJson(pkgPath);
|
|
3699
|
-
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3700
|
-
...pkg.scripts,
|
|
3701
|
-
dev: "alchemy dev",
|
|
3702
|
-
deploy: "alchemy deploy",
|
|
3703
|
-
destroy: "alchemy destroy"
|
|
3704
|
-
};
|
|
3705
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3706
|
-
}
|
|
3707
3620
|
const viteConfigPath = path.join(webAppDir, "vite.config.ts");
|
|
3708
3621
|
if (await fs.pathExists(viteConfigPath)) try {
|
|
3709
3622
|
const project = new Project({ manipulationSettings: {
|
|
@@ -3744,22 +3657,16 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3744
3657
|
|
|
3745
3658
|
//#endregion
|
|
3746
3659
|
//#region src/helpers/deployment/alchemy/alchemy-combined-setup.ts
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
if (await fs.pathExists(rootPkgPath)) {
|
|
3754
|
-
const pkg = await fs.readJson(rootPkgPath);
|
|
3755
|
-
pkg.scripts = {
|
|
3756
|
-
...pkg.scripts,
|
|
3757
|
-
deploy: "alchemy deploy",
|
|
3758
|
-
destroy: "alchemy destroy",
|
|
3759
|
-
dev: "alchemy dev"
|
|
3760
|
-
};
|
|
3761
|
-
await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
|
|
3660
|
+
function getInfraFilter(packageManager, hasTurborepo, infraWorkspace) {
|
|
3661
|
+
if (hasTurborepo) return (script) => `turbo -F ${infraWorkspace} ${script}`;
|
|
3662
|
+
switch (packageManager) {
|
|
3663
|
+
case "pnpm": return (script) => `pnpm --filter ${infraWorkspace} ${script}`;
|
|
3664
|
+
case "npm": return (script) => `npm run ${script} --workspace ${infraWorkspace}`;
|
|
3665
|
+
case "bun": return (script) => `bun run --filter ${infraWorkspace} ${script}`;
|
|
3762
3666
|
}
|
|
3667
|
+
}
|
|
3668
|
+
async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
3669
|
+
await setupInfraScripts(projectDir, packageManager, config);
|
|
3763
3670
|
const serverDir = path.join(projectDir, "apps/server");
|
|
3764
3671
|
if (await fs.pathExists(serverDir)) await setupAlchemyServerDeploy(serverDir, projectDir);
|
|
3765
3672
|
const frontend = config.frontend;
|
|
@@ -3778,6 +3685,77 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
|
3778
3685
|
else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3779
3686
|
else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3780
3687
|
}
|
|
3688
|
+
async function setupInfraScripts(projectDir, packageManager, config) {
|
|
3689
|
+
const projectName = config.projectName;
|
|
3690
|
+
const hasTurborepo = config.addons.includes("turborepo");
|
|
3691
|
+
const infraWorkspace = `@${projectName}/infra`;
|
|
3692
|
+
const rootPkgPath = path.join(projectDir, "package.json");
|
|
3693
|
+
if (await fs.pathExists(rootPkgPath)) {
|
|
3694
|
+
const pkg = await fs.readJson(rootPkgPath);
|
|
3695
|
+
const filter = getInfraFilter(packageManager, hasTurborepo, infraWorkspace);
|
|
3696
|
+
pkg.scripts = {
|
|
3697
|
+
...pkg.scripts,
|
|
3698
|
+
deploy: filter("deploy"),
|
|
3699
|
+
destroy: filter("destroy")
|
|
3700
|
+
};
|
|
3701
|
+
await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
|
|
3702
|
+
}
|
|
3703
|
+
if (config.serverDeploy === "cloudflare") {
|
|
3704
|
+
const serverPkgPath = path.join(projectDir, "apps/server/package.json");
|
|
3705
|
+
if (await fs.pathExists(serverPkgPath)) {
|
|
3706
|
+
const serverPkg = await fs.readJson(serverPkgPath);
|
|
3707
|
+
if (serverPkg.scripts?.dev) {
|
|
3708
|
+
serverPkg.scripts["dev:bare"] = serverPkg.scripts.dev;
|
|
3709
|
+
delete serverPkg.scripts.dev;
|
|
3710
|
+
await fs.writeJson(serverPkgPath, serverPkg, { spaces: 2 });
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
if (config.webDeploy === "cloudflare") {
|
|
3715
|
+
const webPkgPath = path.join(projectDir, "apps/web/package.json");
|
|
3716
|
+
if (await fs.pathExists(webPkgPath)) {
|
|
3717
|
+
const webPkg = await fs.readJson(webPkgPath);
|
|
3718
|
+
if (webPkg.scripts?.dev) {
|
|
3719
|
+
webPkg.scripts["dev:bare"] = webPkg.scripts.dev;
|
|
3720
|
+
delete webPkg.scripts.dev;
|
|
3721
|
+
await fs.writeJson(webPkgPath, webPkg, { spaces: 2 });
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
|
|
3727
|
+
//#endregion
|
|
3728
|
+
//#region src/helpers/deployment/server-deploy-setup.ts
|
|
3729
|
+
async function setupServerDeploy(config) {
|
|
3730
|
+
const { serverDeploy, webDeploy, projectDir, packageManager } = config;
|
|
3731
|
+
if (serverDeploy === "none") return;
|
|
3732
|
+
if (serverDeploy === "cloudflare" && webDeploy === "cloudflare") return;
|
|
3733
|
+
const serverDir = path.join(projectDir, "apps/server");
|
|
3734
|
+
if (!await fs.pathExists(serverDir)) return;
|
|
3735
|
+
if (serverDeploy === "cloudflare") {
|
|
3736
|
+
await setupInfraScripts(projectDir, packageManager, config);
|
|
3737
|
+
await setupAlchemyServerDeploy(serverDir, projectDir);
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
async function setupAlchemyServerDeploy(serverDir, projectDir) {
|
|
3741
|
+
if (!await fs.pathExists(serverDir)) return;
|
|
3742
|
+
await addPackageDependency({
|
|
3743
|
+
devDependencies: [
|
|
3744
|
+
"alchemy",
|
|
3745
|
+
"wrangler",
|
|
3746
|
+
"@types/node",
|
|
3747
|
+
"@cloudflare/workers-types"
|
|
3748
|
+
],
|
|
3749
|
+
projectDir: serverDir
|
|
3750
|
+
});
|
|
3751
|
+
if (projectDir) await addAlchemyPackagesDependencies$1(projectDir);
|
|
3752
|
+
}
|
|
3753
|
+
async function addAlchemyPackagesDependencies$1(projectDir) {
|
|
3754
|
+
await addPackageDependency({
|
|
3755
|
+
devDependencies: ["@cloudflare/workers-types"],
|
|
3756
|
+
projectDir
|
|
3757
|
+
});
|
|
3758
|
+
}
|
|
3781
3759
|
|
|
3782
3760
|
//#endregion
|
|
3783
3761
|
//#region src/helpers/deployment/web-deploy-setup.ts
|
|
@@ -3785,12 +3763,13 @@ async function setupWebDeploy(config) {
|
|
|
3785
3763
|
const { webDeploy, serverDeploy, frontend, projectDir } = config;
|
|
3786
3764
|
const { packageManager } = config;
|
|
3787
3765
|
if (webDeploy === "none") return;
|
|
3788
|
-
if (webDeploy !== "
|
|
3789
|
-
if (webDeploy === "
|
|
3766
|
+
if (webDeploy !== "cloudflare") return;
|
|
3767
|
+
if (webDeploy === "cloudflare" && serverDeploy === "cloudflare") {
|
|
3790
3768
|
await setupCombinedAlchemyDeploy(projectDir, packageManager, config);
|
|
3791
3769
|
await addAlchemyPackagesDependencies(projectDir);
|
|
3792
3770
|
return;
|
|
3793
3771
|
}
|
|
3772
|
+
await setupInfraScripts(projectDir, packageManager, config);
|
|
3794
3773
|
const isNext = frontend.includes("next");
|
|
3795
3774
|
const isNuxt = frontend.includes("nuxt");
|
|
3796
3775
|
const isSvelte = frontend.includes("svelte");
|
|
@@ -3879,7 +3858,9 @@ async function setupCatalogs(projectDir, options) {
|
|
|
3879
3858
|
"packages/db",
|
|
3880
3859
|
"packages/auth",
|
|
3881
3860
|
"packages/backend",
|
|
3882
|
-
"packages/config"
|
|
3861
|
+
"packages/config",
|
|
3862
|
+
"packages/env",
|
|
3863
|
+
"packages/infra"
|
|
3883
3864
|
];
|
|
3884
3865
|
const packagesInfo = [];
|
|
3885
3866
|
for (const pkgPath of packagePaths) {
|
|
@@ -4171,7 +4152,10 @@ function getConvexDependencies(frontend) {
|
|
|
4171
4152
|
web: { dependencies: ["convex"] },
|
|
4172
4153
|
native: { dependencies: ["convex"] }
|
|
4173
4154
|
};
|
|
4174
|
-
if (frontend.includes("tanstack-start"))
|
|
4155
|
+
if (frontend.includes("tanstack-start")) {
|
|
4156
|
+
deps.web.dependencies.push("@convex-dev/react-query");
|
|
4157
|
+
deps.web.dependencies.push("@tanstack/react-router-ssr-query");
|
|
4158
|
+
}
|
|
4175
4159
|
if (frontend.includes("svelte")) deps.web.dependencies.push("convex-svelte");
|
|
4176
4160
|
if (frontend.includes("nuxt")) deps.web.dependencies.push("convex-nuxt", "convex-vue");
|
|
4177
4161
|
return deps;
|
|
@@ -4294,7 +4278,7 @@ async function setupBackendDependencies(config) {
|
|
|
4294
4278
|
//#region src/utils/better-auth-plugin-setup.ts
|
|
4295
4279
|
async function setupBetterAuthPlugins(projectDir, config) {
|
|
4296
4280
|
const authIndexPath = `${projectDir}/packages/auth/src/index.ts`;
|
|
4297
|
-
const authIndexFile = tsProject
|
|
4281
|
+
const authIndexFile = tsProject.addSourceFileAtPath(authIndexPath);
|
|
4298
4282
|
if (!authIndexFile) return;
|
|
4299
4283
|
const pluginsToAdd = [];
|
|
4300
4284
|
const importsToAdd = [];
|
|
@@ -4367,12 +4351,12 @@ async function setupAuth(config) {
|
|
|
4367
4351
|
if (convexBackendDirExists) {
|
|
4368
4352
|
await addPackageDependency({
|
|
4369
4353
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4370
|
-
customDependencies: { "better-auth": "1.4.
|
|
4354
|
+
customDependencies: { "better-auth": "1.4.9" },
|
|
4371
4355
|
projectDir: convexBackendDir
|
|
4372
4356
|
});
|
|
4373
4357
|
if (hasNativeForBA) await addPackageDependency({
|
|
4374
4358
|
dependencies: ["@better-auth/expo"],
|
|
4375
|
-
customDependencies: { "@better-auth/expo": "1.4.
|
|
4359
|
+
customDependencies: { "@better-auth/expo": "1.4.9" },
|
|
4376
4360
|
projectDir: convexBackendDir
|
|
4377
4361
|
});
|
|
4378
4362
|
}
|
|
@@ -4382,17 +4366,17 @@ async function setupAuth(config) {
|
|
|
4382
4366
|
const hasViteReactOther = frontend.some((f) => ["tanstack-router", "react-router"].includes(f));
|
|
4383
4367
|
if (hasNextJs) await addPackageDependency({
|
|
4384
4368
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4385
|
-
customDependencies: { "better-auth": "1.4.
|
|
4369
|
+
customDependencies: { "better-auth": "1.4.9" },
|
|
4386
4370
|
projectDir: clientDir
|
|
4387
4371
|
});
|
|
4388
4372
|
else if (hasTanStackStart) await addPackageDependency({
|
|
4389
4373
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4390
|
-
customDependencies: { "better-auth": "1.4.
|
|
4374
|
+
customDependencies: { "better-auth": "1.4.9" },
|
|
4391
4375
|
projectDir: clientDir
|
|
4392
4376
|
});
|
|
4393
4377
|
else if (hasViteReactOther) await addPackageDependency({
|
|
4394
4378
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4395
|
-
customDependencies: { "better-auth": "1.4.
|
|
4379
|
+
customDependencies: { "better-auth": "1.4.9" },
|
|
4396
4380
|
projectDir: clientDir
|
|
4397
4381
|
});
|
|
4398
4382
|
}
|
|
@@ -4406,8 +4390,8 @@ async function setupAuth(config) {
|
|
|
4406
4390
|
"@convex-dev/better-auth"
|
|
4407
4391
|
],
|
|
4408
4392
|
customDependencies: {
|
|
4409
|
-
"better-auth": "1.4.
|
|
4410
|
-
"@better-auth/expo": "1.4.
|
|
4393
|
+
"better-auth": "1.4.9",
|
|
4394
|
+
"@better-auth/expo": "1.4.9"
|
|
4411
4395
|
},
|
|
4412
4396
|
projectDir: nativeDir
|
|
4413
4397
|
});
|
|
@@ -4566,11 +4550,6 @@ async function setupEnvironmentVariables(config) {
|
|
|
4566
4550
|
value: backend === "convex" ? "https://<YOUR_CONVEX_URL>" : baseVar.value,
|
|
4567
4551
|
condition: backend === "convex" ? true : baseVar.write
|
|
4568
4552
|
}];
|
|
4569
|
-
if (hasNextJs) clientVars.push({
|
|
4570
|
-
key: "PORT",
|
|
4571
|
-
value: "3001",
|
|
4572
|
-
condition: true
|
|
4573
|
-
});
|
|
4574
4553
|
if (backend === "convex" && auth === "clerk") {
|
|
4575
4554
|
if (hasNextJs) clientVars.push({
|
|
4576
4555
|
key: "NEXT_PUBLIC_CLERK_FRONTEND_API_URL",
|
|
@@ -4706,7 +4685,7 @@ ${hasWebFrontend$1 ? "# npx convex env set SITE_URL http://localhost:3001\n" : "
|
|
|
4706
4685
|
databaseUrl = "mongodb://localhost:27017/mydatabase";
|
|
4707
4686
|
break;
|
|
4708
4687
|
case "sqlite":
|
|
4709
|
-
if (config.runtime === "workers" || webDeploy === "
|
|
4688
|
+
if (config.runtime === "workers" || webDeploy === "cloudflare" || serverDeploy === "cloudflare") databaseUrl = "http://127.0.0.1:8080";
|
|
4710
4689
|
else {
|
|
4711
4690
|
const dbAppDir = backend === "self" ? "apps/web" : "apps/server";
|
|
4712
4691
|
databaseUrl = `file:${path.join(config.projectDir, dbAppDir, "local.db")}`;
|
|
@@ -4754,33 +4733,13 @@ ${hasWebFrontend$1 ? "# npx convex env set SITE_URL http://localhost:3001\n" : "
|
|
|
4754
4733
|
const webDir = path.join(projectDir, "apps/web");
|
|
4755
4734
|
if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), serverVars);
|
|
4756
4735
|
} else if (await fs.pathExists(serverDir)) await addEnvVariablesToFile(path.join(serverDir, ".env"), serverVars);
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
else if (isIndividualAlchemy) {
|
|
4765
|
-
if (webDeploy === "alchemy") {
|
|
4766
|
-
const webDir = path.join(projectDir, "apps/web");
|
|
4767
|
-
if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), [{
|
|
4768
|
-
key: "ALCHEMY_PASSWORD",
|
|
4769
|
-
value: "please-change-this",
|
|
4770
|
-
condition: true
|
|
4771
|
-
}]);
|
|
4772
|
-
}
|
|
4773
|
-
if (serverDeploy === "alchemy") {
|
|
4774
|
-
const serverAlchemyVars = [{
|
|
4775
|
-
key: "ALCHEMY_PASSWORD",
|
|
4776
|
-
value: "please-change-this",
|
|
4777
|
-
condition: true
|
|
4778
|
-
}];
|
|
4779
|
-
if (backend === "self") {
|
|
4780
|
-
const webDir = path.join(projectDir, "apps/web");
|
|
4781
|
-
if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), serverAlchemyVars);
|
|
4782
|
-
} else await addEnvVariablesToFile(path.join(serverDir, ".env"), serverAlchemyVars);
|
|
4783
|
-
}
|
|
4736
|
+
if (webDeploy === "cloudflare" && serverDeploy === "cloudflare" || webDeploy === "cloudflare" || serverDeploy === "cloudflare") {
|
|
4737
|
+
const infraDir = path.join(projectDir, "packages/infra");
|
|
4738
|
+
if (await fs.pathExists(infraDir)) await addEnvVariablesToFile(path.join(infraDir, ".env"), [{
|
|
4739
|
+
key: "ALCHEMY_PASSWORD",
|
|
4740
|
+
value: "please-change-this",
|
|
4741
|
+
condition: true
|
|
4742
|
+
}]);
|
|
4784
4743
|
}
|
|
4785
4744
|
}
|
|
4786
4745
|
|
|
@@ -4788,7 +4747,7 @@ ${hasWebFrontend$1 ? "# npx convex env set SITE_URL http://localhost:3001\n" : "
|
|
|
4788
4747
|
//#region src/helpers/database-providers/d1-setup.ts
|
|
4789
4748
|
async function setupCloudflareD1(config) {
|
|
4790
4749
|
const { projectDir, serverDeploy, orm, backend } = config;
|
|
4791
|
-
if (serverDeploy === "
|
|
4750
|
+
if (serverDeploy === "cloudflare" && orm === "prisma") {
|
|
4792
4751
|
const targetApp2 = backend === "self" ? "apps/web" : "apps/server";
|
|
4793
4752
|
await addEnvVariablesToFile(path.join(projectDir, targetApp2, ".env"), [{
|
|
4794
4753
|
key: "DATABASE_URL",
|
|
@@ -4834,8 +4793,8 @@ function getDatabaseUrl(database, projectName) {
|
|
|
4834
4793
|
//#region src/utils/command-exists.ts
|
|
4835
4794
|
async function commandExists(command) {
|
|
4836
4795
|
try {
|
|
4837
|
-
if (process.platform === "win32") return (await
|
|
4838
|
-
return (await
|
|
4796
|
+
if (process.platform === "win32") return (await $({ reject: false })`where ${command}`).exitCode === 0;
|
|
4797
|
+
return (await $({ reject: false })`which ${command}`).exitCode === 0;
|
|
4839
4798
|
} catch {
|
|
4840
4799
|
return false;
|
|
4841
4800
|
}
|
|
@@ -4862,11 +4821,10 @@ async function initMongoDBAtlas(serverDir) {
|
|
|
4862
4821
|
return null;
|
|
4863
4822
|
}
|
|
4864
4823
|
log.info("Running MongoDB Atlas setup...");
|
|
4865
|
-
await
|
|
4824
|
+
await $({
|
|
4866
4825
|
cwd: serverDir,
|
|
4867
|
-
shell: true,
|
|
4868
4826
|
stdio: "inherit"
|
|
4869
|
-
})
|
|
4827
|
+
})`atlas deployments setup`;
|
|
4870
4828
|
log.success("MongoDB Atlas deployment ready");
|
|
4871
4829
|
const connectionString = await text({
|
|
4872
4830
|
message: "Enter your MongoDB connection string:",
|
|
@@ -5004,9 +4962,9 @@ const NEON_REGIONS = [
|
|
|
5004
4962
|
async function executeNeonCommand(packageManager, commandArgsString, spinnerText) {
|
|
5005
4963
|
const s = spinner();
|
|
5006
4964
|
try {
|
|
5007
|
-
const
|
|
4965
|
+
const args = getPackageExecutionArgs(packageManager, commandArgsString);
|
|
5008
4966
|
if (spinnerText) s.start(spinnerText);
|
|
5009
|
-
const result = await
|
|
4967
|
+
const result = await $`${args}`;
|
|
5010
4968
|
if (spinnerText) s.stop(pc.green(spinnerText.replace("...", "").replace("ing ", "ed ").trim()));
|
|
5011
4969
|
return result;
|
|
5012
4970
|
} catch (error) {
|
|
@@ -5051,10 +5009,8 @@ async function setupWithNeonDb(projectDir, packageManager, backend) {
|
|
|
5051
5009
|
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5052
5010
|
const targetDir = path.join(projectDir, targetApp);
|
|
5053
5011
|
await fs.ensureDir(targetDir);
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
cwd: targetDir
|
|
5057
|
-
});
|
|
5012
|
+
const packageArgs = getPackageExecutionArgs(packageManager, "get-db@latest --yes");
|
|
5013
|
+
await $({ cwd: targetDir })`${packageArgs}`;
|
|
5058
5014
|
s.stop(pc.green("Neon database created successfully!"));
|
|
5059
5015
|
return true;
|
|
5060
5016
|
} catch (error) {
|
|
@@ -5240,13 +5196,10 @@ async function setupWithCreateDb(serverDir, packageManager) {
|
|
|
5240
5196
|
initialValue: "ap-southeast-1"
|
|
5241
5197
|
});
|
|
5242
5198
|
if (isCancel(selectedRegion)) return null;
|
|
5243
|
-
const
|
|
5199
|
+
const createDbArgs = getPackageExecutionArgs(packageManager, `create-db@latest --json --region ${selectedRegion}`);
|
|
5244
5200
|
const s = spinner();
|
|
5245
5201
|
s.start("Creating Prisma Postgres database...");
|
|
5246
|
-
const { stdout } = await
|
|
5247
|
-
cwd: serverDir,
|
|
5248
|
-
shell: true
|
|
5249
|
-
});
|
|
5202
|
+
const { stdout } = await $({ cwd: serverDir })`${createDbArgs}`;
|
|
5250
5203
|
s.stop("Database created successfully!");
|
|
5251
5204
|
let createDbResponse;
|
|
5252
5205
|
try {
|
|
@@ -5373,11 +5326,11 @@ function extractDbUrl(output) {
|
|
|
5373
5326
|
async function initializeSupabase(serverDir, packageManager) {
|
|
5374
5327
|
log.info("Initializing Supabase project...");
|
|
5375
5328
|
try {
|
|
5376
|
-
|
|
5329
|
+
const supabaseInitArgs = getPackageExecutionArgs(packageManager, "supabase init");
|
|
5330
|
+
await $({
|
|
5377
5331
|
cwd: serverDir,
|
|
5378
|
-
stdio: "inherit"
|
|
5379
|
-
|
|
5380
|
-
});
|
|
5332
|
+
stdio: "inherit"
|
|
5333
|
+
})`${supabaseInitArgs}`;
|
|
5381
5334
|
log.success("Supabase project initialized");
|
|
5382
5335
|
return true;
|
|
5383
5336
|
} catch (error) {
|
|
@@ -5393,12 +5346,9 @@ async function initializeSupabase(serverDir, packageManager) {
|
|
|
5393
5346
|
}
|
|
5394
5347
|
async function startSupabase(serverDir, packageManager) {
|
|
5395
5348
|
log.info("Starting Supabase services (this may take a moment)...");
|
|
5396
|
-
const
|
|
5349
|
+
const supabaseStartArgs = getPackageExecutionArgs(packageManager, "supabase start");
|
|
5397
5350
|
try {
|
|
5398
|
-
const subprocess = execa(
|
|
5399
|
-
cwd: serverDir,
|
|
5400
|
-
shell: true
|
|
5401
|
-
});
|
|
5351
|
+
const subprocess = execa(supabaseStartArgs[0], supabaseStartArgs.slice(1), { cwd: serverDir });
|
|
5402
5352
|
let stdoutData = "";
|
|
5403
5353
|
if (subprocess.stdout) subprocess.stdout.on("data", (data) => {
|
|
5404
5354
|
const text$1 = data.toString();
|
|
@@ -5944,7 +5894,7 @@ ${generateProjectStructure(projectName, frontend, backend, addons, isConvex, api
|
|
|
5944
5894
|
|
|
5945
5895
|
## Available Scripts
|
|
5946
5896
|
|
|
5947
|
-
${generateScriptsList(packageManagerRunCmd, database, orm, auth, hasNative, addons, backend)}
|
|
5897
|
+
${generateScriptsList(packageManagerRunCmd, database, orm, auth, hasNative, addons, backend, options.dbSetup)}
|
|
5948
5898
|
`;
|
|
5949
5899
|
}
|
|
5950
5900
|
function generateStackDescription(frontend, backend, api, isConvex) {
|
|
@@ -6099,15 +6049,13 @@ function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSet
|
|
|
6099
6049
|
if (database === "none") return "";
|
|
6100
6050
|
const isBackendSelf = backend === "self";
|
|
6101
6051
|
const envPath = isBackendSelf ? "apps/web/.env" : "apps/server/.env";
|
|
6102
|
-
const dbLocalPath = "packages/db";
|
|
6103
6052
|
let setup = "## Database Setup\n\n";
|
|
6104
6053
|
if (database === "sqlite") setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
6105
6054
|
|
|
6106
|
-
1. Start the local SQLite database:
|
|
6055
|
+
1. Start the local SQLite database (optional):
|
|
6107
6056
|
${dbSetup === "d1" ? "D1 local development and migrations are handled automatically by Alchemy during dev and deploy." : `\`\`\`bash
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
`}
|
|
6057
|
+
${packageManagerRunCmd} db:local
|
|
6058
|
+
\`\`\``}
|
|
6111
6059
|
|
|
6112
6060
|
2. Update your \`.env\` file in the \`${isBackendSelf ? "apps/web" : "apps/server"}\` directory with the appropriate connection details if needed.
|
|
6113
6061
|
`;
|
|
@@ -6140,7 +6088,7 @@ ${packageManagerRunCmd} db:push
|
|
|
6140
6088
|
`;
|
|
6141
6089
|
return setup;
|
|
6142
6090
|
}
|
|
6143
|
-
function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNative, addons, backend) {
|
|
6091
|
+
function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNative, addons, backend, dbSetup) {
|
|
6144
6092
|
const isConvex = backend === "convex";
|
|
6145
6093
|
const isBackendNone = backend === "none";
|
|
6146
6094
|
const isBackendSelf = backend === "self";
|
|
@@ -6160,8 +6108,8 @@ function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNati
|
|
|
6160
6108
|
scripts += `
|
|
6161
6109
|
- \`${packageManagerRunCmd} db:push\`: Push schema changes to database
|
|
6162
6110
|
- \`${packageManagerRunCmd} db:studio\`: Open database studio UI`;
|
|
6163
|
-
if (database === "sqlite" &&
|
|
6164
|
-
-
|
|
6111
|
+
if (database === "sqlite" && dbSetup !== "d1") scripts += `
|
|
6112
|
+
- \`${packageManagerRunCmd} db:local\`: Start the local SQLite database`;
|
|
6165
6113
|
}
|
|
6166
6114
|
if (addons.includes("biome")) scripts += `
|
|
6167
6115
|
- \`${packageManagerRunCmd} check\`: Run Biome formatting and linting`;
|
|
@@ -6198,15 +6146,35 @@ BETTER_AUTH_URL={your-production-server-domain}
|
|
|
6198
6146
|
}
|
|
6199
6147
|
function generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy) {
|
|
6200
6148
|
const lines = [];
|
|
6201
|
-
if (webDeploy === "
|
|
6202
|
-
lines.push("## Deployment (Alchemy)");
|
|
6203
|
-
if (webDeploy === "
|
|
6204
|
-
if (serverDeploy === "
|
|
6205
|
-
if (webDeploy === "
|
|
6149
|
+
if (webDeploy === "cloudflare" || serverDeploy === "cloudflare") {
|
|
6150
|
+
lines.push("## Deployment (Cloudflare via Alchemy)");
|
|
6151
|
+
if (webDeploy === "cloudflare" && serverDeploy !== "cloudflare") lines.push(`- Web dev: cd apps/web && ${packageManagerRunCmd} dev`, `- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`, `- Web destroy: cd apps/web && ${packageManagerRunCmd} destroy`);
|
|
6152
|
+
if (serverDeploy === "cloudflare" && webDeploy !== "cloudflare") lines.push(`- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`, `- Server destroy: cd apps/server && ${packageManagerRunCmd} destroy`);
|
|
6153
|
+
if (webDeploy === "cloudflare" && serverDeploy === "cloudflare") lines.push(`- Dev: ${packageManagerRunCmd} dev`, `- Deploy: ${packageManagerRunCmd} deploy`, `- Destroy: ${packageManagerRunCmd} destroy`);
|
|
6206
6154
|
}
|
|
6207
6155
|
return lines.length ? `\n${lines.join("\n")}\n` : "";
|
|
6208
6156
|
}
|
|
6209
6157
|
|
|
6158
|
+
//#endregion
|
|
6159
|
+
//#region src/helpers/core/env-package-setup.ts
|
|
6160
|
+
async function setupEnvPackageDependencies(projectDir, options) {
|
|
6161
|
+
const envDir = path.join(projectDir, "packages/env");
|
|
6162
|
+
if (!await fs.pathExists(envDir)) return;
|
|
6163
|
+
await addPackageDependency({
|
|
6164
|
+
dependencies: getT3EnvDeps(options),
|
|
6165
|
+
projectDir: envDir
|
|
6166
|
+
});
|
|
6167
|
+
}
|
|
6168
|
+
function getT3EnvDeps(options) {
|
|
6169
|
+
const deps = ["zod"];
|
|
6170
|
+
const { frontend, backend, runtime } = options;
|
|
6171
|
+
if (frontend.includes("next")) deps.push("@t3-oss/env-nextjs");
|
|
6172
|
+
else if (frontend.includes("nuxt")) deps.push("@t3-oss/env-nuxt");
|
|
6173
|
+
else deps.push("@t3-oss/env-core");
|
|
6174
|
+
if (backend !== "convex" && backend !== "none" && runtime !== "workers" && !deps.includes("@t3-oss/env-core")) deps.push("@t3-oss/env-core");
|
|
6175
|
+
return deps;
|
|
6176
|
+
}
|
|
6177
|
+
|
|
6210
6178
|
//#endregion
|
|
6211
6179
|
//#region src/helpers/core/git.ts
|
|
6212
6180
|
async function initializeGit(projectDir, useGit) {
|
|
@@ -6229,6 +6197,17 @@ async function initializeGit(projectDir, useGit) {
|
|
|
6229
6197
|
await $({ cwd: projectDir })`git commit -m ${"initial commit"}`;
|
|
6230
6198
|
}
|
|
6231
6199
|
|
|
6200
|
+
//#endregion
|
|
6201
|
+
//#region src/helpers/core/infra-package-setup.ts
|
|
6202
|
+
async function setupInfraPackageDependencies(projectDir, _options) {
|
|
6203
|
+
const infraDir = path.join(projectDir, "packages/infra");
|
|
6204
|
+
if (!await fs.pathExists(infraDir)) return;
|
|
6205
|
+
await addPackageDependency({
|
|
6206
|
+
devDependencies: ["alchemy"],
|
|
6207
|
+
projectDir: infraDir
|
|
6208
|
+
});
|
|
6209
|
+
}
|
|
6210
|
+
|
|
6232
6211
|
//#endregion
|
|
6233
6212
|
//#region src/helpers/core/payments-setup.ts
|
|
6234
6213
|
async function setupPayments(config) {
|
|
@@ -6348,7 +6327,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6348
6327
|
let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
|
|
6349
6328
|
let stepCounter = 2;
|
|
6350
6329
|
if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${packageManager} install\n`;
|
|
6351
|
-
if (database === "sqlite" && dbSetup
|
|
6330
|
+
if (database === "sqlite" && dbSetup !== "d1") output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} db:local\n${pc.dim(" (optional - starts local SQLite database)")}\n`;
|
|
6352
6331
|
if (isConvex) {
|
|
6353
6332
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup\n${pc.dim(" (this will guide you through Convex project setup)")}\n`;
|
|
6354
6333
|
output += `${pc.cyan(`${stepCounter++}.`)} Copy environment variables from\n${pc.white(" packages/backend/.env.local")} to ${pc.white("apps/*/.env")}\n`;
|
|
@@ -6415,7 +6394,7 @@ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup,
|
|
|
6415
6394
|
instructions.push("");
|
|
6416
6395
|
}
|
|
6417
6396
|
}
|
|
6418
|
-
if (dbSetup === "d1" && serverDeploy === "
|
|
6397
|
+
if (dbSetup === "d1" && serverDeploy === "cloudflare") {
|
|
6419
6398
|
if (orm === "drizzle") instructions.push(`${pc.cyan("•")} Generate migrations: ${`${runCmd} db:generate`}`);
|
|
6420
6399
|
else if (orm === "prisma") {
|
|
6421
6400
|
instructions.push(`${pc.cyan("•")} Generate Prisma client: ${`${runCmd} db:generate`}`);
|
|
@@ -6430,15 +6409,15 @@ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup,
|
|
|
6430
6409
|
if (orm === "prisma") {
|
|
6431
6410
|
if (database === "mongodb" && dbSetup === "docker") instructions.push(`${pc.yellow("WARNING:")} Prisma + MongoDB + Docker combination\n may not work.`);
|
|
6432
6411
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6433
|
-
if (!(dbSetup === "d1" && serverDeploy === "
|
|
6412
|
+
if (!(dbSetup === "d1" && serverDeploy === "cloudflare")) {
|
|
6434
6413
|
instructions.push(`${pc.cyan("•")} Generate Prisma Client: ${`${runCmd} db:generate`}`);
|
|
6435
6414
|
instructions.push(`${pc.cyan("•")} Apply schema: ${`${runCmd} db:push`}`);
|
|
6436
6415
|
}
|
|
6437
|
-
if (!(dbSetup === "d1" && serverDeploy === "
|
|
6416
|
+
if (!(dbSetup === "d1" && serverDeploy === "cloudflare")) instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
|
|
6438
6417
|
} else if (orm === "drizzle") {
|
|
6439
6418
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6440
6419
|
if (dbSetup !== "d1") instructions.push(`${pc.cyan("•")} Apply schema: ${`${runCmd} db:push`}`);
|
|
6441
|
-
if (!(dbSetup === "d1" && serverDeploy === "
|
|
6420
|
+
if (!(dbSetup === "d1" && serverDeploy === "cloudflare")) instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
|
|
6442
6421
|
} else if (orm === "mongoose") {
|
|
6443
6422
|
if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
|
|
6444
6423
|
} else if (orm === "none") instructions.push(`${pc.yellow("NOTE:")} Manual database schema setup\n required.`);
|
|
@@ -6469,116 +6448,174 @@ function getPolarInstructions(backend) {
|
|
|
6469
6448
|
function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend) {
|
|
6470
6449
|
const instructions = [];
|
|
6471
6450
|
const isBackendSelf = backend === "self";
|
|
6472
|
-
if (webDeploy === "
|
|
6473
|
-
else if (serverDeploy === "
|
|
6474
|
-
else if (webDeploy === "
|
|
6451
|
+
if (webDeploy === "cloudflare" && serverDeploy !== "cloudflare") 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`}`);
|
|
6452
|
+
else if (serverDeploy === "cloudflare" && webDeploy !== "cloudflare" && !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`}`);
|
|
6453
|
+
else if (webDeploy === "cloudflare" && (serverDeploy === "cloudflare" || 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`}`);
|
|
6475
6454
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
6476
6455
|
}
|
|
6477
6456
|
|
|
6478
6457
|
//#endregion
|
|
6479
6458
|
//#region src/helpers/core/workspace-setup.ts
|
|
6480
6459
|
async function setupWorkspaceDependencies(projectDir, options) {
|
|
6481
|
-
const { projectName, packageManager,
|
|
6460
|
+
const { projectName, packageManager, runtime, backend } = options;
|
|
6482
6461
|
const workspaceVersion = packageManager === "npm" ? "*" : "workspace:*";
|
|
6483
|
-
const
|
|
6484
|
-
const
|
|
6485
|
-
const
|
|
6486
|
-
const
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6462
|
+
const packages = await detectPackages(projectDir);
|
|
6463
|
+
const configDep = packages.config.exists ? { [`@${projectName}/config`]: workspaceVersion } : {};
|
|
6464
|
+
const envDep = packages.env.exists ? { [`@${projectName}/env`]: workspaceVersion } : {};
|
|
6465
|
+
const ctx = {
|
|
6466
|
+
projectName,
|
|
6467
|
+
workspaceVersion,
|
|
6468
|
+
options,
|
|
6469
|
+
commonDeps: ["dotenv", "zod"],
|
|
6470
|
+
commonDevDeps: ["typescript"],
|
|
6471
|
+
configDep,
|
|
6472
|
+
envDep
|
|
6473
|
+
};
|
|
6474
|
+
await Promise.all([
|
|
6475
|
+
setupEnvPackage(packages.env, packages.infra, ctx),
|
|
6476
|
+
setupInfraPackage(packages.infra, ctx),
|
|
6477
|
+
setupDbPackage(packages.db, ctx),
|
|
6478
|
+
setupAuthPackage(packages.auth, packages.db, ctx),
|
|
6479
|
+
setupApiPackage(packages.api, packages.auth, packages.db, ctx),
|
|
6480
|
+
setupBackendPackage(packages.backend, ctx),
|
|
6481
|
+
setupServerPackage(packages.server, packages.api, packages.auth, packages.db, ctx),
|
|
6482
|
+
setupWebPackage(packages.web, packages.api, packages.auth, packages.backend, ctx),
|
|
6483
|
+
setupNativePackage(packages.native, packages.api, packages.backend, ctx)
|
|
6502
6484
|
]);
|
|
6503
|
-
const
|
|
6504
|
-
|
|
6505
|
-
dependencies: commonDeps,
|
|
6506
|
-
devDependencies: commonDevDeps,
|
|
6485
|
+
const runtimeDevDeps = getRuntimeDevDeps(runtime, backend);
|
|
6486
|
+
await addPackageDependency({
|
|
6487
|
+
dependencies: ctx.commonDeps,
|
|
6488
|
+
devDependencies: [...ctx.commonDevDeps, ...runtimeDevDeps],
|
|
6489
|
+
customDependencies: envDep,
|
|
6507
6490
|
customDevDependencies: configDep,
|
|
6508
|
-
projectDir
|
|
6491
|
+
projectDir
|
|
6509
6492
|
});
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
if (
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6493
|
+
}
|
|
6494
|
+
async function detectPackages(projectDir) {
|
|
6495
|
+
const entries = await Promise.all(Object.entries({
|
|
6496
|
+
config: "packages/config",
|
|
6497
|
+
env: "packages/env",
|
|
6498
|
+
infra: "packages/infra",
|
|
6499
|
+
db: "packages/db",
|
|
6500
|
+
auth: "packages/auth",
|
|
6501
|
+
api: "packages/api",
|
|
6502
|
+
backend: "packages/backend",
|
|
6503
|
+
server: "apps/server",
|
|
6504
|
+
web: "apps/web",
|
|
6505
|
+
native: "apps/native"
|
|
6506
|
+
}).map(async ([name, relativePath]) => {
|
|
6507
|
+
const dir = path.join(projectDir, relativePath);
|
|
6508
|
+
return [name, {
|
|
6509
|
+
dir,
|
|
6510
|
+
exists: await fs.pathExists(dir)
|
|
6511
|
+
}];
|
|
6512
|
+
}));
|
|
6513
|
+
return Object.fromEntries(entries);
|
|
6514
|
+
}
|
|
6515
|
+
async function setupEnvPackage(pkg, infraPkg, ctx) {
|
|
6516
|
+
if (!pkg.exists) return;
|
|
6517
|
+
const runtimeDevDeps = getRuntimeDevDeps(ctx.options.runtime, ctx.options.backend);
|
|
6518
|
+
const customDevDeps = { ...ctx.configDep };
|
|
6519
|
+
if ((ctx.options.serverDeploy === "cloudflare" || ctx.options.webDeploy === "cloudflare") && infraPkg.exists) customDevDeps[`@${ctx.projectName}/infra`] = ctx.workspaceVersion;
|
|
6520
|
+
await addPackageDependency({
|
|
6521
|
+
dependencies: ctx.commonDeps,
|
|
6522
|
+
devDependencies: [...ctx.commonDevDeps, ...runtimeDevDeps],
|
|
6523
|
+
customDevDependencies: customDevDeps,
|
|
6524
|
+
projectDir: pkg.dir
|
|
6538
6525
|
});
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
if (auth !== "none" && authExists) serverDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6543
|
-
if (database !== "none" && dbExists) serverDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6544
|
-
await addPackageDependency({
|
|
6545
|
-
dependencies: commonDeps,
|
|
6546
|
-
devDependencies: [...commonDevDeps, "tsdown"],
|
|
6547
|
-
customDependencies: serverDeps,
|
|
6548
|
-
customDevDependencies: configDep,
|
|
6549
|
-
projectDir: serverDir
|
|
6550
|
-
});
|
|
6551
|
-
}
|
|
6552
|
-
if (webExists) {
|
|
6553
|
-
const webDeps = {};
|
|
6554
|
-
if (api !== "none" && apiExists) webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6555
|
-
if (auth !== "none" && authExists) webDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6556
|
-
if (backend === "convex" && backendExists) webDeps[`@${projectName}/backend`] = workspaceVersion;
|
|
6557
|
-
await addPackageDependency({
|
|
6558
|
-
dependencies: commonDeps,
|
|
6559
|
-
devDependencies: commonDevDeps,
|
|
6560
|
-
customDependencies: webDeps,
|
|
6561
|
-
customDevDependencies: configDep,
|
|
6562
|
-
projectDir: webDir
|
|
6563
|
-
});
|
|
6564
|
-
}
|
|
6565
|
-
if (nativeExists) {
|
|
6566
|
-
const nativeDeps = {};
|
|
6567
|
-
if (api !== "none" && apiExists) nativeDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6568
|
-
if (backend === "convex" && backendExists) nativeDeps[`@${projectName}/backend`] = workspaceVersion;
|
|
6569
|
-
await addPackageDependency({
|
|
6570
|
-
dependencies: commonDeps,
|
|
6571
|
-
devDependencies: commonDevDeps,
|
|
6572
|
-
customDependencies: nativeDeps,
|
|
6573
|
-
customDevDependencies: configDep,
|
|
6574
|
-
projectDir: nativeDir
|
|
6575
|
-
});
|
|
6576
|
-
}
|
|
6577
|
-
const runtimeDevDeps = getRuntimeDevDeps(runtime, backend);
|
|
6526
|
+
}
|
|
6527
|
+
async function setupInfraPackage(pkg, ctx) {
|
|
6528
|
+
if (!pkg.exists) return;
|
|
6578
6529
|
await addPackageDependency({
|
|
6579
|
-
dependencies: commonDeps,
|
|
6580
|
-
devDependencies:
|
|
6581
|
-
|
|
6530
|
+
dependencies: ctx.commonDeps,
|
|
6531
|
+
devDependencies: ctx.commonDevDeps,
|
|
6532
|
+
customDevDependencies: ctx.configDep,
|
|
6533
|
+
projectDir: pkg.dir
|
|
6534
|
+
});
|
|
6535
|
+
}
|
|
6536
|
+
async function setupDbPackage(pkg, ctx) {
|
|
6537
|
+
if (!pkg.exists) return;
|
|
6538
|
+
await addPackageDependency({
|
|
6539
|
+
dependencies: ctx.commonDeps,
|
|
6540
|
+
devDependencies: ctx.commonDevDeps,
|
|
6541
|
+
customDependencies: ctx.envDep,
|
|
6542
|
+
customDevDependencies: ctx.configDep,
|
|
6543
|
+
projectDir: pkg.dir
|
|
6544
|
+
});
|
|
6545
|
+
}
|
|
6546
|
+
async function setupAuthPackage(pkg, dbPkg, ctx) {
|
|
6547
|
+
if (!pkg.exists) return;
|
|
6548
|
+
const deps = { ...ctx.envDep };
|
|
6549
|
+
if (ctx.options.database !== "none" && dbPkg.exists) deps[`@${ctx.projectName}/db`] = ctx.workspaceVersion;
|
|
6550
|
+
await addPackageDependency({
|
|
6551
|
+
dependencies: ctx.commonDeps,
|
|
6552
|
+
devDependencies: ctx.commonDevDeps,
|
|
6553
|
+
customDependencies: deps,
|
|
6554
|
+
customDevDependencies: ctx.configDep,
|
|
6555
|
+
projectDir: pkg.dir
|
|
6556
|
+
});
|
|
6557
|
+
}
|
|
6558
|
+
async function setupApiPackage(pkg, authPkg, dbPkg, ctx) {
|
|
6559
|
+
if (!pkg.exists) return;
|
|
6560
|
+
const deps = { ...ctx.envDep };
|
|
6561
|
+
if (ctx.options.auth !== "none" && authPkg.exists) deps[`@${ctx.projectName}/auth`] = ctx.workspaceVersion;
|
|
6562
|
+
if (ctx.options.database !== "none" && dbPkg.exists) deps[`@${ctx.projectName}/db`] = ctx.workspaceVersion;
|
|
6563
|
+
await addPackageDependency({
|
|
6564
|
+
dependencies: ctx.commonDeps,
|
|
6565
|
+
devDependencies: ctx.commonDevDeps,
|
|
6566
|
+
customDependencies: deps,
|
|
6567
|
+
customDevDependencies: ctx.configDep,
|
|
6568
|
+
projectDir: pkg.dir
|
|
6569
|
+
});
|
|
6570
|
+
}
|
|
6571
|
+
async function setupBackendPackage(pkg, ctx) {
|
|
6572
|
+
if (!pkg.exists) return;
|
|
6573
|
+
await addPackageDependency({
|
|
6574
|
+
dependencies: ctx.commonDeps,
|
|
6575
|
+
devDependencies: ctx.commonDevDeps,
|
|
6576
|
+
customDevDependencies: ctx.configDep,
|
|
6577
|
+
projectDir: pkg.dir
|
|
6578
|
+
});
|
|
6579
|
+
}
|
|
6580
|
+
async function setupServerPackage(pkg, apiPkg, authPkg, dbPkg, ctx) {
|
|
6581
|
+
if (!pkg.exists) return;
|
|
6582
|
+
const deps = { ...ctx.envDep };
|
|
6583
|
+
if (ctx.options.api !== "none" && apiPkg.exists) deps[`@${ctx.projectName}/api`] = ctx.workspaceVersion;
|
|
6584
|
+
if (ctx.options.auth !== "none" && authPkg.exists) deps[`@${ctx.projectName}/auth`] = ctx.workspaceVersion;
|
|
6585
|
+
if (ctx.options.database !== "none" && dbPkg.exists) deps[`@${ctx.projectName}/db`] = ctx.workspaceVersion;
|
|
6586
|
+
await addPackageDependency({
|
|
6587
|
+
dependencies: ctx.commonDeps,
|
|
6588
|
+
devDependencies: [...ctx.commonDevDeps, "tsdown"],
|
|
6589
|
+
customDependencies: deps,
|
|
6590
|
+
customDevDependencies: ctx.configDep,
|
|
6591
|
+
projectDir: pkg.dir
|
|
6592
|
+
});
|
|
6593
|
+
}
|
|
6594
|
+
async function setupWebPackage(pkg, apiPkg, authPkg, backendPkg, ctx) {
|
|
6595
|
+
if (!pkg.exists) return;
|
|
6596
|
+
const deps = { ...ctx.envDep };
|
|
6597
|
+
if (ctx.options.api !== "none" && apiPkg.exists) deps[`@${ctx.projectName}/api`] = ctx.workspaceVersion;
|
|
6598
|
+
if (ctx.options.auth !== "none" && authPkg.exists) deps[`@${ctx.projectName}/auth`] = ctx.workspaceVersion;
|
|
6599
|
+
if (ctx.options.backend === "convex" && backendPkg.exists) deps[`@${ctx.projectName}/backend`] = ctx.workspaceVersion;
|
|
6600
|
+
await addPackageDependency({
|
|
6601
|
+
dependencies: ctx.commonDeps,
|
|
6602
|
+
devDependencies: ctx.commonDevDeps,
|
|
6603
|
+
customDependencies: deps,
|
|
6604
|
+
customDevDependencies: ctx.configDep,
|
|
6605
|
+
projectDir: pkg.dir
|
|
6606
|
+
});
|
|
6607
|
+
}
|
|
6608
|
+
async function setupNativePackage(pkg, apiPkg, backendPkg, ctx) {
|
|
6609
|
+
if (!pkg.exists) return;
|
|
6610
|
+
const deps = { ...ctx.envDep };
|
|
6611
|
+
if (ctx.options.api !== "none" && apiPkg.exists) deps[`@${ctx.projectName}/api`] = ctx.workspaceVersion;
|
|
6612
|
+
if (ctx.options.backend === "convex" && backendPkg.exists) deps[`@${ctx.projectName}/backend`] = ctx.workspaceVersion;
|
|
6613
|
+
await addPackageDependency({
|
|
6614
|
+
dependencies: ctx.commonDeps,
|
|
6615
|
+
devDependencies: ctx.commonDevDeps,
|
|
6616
|
+
customDependencies: deps,
|
|
6617
|
+
customDevDependencies: ctx.configDep,
|
|
6618
|
+
projectDir: pkg.dir
|
|
6582
6619
|
});
|
|
6583
6620
|
}
|
|
6584
6621
|
function getRuntimeDevDeps(runtime, backend) {
|
|
@@ -6615,7 +6652,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6615
6652
|
const dbPackageName = `@${projectName}/db`;
|
|
6616
6653
|
const hasTurborepo = addons.includes("turborepo");
|
|
6617
6654
|
const needsDbScripts = backend !== "convex" && database !== "none" && orm !== "none" && orm !== "mongoose";
|
|
6618
|
-
const isD1Alchemy = dbSetup === "d1" && serverDeploy === "
|
|
6655
|
+
const isD1Alchemy = dbSetup === "d1" && serverDeploy === "cloudflare";
|
|
6619
6656
|
const pmConfig = getPackageManagerConfig(packageManager, hasTurborepo);
|
|
6620
6657
|
scripts.dev = pmConfig.dev;
|
|
6621
6658
|
scripts.build = pmConfig.build;
|
|
@@ -6635,7 +6672,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6635
6672
|
if (!isD1Alchemy) scripts["db:migrate"] = pmConfig.filter(dbPackageName, "db:migrate");
|
|
6636
6673
|
}
|
|
6637
6674
|
}
|
|
6638
|
-
if (database === "sqlite" && dbSetup !== "d1"
|
|
6675
|
+
if (database === "sqlite" && dbSetup !== "d1") scripts["db:local"] = pmConfig.filter(dbPackageName, "db:local");
|
|
6639
6676
|
if (dbSetup === "docker") {
|
|
6640
6677
|
scripts["db:start"] = pmConfig.filter(dbPackageName, "db:start");
|
|
6641
6678
|
scripts["db:watch"] = pmConfig.filter(dbPackageName, "db:watch");
|
|
@@ -6643,7 +6680,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6643
6680
|
scripts["db:down"] = pmConfig.filter(dbPackageName, "db:down");
|
|
6644
6681
|
}
|
|
6645
6682
|
try {
|
|
6646
|
-
const { stdout } = await
|
|
6683
|
+
const { stdout } = await $`${packageManager} -v`;
|
|
6647
6684
|
packageJson.packageManager = `${packageManager}@${stdout.trim()}`;
|
|
6648
6685
|
} catch {
|
|
6649
6686
|
log.warn(`Could not determine ${packageManager} version.`);
|
|
@@ -6700,7 +6737,7 @@ async function updateDbPackageJson(projectDir, options) {
|
|
|
6700
6737
|
dbPackageJson.scripts = dbPackageJson.scripts || {};
|
|
6701
6738
|
const scripts = dbPackageJson.scripts;
|
|
6702
6739
|
const { database, orm, dbSetup, serverDeploy } = options;
|
|
6703
|
-
const isD1Alchemy = dbSetup === "d1" && serverDeploy === "
|
|
6740
|
+
const isD1Alchemy = dbSetup === "d1" && serverDeploy === "cloudflare";
|
|
6704
6741
|
if (database !== "none") {
|
|
6705
6742
|
if (database === "sqlite" && dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
|
|
6706
6743
|
if (orm === "prisma") {
|
|
@@ -6750,7 +6787,8 @@ async function updateConvexPackageJson(projectDir, options) {
|
|
|
6750
6787
|
|
|
6751
6788
|
//#endregion
|
|
6752
6789
|
//#region src/helpers/core/create-project.ts
|
|
6753
|
-
async function createProject(options, cliInput) {
|
|
6790
|
+
async function createProject(options, cliInput = {}) {
|
|
6791
|
+
const { silent = false } = cliInput;
|
|
6754
6792
|
const projectDir = options.projectDir;
|
|
6755
6793
|
const isConvex = options.backend === "convex";
|
|
6756
6794
|
const isSelfBackend = options.backend === "self";
|
|
@@ -6766,6 +6804,8 @@ async function createProject(options, cliInput) {
|
|
|
6766
6804
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
|
|
6767
6805
|
await setupAddonsTemplate(projectDir, options);
|
|
6768
6806
|
await setupDeploymentTemplates(projectDir, options);
|
|
6807
|
+
await setupEnvPackageDependencies(projectDir, options);
|
|
6808
|
+
if (options.serverDeploy === "cloudflare" || options.webDeploy === "cloudflare") await setupInfraPackageDependencies(projectDir, options);
|
|
6769
6809
|
await setupApi(options);
|
|
6770
6810
|
if (isConvex || needsServerSetup) await setupBackendDependencies(options);
|
|
6771
6811
|
if (!isConvex) {
|
|
@@ -6784,23 +6824,23 @@ async function createProject(options, cliInput) {
|
|
|
6784
6824
|
await setupCatalogs(projectDir, options);
|
|
6785
6825
|
await createReadme(projectDir, options);
|
|
6786
6826
|
await writeBtsConfig(options);
|
|
6787
|
-
log.success("Project template successfully scaffolded!");
|
|
6827
|
+
if (!silent) log.success("Project template successfully scaffolded!");
|
|
6788
6828
|
if (options.install) await installDependencies({
|
|
6789
6829
|
projectDir,
|
|
6790
6830
|
packageManager: options.packageManager
|
|
6791
6831
|
});
|
|
6792
6832
|
await initializeGit(projectDir, options.git);
|
|
6793
|
-
await displayPostInstallInstructions({
|
|
6833
|
+
if (!silent) await displayPostInstallInstructions({
|
|
6794
6834
|
...options,
|
|
6795
6835
|
depsInstalled: options.install
|
|
6796
6836
|
});
|
|
6797
6837
|
return projectDir;
|
|
6798
6838
|
} catch (error) {
|
|
6799
6839
|
if (error instanceof Error) {
|
|
6800
|
-
console.error(error.stack);
|
|
6840
|
+
if (!silent) console.error(error.stack);
|
|
6801
6841
|
exitWithError(`Error during project creation: ${error.message}`);
|
|
6802
6842
|
} else {
|
|
6803
|
-
console.error(error);
|
|
6843
|
+
if (!silent) console.error(error);
|
|
6804
6844
|
exitWithError(`An unexpected error occurred: ${String(error)}`);
|
|
6805
6845
|
}
|
|
6806
6846
|
}
|
|
@@ -6808,12 +6848,13 @@ async function createProject(options, cliInput) {
|
|
|
6808
6848
|
|
|
6809
6849
|
//#endregion
|
|
6810
6850
|
//#region src/helpers/core/command-handlers.ts
|
|
6811
|
-
async function createProjectHandler(input) {
|
|
6851
|
+
async function createProjectHandler(input, options = {}) {
|
|
6852
|
+
const { silent = false } = options;
|
|
6812
6853
|
const startTime = Date.now();
|
|
6813
6854
|
const timeScaffolded = (/* @__PURE__ */ new Date()).toISOString();
|
|
6814
|
-
if (input.renderTitle !== false) renderTitle();
|
|
6815
|
-
intro(pc.magenta("Creating a new Better-T-Stack project"));
|
|
6816
|
-
if (input.yolo) consola.fatal("YOLO mode enabled - skipping checks. Things may break!");
|
|
6855
|
+
if (!silent && input.renderTitle !== false) renderTitle();
|
|
6856
|
+
if (!silent) intro(pc.magenta("Creating a new Better-T-Stack project"));
|
|
6857
|
+
if (!silent && input.yolo) consola.fatal("YOLO mode enabled - skipping checks. Things may break!");
|
|
6817
6858
|
let currentPathInput;
|
|
6818
6859
|
if (input.yes && input.projectName) currentPathInput = input.projectName;
|
|
6819
6860
|
else if (input.yes) {
|
|
@@ -6882,8 +6923,10 @@ async function createProjectHandler(input) {
|
|
|
6882
6923
|
if (templateConfig) {
|
|
6883
6924
|
const templateName = input.template.toUpperCase();
|
|
6884
6925
|
const templateDescription = getTemplateDescription(input.template);
|
|
6885
|
-
|
|
6886
|
-
|
|
6926
|
+
if (!silent) {
|
|
6927
|
+
log.message(pc.bold(pc.cyan(`Using template: ${pc.white(templateName)}`)));
|
|
6928
|
+
log.message(pc.dim(` ${templateDescription}`));
|
|
6929
|
+
}
|
|
6887
6930
|
const userOverrides = {};
|
|
6888
6931
|
for (const [key, value] of Object.entries(originalInput)) if (value !== void 0) userOverrides[key] = value;
|
|
6889
6932
|
cliInput = {
|
|
@@ -6905,25 +6948,32 @@ async function createProjectHandler(input) {
|
|
|
6905
6948
|
relativePath: finalPathInput
|
|
6906
6949
|
};
|
|
6907
6950
|
validateConfigCompatibility(config, providedFlags, cliInput);
|
|
6908
|
-
|
|
6909
|
-
|
|
6951
|
+
if (!silent) {
|
|
6952
|
+
log.info(pc.yellow("Using default/flag options (config prompts skipped):"));
|
|
6953
|
+
log.message(displayConfig(config));
|
|
6954
|
+
}
|
|
6910
6955
|
} else {
|
|
6911
6956
|
const flagConfig = processAndValidateFlags(cliInput, providedFlags, finalBaseName);
|
|
6912
6957
|
const { projectName: _projectNameFromFlags, ...otherFlags } = flagConfig;
|
|
6913
|
-
if (Object.keys(otherFlags).length > 0) {
|
|
6958
|
+
if (!silent && Object.keys(otherFlags).length > 0) {
|
|
6914
6959
|
log.info(pc.yellow("Using these pre-selected options:"));
|
|
6915
6960
|
log.message(displayConfig(otherFlags));
|
|
6916
6961
|
log.message("");
|
|
6917
6962
|
}
|
|
6918
6963
|
config = await gatherConfig(flagConfig, finalBaseName, finalResolvedPath, finalPathInput);
|
|
6919
6964
|
}
|
|
6920
|
-
await createProject(config, {
|
|
6965
|
+
await createProject(config, {
|
|
6966
|
+
manualDb: cliInput.manualDb ?? input.manualDb,
|
|
6967
|
+
silent
|
|
6968
|
+
});
|
|
6921
6969
|
const reproducibleCommand = generateReproducibleCommand(config);
|
|
6922
|
-
log.success(pc.blue(`You can reproduce this setup with the following command:\n${reproducibleCommand}`));
|
|
6970
|
+
if (!silent) log.success(pc.blue(`You can reproduce this setup with the following command:\n${reproducibleCommand}`));
|
|
6923
6971
|
await trackProjectCreation(config, input.disableAnalytics);
|
|
6924
6972
|
const elapsedTimeMs = Date.now() - startTime;
|
|
6925
|
-
|
|
6926
|
-
|
|
6973
|
+
if (!silent) {
|
|
6974
|
+
const elapsedTimeInSeconds = (elapsedTimeMs / 1e3).toFixed(2);
|
|
6975
|
+
outro(pc.magenta(`Project created successfully in ${pc.bold(elapsedTimeInSeconds)} seconds!`));
|
|
6976
|
+
}
|
|
6927
6977
|
return {
|
|
6928
6978
|
success: true,
|
|
6929
6979
|
projectConfig: config,
|
|
@@ -7035,25 +7085,12 @@ async function addAddonsHandler(input) {
|
|
|
7035
7085
|
//#region src/utils/open-url.ts
|
|
7036
7086
|
async function openUrl(url) {
|
|
7037
7087
|
const platform = process.platform;
|
|
7038
|
-
let command;
|
|
7039
|
-
let args = [];
|
|
7040
|
-
if (platform === "darwin") {
|
|
7041
|
-
command = "open";
|
|
7042
|
-
args = [url];
|
|
7043
|
-
} else if (platform === "win32") {
|
|
7044
|
-
command = "cmd";
|
|
7045
|
-
args = [
|
|
7046
|
-
"/c",
|
|
7047
|
-
"start",
|
|
7048
|
-
"",
|
|
7049
|
-
url.replace(/&/g, "^&")
|
|
7050
|
-
];
|
|
7051
|
-
} else {
|
|
7052
|
-
command = "xdg-open";
|
|
7053
|
-
args = [url];
|
|
7054
|
-
}
|
|
7055
7088
|
try {
|
|
7056
|
-
|
|
7089
|
+
if (platform === "darwin") await $({ stdio: "ignore" })`open ${url}`;
|
|
7090
|
+
else if (platform === "win32") {
|
|
7091
|
+
const escapedUrl = url.replace(/&/g, "^&");
|
|
7092
|
+
await $({ stdio: "ignore" })`cmd /c start "" ${escapedUrl}`;
|
|
7093
|
+
} else await $({ stdio: "ignore" })`xdg-open ${url}`;
|
|
7057
7094
|
} catch {
|
|
7058
7095
|
log.message(`Please open ${url} in your browser.`);
|
|
7059
7096
|
}
|
|
@@ -7103,32 +7140,32 @@ function displaySponsorsBox(sponsors$1) {
|
|
|
7103
7140
|
//#endregion
|
|
7104
7141
|
//#region src/index.ts
|
|
7105
7142
|
const router = os.router({
|
|
7106
|
-
|
|
7143
|
+
create: os.meta({
|
|
7107
7144
|
description: "Create a new Better-T-Stack project",
|
|
7108
7145
|
default: true,
|
|
7109
7146
|
negateBooleans: true
|
|
7110
|
-
}).input(z.tuple([ProjectNameSchema.optional(), z.object({
|
|
7111
|
-
template: TemplateSchema.optional().describe("Use a predefined template"),
|
|
7147
|
+
}).input(z.tuple([types_exports.ProjectNameSchema.optional(), z.object({
|
|
7148
|
+
template: types_exports.TemplateSchema.optional().describe("Use a predefined template"),
|
|
7112
7149
|
yes: z.boolean().optional().default(false).describe("Use default configuration"),
|
|
7113
7150
|
yolo: z.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
|
|
7114
7151
|
verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
|
|
7115
|
-
database: DatabaseSchema.optional(),
|
|
7116
|
-
orm: ORMSchema.optional(),
|
|
7117
|
-
auth: AuthSchema.optional(),
|
|
7118
|
-
payments: PaymentsSchema.optional(),
|
|
7119
|
-
frontend: z.array(FrontendSchema).optional(),
|
|
7120
|
-
addons: z.array(AddonsSchema).optional(),
|
|
7121
|
-
examples: z.array(ExamplesSchema).optional(),
|
|
7152
|
+
database: types_exports.DatabaseSchema.optional(),
|
|
7153
|
+
orm: types_exports.ORMSchema.optional(),
|
|
7154
|
+
auth: types_exports.AuthSchema.optional(),
|
|
7155
|
+
payments: types_exports.PaymentsSchema.optional(),
|
|
7156
|
+
frontend: z.array(types_exports.FrontendSchema).optional(),
|
|
7157
|
+
addons: z.array(types_exports.AddonsSchema).optional(),
|
|
7158
|
+
examples: z.array(types_exports.ExamplesSchema).optional(),
|
|
7122
7159
|
git: z.boolean().optional(),
|
|
7123
|
-
packageManager: PackageManagerSchema.optional(),
|
|
7160
|
+
packageManager: types_exports.PackageManagerSchema.optional(),
|
|
7124
7161
|
install: z.boolean().optional(),
|
|
7125
|
-
dbSetup: DatabaseSetupSchema.optional(),
|
|
7126
|
-
backend: BackendSchema.optional(),
|
|
7127
|
-
runtime: RuntimeSchema.optional(),
|
|
7128
|
-
api: APISchema.optional(),
|
|
7129
|
-
webDeploy: WebDeploySchema.optional(),
|
|
7130
|
-
serverDeploy: ServerDeploySchema.optional(),
|
|
7131
|
-
directoryConflict: DirectoryConflictSchema.optional(),
|
|
7162
|
+
dbSetup: types_exports.DatabaseSetupSchema.optional(),
|
|
7163
|
+
backend: types_exports.BackendSchema.optional(),
|
|
7164
|
+
runtime: types_exports.RuntimeSchema.optional(),
|
|
7165
|
+
api: types_exports.APISchema.optional(),
|
|
7166
|
+
webDeploy: types_exports.WebDeploySchema.optional(),
|
|
7167
|
+
serverDeploy: types_exports.ServerDeploySchema.optional(),
|
|
7168
|
+
directoryConflict: types_exports.DirectoryConflictSchema.optional(),
|
|
7132
7169
|
renderTitle: z.boolean().optional(),
|
|
7133
7170
|
disableAnalytics: z.boolean().optional().default(false).describe("Disable analytics"),
|
|
7134
7171
|
manualDb: z.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup")
|
|
@@ -7141,12 +7178,12 @@ const router = os.router({
|
|
|
7141
7178
|
if (options.verbose) return result;
|
|
7142
7179
|
}),
|
|
7143
7180
|
add: os.meta({ description: "Add addons or deployment configurations to an existing Better-T-Stack project" }).input(z.tuple([z.object({
|
|
7144
|
-
addons: z.array(AddonsSchema).optional().default([]),
|
|
7145
|
-
webDeploy: WebDeploySchema.optional(),
|
|
7146
|
-
serverDeploy: ServerDeploySchema.optional(),
|
|
7181
|
+
addons: z.array(types_exports.AddonsSchema).optional().default([]),
|
|
7182
|
+
webDeploy: types_exports.WebDeploySchema.optional(),
|
|
7183
|
+
serverDeploy: types_exports.ServerDeploySchema.optional(),
|
|
7147
7184
|
projectDir: z.string().optional(),
|
|
7148
7185
|
install: z.boolean().optional().default(false).describe("Install dependencies after adding addons or deployment"),
|
|
7149
|
-
packageManager: PackageManagerSchema.optional()
|
|
7186
|
+
packageManager: types_exports.PackageManagerSchema.optional()
|
|
7150
7187
|
})])).handler(async ({ input }) => {
|
|
7151
7188
|
const [options] = input;
|
|
7152
7189
|
await addAddonsHandler(options);
|
|
@@ -7188,49 +7225,49 @@ function createBtsCli() {
|
|
|
7188
7225
|
});
|
|
7189
7226
|
}
|
|
7190
7227
|
/**
|
|
7191
|
-
*
|
|
7228
|
+
* Programmatic API to create a new Better-T-Stack project.
|
|
7229
|
+
* Returns pure JSON - no console output, no interactive prompts.
|
|
7192
7230
|
*
|
|
7193
|
-
* @example
|
|
7194
|
-
* ```bash
|
|
7195
|
-
* npx create-better-t-stack my-app --yes
|
|
7196
|
-
* ```
|
|
7197
|
-
*
|
|
7198
|
-
* @example Programmatic usage (always returns structured data):
|
|
7231
|
+
* @example
|
|
7199
7232
|
* ```typescript
|
|
7200
|
-
* import {
|
|
7233
|
+
* import { create } from "create-better-t-stack";
|
|
7201
7234
|
*
|
|
7202
|
-
* const result = await
|
|
7203
|
-
* yes: true,
|
|
7235
|
+
* const result = await create("my-app", {
|
|
7204
7236
|
* frontend: ["tanstack-router"],
|
|
7205
7237
|
* backend: "hono",
|
|
7238
|
+
* runtime: "bun",
|
|
7206
7239
|
* database: "sqlite",
|
|
7207
7240
|
* orm: "drizzle",
|
|
7208
|
-
* auth: "better-auth",
|
|
7209
|
-
* addons: ["biome", "turborepo"],
|
|
7210
|
-
* packageManager: "bun",
|
|
7211
|
-
* install: false,
|
|
7212
|
-
* directoryConflict: "increment", // auto-handle conflicts
|
|
7213
|
-
* disableAnalytics: true, // disable analytics
|
|
7214
7241
|
* });
|
|
7215
7242
|
*
|
|
7216
7243
|
* if (result.success) {
|
|
7217
7244
|
* console.log(`Project created at: ${result.projectDirectory}`);
|
|
7218
|
-
* console.log(`Reproducible command: ${result.reproducibleCommand}`);
|
|
7219
|
-
* console.log(`Time taken: ${result.elapsedTimeMs}ms`);
|
|
7220
7245
|
* }
|
|
7221
7246
|
* ```
|
|
7222
7247
|
*/
|
|
7223
|
-
async function
|
|
7224
|
-
const
|
|
7225
|
-
...options
|
|
7226
|
-
|
|
7248
|
+
async function create(projectName, options) {
|
|
7249
|
+
const input = {
|
|
7250
|
+
...options,
|
|
7251
|
+
projectName,
|
|
7252
|
+
renderTitle: false,
|
|
7253
|
+
verbose: true,
|
|
7254
|
+
disableAnalytics: options?.disableAnalytics ?? true,
|
|
7255
|
+
directoryConflict: options?.directoryConflict ?? "error"
|
|
7227
7256
|
};
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7257
|
+
try {
|
|
7258
|
+
return await createProjectHandler(input, { silent: true });
|
|
7259
|
+
} catch (error) {
|
|
7260
|
+
return {
|
|
7261
|
+
success: false,
|
|
7262
|
+
error: error instanceof Error ? error.message : String(error),
|
|
7263
|
+
projectConfig: {},
|
|
7264
|
+
reproducibleCommand: "",
|
|
7265
|
+
timeScaffolded: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7266
|
+
elapsedTimeMs: 0,
|
|
7267
|
+
projectDirectory: "",
|
|
7268
|
+
relativePath: ""
|
|
7269
|
+
};
|
|
7270
|
+
}
|
|
7234
7271
|
}
|
|
7235
7272
|
async function sponsors() {
|
|
7236
7273
|
return caller.sponsors();
|
|
@@ -7243,4 +7280,4 @@ async function builder() {
|
|
|
7243
7280
|
}
|
|
7244
7281
|
|
|
7245
7282
|
//#endregion
|
|
7246
|
-
export { router as a,
|
|
7283
|
+
export { router as a, docs as i, create as n, sponsors as o, createBtsCli as r, builder as t };
|