create-better-t-stack 2.36.3 → 2.37.0-canary.6846bd90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.js +1 -1
- package/dist/{src-CN1zi2A-.js → src-ByxWjVSi.js} +331 -241
- package/package.json +1 -1
- package/templates/addons/ruler/.ruler/bts.md.hbs +2 -2
- package/templates/api/orpc/native/utils/orpc.ts.hbs +2 -2
- package/templates/api/orpc/server/base/src/lib/context.ts.hbs +10 -10
- package/templates/api/orpc/server/base/src/lib/orpc.ts.hbs +1 -1
- package/templates/api/orpc/server/next/src/app/rpc/[...all]/route.ts.hbs +2 -2
- package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +1 -1
- package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +1 -1
- package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +1 -1
- package/templates/api/orpc/web/svelte/src/lib/orpc.ts.hbs +1 -1
- package/templates/api/trpc/native/utils/trpc.ts.hbs +2 -2
- package/templates/api/trpc/server/base/src/lib/context.ts.hbs +10 -10
- package/templates/api/trpc/server/base/src/lib/trpc.ts.hbs +1 -1
- package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +2 -2
- package/templates/auth/clerk/convex/backend/convex/auth.config.ts.hbs +12 -0
- package/templates/auth/clerk/convex/backend/convex/privateData.ts.hbs +16 -0
- package/templates/auth/clerk/convex/native/base/app/(auth)/_layout.tsx.hbs +12 -0
- package/templates/auth/clerk/convex/native/base/app/(auth)/sign-in.tsx.hbs +67 -0
- package/templates/auth/clerk/convex/native/base/app/(auth)/sign-out.tsx.hbs +110 -0
- package/templates/auth/clerk/convex/native/base/components/sign-out-button.tsx.hbs +27 -0
- package/templates/auth/clerk/convex/web/react/next/src/app/dashboard/page.tsx.hbs +29 -0
- package/templates/auth/clerk/convex/web/react/next/src/middleware.ts.hbs +12 -0
- package/templates/auth/clerk/convex/web/react/react-router/src/routes/dashboard.tsx.hbs +32 -0
- package/templates/auth/clerk/convex/web/react/tanstack-router/src/routes/dashboard.tsx.hbs +37 -0
- package/templates/auth/clerk/convex/web/react/tanstack-start/src/routes/dashboard.tsx.hbs +37 -0
- package/templates/auth/clerk/convex/web/react/tanstack-start/src/server.ts.hbs +18 -0
- package/templates/backend/convex/packages/backend/package.json.hbs +1 -0
- package/templates/backend/server/elysia/src/index.ts.hbs +3 -3
- package/templates/backend/server/express/src/index.ts.hbs +6 -6
- package/templates/backend/server/fastify/src/index.ts.hbs +4 -4
- package/templates/backend/server/hono/src/index.ts.hbs +4 -4
- package/templates/backend/server/server-base/src/routers/index.ts.hbs +4 -4
- package/templates/deploy/alchemy/alchemy.run.ts.hbs +3 -18
- package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +35 -3
- package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +28 -0
- package/templates/frontend/native/nativewind/package.json.hbs +1 -0
- package/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs +32 -0
- package/templates/frontend/native/unistyles/app/_layout.tsx.hbs +35 -0
- package/templates/frontend/native/unistyles/package.json.hbs +1 -0
- package/templates/frontend/nuxt/app/components/Header.vue.hbs +3 -3
- package/templates/frontend/react/next/src/app/layout.tsx.hbs +23 -15
- package/templates/frontend/react/next/src/components/providers.tsx.hbs +12 -0
- package/templates/frontend/react/react-router/src/root.tsx.hbs +28 -1
- package/templates/frontend/react/tanstack-router/src/main.tsx.hbs +19 -1
- package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +8 -4
- package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +52 -5
- package/templates/frontend/react/web-base/src/components/header.tsx.hbs +3 -3
- package/templates/frontend/solid/src/components/header.tsx.hbs +3 -3
- package/templates/frontend/svelte/src/components/Header.svelte.hbs +3 -3
- package/templates/deploy/alchemy/wrangler.jsonc.hbs +0 -11
- /package/templates/auth/{native → better-auth/native}/native-base/lib/auth-client.ts.hbs +0 -0
- /package/templates/auth/{native → better-auth/native}/nativewind/app/(drawer)/index.tsx.hbs +0 -0
- /package/templates/auth/{native → better-auth/native}/nativewind/components/sign-in.tsx.hbs +0 -0
- /package/templates/auth/{native → better-auth/native}/nativewind/components/sign-up.tsx.hbs +0 -0
- /package/templates/auth/{native → better-auth/native}/unistyles/app/(drawer)/index.tsx.hbs +0 -0
- /package/templates/auth/{native → better-auth/native}/unistyles/components/sign-in.tsx.hbs +0 -0
- /package/templates/auth/{native → better-auth/native}/unistyles/components/sign-up.tsx.hbs +0 -0
- /package/templates/auth/{server → better-auth/server}/base/src/lib/auth.ts.hbs +0 -0
- /package/templates/auth/{server → better-auth/server}/db/drizzle/mysql/src/db/schema/auth.ts +0 -0
- /package/templates/auth/{server → better-auth/server}/db/drizzle/postgres/src/db/schema/auth.ts +0 -0
- /package/templates/auth/{server → better-auth/server}/db/drizzle/sqlite/src/db/schema/auth.ts +0 -0
- /package/templates/auth/{server → better-auth/server}/db/mongoose/mongodb/src/db/models/auth.model.ts +0 -0
- /package/templates/auth/{server → better-auth/server}/db/prisma/mongodb/prisma/schema/auth.prisma +0 -0
- /package/templates/auth/{server → better-auth/server}/db/prisma/mysql/prisma/schema/auth.prisma +0 -0
- /package/templates/auth/{server → better-auth/server}/db/prisma/postgres/prisma/schema/auth.prisma +0 -0
- /package/templates/auth/{server → better-auth/server}/db/prisma/sqlite/prisma/schema/auth.prisma +0 -0
- /package/templates/auth/{server → better-auth/server}/next/src/app/api/auth/[...all]/route.ts +0 -0
- /package/templates/auth/{web → better-auth/web}/nuxt/app/components/SignInForm.vue +0 -0
- /package/templates/auth/{web → better-auth/web}/nuxt/app/components/SignUpForm.vue +0 -0
- /package/templates/auth/{web → better-auth/web}/nuxt/app/components/UserMenu.vue +0 -0
- /package/templates/auth/{web → better-auth/web}/nuxt/app/middleware/auth.ts +0 -0
- /package/templates/auth/{web → better-auth/web}/nuxt/app/pages/dashboard.vue.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/nuxt/app/pages/login.vue +0 -0
- /package/templates/auth/{web → better-auth/web}/nuxt/app/plugins/auth-client.ts +0 -0
- /package/templates/auth/{web → better-auth/web}/react/base/src/lib/auth-client.ts.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/react/next/src/app/dashboard/page.tsx.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/react/next/src/app/login/page.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/next/src/components/sign-in-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/next/src/components/sign-up-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/next/src/components/theme-provider.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/next/src/components/user-menu.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/sign-in-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/sign-up-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/user-menu.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/react-router/src/routes/dashboard.tsx.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/react/react-router/src/routes/login.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/sign-in-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/sign-up-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/user-menu.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/routes/dashboard.tsx.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/routes/login.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/sign-in-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/sign-up-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/user-menu.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/routes/dashboard.tsx.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/routes/login.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/solid/src/components/sign-in-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/solid/src/components/sign-up-form.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/solid/src/components/user-menu.tsx.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/solid/src/lib/auth-client.ts +0 -0
- /package/templates/auth/{web → better-auth/web}/solid/src/routes/dashboard.tsx.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/solid/src/routes/login.tsx +0 -0
- /package/templates/auth/{web → better-auth/web}/svelte/src/components/SignInForm.svelte +0 -0
- /package/templates/auth/{web → better-auth/web}/svelte/src/components/SignUpForm.svelte +0 -0
- /package/templates/auth/{web → better-auth/web}/svelte/src/components/UserMenu.svelte +0 -0
- /package/templates/auth/{web → better-auth/web}/svelte/src/lib/auth-client.ts +0 -0
- /package/templates/auth/{web → better-auth/web}/svelte/src/routes/dashboard/+page.svelte.hbs +0 -0
- /package/templates/auth/{web → better-auth/web}/svelte/src/routes/login/+page.svelte +0 -0
|
@@ -35,7 +35,7 @@ const DEFAULT_CONFIG_BASE = {
|
|
|
35
35
|
frontend: ["tanstack-router"],
|
|
36
36
|
database: "sqlite",
|
|
37
37
|
orm: "drizzle",
|
|
38
|
-
auth:
|
|
38
|
+
auth: "better-auth",
|
|
39
39
|
addons: ["turborepo"],
|
|
40
40
|
examples: [],
|
|
41
41
|
git: true,
|
|
@@ -61,6 +61,10 @@ const DEFAULT_CONFIG = getDefaultConfig();
|
|
|
61
61
|
const dependencyVersionMap = {
|
|
62
62
|
"better-auth": "^1.3.7",
|
|
63
63
|
"@better-auth/expo": "^1.3.7",
|
|
64
|
+
"@clerk/nextjs": "^6.31.5",
|
|
65
|
+
"@clerk/clerk-react": "^5.45.0",
|
|
66
|
+
"@clerk/tanstack-react-start": "^0.23.1",
|
|
67
|
+
"@clerk/clerk-expo": "^2.14.25",
|
|
64
68
|
"drizzle-orm": "^0.44.2",
|
|
65
69
|
"drizzle-kit": "^0.31.2",
|
|
66
70
|
"@libsql/client": "^0.15.9",
|
|
@@ -129,7 +133,7 @@ const dependencyVersionMap = {
|
|
|
129
133
|
"nitro-cloudflare-dev": "^0.2.2",
|
|
130
134
|
"@sveltejs/adapter-cloudflare": "^7.2.1",
|
|
131
135
|
"@cloudflare/workers-types": "^4.20250822.0",
|
|
132
|
-
alchemy: "^0.
|
|
136
|
+
alchemy: "^0.63.0",
|
|
133
137
|
nitropack: "^2.12.4",
|
|
134
138
|
dotenv: "^17.2.1"
|
|
135
139
|
};
|
|
@@ -239,6 +243,11 @@ const APISchema = z.enum([
|
|
|
239
243
|
"orpc",
|
|
240
244
|
"none"
|
|
241
245
|
]).describe("API type");
|
|
246
|
+
const AuthSchema = z.enum([
|
|
247
|
+
"better-auth",
|
|
248
|
+
"clerk",
|
|
249
|
+
"none"
|
|
250
|
+
]).describe("Authentication provider");
|
|
242
251
|
const ProjectNameSchema = z.string().min(1, "Project name cannot be empty").max(255, "Project name must be less than 255 characters").refine((name) => name === "." || !name.startsWith("."), "Project name cannot start with a dot (except for '.')").refine((name) => name === "." || !name.startsWith("-"), "Project name cannot start with a dash").refine((name) => {
|
|
243
252
|
const invalidChars = [
|
|
244
253
|
"<",
|
|
@@ -495,7 +504,6 @@ function validateWorkersCompatibility(providedFlags, options, config) {
|
|
|
495
504
|
}
|
|
496
505
|
function coerceBackendPresets(config) {
|
|
497
506
|
if (config.backend === "convex") {
|
|
498
|
-
config.auth = false;
|
|
499
507
|
config.database = "none";
|
|
500
508
|
config.orm = "none";
|
|
501
509
|
config.api = "none";
|
|
@@ -504,7 +512,7 @@ function coerceBackendPresets(config) {
|
|
|
504
512
|
config.examples = ["todo"];
|
|
505
513
|
}
|
|
506
514
|
if (config.backend === "none") {
|
|
507
|
-
config.auth =
|
|
515
|
+
config.auth = "none";
|
|
508
516
|
config.database = "none";
|
|
509
517
|
config.orm = "none";
|
|
510
518
|
config.api = "none";
|
|
@@ -516,7 +524,7 @@ function coerceBackendPresets(config) {
|
|
|
516
524
|
function incompatibleFlagsForBackend(backend, providedFlags, options) {
|
|
517
525
|
const list = [];
|
|
518
526
|
if (backend === "convex") {
|
|
519
|
-
if (providedFlags.has("auth") && options.auth
|
|
527
|
+
if (providedFlags.has("auth") && options.auth && options.auth !== "none" && options.auth !== "clerk") list.push(`--auth ${options.auth}`);
|
|
520
528
|
if (providedFlags.has("database") && options.database !== "none") list.push(`--database ${options.database}`);
|
|
521
529
|
if (providedFlags.has("orm") && options.orm !== "none") list.push(`--orm ${options.orm}`);
|
|
522
530
|
if (providedFlags.has("api") && options.api !== "none") list.push(`--api ${options.api}`);
|
|
@@ -524,7 +532,7 @@ function incompatibleFlagsForBackend(backend, providedFlags, options) {
|
|
|
524
532
|
if (providedFlags.has("dbSetup") && options.dbSetup !== "none") list.push(`--db-setup ${options.dbSetup}`);
|
|
525
533
|
}
|
|
526
534
|
if (backend === "none") {
|
|
527
|
-
if (providedFlags.has("auth") && options.auth
|
|
535
|
+
if (providedFlags.has("auth") && options.auth && options.auth !== "none") list.push(`--auth ${options.auth}`);
|
|
528
536
|
if (providedFlags.has("database") && options.database !== "none") list.push(`--database ${options.database}`);
|
|
529
537
|
if (providedFlags.has("orm") && options.orm !== "none") list.push(`--orm ${options.orm}`);
|
|
530
538
|
if (providedFlags.has("api") && options.api !== "none") list.push(`--api ${options.api}`);
|
|
@@ -543,8 +551,16 @@ function validateApiFrontendCompatibility(api, frontends = []) {
|
|
|
543
551
|
const includesSolid = frontends.includes("solid");
|
|
544
552
|
if ((includesNuxt || includesSvelte || includesSolid) && api === "trpc") exitWithError(`tRPC API is not supported with '${includesNuxt ? "nuxt" : includesSvelte ? "svelte" : "solid"}' frontend. Please use --api orpc or --api none or remove '${includesNuxt ? "nuxt" : includesSvelte ? "svelte" : "solid"}' from --frontend.`);
|
|
545
553
|
}
|
|
546
|
-
function isFrontendAllowedWithBackend(frontend, backend) {
|
|
554
|
+
function isFrontendAllowedWithBackend(frontend, backend, auth) {
|
|
547
555
|
if (backend === "convex" && frontend === "solid") return false;
|
|
556
|
+
if (auth === "clerk" && backend === "convex") {
|
|
557
|
+
const incompatibleFrontends = [
|
|
558
|
+
"nuxt",
|
|
559
|
+
"svelte",
|
|
560
|
+
"solid"
|
|
561
|
+
];
|
|
562
|
+
if (incompatibleFrontends.includes(frontend)) return false;
|
|
563
|
+
}
|
|
548
564
|
return true;
|
|
549
565
|
}
|
|
550
566
|
function allowedApisForFrontends(frontends = []) {
|
|
@@ -592,7 +608,7 @@ function validateAlchemyCompatibility(webDeploy, serverDeploy, frontends = []) {
|
|
|
592
608
|
const isAlchemyWebDeploy = webDeploy === "alchemy";
|
|
593
609
|
const isAlchemyServerDeploy = serverDeploy === "alchemy";
|
|
594
610
|
if (isAlchemyWebDeploy || isAlchemyServerDeploy) {
|
|
595
|
-
const incompatibleFrontends = frontends.filter((f) => f === "next"
|
|
611
|
+
const incompatibleFrontends = frontends.filter((f) => f === "next");
|
|
596
612
|
if (incompatibleFrontends.length > 0) {
|
|
597
613
|
const deployType = isAlchemyWebDeploy && isAlchemyServerDeploy ? "web and server deployment" : isAlchemyWebDeploy ? "web deployment" : "server deployment";
|
|
598
614
|
exitWithError(`Alchemy ${deployType} is temporarily not compatible with ${incompatibleFrontends.join(" and ")} frontend(s). Please choose a different frontend or deployment option.`);
|
|
@@ -630,12 +646,41 @@ async function getApiChoice(Api, frontend, backend) {
|
|
|
630
646
|
|
|
631
647
|
//#endregion
|
|
632
648
|
//#region src/prompts/auth.ts
|
|
633
|
-
async function getAuthChoice(auth, hasDatabase, backend) {
|
|
634
|
-
if (backend === "convex") return false;
|
|
635
|
-
if (!hasDatabase) return false;
|
|
649
|
+
async function getAuthChoice(auth, hasDatabase, backend, frontend) {
|
|
636
650
|
if (auth !== void 0) return auth;
|
|
637
|
-
|
|
638
|
-
|
|
651
|
+
if (backend === "convex") {
|
|
652
|
+
const unsupportedFrontends = frontend?.filter((f) => [
|
|
653
|
+
"nuxt",
|
|
654
|
+
"svelte",
|
|
655
|
+
"solid"
|
|
656
|
+
].includes(f));
|
|
657
|
+
if (unsupportedFrontends && unsupportedFrontends.length > 0) return "none";
|
|
658
|
+
const response$1 = await select({
|
|
659
|
+
message: "Select authentication provider",
|
|
660
|
+
options: [{
|
|
661
|
+
value: "clerk",
|
|
662
|
+
label: "Clerk",
|
|
663
|
+
hint: "More than auth, Complete User Management"
|
|
664
|
+
}, {
|
|
665
|
+
value: "none",
|
|
666
|
+
label: "None"
|
|
667
|
+
}],
|
|
668
|
+
initialValue: "clerk"
|
|
669
|
+
});
|
|
670
|
+
if (isCancel(response$1)) return exitCancelled("Operation cancelled");
|
|
671
|
+
return response$1;
|
|
672
|
+
}
|
|
673
|
+
if (!hasDatabase) return "none";
|
|
674
|
+
const response = await select({
|
|
675
|
+
message: "Select authentication provider",
|
|
676
|
+
options: [{
|
|
677
|
+
value: "better-auth",
|
|
678
|
+
label: "Better-Auth",
|
|
679
|
+
hint: "comprehensive auth framework for TypeScript"
|
|
680
|
+
}, {
|
|
681
|
+
value: "none",
|
|
682
|
+
label: "None"
|
|
683
|
+
}],
|
|
639
684
|
initialValue: DEFAULT_CONFIG.auth
|
|
640
685
|
});
|
|
641
686
|
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
@@ -857,7 +902,7 @@ async function getExamplesChoice(examples, database, frontends, backend, api) {
|
|
|
857
902
|
|
|
858
903
|
//#endregion
|
|
859
904
|
//#region src/prompts/frontend.ts
|
|
860
|
-
async function getFrontendChoice(frontendOptions, backend) {
|
|
905
|
+
async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
861
906
|
if (frontendOptions !== void 0) return frontendOptions;
|
|
862
907
|
const frontendTypes = await multiselect({
|
|
863
908
|
message: "Select project type",
|
|
@@ -913,7 +958,7 @@ async function getFrontendChoice(frontendOptions, backend) {
|
|
|
913
958
|
hint: "SSR, Server Functions, API Routes and more with TanStack Router"
|
|
914
959
|
}
|
|
915
960
|
];
|
|
916
|
-
const webOptions = allWebOptions.filter((option) => isFrontendAllowedWithBackend(option.value, backend));
|
|
961
|
+
const webOptions = allWebOptions.filter((option) => isFrontendAllowedWithBackend(option.value, backend, auth));
|
|
917
962
|
const webFramework = await select({
|
|
918
963
|
message: "Choose web",
|
|
919
964
|
options: webOptions,
|
|
@@ -1152,7 +1197,7 @@ function getDeploymentDisplay(deployment) {
|
|
|
1152
1197
|
async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []) {
|
|
1153
1198
|
if (deployment !== void 0) return deployment;
|
|
1154
1199
|
if (!hasWebFrontend(frontend)) return "none";
|
|
1155
|
-
const hasIncompatibleFrontend = frontend.some((f) => f === "next"
|
|
1200
|
+
const hasIncompatibleFrontend = frontend.some((f) => f === "next");
|
|
1156
1201
|
const availableDeployments = hasIncompatibleFrontend ? ["wrangler", "none"] : [
|
|
1157
1202
|
"wrangler",
|
|
1158
1203
|
"alchemy",
|
|
@@ -1176,7 +1221,7 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
|
|
|
1176
1221
|
}
|
|
1177
1222
|
async function getDeploymentToAdd(frontend, existingDeployment) {
|
|
1178
1223
|
if (!hasWebFrontend(frontend)) return "none";
|
|
1179
|
-
const hasIncompatibleFrontend = frontend.some((f) => f === "next"
|
|
1224
|
+
const hasIncompatibleFrontend = frontend.some((f) => f === "next");
|
|
1180
1225
|
const options = [];
|
|
1181
1226
|
if (existingDeployment !== "wrangler") {
|
|
1182
1227
|
const { label, hint } = getDeploymentDisplay("wrangler");
|
|
@@ -1214,13 +1259,13 @@ async function getDeploymentToAdd(frontend, existingDeployment) {
|
|
|
1214
1259
|
//#region src/prompts/config-prompts.ts
|
|
1215
1260
|
async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
1216
1261
|
const result = await group({
|
|
1217
|
-
frontend: () => getFrontendChoice(flags.frontend, flags.backend),
|
|
1262
|
+
frontend: () => getFrontendChoice(flags.frontend, flags.backend, flags.auth),
|
|
1218
1263
|
backend: ({ results }) => getBackendFrameworkChoice(flags.backend, results.frontend),
|
|
1219
1264
|
runtime: ({ results }) => getRuntimeChoice(flags.runtime, results.backend),
|
|
1220
1265
|
database: ({ results }) => getDatabaseChoice(flags.database, results.backend, results.runtime),
|
|
1221
1266
|
orm: ({ results }) => getORMChoice(flags.orm, results.database !== "none", results.database, results.backend, results.runtime),
|
|
1222
1267
|
api: ({ results }) => getApiChoice(flags.api, results.frontend, results.backend),
|
|
1223
|
-
auth: ({ results }) => getAuthChoice(flags.auth, results.database !== "none", results.backend),
|
|
1268
|
+
auth: ({ results }) => getAuthChoice(flags.auth, results.database !== "none", results.backend, results.frontend),
|
|
1224
1269
|
addons: ({ results }) => getAddonsChoice(flags.addons, results.frontend),
|
|
1225
1270
|
examples: ({ results }) => getExamplesChoice(flags.examples, results.database, results.frontend, results.backend, results.api),
|
|
1226
1271
|
dbSetup: ({ results }) => getDBSetupChoice(results.database ?? "none", flags.dbSetup, results.orm, results.backend, results.runtime),
|
|
@@ -1235,7 +1280,6 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
1235
1280
|
result.database = "none";
|
|
1236
1281
|
result.orm = "none";
|
|
1237
1282
|
result.api = "none";
|
|
1238
|
-
result.auth = false;
|
|
1239
1283
|
result.dbSetup = "none";
|
|
1240
1284
|
result.examples = ["todo"];
|
|
1241
1285
|
}
|
|
@@ -1244,7 +1288,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
1244
1288
|
result.database = "none";
|
|
1245
1289
|
result.orm = "none";
|
|
1246
1290
|
result.api = "none";
|
|
1247
|
-
result.auth =
|
|
1291
|
+
result.auth = "none";
|
|
1248
1292
|
result.dbSetup = "none";
|
|
1249
1293
|
result.examples = [];
|
|
1250
1294
|
}
|
|
@@ -1345,7 +1389,7 @@ const getLatestCLIVersion = () => {
|
|
|
1345
1389
|
*/
|
|
1346
1390
|
function isTelemetryEnabled() {
|
|
1347
1391
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1348
|
-
const BTS_TELEMETRY = "
|
|
1392
|
+
const BTS_TELEMETRY = "0";
|
|
1349
1393
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1350
1394
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1351
1395
|
return true;
|
|
@@ -1353,8 +1397,8 @@ function isTelemetryEnabled() {
|
|
|
1353
1397
|
|
|
1354
1398
|
//#endregion
|
|
1355
1399
|
//#region src/utils/analytics.ts
|
|
1356
|
-
const POSTHOG_API_KEY = "
|
|
1357
|
-
const POSTHOG_HOST = "
|
|
1400
|
+
const POSTHOG_API_KEY = "random";
|
|
1401
|
+
const POSTHOG_HOST = "random";
|
|
1358
1402
|
function generateSessionId() {
|
|
1359
1403
|
const rand = Math.random().toString(36).slice(2);
|
|
1360
1404
|
const now = Date.now().toString(36);
|
|
@@ -1400,10 +1444,7 @@ function displayConfig(config) {
|
|
|
1400
1444
|
if (config.api !== void 0) configDisplay.push(`${pc.blue("API:")} ${String(config.api)}`);
|
|
1401
1445
|
if (config.database !== void 0) configDisplay.push(`${pc.blue("Database:")} ${String(config.database)}`);
|
|
1402
1446
|
if (config.orm !== void 0) configDisplay.push(`${pc.blue("ORM:")} ${String(config.orm)}`);
|
|
1403
|
-
if (config.auth !== void 0) {
|
|
1404
|
-
const authText = typeof config.auth === "boolean" ? config.auth ? "Yes" : "No" : String(config.auth);
|
|
1405
|
-
configDisplay.push(`${pc.blue("Authentication:")} ${authText}`);
|
|
1406
|
-
}
|
|
1447
|
+
if (config.auth !== void 0) configDisplay.push(`${pc.blue("Auth:")} ${String(config.auth)}`);
|
|
1407
1448
|
if (config.addons !== void 0) {
|
|
1408
1449
|
const addons = Array.isArray(config.addons) ? config.addons : [config.addons];
|
|
1409
1450
|
const addonsText = addons.length > 0 && addons[0] !== void 0 ? addons.join(", ") : "none";
|
|
@@ -1441,7 +1482,7 @@ function generateReproducibleCommand(config) {
|
|
|
1441
1482
|
flags.push(`--database ${config.database}`);
|
|
1442
1483
|
flags.push(`--orm ${config.orm}`);
|
|
1443
1484
|
flags.push(`--api ${config.api}`);
|
|
1444
|
-
flags.push(config.auth
|
|
1485
|
+
flags.push(`--auth ${config.auth}`);
|
|
1445
1486
|
if (config.addons && config.addons.length > 0) flags.push(`--addons ${config.addons.join(" ")}`);
|
|
1446
1487
|
else flags.push("--addons none");
|
|
1447
1488
|
if (config.examples && config.examples.length > 0) flags.push(`--examples ${config.examples.join(" ")}`);
|
|
@@ -1649,8 +1690,8 @@ function validateDatabaseOrmAuth(cfg, flags) {
|
|
|
1649
1690
|
if (has("database") && has("orm") && db === "mongodb" && orm && orm !== "mongoose" && orm !== "prisma" && orm !== "none") exitWithError("MongoDB database requires Mongoose or Prisma ORM. Please use '--orm mongoose' or '--orm prisma' or choose a different database.");
|
|
1650
1691
|
if (has("database") && has("orm") && db && db !== "none" && orm === "none") exitWithError("Database selection requires an ORM. Please choose '--orm drizzle', '--orm prisma', or '--orm mongoose'.");
|
|
1651
1692
|
if (has("orm") && has("database") && orm && orm !== "none" && db === "none") exitWithError("ORM selection requires a database. Please choose a database or set '--orm none'.");
|
|
1652
|
-
if (has("auth") && has("database") && cfg.auth && db === "none") exitWithError("Authentication requires a database. Please choose a database or set '--
|
|
1653
|
-
if (cfg.auth && db === "none") exitWithError("Authentication requires a database. Please choose a database or set '--
|
|
1693
|
+
if (has("auth") && has("database") && cfg.auth !== "none" && db === "none" && cfg.backend !== "convex") exitWithError("Authentication requires a database. Please choose a database or set '--auth none'.");
|
|
1694
|
+
if (cfg.auth !== "none" && db === "none" && cfg.backend !== "convex") exitWithError("Authentication requires a database. Please choose a database or set '--auth none'.");
|
|
1654
1695
|
if (orm && orm !== "none" && db === "none") exitWithError("ORM selection requires a database. Please choose a database or set '--orm none'.");
|
|
1655
1696
|
}
|
|
1656
1697
|
function validateDatabaseSetup(config, providedFlags) {
|
|
@@ -1697,6 +1738,16 @@ function validateDatabaseSetup(config, providedFlags) {
|
|
|
1697
1738
|
}
|
|
1698
1739
|
function validateBackendConstraints(config, providedFlags, options) {
|
|
1699
1740
|
const { backend } = config;
|
|
1741
|
+
if (config.auth === "clerk" && backend !== "convex") exitWithError("Clerk authentication is only supported with the Convex backend. Please use '--backend convex' or choose a different auth provider.");
|
|
1742
|
+
if (backend === "convex" && config.auth === "clerk" && config.frontend) {
|
|
1743
|
+
const incompatibleFrontends = config.frontend.filter((f) => [
|
|
1744
|
+
"nuxt",
|
|
1745
|
+
"svelte",
|
|
1746
|
+
"solid"
|
|
1747
|
+
].includes(f));
|
|
1748
|
+
if (incompatibleFrontends.length > 0) exitWithError(`Clerk authentication is not compatible with the following frontends: ${incompatibleFrontends.join(", ")}. Please choose a different frontend or auth provider.`);
|
|
1749
|
+
}
|
|
1750
|
+
if (backend === "convex" && config.auth === "better-auth" && providedFlags.has("auth")) exitWithError("Better-Auth is not compatible with the Convex backend. Please use '--auth clerk' or '--auth none'.");
|
|
1700
1751
|
if (providedFlags.has("backend") && backend && backend !== "convex" && backend !== "none") {
|
|
1701
1752
|
if (providedFlags.has("runtime") && options.runtime === "none") exitWithError("'--runtime none' is only supported with '--backend convex' or '--backend none'. Please choose 'bun', 'node', or remove the --runtime flag.");
|
|
1702
1753
|
}
|
|
@@ -2151,7 +2202,7 @@ async function setupDbOrmTemplates(projectDir, context) {
|
|
|
2151
2202
|
if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, serverAppDir, context);
|
|
2152
2203
|
}
|
|
2153
2204
|
async function setupAuthTemplate(projectDir, context) {
|
|
2154
|
-
if (context.
|
|
2205
|
+
if (!context.auth || context.auth === "none") return;
|
|
2155
2206
|
const serverAppDir = path.join(projectDir, "apps/server");
|
|
2156
2207
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
2157
2208
|
const nativeAppDir = path.join(projectDir, "apps/native");
|
|
@@ -2170,27 +2221,61 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2170
2221
|
const hasNativeWind = context.frontend.includes("native-nativewind");
|
|
2171
2222
|
const hasUnistyles = context.frontend.includes("native-unistyles");
|
|
2172
2223
|
const hasNative = hasNativeWind || hasUnistyles;
|
|
2173
|
-
|
|
2174
|
-
|
|
2224
|
+
const authProvider = context.auth;
|
|
2225
|
+
if (context.backend === "convex" && authProvider === "clerk") {
|
|
2226
|
+
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
|
2227
|
+
const convexClerkBackendSrc = path.join(PKG_ROOT, "templates/auth/clerk/convex/backend");
|
|
2228
|
+
if (await fs.pathExists(convexClerkBackendSrc)) {
|
|
2229
|
+
await fs.ensureDir(convexBackendDestDir);
|
|
2230
|
+
await processAndCopyFiles("**/*", convexClerkBackendSrc, convexBackendDestDir, context);
|
|
2231
|
+
}
|
|
2232
|
+
if (webAppDirExists) {
|
|
2233
|
+
const reactFramework = context.frontend.find((f) => [
|
|
2234
|
+
"tanstack-router",
|
|
2235
|
+
"react-router",
|
|
2236
|
+
"tanstack-start",
|
|
2237
|
+
"next"
|
|
2238
|
+
].includes(f));
|
|
2239
|
+
if (reactFramework) {
|
|
2240
|
+
const convexClerkWebSrc = path.join(PKG_ROOT, `templates/auth/clerk/convex/web/react/${reactFramework}`);
|
|
2241
|
+
if (await fs.pathExists(convexClerkWebSrc)) await processAndCopyFiles("**/*", convexClerkWebSrc, webAppDir, context);
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
if (nativeAppDirExists) {
|
|
2245
|
+
const convexClerkNativeBaseSrc = path.join(PKG_ROOT, "templates/auth/clerk/convex/native/base");
|
|
2246
|
+
if (await fs.pathExists(convexClerkNativeBaseSrc)) await processAndCopyFiles("**/*", convexClerkNativeBaseSrc, nativeAppDir, context);
|
|
2247
|
+
const hasNativeWind$1 = context.frontend.includes("native-nativewind");
|
|
2248
|
+
const hasUnistyles$1 = context.frontend.includes("native-unistyles");
|
|
2249
|
+
let nativeFrameworkPath = "";
|
|
2250
|
+
if (hasNativeWind$1) nativeFrameworkPath = "nativewind";
|
|
2251
|
+
else if (hasUnistyles$1) nativeFrameworkPath = "unistyles";
|
|
2252
|
+
if (nativeFrameworkPath) {
|
|
2253
|
+
const convexClerkNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/clerk/convex/native/${nativeFrameworkPath}`);
|
|
2254
|
+
if (await fs.pathExists(convexClerkNativeFrameworkSrc)) await processAndCopyFiles("**/*", convexClerkNativeFrameworkSrc, nativeAppDir, context);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
if (serverAppDirExists && context.backend !== "convex") {
|
|
2260
|
+
const authServerBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/base`);
|
|
2175
2261
|
if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, serverAppDir, context);
|
|
2176
2262
|
if (context.backend === "next") {
|
|
2177
|
-
const authServerNextSrc = path.join(PKG_ROOT,
|
|
2263
|
+
const authServerNextSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/next`);
|
|
2178
2264
|
if (await fs.pathExists(authServerNextSrc)) await processAndCopyFiles("**/*", authServerNextSrc, serverAppDir, context);
|
|
2179
2265
|
}
|
|
2180
2266
|
if (context.orm !== "none" && context.database !== "none") {
|
|
2181
2267
|
const orm = context.orm;
|
|
2182
2268
|
const db = context.database;
|
|
2183
2269
|
let authDbSrc = "";
|
|
2184
|
-
if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/server/db/drizzle/${db}`);
|
|
2185
|
-
else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/server/db/prisma/${db}`);
|
|
2186
|
-
else if (orm === "mongoose") authDbSrc = path.join(PKG_ROOT, `templates/auth/server/db/mongoose/${db}`);
|
|
2270
|
+
if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/drizzle/${db}`);
|
|
2271
|
+
else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/prisma/${db}`);
|
|
2272
|
+
else if (orm === "mongoose") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/mongoose/${db}`);
|
|
2187
2273
|
if (authDbSrc && await fs.pathExists(authDbSrc)) await processAndCopyFiles("**/*", authDbSrc, serverAppDir, context);
|
|
2188
|
-
else if (authDbSrc) {}
|
|
2189
2274
|
}
|
|
2190
2275
|
}
|
|
2191
2276
|
if ((hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) && webAppDirExists) {
|
|
2192
2277
|
if (hasReactWeb) {
|
|
2193
|
-
const authWebBaseSrc = path.join(PKG_ROOT,
|
|
2278
|
+
const authWebBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/react/base`);
|
|
2194
2279
|
if (await fs.pathExists(authWebBaseSrc)) await processAndCopyFiles("**/*", authWebBaseSrc, webAppDir, context);
|
|
2195
2280
|
const reactFramework = context.frontend.find((f) => [
|
|
2196
2281
|
"tanstack-router",
|
|
@@ -2199,28 +2284,28 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2199
2284
|
"next"
|
|
2200
2285
|
].includes(f));
|
|
2201
2286
|
if (reactFramework) {
|
|
2202
|
-
const authWebFrameworkSrc = path.join(PKG_ROOT, `templates/auth/web/react/${reactFramework}`);
|
|
2287
|
+
const authWebFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/react/${reactFramework}`);
|
|
2203
2288
|
if (await fs.pathExists(authWebFrameworkSrc)) await processAndCopyFiles("**/*", authWebFrameworkSrc, webAppDir, context);
|
|
2204
2289
|
}
|
|
2205
2290
|
} else if (hasNuxtWeb) {
|
|
2206
|
-
const authWebNuxtSrc = path.join(PKG_ROOT,
|
|
2291
|
+
const authWebNuxtSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/nuxt`);
|
|
2207
2292
|
if (await fs.pathExists(authWebNuxtSrc)) await processAndCopyFiles("**/*", authWebNuxtSrc, webAppDir, context);
|
|
2208
2293
|
} else if (hasSvelteWeb) {
|
|
2209
|
-
const authWebSvelteSrc = path.join(PKG_ROOT,
|
|
2294
|
+
const authWebSvelteSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/svelte`);
|
|
2210
2295
|
if (await fs.pathExists(authWebSvelteSrc)) await processAndCopyFiles("**/*", authWebSvelteSrc, webAppDir, context);
|
|
2211
2296
|
} else if (hasSolidWeb) {
|
|
2212
|
-
const authWebSolidSrc = path.join(PKG_ROOT,
|
|
2297
|
+
const authWebSolidSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/solid`);
|
|
2213
2298
|
if (await fs.pathExists(authWebSolidSrc)) await processAndCopyFiles("**/*", authWebSolidSrc, webAppDir, context);
|
|
2214
2299
|
}
|
|
2215
2300
|
}
|
|
2216
2301
|
if (hasNative && nativeAppDirExists) {
|
|
2217
|
-
const authNativeBaseSrc = path.join(PKG_ROOT,
|
|
2302
|
+
const authNativeBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/native-base`);
|
|
2218
2303
|
if (await fs.pathExists(authNativeBaseSrc)) await processAndCopyFiles("**/*", authNativeBaseSrc, nativeAppDir, context);
|
|
2219
2304
|
let nativeFrameworkAuthPath = "";
|
|
2220
2305
|
if (hasNativeWind) nativeFrameworkAuthPath = "nativewind";
|
|
2221
2306
|
else if (hasUnistyles) nativeFrameworkAuthPath = "unistyles";
|
|
2222
2307
|
if (nativeFrameworkAuthPath) {
|
|
2223
|
-
const authNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/native/${nativeFrameworkAuthPath}`);
|
|
2308
|
+
const authNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/${nativeFrameworkAuthPath}`);
|
|
2224
2309
|
if (await fs.pathExists(authNativeFrameworkSrc)) await processAndCopyFiles("**/*", authNativeFrameworkSrc, nativeAppDir, context);
|
|
2225
2310
|
}
|
|
2226
2311
|
}
|
|
@@ -2350,10 +2435,7 @@ async function setupDeploymentTemplates(projectDir, context) {
|
|
|
2350
2435
|
if (await fs.pathExists(alchemyTemplateSrc)) {
|
|
2351
2436
|
await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, projectDir, context);
|
|
2352
2437
|
const serverAppDir = path.join(projectDir, "apps/server");
|
|
2353
|
-
if (await fs.pathExists(serverAppDir))
|
|
2354
|
-
await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
2355
|
-
await processAndCopyFiles("wrangler.jsonc.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
2356
|
-
}
|
|
2438
|
+
if (await fs.pathExists(serverAppDir)) await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
2357
2439
|
}
|
|
2358
2440
|
} else {
|
|
2359
2441
|
if (context.webDeploy === "alchemy") {
|
|
@@ -2367,7 +2449,6 @@ async function setupDeploymentTemplates(projectDir, context) {
|
|
|
2367
2449
|
if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(serverAppDir)) {
|
|
2368
2450
|
await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
2369
2451
|
await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
2370
|
-
await processAndCopyFiles("wrangler.jsonc.hbs", alchemyTemplateSrc, serverAppDir, context);
|
|
2371
2452
|
}
|
|
2372
2453
|
}
|
|
2373
2454
|
}
|
|
@@ -2905,7 +2986,7 @@ async function addAddonsToProject(input) {
|
|
|
2905
2986
|
frontend: detectedConfig.frontend || [],
|
|
2906
2987
|
addons: input.addons,
|
|
2907
2988
|
examples: detectedConfig.examples || [],
|
|
2908
|
-
auth: detectedConfig.auth ||
|
|
2989
|
+
auth: detectedConfig.auth || "none",
|
|
2909
2990
|
git: false,
|
|
2910
2991
|
packageManager: input.packageManager || detectedConfig.packageManager || "npm",
|
|
2911
2992
|
install: input.install || false,
|
|
@@ -3000,11 +3081,9 @@ async function setupAlchemyServerDeploy(serverDir, _packageManager) {
|
|
|
3000
3081
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
3001
3082
|
packageJson.scripts = {
|
|
3002
3083
|
...packageJson.scripts,
|
|
3003
|
-
dev: "
|
|
3004
|
-
build: "wrangler deploy --dry-run",
|
|
3084
|
+
dev: "alchemy dev",
|
|
3005
3085
|
deploy: "alchemy deploy",
|
|
3006
|
-
destroy: "alchemy destroy"
|
|
3007
|
-
"alchemy:dev": "alchemy dev"
|
|
3086
|
+
destroy: "alchemy destroy"
|
|
3008
3087
|
};
|
|
3009
3088
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
3010
3089
|
}
|
|
@@ -3012,7 +3091,7 @@ async function setupAlchemyServerDeploy(serverDir, _packageManager) {
|
|
|
3012
3091
|
|
|
3013
3092
|
//#endregion
|
|
3014
3093
|
//#region src/helpers/deployment/alchemy/alchemy-next-setup.ts
|
|
3015
|
-
async function setupNextAlchemyDeploy(projectDir, _packageManager) {
|
|
3094
|
+
async function setupNextAlchemyDeploy(projectDir, _packageManager, options) {
|
|
3016
3095
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3017
3096
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3018
3097
|
await addPackageDependency({
|
|
@@ -3022,11 +3101,11 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3022
3101
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
3023
3102
|
if (await fs.pathExists(pkgPath)) {
|
|
3024
3103
|
const pkg = await fs.readJson(pkgPath);
|
|
3025
|
-
pkg.scripts = {
|
|
3104
|
+
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3026
3105
|
...pkg.scripts,
|
|
3027
3106
|
deploy: "alchemy deploy",
|
|
3028
3107
|
destroy: "alchemy destroy",
|
|
3029
|
-
|
|
3108
|
+
dev: "alchemy dev"
|
|
3030
3109
|
};
|
|
3031
3110
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3032
3111
|
}
|
|
@@ -3034,7 +3113,7 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3034
3113
|
|
|
3035
3114
|
//#endregion
|
|
3036
3115
|
//#region src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts
|
|
3037
|
-
async function setupNuxtAlchemyDeploy(projectDir, _packageManager) {
|
|
3116
|
+
async function setupNuxtAlchemyDeploy(projectDir, _packageManager, options) {
|
|
3038
3117
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3039
3118
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3040
3119
|
await addPackageDependency({
|
|
@@ -3048,11 +3127,11 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3048
3127
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
3049
3128
|
if (await fs.pathExists(pkgPath)) {
|
|
3050
3129
|
const pkg = await fs.readJson(pkgPath);
|
|
3051
|
-
pkg.scripts = {
|
|
3130
|
+
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3052
3131
|
...pkg.scripts,
|
|
3053
3132
|
deploy: "alchemy deploy",
|
|
3054
3133
|
destroy: "alchemy destroy",
|
|
3055
|
-
|
|
3134
|
+
dev: "alchemy dev"
|
|
3056
3135
|
};
|
|
3057
3136
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3058
3137
|
}
|
|
@@ -3102,112 +3181,29 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3102
3181
|
|
|
3103
3182
|
//#endregion
|
|
3104
3183
|
//#region src/helpers/deployment/alchemy/alchemy-react-router-setup.ts
|
|
3105
|
-
async function setupReactRouterAlchemyDeploy(projectDir, _packageManager) {
|
|
3184
|
+
async function setupReactRouterAlchemyDeploy(projectDir, _packageManager, options) {
|
|
3106
3185
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3107
3186
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3108
3187
|
await addPackageDependency({
|
|
3109
|
-
devDependencies: [
|
|
3110
|
-
"alchemy",
|
|
3111
|
-
"@cloudflare/vite-plugin",
|
|
3112
|
-
"dotenv"
|
|
3113
|
-
],
|
|
3188
|
+
devDependencies: ["alchemy", "dotenv"],
|
|
3114
3189
|
projectDir: webAppDir
|
|
3115
3190
|
});
|
|
3116
3191
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
3117
3192
|
if (await fs.pathExists(pkgPath)) {
|
|
3118
3193
|
const pkg = await fs.readJson(pkgPath);
|
|
3119
|
-
pkg.scripts = {
|
|
3194
|
+
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3120
3195
|
...pkg.scripts,
|
|
3121
3196
|
deploy: "alchemy deploy",
|
|
3122
3197
|
destroy: "alchemy destroy",
|
|
3123
|
-
|
|
3198
|
+
dev: "alchemy dev"
|
|
3124
3199
|
};
|
|
3125
3200
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3126
3201
|
}
|
|
3127
|
-
const viteConfigPath = path.join(webAppDir, "vite.config.ts");
|
|
3128
|
-
if (await fs.pathExists(viteConfigPath)) try {
|
|
3129
|
-
const project = new Project({ manipulationSettings: {
|
|
3130
|
-
indentationText: IndentationText.TwoSpaces,
|
|
3131
|
-
quoteKind: QuoteKind.Double
|
|
3132
|
-
} });
|
|
3133
|
-
project.addSourceFileAtPath(viteConfigPath);
|
|
3134
|
-
const sourceFile = project.getSourceFileOrThrow(viteConfigPath);
|
|
3135
|
-
const alchemyImport = sourceFile.getImportDeclaration("alchemy/cloudflare/react-router");
|
|
3136
|
-
if (!alchemyImport) sourceFile.addImportDeclaration({
|
|
3137
|
-
moduleSpecifier: "alchemy/cloudflare/react-router",
|
|
3138
|
-
defaultImport: "alchemy"
|
|
3139
|
-
});
|
|
3140
|
-
const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
|
|
3141
|
-
if (!exportAssignment) return;
|
|
3142
|
-
const defineConfigCall = exportAssignment.getExpression();
|
|
3143
|
-
if (!Node.isCallExpression(defineConfigCall) || defineConfigCall.getExpression().getText() !== "defineConfig") return;
|
|
3144
|
-
let configObject = defineConfigCall.getArguments()[0];
|
|
3145
|
-
if (!configObject) configObject = defineConfigCall.addArgument("{}");
|
|
3146
|
-
if (Node.isObjectLiteralExpression(configObject)) {
|
|
3147
|
-
const pluginsProperty = configObject.getProperty("plugins");
|
|
3148
|
-
if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
|
|
3149
|
-
const initializer = pluginsProperty.getInitializer();
|
|
3150
|
-
if (Node.isArrayLiteralExpression(initializer)) {
|
|
3151
|
-
const hasCloudflarePlugin = initializer.getElements().some((el) => el.getText().includes("cloudflare("));
|
|
3152
|
-
if (!hasCloudflarePlugin) initializer.addElement("alchemy()");
|
|
3153
|
-
}
|
|
3154
|
-
} else if (!pluginsProperty) configObject.addPropertyAssignment({
|
|
3155
|
-
name: "plugins",
|
|
3156
|
-
initializer: "[alchemy()]"
|
|
3157
|
-
});
|
|
3158
|
-
}
|
|
3159
|
-
await project.save();
|
|
3160
|
-
} catch (error) {
|
|
3161
|
-
console.warn("Failed to update vite.config.ts:", error);
|
|
3162
|
-
}
|
|
3163
|
-
const reactRouterConfigPath = path.join(webAppDir, "react-router.config.ts");
|
|
3164
|
-
if (await fs.pathExists(reactRouterConfigPath)) try {
|
|
3165
|
-
const project = new Project({ manipulationSettings: {
|
|
3166
|
-
indentationText: IndentationText.TwoSpaces,
|
|
3167
|
-
quoteKind: QuoteKind.Double
|
|
3168
|
-
} });
|
|
3169
|
-
project.addSourceFileAtPath(reactRouterConfigPath);
|
|
3170
|
-
const sourceFile = project.getSourceFileOrThrow(reactRouterConfigPath);
|
|
3171
|
-
const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
|
|
3172
|
-
if (!exportAssignment) return;
|
|
3173
|
-
const configExpression = exportAssignment.getExpression();
|
|
3174
|
-
let configObject;
|
|
3175
|
-
if (Node.isObjectLiteralExpression(configExpression)) configObject = configExpression;
|
|
3176
|
-
else if (Node.isSatisfiesExpression(configExpression)) {
|
|
3177
|
-
const expression = configExpression.getExpression();
|
|
3178
|
-
if (Node.isObjectLiteralExpression(expression)) configObject = expression;
|
|
3179
|
-
}
|
|
3180
|
-
if (!configObject || !Node.isObjectLiteralExpression(configObject)) return;
|
|
3181
|
-
const futureProperty = configObject.getProperty("future");
|
|
3182
|
-
if (!futureProperty) configObject.addPropertyAssignment({
|
|
3183
|
-
name: "future",
|
|
3184
|
-
initializer: `{
|
|
3185
|
-
unstable_viteEnvironmentApi: true,
|
|
3186
|
-
}`
|
|
3187
|
-
});
|
|
3188
|
-
else if (Node.isPropertyAssignment(futureProperty)) {
|
|
3189
|
-
const futureInitializer = futureProperty.getInitializer();
|
|
3190
|
-
if (Node.isObjectLiteralExpression(futureInitializer)) {
|
|
3191
|
-
const viteEnvApiProp = futureInitializer.getProperty("unstable_viteEnvironmentApi");
|
|
3192
|
-
if (!viteEnvApiProp) futureInitializer.addPropertyAssignment({
|
|
3193
|
-
name: "unstable_viteEnvironmentApi",
|
|
3194
|
-
initializer: "true"
|
|
3195
|
-
});
|
|
3196
|
-
else if (Node.isPropertyAssignment(viteEnvApiProp)) {
|
|
3197
|
-
const value = viteEnvApiProp.getInitializer()?.getText();
|
|
3198
|
-
if (value === "false") viteEnvApiProp.setInitializer("true");
|
|
3199
|
-
}
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
await project.save();
|
|
3203
|
-
} catch (error) {
|
|
3204
|
-
console.warn("Failed to update react-router.config.ts:", error);
|
|
3205
|
-
}
|
|
3206
3202
|
}
|
|
3207
3203
|
|
|
3208
3204
|
//#endregion
|
|
3209
3205
|
//#region src/helpers/deployment/alchemy/alchemy-solid-setup.ts
|
|
3210
|
-
async function setupSolidAlchemyDeploy(projectDir, _packageManager) {
|
|
3206
|
+
async function setupSolidAlchemyDeploy(projectDir, _packageManager, options) {
|
|
3211
3207
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3212
3208
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3213
3209
|
await addPackageDependency({
|
|
@@ -3217,11 +3213,11 @@ async function setupSolidAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3217
3213
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
3218
3214
|
if (await fs.pathExists(pkgPath)) {
|
|
3219
3215
|
const pkg = await fs.readJson(pkgPath);
|
|
3220
|
-
pkg.scripts = {
|
|
3216
|
+
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3221
3217
|
...pkg.scripts,
|
|
3222
3218
|
deploy: "alchemy deploy",
|
|
3223
3219
|
destroy: "alchemy destroy",
|
|
3224
|
-
|
|
3220
|
+
dev: "alchemy dev"
|
|
3225
3221
|
};
|
|
3226
3222
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3227
3223
|
}
|
|
@@ -3229,7 +3225,7 @@ async function setupSolidAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3229
3225
|
|
|
3230
3226
|
//#endregion
|
|
3231
3227
|
//#region src/helpers/deployment/alchemy/alchemy-svelte-setup.ts
|
|
3232
|
-
async function setupSvelteAlchemyDeploy(projectDir, _packageManager) {
|
|
3228
|
+
async function setupSvelteAlchemyDeploy(projectDir, _packageManager, options) {
|
|
3233
3229
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3234
3230
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3235
3231
|
await addPackageDependency({
|
|
@@ -3243,11 +3239,11 @@ async function setupSvelteAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3243
3239
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
3244
3240
|
if (await fs.pathExists(pkgPath)) {
|
|
3245
3241
|
const pkg = await fs.readJson(pkgPath);
|
|
3246
|
-
pkg.scripts = {
|
|
3242
|
+
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3247
3243
|
...pkg.scripts,
|
|
3248
3244
|
deploy: "alchemy deploy",
|
|
3249
3245
|
destroy: "alchemy destroy",
|
|
3250
|
-
|
|
3246
|
+
dev: "alchemy dev"
|
|
3251
3247
|
};
|
|
3252
3248
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3253
3249
|
}
|
|
@@ -3300,7 +3296,7 @@ function updateAdapterInConfig(configObject) {
|
|
|
3300
3296
|
|
|
3301
3297
|
//#endregion
|
|
3302
3298
|
//#region src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts
|
|
3303
|
-
async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager) {
|
|
3299
|
+
async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager, options) {
|
|
3304
3300
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3305
3301
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3306
3302
|
await addPackageDependency({
|
|
@@ -3310,11 +3306,11 @@ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3310
3306
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
3311
3307
|
if (await fs.pathExists(pkgPath)) {
|
|
3312
3308
|
const pkg = await fs.readJson(pkgPath);
|
|
3313
|
-
pkg.scripts = {
|
|
3309
|
+
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3314
3310
|
...pkg.scripts,
|
|
3315
3311
|
deploy: "alchemy deploy",
|
|
3316
3312
|
destroy: "alchemy destroy",
|
|
3317
|
-
|
|
3313
|
+
dev: "alchemy dev"
|
|
3318
3314
|
};
|
|
3319
3315
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3320
3316
|
}
|
|
@@ -3322,7 +3318,7 @@ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3322
3318
|
|
|
3323
3319
|
//#endregion
|
|
3324
3320
|
//#region src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts
|
|
3325
|
-
async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager) {
|
|
3321
|
+
async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, options) {
|
|
3326
3322
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3327
3323
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3328
3324
|
await addPackageDependency({
|
|
@@ -3336,11 +3332,11 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager) {
|
|
|
3336
3332
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
3337
3333
|
if (await fs.pathExists(pkgPath)) {
|
|
3338
3334
|
const pkg = await fs.readJson(pkgPath);
|
|
3339
|
-
pkg.scripts = {
|
|
3335
|
+
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3340
3336
|
...pkg.scripts,
|
|
3341
3337
|
deploy: "alchemy deploy",
|
|
3342
3338
|
destroy: "alchemy destroy",
|
|
3343
|
-
|
|
3339
|
+
dev: "alchemy dev"
|
|
3344
3340
|
};
|
|
3345
3341
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3346
3342
|
}
|
|
@@ -3456,7 +3452,7 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
|
3456
3452
|
...pkg.scripts,
|
|
3457
3453
|
deploy: "alchemy deploy",
|
|
3458
3454
|
destroy: "alchemy destroy",
|
|
3459
|
-
|
|
3455
|
+
dev: "alchemy dev"
|
|
3460
3456
|
};
|
|
3461
3457
|
await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
|
|
3462
3458
|
}
|
|
@@ -3470,13 +3466,13 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
|
3470
3466
|
const isTanstackStart = frontend.includes("tanstack-start");
|
|
3471
3467
|
const isReactRouter = frontend.includes("react-router");
|
|
3472
3468
|
const isSolid = frontend.includes("solid");
|
|
3473
|
-
if (isNext) await setupNextAlchemyDeploy(projectDir, packageManager);
|
|
3474
|
-
else if (isNuxt) await setupNuxtAlchemyDeploy(projectDir, packageManager);
|
|
3475
|
-
else if (isSvelte) await setupSvelteAlchemyDeploy(projectDir, packageManager);
|
|
3476
|
-
else if (isTanstackStart) await setupTanStackStartAlchemyDeploy(projectDir, packageManager);
|
|
3477
|
-
else if (isTanstackRouter) await setupTanStackRouterAlchemyDeploy(projectDir, packageManager);
|
|
3478
|
-
else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager);
|
|
3479
|
-
else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager);
|
|
3469
|
+
if (isNext) await setupNextAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3470
|
+
else if (isNuxt) await setupNuxtAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3471
|
+
else if (isSvelte) await setupSvelteAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3472
|
+
else if (isTanstackStart) await setupTanStackStartAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3473
|
+
else if (isTanstackRouter) await setupTanStackRouterAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3474
|
+
else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3475
|
+
else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
|
|
3480
3476
|
}
|
|
3481
3477
|
|
|
3482
3478
|
//#endregion
|
|
@@ -3762,7 +3758,7 @@ async function addDeploymentToProject(input) {
|
|
|
3762
3758
|
frontend: detectedConfig.frontend || [],
|
|
3763
3759
|
addons: detectedConfig.addons || [],
|
|
3764
3760
|
examples: detectedConfig.examples || [],
|
|
3765
|
-
auth: detectedConfig.auth ||
|
|
3761
|
+
auth: detectedConfig.auth || "none",
|
|
3766
3762
|
git: false,
|
|
3767
3763
|
packageManager: input.packageManager || detectedConfig.packageManager || "npm",
|
|
3768
3764
|
install: input.install || false,
|
|
@@ -3838,58 +3834,6 @@ async function formatProjectWithBiome(projectDir) {
|
|
|
3838
3834
|
} catch {}
|
|
3839
3835
|
}
|
|
3840
3836
|
|
|
3841
|
-
//#endregion
|
|
3842
|
-
//#region src/helpers/addons/auth-setup.ts
|
|
3843
|
-
async function setupAuth(config) {
|
|
3844
|
-
const { auth, frontend, backend, projectDir } = config;
|
|
3845
|
-
if (backend === "convex" || !auth) return;
|
|
3846
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
3847
|
-
const clientDir = path.join(projectDir, "apps/web");
|
|
3848
|
-
const nativeDir = path.join(projectDir, "apps/native");
|
|
3849
|
-
const clientDirExists = await fs.pathExists(clientDir);
|
|
3850
|
-
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
3851
|
-
const serverDirExists = await fs.pathExists(serverDir);
|
|
3852
|
-
try {
|
|
3853
|
-
if (serverDirExists) await addPackageDependency({
|
|
3854
|
-
dependencies: ["better-auth"],
|
|
3855
|
-
projectDir: serverDir
|
|
3856
|
-
});
|
|
3857
|
-
const hasWebFrontend$1 = frontend.some((f) => [
|
|
3858
|
-
"react-router",
|
|
3859
|
-
"tanstack-router",
|
|
3860
|
-
"tanstack-start",
|
|
3861
|
-
"next",
|
|
3862
|
-
"nuxt",
|
|
3863
|
-
"svelte",
|
|
3864
|
-
"solid"
|
|
3865
|
-
].includes(f));
|
|
3866
|
-
if (hasWebFrontend$1 && clientDirExists) await addPackageDependency({
|
|
3867
|
-
dependencies: ["better-auth"],
|
|
3868
|
-
projectDir: clientDir
|
|
3869
|
-
});
|
|
3870
|
-
if ((frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) && nativeDirExists) {
|
|
3871
|
-
await addPackageDependency({
|
|
3872
|
-
dependencies: ["better-auth", "@better-auth/expo"],
|
|
3873
|
-
projectDir: nativeDir
|
|
3874
|
-
});
|
|
3875
|
-
if (serverDirExists) await addPackageDependency({
|
|
3876
|
-
dependencies: ["@better-auth/expo"],
|
|
3877
|
-
projectDir: serverDir
|
|
3878
|
-
});
|
|
3879
|
-
}
|
|
3880
|
-
} catch (error) {
|
|
3881
|
-
consola.error(pc.red("Failed to configure authentication dependencies"));
|
|
3882
|
-
if (error instanceof Error) consola.error(pc.red(error.message));
|
|
3883
|
-
}
|
|
3884
|
-
}
|
|
3885
|
-
function generateAuthSecret(length = 32) {
|
|
3886
|
-
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
3887
|
-
let result = "";
|
|
3888
|
-
const charactersLength = 62;
|
|
3889
|
-
for (let i = 0; i < length; i++) result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
3890
|
-
return result;
|
|
3891
|
-
}
|
|
3892
|
-
|
|
3893
3837
|
//#endregion
|
|
3894
3838
|
//#region src/helpers/addons/examples-setup.ts
|
|
3895
3839
|
async function setupExamples(config) {
|
|
@@ -4139,6 +4083,88 @@ async function setupBackendDependencies(config) {
|
|
|
4139
4083
|
});
|
|
4140
4084
|
}
|
|
4141
4085
|
|
|
4086
|
+
//#endregion
|
|
4087
|
+
//#region src/helpers/core/auth-setup.ts
|
|
4088
|
+
async function setupAuth(config) {
|
|
4089
|
+
const { auth, frontend, backend, projectDir } = config;
|
|
4090
|
+
if (!auth || auth === "none") return;
|
|
4091
|
+
const serverDir = path.join(projectDir, "apps/server");
|
|
4092
|
+
const clientDir = path.join(projectDir, "apps/web");
|
|
4093
|
+
const nativeDir = path.join(projectDir, "apps/native");
|
|
4094
|
+
const clientDirExists = await fs.pathExists(clientDir);
|
|
4095
|
+
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
4096
|
+
const serverDirExists = await fs.pathExists(serverDir);
|
|
4097
|
+
try {
|
|
4098
|
+
if (backend === "convex") {
|
|
4099
|
+
if (auth === "clerk" && clientDirExists) {
|
|
4100
|
+
const hasNextJs = frontend.includes("next");
|
|
4101
|
+
const hasTanStackStart = frontend.includes("tanstack-start");
|
|
4102
|
+
const hasViteReactOther = frontend.some((f) => ["tanstack-router", "react-router"].includes(f));
|
|
4103
|
+
if (hasNextJs) await addPackageDependency({
|
|
4104
|
+
dependencies: ["@clerk/nextjs"],
|
|
4105
|
+
projectDir: clientDir
|
|
4106
|
+
});
|
|
4107
|
+
else if (hasTanStackStart) await addPackageDependency({
|
|
4108
|
+
dependencies: ["@clerk/tanstack-react-start"],
|
|
4109
|
+
projectDir: clientDir
|
|
4110
|
+
});
|
|
4111
|
+
else if (hasViteReactOther) await addPackageDependency({
|
|
4112
|
+
dependencies: ["@clerk/clerk-react"],
|
|
4113
|
+
projectDir: clientDir
|
|
4114
|
+
});
|
|
4115
|
+
}
|
|
4116
|
+
const hasNativeWind = frontend.includes("native-nativewind");
|
|
4117
|
+
const hasUnistyles = frontend.includes("native-unistyles");
|
|
4118
|
+
if (auth === "clerk" && nativeDirExists && (hasNativeWind || hasUnistyles)) await addPackageDependency({
|
|
4119
|
+
dependencies: ["@clerk/clerk-expo"],
|
|
4120
|
+
projectDir: nativeDir
|
|
4121
|
+
});
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
if (serverDirExists && auth === "better-auth") await addPackageDependency({
|
|
4125
|
+
dependencies: ["better-auth"],
|
|
4126
|
+
projectDir: serverDir
|
|
4127
|
+
});
|
|
4128
|
+
const hasWebFrontend$1 = frontend.some((f) => [
|
|
4129
|
+
"react-router",
|
|
4130
|
+
"tanstack-router",
|
|
4131
|
+
"tanstack-start",
|
|
4132
|
+
"next",
|
|
4133
|
+
"nuxt",
|
|
4134
|
+
"svelte",
|
|
4135
|
+
"solid"
|
|
4136
|
+
].includes(f));
|
|
4137
|
+
if (hasWebFrontend$1 && clientDirExists) {
|
|
4138
|
+
if (auth === "better-auth") await addPackageDependency({
|
|
4139
|
+
dependencies: ["better-auth"],
|
|
4140
|
+
projectDir: clientDir
|
|
4141
|
+
});
|
|
4142
|
+
}
|
|
4143
|
+
if ((frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) && nativeDirExists) {
|
|
4144
|
+
if (auth === "better-auth") {
|
|
4145
|
+
await addPackageDependency({
|
|
4146
|
+
dependencies: ["better-auth", "@better-auth/expo"],
|
|
4147
|
+
projectDir: nativeDir
|
|
4148
|
+
});
|
|
4149
|
+
if (serverDirExists) await addPackageDependency({
|
|
4150
|
+
dependencies: ["@better-auth/expo"],
|
|
4151
|
+
projectDir: serverDir
|
|
4152
|
+
});
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4155
|
+
} catch (error) {
|
|
4156
|
+
consola.error(pc.red("Failed to configure authentication dependencies"));
|
|
4157
|
+
if (error instanceof Error) consola.error(pc.red(error.message));
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
function generateAuthSecret(length = 32) {
|
|
4161
|
+
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
4162
|
+
let result = "";
|
|
4163
|
+
const charactersLength = 62;
|
|
4164
|
+
for (let i = 0; i < length; i++) result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
4165
|
+
return result;
|
|
4166
|
+
}
|
|
4167
|
+
|
|
4142
4168
|
//#endregion
|
|
4143
4169
|
//#region src/helpers/core/env-setup.ts
|
|
4144
4170
|
async function addEnvVariablesToFile(filePath, variables) {
|
|
@@ -4217,6 +4243,33 @@ async function setupEnvironmentVariables(config) {
|
|
|
4217
4243
|
value: serverUrl,
|
|
4218
4244
|
condition: true
|
|
4219
4245
|
}];
|
|
4246
|
+
if (backend === "convex" && auth === "clerk") {
|
|
4247
|
+
if (hasNextJs) clientVars.push({
|
|
4248
|
+
key: "NEXT_PUBLIC_CLERK_FRONTEND_API_URL",
|
|
4249
|
+
value: "",
|
|
4250
|
+
condition: true
|
|
4251
|
+
}, {
|
|
4252
|
+
key: "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY",
|
|
4253
|
+
value: "",
|
|
4254
|
+
condition: true
|
|
4255
|
+
}, {
|
|
4256
|
+
key: "CLERK_SECRET_KEY",
|
|
4257
|
+
value: "",
|
|
4258
|
+
condition: true
|
|
4259
|
+
});
|
|
4260
|
+
else if (hasReactRouter || hasTanStackRouter || hasTanStackStart) {
|
|
4261
|
+
clientVars.push({
|
|
4262
|
+
key: "VITE_CLERK_PUBLISHABLE_KEY",
|
|
4263
|
+
value: "",
|
|
4264
|
+
condition: true
|
|
4265
|
+
});
|
|
4266
|
+
if (hasTanStackStart) clientVars.push({
|
|
4267
|
+
key: "CLERK_SECRET_KEY",
|
|
4268
|
+
value: "",
|
|
4269
|
+
condition: true
|
|
4270
|
+
});
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4220
4273
|
await addEnvVariablesToFile(path.join(clientDir, ".env"), clientVars);
|
|
4221
4274
|
}
|
|
4222
4275
|
}
|
|
@@ -4234,6 +4287,11 @@ async function setupEnvironmentVariables(config) {
|
|
|
4234
4287
|
value: serverUrl,
|
|
4235
4288
|
condition: true
|
|
4236
4289
|
}];
|
|
4290
|
+
if (backend === "convex" && auth === "clerk") nativeVars.push({
|
|
4291
|
+
key: "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY",
|
|
4292
|
+
value: "",
|
|
4293
|
+
condition: true
|
|
4294
|
+
});
|
|
4237
4295
|
await addEnvVariablesToFile(path.join(nativeDir, ".env"), nativeVars);
|
|
4238
4296
|
}
|
|
4239
4297
|
}
|
|
@@ -5282,7 +5340,7 @@ async function createReadme(projectDir, options) {
|
|
|
5282
5340
|
}
|
|
5283
5341
|
}
|
|
5284
5342
|
function generateReadmeContent(options) {
|
|
5285
|
-
const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc" } = options;
|
|
5343
|
+
const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc", webDeploy, serverDeploy } = options;
|
|
5286
5344
|
const isConvex = backend === "convex";
|
|
5287
5345
|
const hasReactRouter = frontend.includes("react-router");
|
|
5288
5346
|
const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
|
|
@@ -5315,7 +5373,7 @@ This project uses Convex as a backend. You'll need to set up Convex before runni
|
|
|
5315
5373
|
${packageManagerRunCmd} dev:setup
|
|
5316
5374
|
\`\`\`
|
|
5317
5375
|
|
|
5318
|
-
Follow the prompts to create a new Convex project and connect it to your application
|
|
5376
|
+
Follow the prompts to create a new Convex project and connect it to your application.${auth === "clerk" ? " See [Convex + Clerk guide](https://docs.convex.dev/auth/clerk) for auth setup." : ""}` : generateDatabaseSetup(database, auth, packageManagerRunCmd, orm, options.dbSetup, options.serverDeploy)}
|
|
5319
5377
|
|
|
5320
5378
|
Then, run the development server:
|
|
5321
5379
|
|
|
@@ -5327,10 +5385,12 @@ ${generateRunningInstructions(frontend, backend, webPort, hasNative, isConvex)}
|
|
|
5327
5385
|
|
|
5328
5386
|
${addons.includes("pwa") && hasReactRouter ? "\n## PWA Support with React Router v7\n\nThere is a known compatibility issue between VitePWA and React Router v7.\nSee: https://github.com/vite-pwa/vite-plugin-pwa/issues/809\n" : ""}
|
|
5329
5387
|
|
|
5388
|
+
${generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy)}
|
|
5389
|
+
|
|
5330
5390
|
## Project Structure
|
|
5331
5391
|
|
|
5332
5392
|
\`\`\`
|
|
5333
|
-
${generateProjectStructure(projectName, frontend, backend, addons, isConvex, api)}
|
|
5393
|
+
${generateProjectStructure(projectName, frontend, backend, addons, isConvex, api, auth)}
|
|
5334
5394
|
\`\`\`
|
|
5335
5395
|
|
|
5336
5396
|
## Available Scripts
|
|
@@ -5380,7 +5440,7 @@ function generateRunningInstructions(frontend, backend, webPort, hasNative, isCo
|
|
|
5380
5440
|
else if (!isBackendNone) instructions.push("The API is running at [http://localhost:3000](http://localhost:3000).");
|
|
5381
5441
|
return instructions.join("\n");
|
|
5382
5442
|
}
|
|
5383
|
-
function generateProjectStructure(projectName, frontend, backend, addons, isConvex, api) {
|
|
5443
|
+
function generateProjectStructure(projectName, frontend, backend, addons, isConvex, api, auth) {
|
|
5384
5444
|
const structure = [`${projectName}/`, "├── apps/"];
|
|
5385
5445
|
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
|
|
5386
5446
|
const isBackendNone = backend === "none";
|
|
@@ -5410,6 +5470,7 @@ function generateProjectStructure(projectName, frontend, backend, addons, isConv
|
|
|
5410
5470
|
if (isConvex) {
|
|
5411
5471
|
structure.push("├── packages/");
|
|
5412
5472
|
structure.push("│ └── backend/ # Convex backend functions and schema");
|
|
5473
|
+
if (auth === "clerk") structure.push("│ ├── convex/ # Convex functions and schema", "│ └── .env.local # Convex environment variables");
|
|
5413
5474
|
} else if (!isBackendNone) {
|
|
5414
5475
|
const backendName = backend[0].toUpperCase() + backend.slice(1);
|
|
5415
5476
|
const apiName = api !== "none" ? api.toUpperCase() : "";
|
|
@@ -5461,7 +5522,10 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
5461
5522
|
const dbName = database === "sqlite" ? "SQLite/Turso" : database === "postgres" ? "PostgreSQL" : database === "mysql" ? "MySQL" : database === "mongodb" ? "MongoDB" : "Database";
|
|
5462
5523
|
addonsList.push(`- **${ormName}** - TypeScript-first ORM`, `- **${dbName}** - Database engine`);
|
|
5463
5524
|
}
|
|
5464
|
-
if (auth
|
|
5525
|
+
if (auth !== "none") {
|
|
5526
|
+
const authLabel = auth === "clerk" ? "Clerk" : "Better-Auth";
|
|
5527
|
+
addonsList.push(`- **Authentication** - ${authLabel}`);
|
|
5528
|
+
}
|
|
5465
5529
|
for (const addon of addons) if (addon === "pwa") addonsList.push("- **PWA** - Progressive Web App support");
|
|
5466
5530
|
else if (addon === "tauri") addonsList.push("- **Tauri** - Build native desktop applications");
|
|
5467
5531
|
else if (addon === "biome") addonsList.push("- **Biome** - Linting and formatting");
|
|
@@ -5470,13 +5534,13 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
5470
5534
|
else if (addon === "turborepo") addonsList.push("- **Turborepo** - Optimized monorepo build system");
|
|
5471
5535
|
return addonsList.join("\n");
|
|
5472
5536
|
}
|
|
5473
|
-
function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup) {
|
|
5537
|
+
function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup, serverDeploy) {
|
|
5474
5538
|
if (database === "none") return "";
|
|
5475
5539
|
let setup = "## Database Setup\n\n";
|
|
5476
5540
|
if (database === "sqlite") setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
5477
5541
|
|
|
5478
5542
|
1. Start the local SQLite database:
|
|
5479
|
-
${dbSetup === "d1" ? "Local development for a Cloudflare D1 database will already be running as part of the `wrangler dev` command." : `\`\`\`bash
|
|
5543
|
+
${dbSetup === "d1" ? serverDeploy === "alchemy" ? "D1 local development and migrations are handled automatically by Alchemy during dev and deploy." : "Local development for a Cloudflare D1 database will already be running as part of the `wrangler dev` command." : `\`\`\`bash
|
|
5480
5544
|
cd apps/server && ${packageManagerRunCmd} db:local
|
|
5481
5545
|
\`\`\`
|
|
5482
5546
|
`}
|
|
@@ -5546,6 +5610,21 @@ function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNati
|
|
|
5546
5610
|
- \`cd apps/docs && ${packageManagerRunCmd} build\`: Build documentation site`;
|
|
5547
5611
|
return scripts;
|
|
5548
5612
|
}
|
|
5613
|
+
function generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy) {
|
|
5614
|
+
const lines = [];
|
|
5615
|
+
if (webDeploy === "alchemy" || serverDeploy === "alchemy") {
|
|
5616
|
+
lines.push("## Deployment (Alchemy)");
|
|
5617
|
+
if (webDeploy === "alchemy" && serverDeploy !== "alchemy") lines.push(`- Web dev: cd apps/web && ${packageManagerRunCmd} dev`, `- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`, `- Web destroy: cd apps/web && ${packageManagerRunCmd} destroy`);
|
|
5618
|
+
if (serverDeploy === "alchemy" && webDeploy !== "alchemy") lines.push(`- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`, `- Server destroy: cd apps/server && ${packageManagerRunCmd} destroy`);
|
|
5619
|
+
if (webDeploy === "alchemy" && serverDeploy === "alchemy") lines.push(`- Dev: ${packageManagerRunCmd} dev`, `- Deploy: ${packageManagerRunCmd} deploy`, `- Destroy: ${packageManagerRunCmd} destroy`);
|
|
5620
|
+
}
|
|
5621
|
+
if (webDeploy === "wrangler" || serverDeploy === "wrangler") {
|
|
5622
|
+
lines.push("\n## Deployment (Cloudflare Wrangler)");
|
|
5623
|
+
if (webDeploy === "wrangler") lines.push(`- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`);
|
|
5624
|
+
if (serverDeploy === "wrangler") lines.push(`- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`);
|
|
5625
|
+
}
|
|
5626
|
+
return lines.length ? `\n${lines.join("\n")}\n` : "";
|
|
5627
|
+
}
|
|
5549
5628
|
|
|
5550
5629
|
//#endregion
|
|
5551
5630
|
//#region src/helpers/core/git.ts
|
|
@@ -5637,6 +5716,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
5637
5716
|
const nativeInstructions = frontend?.includes("native-nativewind") || frontend?.includes("native-unistyles") ? getNativeInstructions(isConvex) : "";
|
|
5638
5717
|
const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
|
|
5639
5718
|
const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
|
|
5719
|
+
const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
|
|
5640
5720
|
const wranglerDeployInstructions = getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy);
|
|
5641
5721
|
const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy);
|
|
5642
5722
|
const hasWeb = frontend?.some((f) => [
|
|
@@ -5660,6 +5740,12 @@ async function displayPostInstallInstructions(config) {
|
|
|
5660
5740
|
if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${packageManager} install\n`;
|
|
5661
5741
|
if (isConvex) {
|
|
5662
5742
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup\n${pc.dim(" (this will guide you through Convex project setup)")}\n`;
|
|
5743
|
+
if (config.auth === "clerk") {
|
|
5744
|
+
output += `${pc.cyan(`${stepCounter++}.`)} ${pc.bold("Clerk Setup:")}\n${pc.dim(" Follow the Convex + Clerk guide to configure authentication:")}\n${pc.cyan(" ")}${pc.underline("https://docs.convex.dev/auth/clerk")}\n\n`;
|
|
5745
|
+
output += `${pc.cyan(`${stepCounter++}.`)} ${pc.bold("Required Environment Variables:")}\n`;
|
|
5746
|
+
output += `${pc.dim(" •")} Set CLERK_JWT_ISSUER_DOMAIN in Convex Dashboard\n`;
|
|
5747
|
+
output += `${pc.dim(" •")} Set CLERK_PUBLISHABLE_KEY in apps/*/.env\n`;
|
|
5748
|
+
}
|
|
5663
5749
|
output += `${pc.cyan(`${stepCounter++}.`)} Copy environment variables from\n${pc.white(" packages/backend/.env.local")} to ${pc.white("apps/*/.env")}\n`;
|
|
5664
5750
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n\n`;
|
|
5665
5751
|
} else {
|
|
@@ -5684,6 +5770,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
5684
5770
|
if (wranglerDeployInstructions) output += `\n${wranglerDeployInstructions.trim()}\n`;
|
|
5685
5771
|
if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
|
|
5686
5772
|
if (starlightInstructions) output += `\n${starlightInstructions.trim()}\n`;
|
|
5773
|
+
if (clerkInstructions) output += `\n${clerkInstructions.trim()}\n`;
|
|
5687
5774
|
if (noOrmWarning) output += `\n${noOrmWarning.trim()}\n`;
|
|
5688
5775
|
if (bunWebNativeWarning) output += `\n${bunWebNativeWarning.trim()}\n`;
|
|
5689
5776
|
output += `\n${pc.bold("Update all dependencies:\n")}${pc.cyan(tazeCommand)}\n\n`;
|
|
@@ -5759,11 +5846,14 @@ function getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy) {
|
|
|
5759
5846
|
if (serverDeploy === "wrangler") instructions.push(`${pc.bold("Deploy server to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} run deploy`}`);
|
|
5760
5847
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
5761
5848
|
}
|
|
5849
|
+
function getClerkInstructions() {
|
|
5850
|
+
return `${pc.bold("Clerk Authentication Setup:")}\n${pc.cyan("1.")} Sign up for Clerk at ${pc.underline("https://clerk.com/sign-up")}\n${pc.cyan("2.")} Create a new application in Clerk Dashboard\n${pc.cyan("3.")} Create a JWT template named ${pc.bold("'convex'")} (exact name required)\n${pc.cyan("4.")} Copy your Clerk Frontend API URL (Issuer URL)\n${pc.cyan("5.")} Set environment variables:\n${pc.dim(" •")} CLERK_JWT_ISSUER_DOMAIN in Convex Dashboard\n${pc.dim(" •")} CLERK_PUBLISHABLE_KEY in apps/*/.env\n${pc.cyan("6.")} Follow the complete guide: ${pc.underline("https://docs.convex.dev/auth/clerk")}\n${pc.yellow("NOTE:")} Use Convex's <Authenticated> components instead of Clerk's <SignedIn>`;
|
|
5851
|
+
}
|
|
5762
5852
|
function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy) {
|
|
5763
5853
|
const instructions = [];
|
|
5764
|
-
if (webDeploy === "alchemy" && serverDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd}
|
|
5765
|
-
else if (serverDeploy === "alchemy" && webDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy server with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/server && ${runCmd}
|
|
5766
|
-
else if (webDeploy === "alchemy" && serverDeploy === "alchemy") instructions.push(`${pc.bold("Deploy with Alchemy:")}\n${pc.cyan("•")} Dev: ${`${runCmd}
|
|
5854
|
+
if (webDeploy === "alchemy" && serverDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/web && ${runCmd} destroy`}`);
|
|
5855
|
+
else if (serverDeploy === "alchemy" && webDeploy !== "alchemy") 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`}`);
|
|
5856
|
+
else if (webDeploy === "alchemy" && serverDeploy === "alchemy") 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`}`);
|
|
5767
5857
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
5768
5858
|
}
|
|
5769
5859
|
|
|
@@ -5961,8 +6051,8 @@ async function createProject(options) {
|
|
|
5961
6051
|
if (!isConvex) {
|
|
5962
6052
|
await setupDbOrmTemplates(projectDir, options);
|
|
5963
6053
|
await setupDockerComposeTemplates(projectDir, options);
|
|
5964
|
-
await setupAuthTemplate(projectDir, options);
|
|
5965
6054
|
}
|
|
6055
|
+
await setupAuthTemplate(projectDir, options);
|
|
5966
6056
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
|
|
5967
6057
|
await setupAddonsTemplate(projectDir, options);
|
|
5968
6058
|
await setupDeploymentTemplates(projectDir, options);
|
|
@@ -5974,12 +6064,12 @@ async function createProject(options) {
|
|
|
5974
6064
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
|
|
5975
6065
|
}
|
|
5976
6066
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
5977
|
-
if (
|
|
6067
|
+
if (options.auth && options.auth !== "none") await setupAuth(options);
|
|
5978
6068
|
await handleExtras(projectDir, options);
|
|
5979
|
-
await setupWebDeploy(options);
|
|
5980
|
-
await setupServerDeploy(options);
|
|
5981
6069
|
await setupEnvironmentVariables(options);
|
|
5982
6070
|
await updatePackageConfigurations(projectDir, options);
|
|
6071
|
+
await setupWebDeploy(options);
|
|
6072
|
+
await setupServerDeploy(options);
|
|
5983
6073
|
await createReadme(projectDir, options);
|
|
5984
6074
|
await writeBtsConfig(options);
|
|
5985
6075
|
await formatProjectWithBiome(projectDir);
|
|
@@ -6053,7 +6143,7 @@ async function createProjectHandler(input) {
|
|
|
6053
6143
|
frontend: [],
|
|
6054
6144
|
addons: [],
|
|
6055
6145
|
examples: [],
|
|
6056
|
-
auth:
|
|
6146
|
+
auth: "none",
|
|
6057
6147
|
git: false,
|
|
6058
6148
|
packageManager: "npm",
|
|
6059
6149
|
install: false,
|
|
@@ -6088,8 +6178,8 @@ async function createProjectHandler(input) {
|
|
|
6088
6178
|
};
|
|
6089
6179
|
coerceBackendPresets(config);
|
|
6090
6180
|
validateConfigCompatibility(config, providedFlags, cliInput);
|
|
6091
|
-
if (config.backend === "convex") log.info(
|
|
6092
|
-
else if (config.backend === "none") log.info("Due to '--backend none', the following options have been automatically set: --auth
|
|
6181
|
+
if (config.backend === "convex") log.info(`Due to '--backend convex' flag, the following options have been automatically set: database=none, orm=none, api=none, runtime=none, dbSetup=none, examples=todo`);
|
|
6182
|
+
else if (config.backend === "none") log.info("Due to '--backend none', the following options have been automatically set: --auth none, --database=none, --orm=none, --api=none, --runtime=none, --db-setup=none, --examples=none");
|
|
6093
6183
|
log.info(pc.yellow("Using default/flag options (config prompts skipped):"));
|
|
6094
6184
|
log.message(displayConfig(config));
|
|
6095
6185
|
log.message("");
|
|
@@ -6295,7 +6385,7 @@ const router = t.router({
|
|
|
6295
6385
|
verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
|
|
6296
6386
|
database: DatabaseSchema.optional(),
|
|
6297
6387
|
orm: ORMSchema.optional(),
|
|
6298
|
-
auth:
|
|
6388
|
+
auth: AuthSchema.optional(),
|
|
6299
6389
|
frontend: z.array(FrontendSchema).optional(),
|
|
6300
6390
|
addons: z.array(AddonsSchema).optional(),
|
|
6301
6391
|
examples: z.array(ExamplesSchema).optional(),
|
|
@@ -6386,7 +6476,7 @@ function createBtsCli() {
|
|
|
6386
6476
|
* backend: "hono",
|
|
6387
6477
|
* database: "sqlite",
|
|
6388
6478
|
* orm: "drizzle",
|
|
6389
|
-
* auth:
|
|
6479
|
+
* auth: "better-auth",
|
|
6390
6480
|
* addons: ["biome", "turborepo"],
|
|
6391
6481
|
* packageManager: "bun",
|
|
6392
6482
|
* install: false,
|