Skip to content

Commit 54bcdf1

Browse files
feat: add clerk auth support with convex (#548)
1 parent 8d48ae0 commit 54bcdf1

File tree

153 files changed

+1953
-770
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

153 files changed

+1953
-770
lines changed

apps/cli/src/constants.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const DEFAULT_CONFIG_BASE = {
1313
frontend: ["tanstack-router"],
1414
database: "sqlite",
1515
orm: "drizzle",
16-
auth: true,
16+
auth: "better-auth",
1717
addons: ["turborepo"],
1818
examples: [],
1919
git: true,
@@ -43,6 +43,11 @@ export const dependencyVersionMap = {
4343
"better-auth": "^1.3.7",
4444
"@better-auth/expo": "^1.3.7",
4545

46+
"@clerk/nextjs": "^6.31.5",
47+
"@clerk/clerk-react": "^5.45.0",
48+
"@clerk/tanstack-react-start": "^0.23.1",
49+
"@clerk/clerk-expo": "^2.14.25",
50+
4651
"drizzle-orm": "^0.44.2",
4752
"drizzle-kit": "^0.31.2",
4853

apps/cli/src/helpers/core/add-addons.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export async function addAddonsToProject(
4444
frontend: detectedConfig.frontend || [],
4545
addons: input.addons,
4646
examples: detectedConfig.examples || [],
47-
auth: detectedConfig.auth || false,
47+
auth: detectedConfig.auth || "none",
4848
git: false,
4949
packageManager:
5050
input.packageManager || detectedConfig.packageManager || "npm",

apps/cli/src/helpers/core/add-deployment.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function addDeploymentToProject(
6868
frontend: detectedConfig.frontend || [],
6969
addons: detectedConfig.addons || [],
7070
examples: detectedConfig.examples || [],
71-
auth: detectedConfig.auth || false,
71+
auth: detectedConfig.auth || "none",
7272
git: false,
7373
packageManager:
7474
input.packageManager || detectedConfig.packageManager || "npm",

apps/cli/src/helpers/addons/auth-setup.ts renamed to apps/cli/src/helpers/core/auth-setup.ts

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { addPackageDependency } from "../../utils/add-package-deps";
77

88
export async function setupAuth(config: ProjectConfig) {
99
const { auth, frontend, backend, projectDir } = config;
10-
if (backend === "convex" || !auth) {
10+
if (!auth || auth === "none") {
1111
return;
1212
}
1313

@@ -20,7 +20,48 @@ export async function setupAuth(config: ProjectConfig) {
2020
const serverDirExists = await fs.pathExists(serverDir);
2121

2222
try {
23-
if (serverDirExists) {
23+
if (backend === "convex") {
24+
if (auth === "clerk" && clientDirExists) {
25+
const hasNextJs = frontend.includes("next");
26+
const hasTanStackStart = frontend.includes("tanstack-start");
27+
const hasViteReactOther = frontend.some((f) =>
28+
["tanstack-router", "react-router"].includes(f),
29+
);
30+
31+
if (hasNextJs) {
32+
await addPackageDependency({
33+
dependencies: ["@clerk/nextjs"],
34+
projectDir: clientDir,
35+
});
36+
} else if (hasTanStackStart) {
37+
await addPackageDependency({
38+
dependencies: ["@clerk/tanstack-react-start"],
39+
projectDir: clientDir,
40+
});
41+
} else if (hasViteReactOther) {
42+
await addPackageDependency({
43+
dependencies: ["@clerk/clerk-react"],
44+
projectDir: clientDir,
45+
});
46+
}
47+
}
48+
49+
const hasNativeWind = frontend.includes("native-nativewind");
50+
const hasUnistyles = frontend.includes("native-unistyles");
51+
if (
52+
auth === "clerk" &&
53+
nativeDirExists &&
54+
(hasNativeWind || hasUnistyles)
55+
) {
56+
await addPackageDependency({
57+
dependencies: ["@clerk/clerk-expo"],
58+
projectDir: nativeDir,
59+
});
60+
}
61+
return;
62+
}
63+
64+
if (serverDirExists && auth === "better-auth") {
2465
await addPackageDependency({
2566
dependencies: ["better-auth"],
2667
projectDir: serverDir,
@@ -40,26 +81,30 @@ export async function setupAuth(config: ProjectConfig) {
4081
);
4182

4283
if (hasWebFrontend && clientDirExists) {
43-
await addPackageDependency({
44-
dependencies: ["better-auth"],
45-
projectDir: clientDir,
46-
});
84+
if (auth === "better-auth") {
85+
await addPackageDependency({
86+
dependencies: ["better-auth"],
87+
projectDir: clientDir,
88+
});
89+
}
4790
}
4891

4992
if (
5093
(frontend.includes("native-nativewind") ||
5194
frontend.includes("native-unistyles")) &&
5295
nativeDirExists
5396
) {
54-
await addPackageDependency({
55-
dependencies: ["better-auth", "@better-auth/expo"],
56-
projectDir: nativeDir,
57-
});
58-
if (serverDirExists) {
97+
if (auth === "better-auth") {
5998
await addPackageDependency({
60-
dependencies: ["@better-auth/expo"],
61-
projectDir: serverDir,
99+
dependencies: ["better-auth", "@better-auth/expo"],
100+
projectDir: nativeDir,
62101
});
102+
if (serverDirExists) {
103+
await addPackageDependency({
104+
dependencies: ["@better-auth/expo"],
105+
projectDir: serverDir,
106+
});
107+
}
63108
}
64109
}
65110
} catch (error) {

apps/cli/src/helpers/core/command-handlers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export async function createProjectHandler(
103103
frontend: [],
104104
addons: [],
105105
examples: [],
106-
auth: false,
106+
auth: "none",
107107
git: false,
108108
packageManager: "npm",
109109
install: false,
@@ -154,11 +154,11 @@ export async function createProjectHandler(
154154

155155
if (config.backend === "convex") {
156156
log.info(
157-
"Due to '--backend convex' flag, the following options have been automatically set: auth=false, database=none, orm=none, api=none, runtime=none, dbSetup=none, examples=todo",
157+
`Due to '--backend convex' flag, the following options have been automatically set: database=none, orm=none, api=none, runtime=none, dbSetup=none, examples=todo`,
158158
);
159159
} else if (config.backend === "none") {
160160
log.info(
161-
"Due to '--backend none', the following options have been automatically set: --auth=false, --database=none, --orm=none, --api=none, --runtime=none, --db-setup=none, --examples=none",
161+
"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",
162162
);
163163
}
164164

apps/cli/src/helpers/core/create-project.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import { writeBtsConfig } from "../../utils/bts-config";
55
import { exitWithError } from "../../utils/errors";
66
import { formatProjectWithBiome } from "../../utils/format-with-biome";
77
import { setupAddons } from "../addons/addons-setup";
8-
import { setupAuth } from "../addons/auth-setup";
98
import { setupExamples } from "../addons/examples-setup";
109
import { setupApi } from "../core/api-setup";
1110
import { setupBackendDependencies } from "../core/backend-setup";
1211
import { setupDatabase } from "../core/db-setup";
1312
import { setupRuntime } from "../core/runtime-setup";
1413
import { setupServerDeploy } from "../deployment/server-deploy-setup";
1514
import { setupWebDeploy } from "../deployment/web-deploy-setup";
15+
import { setupAuth } from "./auth-setup";
1616
import { runConvexCodegen } from "./convex-codegen";
1717
import { createReadme } from "./create-readme";
1818
import { setupEnvironmentVariables } from "./env-setup";
@@ -46,8 +46,8 @@ export async function createProject(options: ProjectConfig) {
4646
if (!isConvex) {
4747
await setupDbOrmTemplates(projectDir, options);
4848
await setupDockerComposeTemplates(projectDir, options);
49-
await setupAuthTemplate(projectDir, options);
5049
}
50+
await setupAuthTemplate(projectDir, options);
5151
if (options.examples.length > 0 && options.examples[0] !== "none") {
5252
await setupExamplesTemplate(projectDir, options);
5353
}
@@ -70,7 +70,7 @@ export async function createProject(options: ProjectConfig) {
7070
await setupAddons(options);
7171
}
7272

73-
if (!isConvex && options.auth) {
73+
if (options.auth && options.auth !== "none") {
7474
await setupAuth(options);
7575
}
7676

apps/cli/src/helpers/core/create-readme.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import fs from "fs-extra";
44
import type {
55
Addons,
66
API,
7+
Auth,
78
Database,
89
DatabaseSetup,
910
Frontend,
@@ -98,7 +99,11 @@ This project uses Convex as a backend. You'll need to set up Convex before runni
9899
${packageManagerRunCmd} dev:setup
99100
\`\`\`
100101
101-
Follow the prompts to create a new Convex project and connect it to your application.`
102+
Follow the prompts to create a new Convex project and connect it to your application.${
103+
auth === "clerk"
104+
? " See [Convex + Clerk guide](https://docs.convex.dev/auth/clerk) for auth setup."
105+
: ""
106+
}`
102107
: generateDatabaseSetup(
103108
database,
104109
auth,
@@ -135,6 +140,7 @@ ${generateProjectStructure(
135140
addons,
136141
isConvex,
137142
api,
143+
auth,
138144
)}
139145
\`\`\`
140146
@@ -258,6 +264,7 @@ function generateProjectStructure(
258264
addons: Addons[],
259265
isConvex: boolean,
260266
api: API,
267+
auth: Auth,
261268
): string {
262269
const structure: string[] = [`${projectName}/`, "├── apps/"];
263270

@@ -317,6 +324,12 @@ function generateProjectStructure(
317324
structure.push(
318325
"│ └── backend/ # Convex backend functions and schema",
319326
);
327+
if (auth === "clerk") {
328+
structure.push(
329+
"│ ├── convex/ # Convex functions and schema",
330+
"│ └── .env.local # Convex environment variables",
331+
);
332+
}
320333
} else if (!isBackendNone) {
321334
const backendName = backend[0].toUpperCase() + backend.slice(1);
322335
const apiName = api !== "none" ? api.toUpperCase() : "";
@@ -329,7 +342,7 @@ function generateProjectStructure(
329342

330343
function generateFeaturesList(
331344
database: Database,
332-
auth: boolean,
345+
auth: Auth,
333346
addons: Addons[],
334347
orm: ORM,
335348
runtime: Runtime,
@@ -449,10 +462,9 @@ function generateFeaturesList(
449462
);
450463
}
451464

452-
if (auth && !isConvex) {
453-
addonsList.push(
454-
"- **Authentication** - Email & password authentication with Better Auth",
455-
);
465+
if (auth !== "none") {
466+
const authLabel = auth === "clerk" ? "Clerk" : "Better-Auth";
467+
addonsList.push(`- **Authentication** - ${authLabel}`);
456468
}
457469

458470
for (const addon of addons) {
@@ -476,7 +488,7 @@ function generateFeaturesList(
476488

477489
function generateDatabaseSetup(
478490
database: Database,
479-
_auth: boolean,
491+
_auth: Auth,
480492
packageManagerRunCmd: string,
481493
orm: ORM,
482494
dbSetup: DatabaseSetup,
@@ -575,7 +587,7 @@ function generateScriptsList(
575587
packageManagerRunCmd: string,
576588
database: Database,
577589
orm: ORM,
578-
_auth: boolean,
590+
_auth: Auth,
579591
hasNative: boolean,
580592
addons: Addons[],
581593
backend: string,

apps/cli/src/helpers/core/env-setup.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import path from "node:path";
22
import fs from "fs-extra";
33
import type { ProjectConfig } from "../../types";
4-
import { generateAuthSecret } from "../addons/auth-setup";
4+
import { generateAuthSecret } from "./auth-setup";
55

66
export interface EnvVariable {
77
key: string;
@@ -143,6 +143,42 @@ export async function setupEnvironmentVariables(config: ProjectConfig) {
143143
condition: true,
144144
},
145145
];
146+
147+
if (backend === "convex" && auth === "clerk") {
148+
if (hasNextJs) {
149+
clientVars.push(
150+
{
151+
key: "NEXT_PUBLIC_CLERK_FRONTEND_API_URL",
152+
value: "",
153+
condition: true,
154+
},
155+
{
156+
key: "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY",
157+
value: "",
158+
condition: true,
159+
},
160+
{
161+
key: "CLERK_SECRET_KEY",
162+
value: "",
163+
condition: true,
164+
},
165+
);
166+
} else if (hasReactRouter || hasTanStackRouter || hasTanStackStart) {
167+
clientVars.push({
168+
key: "VITE_CLERK_PUBLISHABLE_KEY",
169+
value: "",
170+
condition: true,
171+
});
172+
if (hasTanStackStart) {
173+
clientVars.push({
174+
key: "CLERK_SECRET_KEY",
175+
value: "",
176+
condition: true,
177+
});
178+
}
179+
}
180+
}
181+
146182
await addEnvVariablesToFile(path.join(clientDir, ".env"), clientVars);
147183
}
148184
}
@@ -168,6 +204,14 @@ export async function setupEnvironmentVariables(config: ProjectConfig) {
168204
condition: true,
169205
},
170206
];
207+
208+
if (backend === "convex" && auth === "clerk") {
209+
nativeVars.push({
210+
key: "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY",
211+
value: "",
212+
condition: true,
213+
});
214+
}
171215
await addEnvVariablesToFile(path.join(nativeDir, ".env"), nativeVars);
172216
}
173217
}

0 commit comments

Comments
 (0)