-
-
Notifications
You must be signed in to change notification settings - Fork 221
feat(cli): add better-auth + convex + native app support #634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
You have run out of free Bugbot PR reviews for this billing cycle. This will reset on November 7. To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThis PR extends native frontend support (nativewind, unistyles) for Better-Auth with Convex backend integration. Changes span CLI helpers, templates, and UI components to enable authentication flows for React Native applications through updated setup logic, conditional branching, and new auth client/component templates. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant NativeApp as Native App<br/>(SignIn/SignUp)
participant AuthClient as authClient
participant Backend as Convex Backend<br/>(createAuth)
participant Provider as ConvexBetterAuth<br/>Provider
Note over NativeApp,Backend: Setup Flow
Provider->>Backend: wrap layout with<br/>ConvexBetterAuthProvider
Note over NativeApp,Backend: Authentication Flow
User->>NativeApp: enters credentials
NativeApp->>AuthClient: signIn.email() or signUp.email()
AuthClient->>Backend: POST /auth/sign-in or /auth/sign-up
Backend->>Backend: createAuth validates<br/>with expo plugin
Backend-->>AuthClient: returns session/user
AuthClient-->>NativeApp: onSuccess/onError callback
NativeApp->>NativeApp: update UI state<br/>(clear inputs/show user)
NativeApp->>User: render authenticated view
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Rationale: The PR spans 16+ files across diverse layers (CLI helpers, backend templates, multiple UI component templates, frontend layouts). While changes follow consistent patterns (native framework detection, conditional branching, auth component implementations), reviewers must understand the interconnections between helper logic, template generation, and the resulting client-side flows. The template files introduce new conditional branches with platform-specific plugin composition and provider wrapping that require careful validation against existing paths. Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (22)
apps/cli/src/utils/config-validation.ts (2)
238-244: Add native frontends: LGTMExpanded support list looks correct and aligns with the PR’s goals.
Consider centralizing this “supported Better‑Auth + Convex frontends” list in a shared constant to avoid drift with prompts/auth.ts and convex/http.ts.hbs.
251-251: Message clarityConsider explicitly naming Native variants to reduce ambiguity: “... or Native (NativeWind/Unistyles).”
apps/cli/templates/auth/better-auth/convex/backend/convex/http.ts.hbs (1)
6-10: Condition update: LGTM; consider de-dup of frontend listAdding native-nativewind and native-unistyles to the non‑CORS branch is correct for RN (no browser CORS). To reduce drift, centralize the compatible frontend list used here, in config-validation.ts, and prompts/auth.ts.
Based on learnings
apps/cli/src/prompts/auth.ts (1)
15-21: Better‑Auth detection updated: LGTMInclusion of native‑nativewind and native‑unistyles is consistent with the new templates.
Consider a shared constant for the supported list (used here, in validation, and http.ts.hbs) to prevent future mismatch.
apps/cli/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbs (1)
18-43: Add try/catch as a safety net around awaitauthClient.signUp.email uses callbacks, but transport errors could still throw. Wrap with try/catch to surface unexpected failures.
- await authClient.signUp.email( + try { + await authClient.signUp.email( { name, email, password, }, { onError: (error) => { setError(error.error?.message || "Failed to sign up"); setIsLoading(false); }, onSuccess: () => { setName(""); setEmail(""); setPassword(""); }, onFinished: () => { setIsLoading(false); }, }, - ); + ); + } catch (e) { + setError(e instanceof Error ? e.message : "Failed to sign up"); + setIsLoading(false); + }apps/cli/src/helpers/core/template-manager.ts (1)
517-548: Convex + Better‑Auth native template copy: LGTM; consider factoring duplicate logicThe block correctly copies native base and framework assets when apps/native exists. Similar copy logic appears in the Clerk path; consider extracting a small helper to reduce duplication and future maintenance cost.
apps/cli/templates/auth/better-auth/convex/native/unistyles/components/sign-up.tsx.hbs (3)
19-44: Use a function declaration, avoid duplicate setState, and add try/catch
- Switch from arrow to function declaration (guidelines).
- Rely on onFinished for loading reset; drop duplicate setIsLoading in onError.
- Add try/catch in case the call throws before callbacks.
As per coding guidelines
- const handleSignUp = async () => { + async function handleSignUp() { setIsLoading(true); setError(null); - await authClient.signUp.email( - { - name, - email, - password, - }, - { - onError: (error) => { - setError(error.error?.message || "Failed to sign up"); - setIsLoading(false); - }, - onSuccess: () => { - setName(""); - setEmail(""); - setPassword(""); - }, - onFinished: () => { - setIsLoading(false); - }, - }, - ); - }; + try { + await authClient.signUp.email( + { name, email, password }, + { + onError: (error) => { + setError(error.error?.message || "Failed to sign up"); + }, + onSuccess: () => { + setName(""); + setEmail(""); + setPassword(""); + }, + onFinished: () => { + setIsLoading(false); + }, + }, + ); + } catch (e) { + setError(e instanceof Error ? e.message : "Failed to sign up"); + setIsLoading(false); + } + };
63-78: Polish inputs for RN UX
- Email: add autoCorrect={false} and textContentType="emailAddress".
- Password: add textContentType="password".
<TextInput style={styles.input} placeholder="Email" value={email} onChangeText={setEmail} keyboardType="email-address" autoCapitalize="none" + autoCorrect={false} + textContentType="emailAddress" /> ... <TextInput style={styles.inputLast} placeholder="Password" value={password} onChangeText={setPassword} secureTextEntry + textContentType="password" />
80-90: Reflect disabled state visually and add a11y role
- Add accessibilityRole and fade the button when disabled.
- <TouchableOpacity - onPress={handleSignUp} - disabled={isLoading} - style={styles.button} - > + <TouchableOpacity + onPress={handleSignUp} + disabled={isLoading} + accessibilityRole="button" + style={[styles.button, isLoading && { opacity: 0.7 }]} + >apps/cli/src/helpers/core/auth-setup.ts (2)
21-21: Remove unused variable
_serverDirExistsis never used.- const _serverDirExists = await fs.pathExists(serverDir);
101-116: Centralize Better Auth version into a constant
Add at the top of apps/cli/src/helpers/core/auth-setup.ts:const BA_VERSION = "1.3.27";Then replace all hardcoded
"1.3.27"in your seven customDependencies blocks withBA_VERSION.
Optionally, move thehasNativeWind/hasUnistyleschecks to the top ofsetupAuthand reuse them.apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs (1)
37-41: Environment var pattern differs from nativewind variantHere you use
process.env.EXPO_PUBLIC_CONVEX_URL || ""while nativewind uses a non-null assertion. Consider aligning patterns across templates for consistency.apps/cli/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbs (3)
17-40: Use a function declaration for the handler (guideline) and trim inputsReplace the arrow function with a standard function and trim email before submit.
- const handleLogin = async () => { + async function handleLogin() { setIsLoading(true); setError(null); await authClient.signIn.email( { - email, + email: email.trim(), password, }, { onError: (error) => { setError(error.error?.message || "Failed to sign in"); setIsLoading(false); }, onSuccess: () => { setEmail(""); setPassword(""); }, onFinished: () => { setIsLoading(false); }, }, ); - }; + }As per coding guidelines
27-37: Avoid duplicate loading state toggles and broaden error fallbackLet onFinished handle setIsLoading(false) and avoid a second toggle in onError. Also fall back to error.message when nested error shape is absent.
- onError: (error) => { - setError(error.error?.message || "Failed to sign in"); - setIsLoading(false); - }, + onError: (error) => { + setError(error.error?.message || (error as any)?.message || "Failed to sign in"); + },
73-83: Disable submit when inputs are emptyPrevents accidental empty submissions and improves UX.
- <TouchableOpacity - onPress={handleLogin} - disabled={isLoading} + <TouchableOpacity + onPress={handleLogin} + disabled={isLoading || !email.trim() || !password} className="bg-primary p-4 rounded-md flex-row justify-center items-center" >apps/cli/templates/auth/better-auth/convex/native/unistyles/components/sign-in.tsx.hbs (3)
18-41: Prefer a function declaration and trim inputsAlign with the codebase guideline and trim email before submit.
- const handleLogin = async () => { + async function handleLogin() { setIsLoading(true); setError(null); await authClient.signIn.email( { - email, + email: email.trim(), password, }, { onError: (error) => { setError(error.error?.message || "Failed to sign in"); setIsLoading(false); }, onSuccess: () => { setEmail(""); setPassword(""); }, onFinished: () => { setIsLoading(false); }, }, ); - }; + }As per coding guidelines
28-38: Single source of truth for loading state; better error fallbackLet onFinished clear loading; broaden error fallback.
- onError: (error) => { - setError(error.error?.message || "Failed to sign in"); - setIsLoading(false); - }, + onError: (error) => { + setError(error.error?.message || (error as any)?.message || "Failed to sign in"); + },
70-80: Disable submit until inputs are validSmall UX win; avoids empty auth calls.
- <TouchableOpacity - onPress={handleLogin} - disabled={isLoading} + <TouchableOpacity + onPress={handleLogin} + disabled={isLoading || !email.trim() || !password} style={styles.button} >apps/cli/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs (2)
136-143: Await and handle sign out to avoid unhandled rejectionsSign-out is likely async; handle it to prevent silent failures.
- <TouchableOpacity - className="bg-destructive py-2 px-4 rounded-md self-start" - onPress={() => { - authClient.signOut(); - }} - > + <TouchableOpacity + className="bg-destructive py-2 px-4 rounded-md self-start" + onPress={async () => { + try { + await authClient.signOut(); + } catch (e) { + // no-op or add a toast/log + } + }} + >
55-102: Unify health status conditions for consistencyYou mix truthy checks and explicit equality against "OK". Prefer one approach (explicit equality) for both dot color and text to prevent mismatched states.
apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs (1)
154-160: Await/handle sign outAvoid unhandled promise rejections and give room for UX feedback on failure.
- <TouchableOpacity - style={styles.signOutButton} - onPress={() => { - authClient.signOut(); - }} - > + <TouchableOpacity + style={styles.signOutButton} + onPress={async () => { + try { + await authClient.signOut(); + } catch {} + }} + >apps/cli/src/helpers/core/env-setup.ts (1)
41-46: Use a type alias instead of an interface (guideline)Switch EnvVariable to a type alias.
-export interface EnvVariable { - key: string; - value: string | null | undefined; - condition: boolean; - comment?: string; -} +export type EnvVariable = { + key: string; + value: string | null | undefined; + condition: boolean; + comment?: string; +};As per coding guidelines
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (10)
apps/cli/templates/frontend/native/base/assets/images/android-icon-background.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/android-icon-foreground.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/android-icon-monochrome.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/favicon.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/icon.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/partial-react-logo.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/react-logo.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/react-logo@2x.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/react-logo@3x.pngis excluded by!**/*.pngapps/cli/templates/frontend/native/base/assets/images/splash-icon.pngis excluded by!**/*.png
📒 Files selected for processing (19)
apps/cli/src/helpers/addons/ruler-setup.ts(1 hunks)apps/cli/src/helpers/core/auth-setup.ts(2 hunks)apps/cli/src/helpers/core/env-setup.ts(3 hunks)apps/cli/src/helpers/core/template-manager.ts(3 hunks)apps/cli/src/prompts/auth.ts(1 hunks)apps/cli/src/utils/config-validation.ts(1 hunks)apps/cli/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs(1 hunks)apps/cli/templates/auth/better-auth/convex/backend/convex/http.ts.hbs(1 hunks)apps/cli/templates/auth/better-auth/convex/native/base/lib/auth-client.ts.hbs(1 hunks)apps/cli/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbs(1 hunks)apps/cli/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbs(1 hunks)apps/cli/templates/auth/better-auth/convex/native/unistyles/components/sign-in.tsx.hbs(1 hunks)apps/cli/templates/auth/better-auth/convex/native/unistyles/components/sign-up.tsx.hbs(1 hunks)apps/cli/templates/auth/better-auth/native/base/lib/auth-client.ts.hbs(1 hunks)apps/cli/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs(3 hunks)apps/cli/templates/frontend/native/nativewind/app/_layout.tsx.hbs(2 hunks)apps/cli/templates/frontend/native/unistyles/app.json.hbs(1 hunks)apps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs(7 hunks)apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs(2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)
**/*.{ts,tsx}: Use Id from './_generated/dataModel' to type document ids (e.g., Id<'users'>)
Ensure Record key/value types align with validators (e.g., v.record(v.id('users'), v.string()) => Record<Id<'users'>, string>)
Be strict with types for document ids; prefer Id<'table'> over string
Use 'as const' for string literals in discriminated unions
When using Array and Record types, declare with explicit generic types (e.g., const arr: Array = ...)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations.
Do not use explicit return types in TypeScript.
Files:
apps/cli/src/helpers/addons/ruler-setup.tsapps/cli/src/utils/config-validation.tsapps/cli/src/prompts/auth.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/helpers/core/env-setup.tsapps/cli/src/helpers/core/auth-setup.ts
**/*.{js,jsx,ts,tsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{js,jsx,ts,tsx,mjs,cjs}: Do not use dotenv; Bun auto-loads .env
UseBun.serve()for HTTP/WebSockets; do not useexpress
Usebun:sqlitefor SQLite; do not usebetter-sqlite3
UseBun.redisfor Redis; do not useioredis
UseBun.sqlfor Postgres; do not usepgorpostgres.js
Use built-inWebSocket; do not usews
PreferBun.fileovernode:fsreadFile/writeFile
UseBun.$instead ofexecafor shelling out
Files:
apps/cli/src/helpers/addons/ruler-setup.tsapps/cli/src/utils/config-validation.tsapps/cli/src/prompts/auth.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/helpers/core/env-setup.tsapps/cli/src/helpers/core/auth-setup.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions.
Files:
apps/cli/src/helpers/addons/ruler-setup.tsapps/cli/src/utils/config-validation.tsapps/cli/src/prompts/auth.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/helpers/core/env-setup.tsapps/cli/src/helpers/core/auth-setup.ts
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbsapps/cli/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbsapps/cli/templates/auth/better-auth/convex/native/unistyles/components/sign-in.tsx.hbsapps/cli/templates/auth/better-auth/native/base/lib/auth-client.ts.hbsapps/cli/templates/frontend/native/unistyles/app.json.hbsapps/cli/templates/frontend/native/nativewind/app/_layout.tsx.hbsapps/cli/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbsapps/cli/templates/auth/better-auth/convex/native/base/lib/auth-client.ts.hbsapps/cli/templates/auth/better-auth/convex/native/unistyles/components/sign-up.tsx.hbsapps/cli/templates/auth/better-auth/convex/backend/convex/auth.ts.hbsapps/cli/templates/auth/better-auth/convex/backend/convex/http.ts.hbsapps/cli/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbsapps/cli/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs
🧠 Learnings (1)
📚 Learning: 2025-08-24T18:00:39.152Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-08-24T18:00:39.152Z
Learning: Applies to convex/http.ts : Define HTTP endpoints only in convex/http.ts and wrap handlers with httpAction
Applied to files:
apps/cli/templates/auth/better-auth/convex/backend/convex/http.ts.hbs
🧬 Code graph analysis (3)
apps/cli/src/utils/config-validation.ts (1)
apps/cli/src/utils/errors.ts (1)
exitWithError(9-15)
apps/cli/src/helpers/core/template-manager.ts (1)
apps/cli/src/constants.ts (1)
PKG_ROOT(7-7)
apps/cli/src/helpers/core/auth-setup.ts (1)
apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-59)
🔇 Additional comments (10)
apps/cli/src/helpers/addons/ruler-setup.ts (1)
49-58: Formatting looks good.Spacing updates keep the EDITORS map consistent with surrounding entries; no functional impact.
apps/cli/src/helpers/core/template-manager.ts (2)
208-213: Native base path change: LGTMSwitching to templates/frontend/native/base aligns with the new structure.
681-682: Path consistency: LGTMtemplates/auth/${authProvider}/native/base matches the new native base layout.
apps/cli/src/helpers/core/auth-setup.ts (1)
58-70: Good: backend gets @better-auth/expo only when native frontends are presentThe conditional install aligns with the backend template importing expo() only for native variants.
Please confirm dependencyVersionMap contains versions for "@convex-dev/better-auth" so installs are pinned consistently.
apps/cli/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs (2)
17-22: Env assumptions for siteUrl/nativeAppUrlThe template expects SITE_URL (for web) and optionally NATIVE_APP_URL (for native). Ensure these are set in the generated env for selected frontends; otherwise trustedOrigins/baseURL may be undefined or fall back.
Confirm:
- When only native is selected: NATIVE_APP_URL is set (or default acceptable).
- When any web frontend is selected: SITE_URL is set.
Also applies to: 34-44, 50-58
26-60: createAuth function: structure looks correct
- Function declaration aligns with guidelines.
- Logger toggle via optionsOnly is neat.
- Plugin composition matches the import guards.
apps/cli/templates/frontend/native/nativewind/app/_layout.tsx.hbs (2)
5-9: Imports for Better Auth + Convex are correctConvexReactClient, ConvexBetterAuthProvider, and authClient are the right trio for this branch.
107-122: Confirm omission of "(auth)" screen under Better AuthClerk branch includes an "(auth)" stack, BA branch doesn’t. If the BA flow uses inline screens within (drawer), this is fine; otherwise consider adding a dedicated (auth) route for parity.
apps/cli/templates/frontend/native/unistyles/app/_layout.tsx.hbs (1)
76-98: Confirm omission of "(auth)" screen under Better AuthAs with nativewind, BA branch omits an "(auth)" route. Confirm that’s intentional.
apps/cli/src/helpers/core/env-setup.ts (1)
296-326: Confirm .env.local usage for Convex devYou’re writing public SITE_URL and *_CONVEX_SITE_URL entries into packages/backend/.env.local. Ensure Convex dev actually reads these (vs only convex env set). If not, they’ll be inert and may confuse users.
Do you want me to add comments clarifying which vars are read by Convex vs client apps?
Summary by CodeRabbit
Release Notes
New Features
Improvements