Repository navigation
Social Login - #27
Social Login#27
Conversation
…endencies, and refine mobile splash screen layout.
…new environment variables and dynamic trusted origins for development.
…ariants and accessibility, and refactor auth pages for consistent layout.
…er, and enhance mobile screen component with keyboard avoiding and system bar handling.
|
CodeAnt AI is reviewing your PR. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
Reviewer's GuideImplements social login flow and redesigns the mobile auth screens while wiring backend auth and email configuration to use a typed env module, plus updates shared UI primitives (Button, Text, Screen, Icon) to support the new UX and platform behaviors. Sequence diagram for the new social login flowsequenceDiagram
actor User
participant MobileAuthIndex as MobileAuthIndexScreen
participant AuthClient as AuthClient
participant ApiAuth as ApiAuthService
participant SocialProvider as SocialProvider
User->>MobileAuthIndex: Tap social login button
MobileAuthIndex->>AuthClient: signIn.social(provider, callbackURL)
AuthClient->>ApiAuth: POST /api/auth/social/{provider}
ApiAuth->>SocialProvider: Redirect user to provider auth
SocialProvider-->>User: Show provider login UI
User-->>SocialProvider: Authenticate and consent
SocialProvider->>ApiAuth: Redirect to callback with code
ApiAuth->>ApiAuth: Exchange code for tokens
ApiAuth->>ApiAuth: Create_or_update_user
ApiAuth->>AuthClient: Set session cookies
ApiAuth-->>AuthClient: Response with redirect URL
AuthClient-->>MobileAuthIndex: Resolve signIn.social
MobileAuthIndex-->>User: Navigate to /
Class diagram for env configuration and social auth setupclassDiagram
class EnvSchema {
+DATABASE_URL string
+BETTER_AUTH_SECRET string
+BETTER_AUTH_URL url
+GOOGLE_CLIENT_ID string
+GOOGLE_CLIENT_SECRET string
+FACEBOOK_CLIENT_ID string?
+FACEBOOK_CLIENT_SECRET string?
+GITHUB_CLIENT_ID string?
+GITHUB_CLIENT_SECRET string?
+APPLE_CLIENT_ID string?
+APPLE_CLIENT_SECRET string?
+LINKEDIN_CLIENT_ID string?
+LINKEDIN_CLIENT_SECRET string?
+EMAIL_PROVIDER enum nodemailer resnd plunk smtp
+RESEND_API_KEY string?
+PLUNK_API_KEY string?
+SMTP_HOST string?
+SMTP_PORT number?
+SMTP_SECURE boolean?
+SMTP_USER string?
+SMTP_PASS string?
+NODEMAILER_SERVICE string?
+NODEMAILER_USER string?
+NODEMAILER_PASS string?
+EMAIL_FROM email
+EMAIL_FROM_NAME string
+AXIOM_DOMAIN url?
+AXIOM_TOKEN string?
+DATASET_NAME string?
+REDIS_URL url
+NODE_ENV enum development test production
}
class EnvModule {
+env EnvSchema
}
class AuthConfig {
+trustedOrigins string[]
+database PrismaAdapter
+socialProviders SocialProviders
+emailAndPassword EmailAndPasswordConfig
}
class SocialProviders {
+google GoogleConfig
+facebook FacebookConfig
+github GithubConfig
+apple AppleConfig
+linkedin LinkedinConfig
}
class GoogleConfig {
+prompt string
+clientId string
+clientSecret string
}
class OAuthProviderConfig {
+clientId string
+clientSecret string
}
class EmailConfig {
+provider string
+from string
+fromName string
+resendApiKey string?
+plunkApiKey string?
+smtpHost string?
+smtpPort number
+smtpSecure boolean
+smtpUser string?
+smtpPass string?
+nodemailerService string?
+nodemailerUser string?
+nodemailerPass string?
}
EnvModule --> EnvSchema
AuthConfig --> SocialProviders
SocialProviders --> GoogleConfig
SocialProviders --> OAuthProviderConfig
EnvModule --> AuthConfig
EnvModule --> EmailConfig
Class diagram for updated UI primitives and Screen componentclassDiagram
class Screen {
+ReactNode children
+string className
+SystemBarsProps SystemBarsProps
+KeyboardAvoidingViewProps KeyboardAvoidingViewProps
+render() void
}
class Button {
+variant default destructive outline secondary ghost link
+size default sm lg icon
+onPress() void
+disabled boolean
+className string
}
class ButtonVariants {
+variant string
+size string
}
class ButtonTextVariants {
+variant string
+size string
}
class Text {
+variant default h1 h2 h3 h4 p blockquote code lead large small muted
+asChild boolean
+className string
}
class TextVariants {
+variant string
}
class Icon {
+as LucideIcon
+className string
+size number
}
Screen --> Button : contains
Screen --> Text : contains
Button --> ButtonVariants
Button --> Text : uses TextClassContext
Text --> TextVariants
Icon --> Text : can be used alongside
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughSummary by CodeRabbitRelease Notes
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughAdds Zod-based environment validation and social-provider env keys, wires env loader into API bootstrap, integrates social providers into auth, refactors mobile auth UIs to Screen/Header layouts (removing Card-based components), introduces new mobile primitives (Screen, Header, Icon), platform-aware UI variants, tooling updates, and several dependency/version bumps. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant MobileApp as Mobile App
participant AuthClient
participant API as API Server
participant Provider as OAuth Provider
rect rgb(240,250,240)
Note over MobileApp,API: Social login flow (uses env-backed creds)
end
User->>MobileApp: Tap social provider button
MobileApp->>AuthClient: authClient.signIn.social({ provider, callbackURL })
AuthClient->>API: POST /auth/social/signin
API->>Provider: OAuth handshake (uses env.GOOGLE_*/GITHUB_*)
Provider-->>API: callback (code/token)
API->>AuthClient: session created / callback response
AuthClient->>MobileApp: redirect to callbackURL
MobileApp->>User: Navigate to authenticated screen
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~28 minutes
Suggested labels
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 |
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
||||||||||||||||||||||||||||
There was a problem hiding this comment.
Hey there - I've reviewed your changes - here's some feedback:
- In the auth backend, several social providers are always registered with empty-string client IDs/secrets when env vars are missing (e.g., facebook/github/linkedin in auth.ts); consider only enabling a provider when its credentials are actually present to avoid misconfigured or partially working OAuth flows.
- In the new /auth social login screen, the FontAwesome icons use hard-coded
color="black"; it would be more consistent with theming to derive the color from your design system (e.g., viatext-classes or theme tokens) so icons adapt correctly to light/dark modes. - The updated
trustedOriginslist for Better Auth includes very broad patterns like"exp://*/*"; it would be safer to restrict these to the minimal set of development origins actually needed rather than using wide wildcards.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the auth backend, several social providers are always registered with empty-string client IDs/secrets when env vars are missing (e.g., facebook/github/linkedin in auth.ts); consider only enabling a provider when its credentials are actually present to avoid misconfigured or partially working OAuth flows.
- In the new /auth social login screen, the FontAwesome icons use hard-coded `color="black"`; it would be more consistent with theming to derive the color from your design system (e.g., via `text-` classes or theme tokens) so icons adapt correctly to light/dark modes.
- The updated `trustedOrigins` list for Better Auth includes very broad patterns like `"exp://*/*"`; it would be safer to restrict these to the minimal set of development origins actually needed rather than using wide wildcards.
## Individual Comments
### Comment 1
<location> `apps/mobile/src/components/ui/button.tsx:91-92` </location>
<code_context>
);
-type ButtonProps = React.ComponentProps<typeof Pressable> & VariantProps<typeof buttonVariants>;
+type ButtonProps = React.ComponentProps<typeof Pressable> &
+ React.RefAttributes<typeof Pressable> &
+ VariantProps<typeof buttonVariants>;
</code_context>
<issue_to_address>
**suggestion (bug_risk):** ButtonProps typing around `ref` is misleading and not actually supported by the component implementation.
Because `Button` is a plain function component (not using `forwardRef`), adding `React.RefAttributes<typeof Pressable>` makes TypeScript accept a `ref` that will be treated as a normal prop and never attached to the underlying `Pressable`. It’s also not the right shape for a `Pressable` instance ref.
To fix this:
- If refs aren’t supported, drop `React.RefAttributes<typeof Pressable>` and use `React.ComponentPropsWithoutRef<typeof Pressable>`.
- If refs should be supported, wrap `Button` in `React.forwardRef<Pressable, ButtonProps>` (or similar) and handle the ref properly.
This keeps the type definition aligned with the actual behavior and avoids confusing consumers relying on refs.
Suggested implementation:
```typescript
type ButtonProps = React.ComponentPropsWithoutRef<typeof Pressable> &
VariantProps<typeof buttonVariants>;
```
- No further code changes are strictly required if the `Button` component does not currently support refs (i.e., it is not wrapped with `React.forwardRef` and does not handle a `ref` prop).
- If there are any usages of `Button` that currently pass a `ref` expecting it to be attached to the underlying `Pressable`, those call sites should be updated to not rely on refs, or the component should be refactored to use `React.forwardRef` if ref support is desired in the future.
</issue_to_address>
### Comment 2
<location> `apps/api/src/lib/auth.ts:21-26` </location>
<code_context>
"http://localhost:8081",
+
+ // Development mode - Expo's exp:// scheme with local IP ranges
+ ...(env.NODE_ENV === "development" ? [
+ "exp://*/*", // Trust all Expo development URLs
+ "exp://10.0.0.*:*/*", // Trust 10.0.0.x IP range
+ "exp://192.168.*.*:*/*", // Trust 192.168.x.x IP range
+ "exp://172.*.*.*:*/*", // Trust 172.x.x.x IP range
+ "exp://localhost:*/*" // Trust localhost
+ ] : [])
],
</code_context>
<issue_to_address>
**🚨 question (security):** The wildcard-heavy trustedOrigins entries may not be interpreted as intended and could broaden trust too much.
These dev `trustedOrigins` entries use very broad patterns (e.g., `"exp://*/*"`, `"exp://10.0.0.*:*/*"`). Depending on how `betterAuth` parses them, they may either be unsupported and silently ignored or match more origins than intended, which can hide misconfigurations and make origin issues harder to diagnose.
Please:
- Verify whether `betterAuth` supports this wildcard syntax.
- If not, replace with explicit Expo dev origins (e.g., the concrete `exp://` URLs you use).
- If it does, tighten the patterns to only the specific hosts/ports you actually need in development.
</issue_to_address>
### Comment 3
<location> `apps/mobile/src/app/(public)/auth/reset-password.tsx:105` </location>
<code_context>
- <View className="flex-row justify-center items-center">
- <Text className="text-sm text-muted-foreground">
- Remember your password?{" "}
+ <View className="flex-1 justify-center items-center p-4">
+ {router.canGoBack() && (
+ <Button
</code_context>
<issue_to_address>
**suggestion:** Reset password screen is not using the shared Screen wrapper, which may cause layout/status bar inconsistencies.
Other auth screens were updated to use the shared `Screen` component for safe area handling, system bar configuration, and keyboard avoidance. This screen still uses a bare `View` as the root, which can lead to status bar overlap, inconsistent keyboard behavior on password fields, and visual differences from the rest of the auth flow. Please wrap this screen in `Screen` as well for consistent behavior and layout.
Suggested implementation:
```typescript
import { View, Text } from "react-native";
import { Screen } from "@/components/Screen";
```
```typescript
export default function ResetPassword() {
```
```typescript
return (
<Screen>
<View className="flex-1 justify-center items-center p-4">
{router.canGoBack() && (
<Button
```
```typescript
{router.canGoBack() && (
<Button
```
```typescript
)}
</View>
</Screen>
);
```
- The exact import path and named export for `Screen` (`@/components/Screen`, `@/components/ui/screen`, default vs named export, etc.) should match how it is done in the other auth screens (e.g. login, signup). Adjust the import line accordingly.
- The `Screen` component may expect specific props for consistent behavior across auth screens (e.g. `preset`, `safeAreaEdges`, `statusBarStyle`, `keyboardOffset`). Please copy the same `Screen` usage (component name and props) from the other updated auth screens to ensure consistent safe area handling, system bar configuration, and keyboard avoidance behavior.
- If the other auth screens use `Screen` as the outermost wrapper without an extra `View` for layout, you can move the `className` from the `View` directly onto `Screen` (or use the equivalent props) and remove the nested `View` to keep the structure consistent.
</issue_to_address>
### Comment 4
<location> `apps/mobile/src/app/(public)/auth/index.tsx:13-19` </location>
<code_context>
- return <Redirect href="/(public)/auth/sign-in" />;
+ const router = useRouter();
+
+ const handleSocialLogin = async (
+ provider: "google" | "facebook" | "github" | "apple" | "linkedin"
+ ) => {
+ await authClient.signIn.social({
+ provider,
+ callbackURL: "/",
+ });
+ };
+
</code_context>
<issue_to_address>
**suggestion:** Social login handler lacks error handling, so failures will be silent for users.
Right now `handleSocialLogin` just awaits `authClient.signIn.social` and ignores failures, so users get no indication if something goes wrong (e.g., network issues, provider misconfig, popup blocked). Please wrap this call in a try/catch, show a user-visible error (e.g., toast/snackbar), and optionally log/track the error to aid debugging when provider configuration is incorrect.
Suggested implementation:
```typescript
import { Button } from "~/components/ui/button";
import { Text } from "~/components/ui/text";
import { useToast } from "~/components/ui/use-toast";
```
```typescript
export default function AuthIndex() {
const router = useRouter();
const { toast } = useToast();
```
```typescript
const handleSocialLogin = async (
provider: "google" | "facebook" | "github" | "apple" | "linkedin"
) => {
try {
await authClient.signIn.social({
provider,
callbackURL: "/",
});
} catch (error) {
// Log for debugging / error tracking
console.error("Social login failed", error);
// User-visible feedback
toast?.({
variant: "destructive",
title: "Unable to sign in",
description:
"Something went wrong while connecting to the provider. Please try again.",
});
}
};
```
To fully integrate this change, you will likely need to:
1) Ensure `authClient` is imported in this file from wherever it is defined (for example, a module like `"~/lib/auth/client"`), if it is not already imported elsewhere in the file.
2) Confirm the correct import path and API for the toast hook in your codebase. If your project uses a different hook (e.g., `useToast` from `"~/components/ui/toast"` or similar) or a different options shape, adjust the `import { useToast } from "~/components/ui/use-toast";` line and the `toast?.({ ... })` call accordingly.
3) If your UI library does not support the `variant` prop or uses different props for destructive/error toasts, align the toast options with your existing toast/snackbar conventions.
</issue_to_address>
### Comment 5
<location> `apps/mobile/src/app/(public)/auth/index.tsx:25-34` </location>
<code_context>
- />
- </CardContent>
- <CardFooter>
- <Button
- onPress={handleResetPassword}
- className="flex-1 flex-row items-center gap-4"
</code_context>
<issue_to_address>
**suggestion:** Hardcoded black icon color can clash with theming (especially dark mode).
All social buttons render `FontAwesome` icons with `color="black"`, which can become nearly invisible on dark backgrounds and inconsistent with the rest of the theme-aware UI.
Please update these icons to use theme-aware colors (e.g., your design system’s foreground/text color) or the `Icon` component / NativeWind classes so they inherit the surrounding text/foreground color and remain legible in both light and dark mode.
</issue_to_address>
### Comment 6
<location> `apps/api/src/lib/email/config.ts:11-35` </location>
<code_context>
const config = {
provider: env.EMAIL_PROVIDER as EmailConfig["provider"],
from: env.EMAIL_FROM,
fromName: env.EMAIL_FROM_NAME,
// Resend
resendApiKey: env.RESEND_API_KEY,
// Plunk
plunkApiKey: env.PLUNK_API_KEY,
// SMTP
smtpHost: env.SMTP_HOST,
smtpPort: env.SMTP_PORT ?? 587,
smtpSecure: env.SMTP_SECURE ?? false,
smtpUser: env.SMTP_USER,
smtpPass: env.SMTP_PASS,
// Nodemailer
nodemailerService: env.NODEMAILER_SERVICE,
nodemailerUser: env.NODEMAILER_USER,
nodemailerPass: env.NODEMAILER_PASS,
};
return config;
</code_context>
<issue_to_address>
**suggestion (code-quality):** Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/inline-immediately-returned-variable))
```suggestion
return {
provider: env.EMAIL_PROVIDER as EmailConfig["provider"],
from: env.EMAIL_FROM,
fromName: env.EMAIL_FROM_NAME,
// Resend
resendApiKey: env.RESEND_API_KEY,
// Plunk
plunkApiKey: env.PLUNK_API_KEY,
// SMTP
smtpHost: env.SMTP_HOST,
smtpPort: env.SMTP_PORT ?? 587,
smtpSecure: env.SMTP_SECURE ?? false,
smtpUser: env.SMTP_USER,
smtpPass: env.SMTP_PASS,
// Nodemailer
nodemailerService: env.NODEMAILER_SERVICE,
nodemailerUser: env.NODEMAILER_USER,
nodemailerPass: env.NODEMAILER_PASS,
};
```
<br/><details><summary>Explanation</summary>Something that we often see in people's code is assigning to a result variable
and then immediately returning it.
Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.
Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
</details>
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| type ButtonProps = React.ComponentProps<typeof Pressable> & | ||
| React.RefAttributes<typeof Pressable> & |
There was a problem hiding this comment.
suggestion (bug_risk): ButtonProps typing around ref is misleading and not actually supported by the component implementation.
Because Button is a plain function component (not using forwardRef), adding React.RefAttributes<typeof Pressable> makes TypeScript accept a ref that will be treated as a normal prop and never attached to the underlying Pressable. It’s also not the right shape for a Pressable instance ref.
To fix this:
- If refs aren’t supported, drop
React.RefAttributes<typeof Pressable>and useReact.ComponentPropsWithoutRef<typeof Pressable>. - If refs should be supported, wrap
ButtoninReact.forwardRef<Pressable, ButtonProps>(or similar) and handle the ref properly.
This keeps the type definition aligned with the actual behavior and avoids confusing consumers relying on refs.
Suggested implementation:
type ButtonProps = React.ComponentPropsWithoutRef<typeof Pressable> &
VariantProps<typeof buttonVariants>;- No further code changes are strictly required if the
Buttoncomponent does not currently support refs (i.e., it is not wrapped withReact.forwardRefand does not handle arefprop). - If there are any usages of
Buttonthat currently pass arefexpecting it to be attached to the underlyingPressable, those call sites should be updated to not rely on refs, or the component should be refactored to useReact.forwardRefif ref support is desired in the future.
| ...(env.NODE_ENV === "development" ? [ | ||
| "exp://*/*", // Trust all Expo development URLs | ||
| "exp://10.0.0.*:*/*", // Trust 10.0.0.x IP range | ||
| "exp://192.168.*.*:*/*", // Trust 192.168.x.x IP range | ||
| "exp://172.*.*.*:*/*", // Trust 172.x.x.x IP range | ||
| "exp://localhost:*/*" // Trust localhost |
There was a problem hiding this comment.
🚨 question (security): The wildcard-heavy trustedOrigins entries may not be interpreted as intended and could broaden trust too much.
These dev trustedOrigins entries use very broad patterns (e.g., "exp://*/*", "exp://10.0.0.*:*/*"). Depending on how betterAuth parses them, they may either be unsupported and silently ignored or match more origins than intended, which can hide misconfigurations and make origin issues harder to diagnose.
Please:
- Verify whether
betterAuthsupports this wildcard syntax. - If not, replace with explicit Expo dev origins (e.g., the concrete
exp://URLs you use). - If it does, tighten the patterns to only the specific hosts/ports you actually need in development.
| const config = { | ||
| provider: process.env.EMAIL_PROVIDER as EmailConfig["provider"], | ||
| from: process.env.EMAIL_FROM || "onboarding@resend.dev", | ||
| fromName: process.env.EMAIL_FROM_NAME || "Universal Expo App", | ||
| provider: env.EMAIL_PROVIDER as EmailConfig["provider"], | ||
| from: env.EMAIL_FROM, | ||
| fromName: env.EMAIL_FROM_NAME, | ||
|
|
||
| // Resend | ||
| resendApiKey: process.env.RESEND_API_KEY, | ||
| resendApiKey: env.RESEND_API_KEY, | ||
|
|
||
| // Plunk | ||
| plunkApiKey: process.env.PLUNK_API_KEY, | ||
| plunkApiKey: env.PLUNK_API_KEY, | ||
|
|
||
| // SMTP | ||
| smtpHost: process.env.SMTP_HOST, | ||
| smtpPort: process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT) : 587, | ||
| smtpSecure: process.env.SMTP_SECURE === "true", | ||
| smtpUser: process.env.SMTP_USER, | ||
| smtpPass: process.env.SMTP_PASS, | ||
| smtpHost: env.SMTP_HOST, | ||
| smtpPort: env.SMTP_PORT ?? 587, | ||
| smtpSecure: env.SMTP_SECURE ?? false, | ||
| smtpUser: env.SMTP_USER, | ||
| smtpPass: env.SMTP_PASS, | ||
|
|
||
| // Nodemailer | ||
| nodemailerService: process.env.NODEMAILER_SERVICE, | ||
| nodemailerUser: process.env.NODEMAILER_USER, | ||
| nodemailerPass: process.env.NODEMAILER_PASS, | ||
| nodemailerService: env.NODEMAILER_SERVICE, | ||
| nodemailerUser: env.NODEMAILER_USER, | ||
| nodemailerPass: env.NODEMAILER_PASS, | ||
| }; | ||
|
|
||
| return config; |
There was a problem hiding this comment.
suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)
| const config = { | |
| provider: process.env.EMAIL_PROVIDER as EmailConfig["provider"], | |
| from: process.env.EMAIL_FROM || "onboarding@resend.dev", | |
| fromName: process.env.EMAIL_FROM_NAME || "Universal Expo App", | |
| provider: env.EMAIL_PROVIDER as EmailConfig["provider"], | |
| from: env.EMAIL_FROM, | |
| fromName: env.EMAIL_FROM_NAME, | |
| // Resend | |
| resendApiKey: process.env.RESEND_API_KEY, | |
| resendApiKey: env.RESEND_API_KEY, | |
| // Plunk | |
| plunkApiKey: process.env.PLUNK_API_KEY, | |
| plunkApiKey: env.PLUNK_API_KEY, | |
| // SMTP | |
| smtpHost: process.env.SMTP_HOST, | |
| smtpPort: process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT) : 587, | |
| smtpSecure: process.env.SMTP_SECURE === "true", | |
| smtpUser: process.env.SMTP_USER, | |
| smtpPass: process.env.SMTP_PASS, | |
| smtpHost: env.SMTP_HOST, | |
| smtpPort: env.SMTP_PORT ?? 587, | |
| smtpSecure: env.SMTP_SECURE ?? false, | |
| smtpUser: env.SMTP_USER, | |
| smtpPass: env.SMTP_PASS, | |
| // Nodemailer | |
| nodemailerService: process.env.NODEMAILER_SERVICE, | |
| nodemailerUser: process.env.NODEMAILER_USER, | |
| nodemailerPass: process.env.NODEMAILER_PASS, | |
| nodemailerService: env.NODEMAILER_SERVICE, | |
| nodemailerUser: env.NODEMAILER_USER, | |
| nodemailerPass: env.NODEMAILER_PASS, | |
| }; | |
| return config; | |
| return { | |
| provider: env.EMAIL_PROVIDER as EmailConfig["provider"], | |
| from: env.EMAIL_FROM, | |
| fromName: env.EMAIL_FROM_NAME, | |
| // Resend | |
| resendApiKey: env.RESEND_API_KEY, | |
| // Plunk | |
| plunkApiKey: env.PLUNK_API_KEY, | |
| // SMTP | |
| smtpHost: env.SMTP_HOST, | |
| smtpPort: env.SMTP_PORT ?? 587, | |
| smtpSecure: env.SMTP_SECURE ?? false, | |
| smtpUser: env.SMTP_USER, | |
| smtpPass: env.SMTP_PASS, | |
| // Nodemailer | |
| nodemailerService: env.NODEMAILER_SERVICE, | |
| nodemailerUser: env.NODEMAILER_USER, | |
| nodemailerPass: env.NODEMAILER_PASS, | |
| }; | |
Explanation
Something that we often see in people's code is assigning to a result variableand then immediately returning it.
Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.
Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||||||||||||
| <Stack.Screen name="sign-in" /> | ||
| <Stack.Screen name="sign-up" /> | ||
| <Stack.Screen name="forgot-password" /> | ||
| </Stack> |
There was a problem hiding this comment.
Suggestion: The layout now only registers the four listed screens with the stack, so the reset-password.tsx page never gets a Stack.Screen entry and navigating to the password reset page will throw because that route is not defined anymore. [logic error]
Severity Level: Minor
| </Stack> | |
| <Stack.Screen name="reset-password" /> |
Why it matters? ⭐
There is a reset-password.tsx screen under this layout, so the stack should register that route; without the entry the screen never gets a defined path and navigation from the forgot-password flow will fail. Adding the missing <Stack.Screen name="reset-password" /> fixes a real navigation bug introduced by removing the route.
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/mobile/src/app/(public)/auth/_layout.tsx
**Line:** 21:21
**Comment:**
*Logic Error: The layout now only registers the four listed screens with the stack, so the `reset-password.tsx` page never gets a `Stack.Screen` entry and navigating to the password reset page will throw because that route is not defined anymore.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.| </View> | ||
|
|
||
| <Button | ||
| onPress={() => router.push("/(public)/auth/sign-in")} |
There was a problem hiding this comment.
Suggestion: Pushing to "/(public)/auth/sign-in" tries to navigate to a literal path that includes the route group segment, but expo-router omits (public) from the actual URL, so this navigation target never exists and the screen will not load. [logic error]
Severity Level: Minor
| onPress={() => router.push("/(public)/auth/sign-in")} | |
| onPress={() => router.push("/auth/sign-in")} |
Why it matters? ⭐
In expo-router the (public) route group is never part of the actual URL, so pushing to "/(public)/auth/sign-in" will never resolve to a screen. Changing it to "/auth/sign-in" points at the real route and makes the button work.
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/mobile/src/app/(public)/auth/index.tsx
**Line:** 89:89
**Comment:**
*Logic Error: Pushing to `"/(public)/auth/sign-in"` tries to navigate to a literal path that includes the route group segment, but expo-router omits `(public)` from the actual URL, so this navigation target never exists and the screen will not load.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.| // For web, also check window location search params | ||
| if (!resetToken && typeof window !== "undefined") { | ||
| resetToken = new URLSearchParams(window.location.search).get("token"); | ||
| resetToken = new URLSearchParams(window.location.search).get("token") || ""; |
There was a problem hiding this comment.
Suggestion: Guard against missing window.location before reading search: on React Native window exists but window.location is undefined, so calling window.location.search when the URL token is absent will crash the app instead of showing the reset form. [null pointer]
Severity Level: Minor
| resetToken = new URLSearchParams(window.location.search).get("token") || ""; | |
| const searchParams = window.location?.search; | |
| if (searchParams) { | |
| resetToken = new URLSearchParams(searchParams).get("token") || ""; | |
| } |
Why it matters? ⭐
On native runtimes window exists but window.location is undefined, so the current code would throw whenever the token isn't already in params. The guard prevents a runtime crash before showing the reset form, so it fixes a real platform bug.
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/mobile/src/app/(public)/auth/reset-password.tsx
**Line:** 27:27
**Comment:**
*Null Pointer: Guard against missing `window.location` before reading `search`: on React Native `window` exists but `window.location` is undefined, so calling `window.location.search` when the URL token is absent will crash the app instead of showing the reset form.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.| size="sm" | ||
| onPress={() => { | ||
| push("/auth/sign-in", { withAnchor: true }); | ||
| push("/auth", { withAnchor: true }); |
There was a problem hiding this comment.
Suggestion: The desktop login button now navigates to /auth, but the actual login screen lives at /auth/sign-in (see the mobile flow), so tapping this button will push to a route that has no page and results in a runtime navigation error/blank screen; it should navigate to /auth/sign-in instead. [logic error]
Severity Level: Minor
| push("/auth", { withAnchor: true }); | |
| push("/auth/sign-in", { withAnchor: true }); |
Why it matters? ⭐
The mobile flow already pushes to /auth/sign-in, and there is no evidence that /auth is a valid screen, so keeping the desktop button on /auth almost certainly produces a blank/errored navigation. Aligning the desktop handler with the actual login route fixes a real runtime navigation bug introduced in this PR.
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/mobile/src/containers/core/HeaderUser.tsx
**Line:** 135:135
**Comment:**
*Logic Error: The desktop login button now navigates to `/auth`, but the actual login screen lives at `/auth/sign-in` (see the mobile flow), so tapping this button will push to a route that has no page and results in a runtime navigation error/blank screen; it should navigate to `/auth/sign-in` instead.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.|
|
||
| if (!parsed.success) { | ||
| logger.error("❌ Invalid environment variables:"); | ||
| logger.error(JSON.stringify(z.flattenError(parsed.error).fieldErrors, null, 2)); |
There was a problem hiding this comment.
Suggestion: z.flattenError is not a function exported by Zod, so whenever the schema validation fails this line throws TypeError: z.flattenError is not a function before your logging or process.exit(1) can run; call parsed.error.flatten() instead so you actually log the validation errors and exit cleanly. [logic error]
Severity Level: Minor
| logger.error(JSON.stringify(z.flattenError(parsed.error).fieldErrors, null, 2)); | |
| logger.error(JSON.stringify(parsed.error.flatten().fieldErrors, null, 2)); |
Why it matters? ⭐
z.flattenError is not part of Zod's API, so this line throws TypeError: z.flattenError is not a function the moment validation fails and nothing is logged before the process exits. Using parsed.error.flatten() is the documented way to access the field errors from a ZodError, so the suggested change fixes a real runtime crash during env validation.
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/api/src/env.ts
**Line:** 66:66
**Comment:**
*Logic Error: `z.flattenError` is not a function exported by Zod, so whenever the schema validation fails this line throws `TypeError: z.flattenError is not a function` before your logging or `process.exit(1)` can run; call `parsed.error.flatten()` instead so you actually log the validation errors and exit cleanly.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.|
CodeAnt AI finished reviewing your PR. |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
apps/mobile/src/containers/core/HeaderUser.tsx (1)
143-143: Replace HTML<div>with React Native<View>primitive.Line 143 uses an HTML
<div>element instead of the React Native<View>primitive, which violates the coding guidelines and will break on native iOS/Android platforms.Apply this diff to fix the issue:
- <div className="flex md:hidden"> + <View className="flex md:hidden">Also update the closing tag on line 162:
- </div> + </View>As per coding guidelines, React Native primitives must be used instead of HTML elements.
apps/mobile/src/app/index.tsx (1)
5-27: Perfect! I now have all the necessary information to verify the review comment. Let me analyze the findings:Key Verification Results:
Session State Check Issue (CONFIRMED):
- Line 9:
const session = authClient.useSession();returns an object- Line 19:
if (!session)will never be true becausesessionis always an object (even when loading)- The AdminLayout at line 6 shows the correct pattern:
const { isPending, data } = authClient.useSession();- AdminLayout then properly checks
if (isPending)(line 7), not the session object itselfRedirect Inconsistency (CONFIRMED):
- index.tsx line 36:
return <Redirect href="/(public)/auth" />;- AdminLayout line 13:
return <Redirect href="/auth" />;- These are indeed different redirect targets
The review's suggested fix is valid - the pattern should follow AdminLayout's destructuring approach
The review comment is substantially correct. The original analysis properly identified that the
if (!session)condition is unreachable and that redirects are inconsistent. The suggested refactor aligns with the existing pattern used elsewhere in the codebase.
Fix the session state condition to match the destructuring pattern used in AdminLayout, and standardize redirect routes
The
if (!session)check on line 19 will never execute becauseauthClient.useSession()returns an object with properties like{ isPending, data }, not a falsy value. This makes the loading UI unreachable.The AdminLayout (at
apps/mobile/src/app/(public)/(protected)/admin/_layout.tsx) demonstrates the correct pattern:const { isPending, data } = authClient.useSession(); if (isPending) { return <LoadingScreen />; }Additionally, redirect routes differ across files:
- index.tsx (line 36):
"/(public)/auth"- AdminLayout (line 13):
"/auth"Update index.tsx to destructure
isPendinganddata, checkisPendingfor the loading state, and align redirects with AdminLayout or establish a consistent route naming convention across the app.apps/mobile/src/components/ui/button.tsx (1)
91-105: Forward ref prop to Pressable.
ButtonPropsincludesReact.RefAttributes<typeof Pressable>which indicates ref support, but the Button component doesn't forward the ref to the underlying Pressable. In React 19, ref is a regular prop and should be passed through.Apply this diff to forward the ref:
-function Button({ className, variant, size, ...props }: ButtonProps) { +function Button({ className, variant, size, ref, ...props }: ButtonProps) { return ( <TextClassContext.Provider value={buttonTextVariants({ variant, size })}> <Pressable className={cn(props.disabled && 'opacity-50', buttonVariants({ variant, size }), className)} role="button" + ref={ref} {...props} /> </TextClassContext.Provider> ); }apps/mobile/src/app/(public)/auth/sign-in.tsx (1)
52-53: Remove console.error from committed code.Line 52 uses
console.error, which violates the coding guideline: "Don't use console or debugger in committed code." The same issue occurs at line 80.Remove or replace with a proper logging solution:
} catch (error) { - console.error("Login error:", error); toast.error("An unexpected error occurred", { position: "bottom-center", });Apply the same fix to line 80:
} catch (error) { - console.error("Verification email error:", error); toast.error("Failed to send verification email", { position: "bottom-center", });apps/mobile/src/app/(public)/auth/forgot-password.tsx (1)
53-57: Remove console.error from committed code.Line 54 uses
console.error, which violates the coding guideline: "Don't use console or debugger in committed code."Remove the console.error statement:
} catch (error) { - console.error("Password reset error:", error); toast.error("Failed to send reset instructions. Please try again.", { position: "bottom-center", });
🧹 Nitpick comments (9)
apps/mobile/src/app/(public)/(protected)/admin/_layout.tsx (1)
12-14: Align admin unauthenticated redirect path with the rest of the appRedirecting to
/authmakes sense, but other places (e.g.,apps/mobile/src/app/index.tsx) use"/(public)/auth"for the same target. For consistency with expo-router’s typed routes and to avoid subtle mismatches, consider standardizing on one form across the app (probably the grouped path).apps/mobile/src/components/auth/sign-up-success-card.tsx (1)
30-75: Refactored success card layout looks clean and preserves behaviorThe move to a View/Text-based layout keeps all the previous behaviors (continue CTA, resend with loading/feedback states) while simplifying structure and matching the rest of the mobile UI primitives. No issues from a logic or typing standpoint.
If you later standardize spacing/typography across auth screens, this component already aligns well with that direction.
apps/mobile/src/app/(public)/auth/reset-password.tsx (3)
26-28: Empty string fallback is redundant.Line 27 provides an empty string fallback for a missing token, but the subsequent validation at lines 30-36 will immediately catch this case and redirect to sign-in. The fallback doesn't add value since
!resetTokenchecks for bothnull/undefinedand empty strings.Simplify by removing the fallback:
- resetToken = new URLSearchParams(window.location.search).get("token") || ""; + resetToken = new URLSearchParams(window.location.search).get("token");
106-114: Back button positioning inconsistency.The back button uses
top-0(line 109) while other auth screens usetop-4(e.g., index.tsx line 27, forgot-password.tsx). This creates visual inconsistency.Apply this diff for consistent spacing:
- className="absolute top-0 left-0 z-10" + className="absolute top-4 left-4 z-10"
94-102: Loading state lacks Screen wrapper.The loading state (lines 96-100) doesn't use the
Screencomponent, while the main render (line 105) does. This creates an inconsistent experience if users see the loading state.Wrap the loading state in Screen for consistency:
if (!token) { return ( - <View className="flex-1 justify-center items-center"> + <Screen className="flex-1 justify-center items-center"> <View className="w-full max-w-sm p-6"> <Text className="text-center text-muted-foreground">Loading...</Text> </View> - </View> + </Screen> ); }apps/mobile/src/components/screen.tsx (4)
11-12: Consider making keyboard offset configurable.The hardcoded 20px offset for iOS may not suit all screen layouts. Consider accepting an optional
keyboardOffsetprop to allow consumers to customize this value when needed.Example:
-const isIos = Platform.OS === "ios"; -const keyboardOffset = isIos ? 20 : 0; - export const Screen = ({ children, className, SystemBarsProps, KeyboardAvoidingViewProps, + keyboardOffset, }: { children: React.ReactNode; className?: string; SystemBarsProps?: SystemBarsProps; KeyboardAvoidingViewProps?: KeyboardAvoidingViewProps; + keyboardOffset?: number; }) => { + const isIos = Platform.OS === "ios"; + const offset = keyboardOffset ?? (isIos ? 20 : 0); const { isDarkColorScheme } = useColorScheme(); return ( <SafeAreaView className={cn("flex-1", className)}> <SystemBars style={isDarkColorScheme ? "dark" : "light"} {...SystemBarsProps} /> <KeyboardAvoidingView behavior={isIos ? "padding" : "height"} - keyboardVerticalOffset={keyboardOffset} + keyboardVerticalOffset={offset} {...KeyboardAvoidingViewProps} style={[{ flex: 1 }, KeyboardAvoidingViewProps?.style]} > {children} </KeyboardAvoidingView> </SafeAreaView> ); };
17-18: Use camelCase for prop names.The prop names
SystemBarsPropsandKeyboardAvoidingViewPropsuse PascalCase, which deviates from standard JavaScript and React naming conventions. Props should be camelCase for consistency.export const Screen = ({ children, className, - SystemBarsProps, - KeyboardAvoidingViewProps, + systemBarsProps, + keyboardAvoidingViewProps, }: { children: React.ReactNode; className?: string; - SystemBarsProps?: SystemBarsProps; - KeyboardAvoidingViewProps?: KeyboardAvoidingViewProps; + systemBarsProps?: SystemBarsProps; + keyboardAvoidingViewProps?: KeyboardAvoidingViewProps; }) => { const { isDarkColorScheme } = useColorScheme(); return ( <SafeAreaView className={cn("flex-1", className)}> <SystemBars style={isDarkColorScheme ? "dark" : "light"} - {...SystemBarsProps} + {...systemBarsProps} /> <KeyboardAvoidingView behavior={isIos ? "padding" : "height"} keyboardVerticalOffset={keyboardOffset} - {...KeyboardAvoidingViewProps} - style={[{ flex: 1 }, KeyboardAvoidingViewProps?.style]} + {...keyboardAvoidingViewProps} + style={[{ flex: 1 }, keyboardAvoidingViewProps?.style]} > {children} </KeyboardAvoidingView> </SafeAreaView> ); };
14-24: Extract props type to a separate interface.As per coding guidelines, "define shapes with TypeScript interfaces" when using object destructuring for parameters. Extract the inline type definition to improve reusability and type composition.
+export interface ScreenProps { + children: React.ReactNode; + className?: string; + systemBarsProps?: SystemBarsProps; + keyboardAvoidingViewProps?: KeyboardAvoidingViewProps; +} + -export const Screen = ({ - children, - className, - SystemBarsProps, - KeyboardAvoidingViewProps, -}: { - children: React.ReactNode; - className?: string; - SystemBarsProps?: SystemBarsProps; - KeyboardAvoidingViewProps?: KeyboardAvoidingViewProps; -}) => { +export const Screen = ({ + children, + className, + systemBarsProps, + keyboardAvoidingViewProps, +}: ScreenProps) => {
27-27: Consider making SafeAreaView edges configurable.The
SafeAreaViewuses default edges (all sides). For some screen layouts, you may want to control which edges receive safe area insets. Consider accepting an optionaledgesprop.export const Screen = ({ children, className, SystemBarsProps, KeyboardAvoidingViewProps, + safeAreaEdges, }: { children: React.ReactNode; className?: string; SystemBarsProps?: SystemBarsProps; KeyboardAvoidingViewProps?: KeyboardAvoidingViewProps; + safeAreaEdges?: ('top' | 'right' | 'bottom' | 'left')[]; }) => { const { isDarkColorScheme } = useColorScheme(); return ( - <SafeAreaView className={cn("flex-1", className)}> + <SafeAreaView className={cn("flex-1", className)} edges={safeAreaEdges}> <SystemBars style={isDarkColorScheme ? "dark" : "light"} {...SystemBarsProps} />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
apps/mobile/assets/images/partial-react-logo.pngis excluded by!**/*.pngapps/mobile/assets/images/react-logo.pngis excluded by!**/*.pngapps/mobile/assets/images/react-logo@2x.pngis excluded by!**/*.pngapps/mobile/assets/images/react-logo@3x.pngis excluded by!**/*.pngpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (30)
.vscode/settings.json(1 hunks)apps/api/.env.example(1 hunks)apps/api/src/env.ts(1 hunks)apps/api/src/index.ts(1 hunks)apps/api/src/lib/auth.ts(1 hunks)apps/api/src/lib/email/config.ts(1 hunks)apps/mobile/components.json(1 hunks)apps/mobile/src/app/(public)/(protected)/_layout.tsx(1 hunks)apps/mobile/src/app/(public)/(protected)/admin/_layout.tsx(1 hunks)apps/mobile/src/app/(public)/auth/_layout.tsx(1 hunks)apps/mobile/src/app/(public)/auth/forgot-password.tsx(2 hunks)apps/mobile/src/app/(public)/auth/index.tsx(1 hunks)apps/mobile/src/app/(public)/auth/reset-password.tsx(3 hunks)apps/mobile/src/app/(public)/auth/sign-in.tsx(2 hunks)apps/mobile/src/app/(public)/auth/sign-up.tsx(1 hunks)apps/mobile/src/app/(public)/auth/social-sign-in.tsx(0 hunks)apps/mobile/src/app/index.tsx(3 hunks)apps/mobile/src/components/auth/sign-up-form.tsx(4 hunks)apps/mobile/src/components/auth/sign-up-success-card.tsx(4 hunks)apps/mobile/src/components/screen.tsx(1 hunks)apps/mobile/src/components/ui/button.tsx(3 hunks)apps/mobile/src/components/ui/icon.tsx(1 hunks)apps/mobile/src/components/ui/text.tsx(1 hunks)apps/mobile/src/containers/auth/sign-up.container.tsx(1 hunks)apps/mobile/src/containers/core/HeaderUser.tsx(1 hunks)apps/mobile/src/lib/auth-client.ts(0 hunks)biome.jsonc(1 hunks)package.json(1 hunks)pnpm-workspace.yaml(1 hunks)turbo.json(3 hunks)
💤 Files with no reviewable changes (2)
- apps/mobile/src/app/(public)/auth/social-sign-in.tsx
- apps/mobile/src/lib/auth-client.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use object destructuring for method parameters (wrap multiple parameters in an object; define shapes with TypeScript interfaces)
Use authClient.useSession() for session state
Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)
Import UI components via path aliases (e.g., @/src/components/ui/)
Prefer union string/number literals over TypeScript enums
Use export type and import type for types
Don't use non-null assertions (!) or implicit any
Avoid TypeScript namespaces; prefer ESM modules
Files:
apps/mobile/src/containers/auth/sign-up.container.tsxapps/api/src/env.tsapps/mobile/src/app/(public)/(protected)/admin/_layout.tsxapps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/index.tsxapps/mobile/src/components/ui/icon.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/sign-up.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/containers/core/HeaderUser.tsxapps/api/src/lib/auth.tsapps/mobile/src/components/ui/button.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/app/(public)/(protected)/_layout.tsxapps/api/src/lib/email/config.tsapps/api/src/index.tsapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/components/auth/sign-up-success-card.tsxapps/mobile/src/components/ui/text.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Platform.OS and process.env.EXPO_OS for conditional platform logic
Files:
apps/mobile/src/containers/auth/sign-up.container.tsxapps/api/src/env.tsapps/mobile/src/app/(public)/(protected)/admin/_layout.tsxapps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/index.tsxapps/mobile/src/components/ui/icon.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/sign-up.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/containers/core/HeaderUser.tsxapps/api/src/lib/auth.tsapps/mobile/src/components/ui/button.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/app/(public)/(protected)/_layout.tsxapps/api/src/lib/email/config.tsapps/api/src/index.tsapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/components/auth/sign-up-success-card.tsxapps/mobile/src/components/ui/text.tsx
**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.tsx: Use React Native primitives (View, Text, etc.) instead of HTML elements
Use Tailwind responsive prefixes (sm:, md:, lg:) and NativeWind responsive utilities
Use web: prefix for web-only styles; use conditional rendering for native-only components
Use IconSymbol to map SF Symbols on iOS to Material Icons on other platforms
Web a11y: ensure buttons have type, anchors are valid, SVGs/iframes have title, html has lang, inputs have valid autocomplete, ARIA roles/props/values are valid
Files:
apps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/app/(public)/(protected)/admin/_layout.tsxapps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/index.tsxapps/mobile/src/components/ui/icon.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/sign-up.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/containers/core/HeaderUser.tsxapps/mobile/src/components/ui/button.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/app/(public)/(protected)/_layout.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/components/auth/sign-up-success-card.tsxapps/mobile/src/components/ui/text.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx,js,jsx}: Don't use the arguments object
Use for...of instead of Array.forEach
Use arrow functions instead of function expressions
Use Date.now() instead of new Date().getTime()
Use .flatMap() instead of map().flat() when possible
Prefer regex literals over RegExp constructor when possible
Use concise optional chaining instead of chained logical expressions
Always provide radix to parseInt()
Don't use var; use const/let and prefer const when single assignment
Use template literals over string concatenation
Use strict equality (===/!==)
Don't use console or debugger in committed code
Prevent import cycles and avoid namespace imports
Don't hardcode secrets (API keys/tokens) in source
Don't have unused vars, params, imports, labels, or private members
Avoid await inside loops; ensure Promise-like statements are handled
Disallow bitwise operators and comma operator
Ensure switch statements are exhaustive; default clause comes last; no fallthrough or duplicate cases
Use object spread over Object.assign when creating new objects
Prefer Array.isArray over instanceof Array; use at() instead of integer index access where appropriate
No unreachable code, duplicate conditions, or assignments in conditionals
Always use radix with parseInt; prefer Number.isNaN/Number.isFinite over globals
Disallow using global eval, with, var, and unsafe negation
Ensure typeof comparisons use valid strings; getters return values; constructors don’t return values
Files:
apps/mobile/src/containers/auth/sign-up.container.tsxapps/api/src/env.tsapps/mobile/src/app/(public)/(protected)/admin/_layout.tsxapps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/index.tsxapps/mobile/src/components/ui/icon.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/sign-up.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/containers/core/HeaderUser.tsxapps/api/src/lib/auth.tsapps/mobile/src/components/ui/button.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/app/(public)/(protected)/_layout.tsxapps/api/src/lib/email/config.tsapps/api/src/index.tsapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/components/auth/sign-up-success-card.tsxapps/mobile/src/components/ui/text.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{tsx,jsx}: Provide key props in lists; avoid array index as key
Don't define React components inside other components
Don't use event handlers on non-interactive elements; make interactive roles focusable
Don't use both children and dangerouslySetInnerHTML; avoid dangerous JSX props
Use <>...</> instead of ...
Files:
apps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/app/(public)/(protected)/admin/_layout.tsxapps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/index.tsxapps/mobile/src/components/ui/icon.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/sign-up.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/containers/core/HeaderUser.tsxapps/mobile/src/components/ui/button.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/app/(public)/(protected)/_layout.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/components/auth/sign-up-success-card.tsxapps/mobile/src/components/ui/text.tsx
🧠 Learnings (23)
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/lib/auth-client.ts : Initialize Better Auth client in src/lib/auth-client.ts with platform-specific plugins
Applied to files:
apps/api/.env.exampleapps/mobile/src/app/(public)/auth/index.tsxapps/api/src/lib/auth.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/containers/**/*.container.tsx : Create containers in src/containers/ mirroring Expo Router paths (e.g., admin/add-user.container.tsx)
Applied to files:
apps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/app/index.tsxapps/mobile/src/app/(public)/auth/sign-up.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/components/**/*.{ts,tsx} : Use NativeWind with className and Tailwind utilities for component styling
Applied to files:
apps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/components/ui/icon.tsxapps/mobile/src/components/ui/text.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Use authClient.useSession() for session state
Applied to files:
apps/mobile/src/app/(public)/(protected)/admin/_layout.tsxapps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/index.tsxapps/api/src/lib/auth.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/app/**/_layout.{ts,tsx} : Ensure global.css is imported in the app entry layout for NativeWind setup
Applied to files:
apps/mobile/src/app/(public)/(protected)/admin/_layout.tsxapps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/index.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/(protected)/_layout.tsxapps/api/src/index.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/components/ui/**/*.{ts,tsx} : Only truly reusable UI components belong in src/components/ui with proper TypeScript interfaces
Applied to files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/components/screen.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Use React Native primitives (View, Text, etc.) instead of HTML elements
Applied to files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/index.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/components/ui/button.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/components/auth/sign-up-success-card.tsxapps/mobile/src/components/ui/text.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/app/** : Expo Router: keep all routes under src/app with route groups (e.g., (auth), (tabs))
Applied to files:
apps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/index.tsxapps/mobile/src/app/(public)/auth/_layout.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Follow Expo Router file-based routing conventions for navigation structure
Applied to files:
apps/mobile/src/app/(public)/auth/index.tsxapps/mobile/src/app/(public)/auth/sign-up.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)
Applied to files:
apps/mobile/src/app/index.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Use web: prefix for web-only styles; use conditional rendering for native-only components
Applied to files:
apps/mobile/src/app/index.tsxapps/mobile/src/components/ui/button.tsxapps/mobile/components.jsonapps/mobile/src/components/ui/text.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Use IconSymbol to map SF Symbols on iOS to Material Icons on other platforms
Applied to files:
apps/mobile/src/components/ui/icon.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Web a11y: ensure buttons have type, anchors are valid, SVGs/iframes have title, html has lang, inputs have valid autocomplete, ARIA roles/props/values are valid
Applied to files:
apps/mobile/src/components/ui/button.tsxapps/mobile/src/components/ui/text.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/components/**/*.{ts,tsx} : Implement component variants with class-variance-authority (cva)
Applied to files:
apps/mobile/src/components/ui/button.tsxapps/mobile/src/components/ui/text.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ios,android,web}.{ts,tsx,js} : Use platform-specific file extensions (.ios.tsx, .web.ts, etc.) for platform implementations
Applied to files:
apps/mobile/src/components/ui/button.tsxapps/mobile/src/components/ui/text.tsx
📚 Learning: 2025-08-28T12:01:24.375Z
Learnt from: chakrihacker
Repo: fyndx/universal-starter PR: 13
File: apps/frontend/tsconfig.json:13-17
Timestamp: 2025-08-28T12:01:24.375Z
Learning: When using TypeScript project references for Eden Treaty type safety, the backend needs both "composite": true and "declaration": true in tsconfig.json to emit .d.ts files that the frontend can consume. The workspace root also needs TypeScript as a devDependency for the build commands to work properly.
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Prevent import cycles and avoid namespace imports
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Import UI components via path aliases (e.g., @/src/components/ui/)
Applied to files:
apps/api/src/index.tsapps/mobile/components.json
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't hardcode secrets (API keys/tokens) in source
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Use export type and import type for types
Applied to files:
apps/api/src/index.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to metro.config.js : Metro config must support CSS, package exports, and .mjs files
Applied to files:
apps/mobile/components.json
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to babel.config.js : Configure NativeWind Babel/Metro plugins for Tailwind compilation
Applied to files:
apps/mobile/components.json
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to tailwind.config.js : Configure themes in Tailwind via CSS custom properties in tailwind.config.js
Applied to files:
apps/mobile/components.json
🧬 Code graph analysis (17)
apps/mobile/src/app/(public)/auth/sign-in.tsx (2)
apps/mobile/src/components/screen.tsx (1)
Screen(14-42)apps/frontend/src/app/(public)/auth/sign-in.tsx (3)
SignIn(21-180)ctx(41-52)setIsLoading(30-67)
apps/mobile/src/app/(public)/auth/index.tsx (3)
apps/mobile/src/lib/auth-client.ts (1)
authClient(21-28)apps/mobile/src/components/screen.tsx (1)
Screen(14-42)apps/frontend/src/app/(public)/auth/sign-in.tsx (4)
SignIn(21-180)setIsLoading(30-67)ctx(41-52)
apps/mobile/src/app/index.tsx (2)
apps/frontend/src/app/(public)/(protected)/home/(tabs)/index.tsx (2)
HomeScreen(7-18)router(12-12)apps/frontend/src/app/(public)/auth/sign-in.tsx (3)
SignIn(21-180)setIsLoading(30-67)ctx(41-52)
apps/mobile/src/components/ui/icon.tsx (1)
apps/mobile/src/lib/utils.ts (1)
cn(4-6)
apps/mobile/src/components/screen.tsx (2)
apps/mobile/src/hooks/useColorScheme.ts (1)
useColorScheme(9-64)apps/mobile/src/lib/utils.ts (1)
cn(4-6)
apps/mobile/src/app/(public)/auth/_layout.tsx (1)
apps/frontend/src/app/(public)/auth/sign-in.tsx (2)
SignIn(21-180)ctx(41-52)
apps/mobile/src/app/(public)/auth/sign-up.tsx (2)
apps/mobile/src/components/screen.tsx (1)
Screen(14-42)apps/mobile/src/containers/auth/sign-up.container.tsx (1)
SignUpContainer(7-56)
apps/mobile/src/components/auth/sign-up-form.tsx (4)
apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)apps/mobile/src/components/ui/activity-indicator.tsx (1)
ActivityIndicator(12-12)apps/frontend/src/app/(public)/auth/sign-in.tsx (1)
SignIn(21-180)
apps/mobile/src/containers/core/HeaderUser.tsx (1)
apps/frontend/src/app/(public)/auth/sign-in.tsx (1)
SignIn(21-180)
apps/api/src/lib/auth.ts (3)
apps/api/src/env.ts (1)
env(70-70)apps/api/src/infra/db.ts (1)
prisma(2-2)apps/api/src/plugins/auth.ts (1)
Elysia(4-16)
apps/mobile/src/components/ui/button.tsx (2)
apps/mobile/src/lib/utils.ts (1)
cn(4-6)apps/mobile/src/components/ui/text.tsx (1)
TextClassContext(89-89)
apps/mobile/src/app/(public)/auth/reset-password.tsx (6)
apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)apps/mobile/src/components/ui/password.tsx (1)
PasswordInput(50-50)apps/mobile/src/models/admin/user-detail.model.ts (1)
handleResetPassword(184-189)apps/mobile/src/components/ui/activity-indicator.tsx (1)
ActivityIndicator(12-12)apps/frontend/src/app/(public)/auth/sign-in.tsx (2)
SignIn(21-180)ctx(41-52)
apps/mobile/src/app/(public)/(protected)/_layout.tsx (1)
apps/frontend/src/app/(public)/auth/sign-in.tsx (1)
SignIn(21-180)
apps/api/src/lib/email/config.ts (2)
apps/api/src/lib/email/types.ts (1)
EmailConfig(27-49)apps/api/src/env.ts (1)
env(70-70)
apps/mobile/src/app/(public)/auth/forgot-password.tsx (6)
apps/mobile/src/components/screen.tsx (1)
Screen(14-42)apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)apps/mobile/src/components/ui/input.tsx (1)
Input(25-25)apps/mobile/src/models/admin/user-detail.model.ts (1)
handleResetPassword(184-189)apps/mobile/src/components/ui/activity-indicator.tsx (1)
ActivityIndicator(12-12)
apps/mobile/src/components/auth/sign-up-success-card.tsx (1)
apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)
apps/mobile/src/components/ui/text.tsx (1)
apps/mobile/src/lib/utils.ts (1)
cn(4-6)
🪛 dotenv-linter (4.0.0)
apps/api/.env.example
[warning] 7-7: [UnorderedKey] The FACEBOOK_CLIENT_ID key should go before the GOOGLE_CLIENT_ID key
(UnorderedKey)
[warning] 8-8: [UnorderedKey] The FACEBOOK_CLIENT_SECRET key should go before the GOOGLE_CLIENT_ID key
(UnorderedKey)
[warning] 9-9: [UnorderedKey] The GITHUB_CLIENT_ID key should go before the GOOGLE_CLIENT_ID key
(UnorderedKey)
[warning] 10-10: [UnorderedKey] The GITHUB_CLIENT_SECRET key should go before the GOOGLE_CLIENT_ID key
(UnorderedKey)
[warning] 11-11: [UnorderedKey] The APPLE_CLIENT_ID key should go before the BETTER_AUTH_SECRET key
(UnorderedKey)
[warning] 12-12: [UnorderedKey] The APPLE_CLIENT_SECRET key should go before the BETTER_AUTH_SECRET key
(UnorderedKey)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Sourcery review
🔇 Additional comments (33)
apps/mobile/components.json (2)
14-17: I'll verify the path alias consistency concerns across the mobile app codebase. Let me start by examining the configuration files and checking if the referenced directories exist.
<function_calls>
#!/bin/bashCheck components.json and tsconfig.json configuration for apps/mobile
echo "=== Checking components.json in apps/mobile ==="
if [ -f "apps/mobile/components.json" ]; then
cat -n "apps/mobile/components.json" | head -30
else
echo "components.json not found"
fiecho ""
echo "=== Checking tsconfig.json in apps/mobile ==="
if [ -f "apps/mobile/tsconfig.json" ]; then
cat -n "apps/mobile/tsconfig.json"
else
echo "tsconfig.json not found in apps/mobile"
fiecho ""
echo "=== Checking root tsconfig.json ==="
if [ -f "tsconfig.json" ]; then
cat -n "tsconfig.json" | head -50
else
echo "tsconfig.json not found in root"
fi
</function_calls><function_calls>
#!/bin/bashCheck if the aliased directories exist in apps/mobile
echo "=== Checking referenced alias directories ==="
Define directories to check
dirs=(
"apps/mobile/lib/utils"
"apps/mobile/components/ui"
"apps/mobile/lib"
"apps/mobile/hooks"
)for dir in "${dirs[@]}"; do
if [ -d "$dir" ]; then
echo "✓ Directory exists: $dir"
# List contents if directory exists
echo " Contents:"
ls -la "$dir" | head -10
else
echo "✗ Directory NOT found: $dir"
fi
done
</function_calls><function_calls>
#!/bin/bashSearch for import patterns in apps/mobile to check what import style is actually used
echo "=== Searching for import patterns in apps/mobile ==="
echo ""
echo "Searching for @/ style imports..."
rg -n "from ['"]@/" apps/mobile --type=ts --type=tsx -C 2 | head -50echo ""
echo "Searching for/ style imports..."/" apps/mobile --type=ts --type=tsx -C 2 | head -50
rg -n "from ['"]echo ""
echo "Searching for relative imports../"
rg -n "from ['"]../" apps/mobile --type=ts --type=tsx -C 2 | head -30
</function_calls>
2-11: The Tailwind and styling files are correctly configured and already exist.The configuration references to
tailwind.config.jsandglobal.cssuse relative paths that correctly point toapps/mobile/tailwind.config.jsandapps/mobile/global.css, which are both present in the codebase. This is the standard monorepo structure where each app maintains its own configuration files at the app root. No additional action is needed.Likely an incorrect or invalid review comment.
apps/mobile/src/app/(public)/(protected)/_layout.tsx (1)
14-14: Redirect to social login landing page is correctly configured.The "/auth" route exists and is properly structured as a landing page (
apps/mobile/src/app/(public)/auth/index.tsx) that presents multiple social login options (Google, Facebook, GitHub, Apple, LinkedIn). The redirect change from "/auth/sign-in" to "/auth" correctly routes unauthenticated users to this landing page, aligning with the PR's social login feature..vscode/settings.json (1)
6-6: Default formatter switch to Biome is consistent with tooling updatesSetting the global
editor.defaultFormattertobiomejs.biomealigns with the updated Biome tooling and the language-specific overrides below. This should help keep formatting consistent across JS/TS/JSON files as long as the Biome extension is installed in VS Code.You may want to confirm everyone on the team has
biomejs.biomeenabled in their editor.pnpm-workspace.yaml (1)
9-10: I'll help you verify the workspace-wide Biome and TypeScript version bumps. Let me search for how these tools are referenced across the workspace and check compatibility.
<function_calls>
#!/bin/bashSearch for @biomejs/biome and typescript references across the workspace
echo "=== Searching for @biomejs/biome references ==="
rg -n '"@biomejs/biome"' --type=json --type=yamlecho ""
echo "=== Searching for typescript references ==="
rg -n 'typescript' --type=json --type=yaml | head -50
</function_calls>Now let me check the tsconfig files and CI configuration:
<function_calls>
#!/bin/bashFind and examine tsconfig files
echo "=== Finding tsconfig files ==="
fd -name 'tsconfig*.json' -o -name 'tsconfig*.yaml'echo ""
echo "=== Examining main tsconfig.json ==="
if [ -f tsconfig.json ]; then
cat -n tsconfig.json | head -40
fiecho ""
echo "=== Finding CI configuration files ==="
fd -path '.github/workflows/.yml' -o -path '.github/workflows/.yaml'
</function_calls>Let me also check if there are any package.json files that might override the catalog versions:
<function_calls>
#!/bin/bashLook for packages that might override biome/typescript versions
echo "=== Checking for package.json files with biome/typescript overrides ==="
fd -name 'package.json' | xargs grep -l '@biomejs/biome|typescript' 2>/dev/nullecho ""
echo "=== Examining pnpm-workspace.yaml ==="
cat -n pnpm-workspace.yaml
</function_calls>turbo.json (1)
3-3: Turbo configuration options are supported; verify db:reset script is wired in package.json.The
ui: "tui"option andinteractiveflag are both supported in Turborepo's turbo.json. The pattern you're using—cache: falsewithinteractive: trueon thedevtask, andcache: falsewithpersistent: trueondb:reset—aligns with documented Turbo constraints (interactive tasks requirepersistent: trueand cannot be cached).However, verify that
db:resetis defined as a script in your package.json, since Turbo task definitions must map to actual executable scripts. The repository clone failed, so I cannot confirm this directly. Ifdb:resetisn't found in package.json scripts, Turbo will fail when trying to run that task.package.json (1)
20-20: Based on my verification:The ultracite 6.3.6 version is fully compatible with the biome.jsonc extends configuration.
The web search confirms that ultracite v6.3.6 explicitly supports the preset system with
"ultracite/core"and"ultracite/react"extends. Your biome.jsonc is correctly configured and follows the official ultracite v6 documentation pattern exactly. No compatibility drift or version misalignment detected.biome.jsonc (1)
2-3: Biome 2.3.7 configuration is correct and compatible with ultracite 6.3.6The schema version (2.3.7) matches the installed Biome version, and ultracite 6.3.6 explicitly supports the split presets
["ultracite/core", "ultracite/react"]as the recommended configuration for v6. The extends array syntax is the documented approach for v6 and poses no resolution issues.apps/mobile/src/components/ui/icon.tsx (2)
1-11: LGTM!The Icon implementation is clean and follows coding guidelines: uses type imports, path aliases, proper destructuring, and avoids React hooks.
43-43: Verify the default icon size.The default size of 14 is smaller than typical icon sizes (16, 20, 24). Please confirm this is intentional and aligns with your design system.
apps/mobile/src/components/ui/button.tsx (2)
6-54: LGTM!The platform-aware variant system is well-implemented, using
Platform.selectappropriately for web-only hover/focus states and maintaining clean separation of concerns.
56-89: LGTM!Text variant system correctly complements button variants with appropriate platform-specific styling.
apps/mobile/src/components/ui/text.tsx (3)
7-43: LGTM!The text variant system provides a comprehensive typography scale with appropriate platform-specific enhancements for web.
49-63: LGTM!Accessibility mappings correctly provide semantic roles and ARIA attributes for heading hierarchy and special text types.
67-87: Verify role/aria-level behavior with asChild.When
asChild={true}, theroleandaria-levelprops are passed to the child component viaSlot.Text. Ensure that these accessibility attributes are correctly handled by all potential child components, as non-text children may not support these props.Consider conditionally applying these attributes only when
asChild={false}:role={asChild ? undefined : (variant ? ROLE[variant] : undefined)} aria-level={asChild ? undefined : (variant ? ARIA_LEVEL[variant] : undefined)}apps/mobile/src/containers/auth/sign-up.container.tsx (1)
35-35: LGTM!Adding padding improves spacing and aligns with the new Screen-based layout approach used throughout the PR.
apps/api/src/index.ts (1)
1-1: LGTM!The environment loader import at the top ensures environment variables are validated before any other initialization occurs, which is the correct pattern for startup configuration.
apps/mobile/src/app/(public)/auth/sign-up.tsx (1)
1-10: LGTM!Imports are well-organized and follow the project's path alias conventions.
apps/mobile/src/app/(public)/auth/_layout.tsx (1)
1-23: LGTM!The layout simplification and updated redirect path correctly align with the new Screen-based approach and route structure. The explicit screen declarations improve clarity and the removal of the separate social-sign-in screen is consistent with integrating social login into the main auth flow.
apps/api/.env.example (1)
4-14: LGTM!The social login provider credentials are correctly added as placeholders. The environment variables are well-organized and follow the existing pattern.
Note: The static analysis warnings about key ordering are cosmetic. The current grouping by provider (CLIENT_ID followed by CLIENT_SECRET for each provider) is more intuitive than alphabetical ordering.
apps/api/src/env.ts (2)
34-37: LGTM: Clean boolean transform for SMTP_SECURE.The string-to-boolean transform handles environment variable parsing correctly.
62-68: LGTM: Proper validation error handling.The safeParse approach with error logging and process exit ensures the application doesn't start with invalid configuration. Using
z.flattenErrorprovides clear field-level error messages.apps/mobile/src/app/(public)/auth/index.tsx (1)
22-32: LGTM: Clean back navigation pattern.The conditional back button with
router.canGoBack()check follows the established pattern used in other auth screens.apps/mobile/src/app/(public)/auth/reset-password.tsx (1)
115-159: LGTM: Clean Screen-based refactor.The transition from Card-based to Screen-based layout is well-executed, maintaining all functionality while improving consistency with other auth screens.
apps/api/src/lib/email/config.ts (1)
7-33: LGTM: Clean refactor to centralized env module.The migration from
process.envto the typedenvobject improves type safety and centralizes environment validation. The nullish coalescing defaults forsmtpPort(587) andsmtpSecure(false) are sensible fallbacks.apps/mobile/src/components/auth/sign-up-form.tsx (1)
70-137: LGTM: Consistent Card-to-View refactor.The sign-up form successfully transitions to the Screen-based layout pattern used across all auth screens. All functionality is preserved, including password strength calculation and validation.
apps/mobile/src/app/(public)/auth/sign-in.tsx (1)
91-173: LGTM: Successful Screen-based refactor.The transition from Card-based to Screen-based layout is clean and maintains all authentication functionality, including email verification prompts and resend capability. The use of
asChildwith Link (lines 123, 165) follows React Native best practices.apps/mobile/src/app/(public)/auth/forgot-password.tsx (1)
64-116: LGTM: Clean Screen-based refactor.The forgot password screen successfully adopts the Screen-based layout pattern, maintaining all functionality while ensuring visual consistency with other auth screens.
apps/api/src/lib/auth.ts (2)
32-38: I'll verify the Google OAuth configuration concern by examining the Better Auth setup, checking the version in use, and researching the redirect URI handling behavior.
<function_calls>
#!/bin/bashFind package.json files and check for better-auth dependency
find . -name "package.json" -type f | head -5 | while read f; do
if grep -q "better-auth" "$f"; then
echo "=== Found in: $f ==="
cat "$f" | grep -A 2 -B 2 "better-auth"
fi
done
</function_calls><function_calls>
Better Auth redirect URI auto-generated or explicit configuration required OAuth
</function_calls>I need to gather information about the Better Auth configuration. Let me search the codebase for the context and also check the project dependencies.
<function_calls>
#!/bin/bashFind and read the auth.ts file to understand full context
find . -path "*/apps/api/src/lib/auth.ts" -type f
</function_calls>
11-11: Based on my analysis of the codebase, I can now provide the verification results:Auth routes are configured to expect
/api/authprefix, and uncommenting the basePath is necessary.The routing setup shows:
- Elysia app created with
prefix: "/api"(line 19, apps/api/src/index.ts)- Better Auth handler mounted directly without sub-path specification (line 57:
.mount(auth.handler))- When
basePath: "/auth"is commented out, Better Auth uses its default basePath of"/", resulting in auth routes at/api/*- Mobile client hardcodes
baseURL: "${env.EXPO_PUBLIC_API_URL}/api/auth"(apps/mobile/src/lib/auth-client.ts:22)- OpenAPI plugin explicitly defaults to
prefix = "/api/auth"(apps/api/src/lib/open-api.ts:8)- Google OAuth redirect URI expects
/api/auth/callback/google(apps/api/src/lib/auth.ts:37)This creates a routing mismatch: without the basePath, auth endpoints will be at
/api/*instead of/api/auth/*, breaking all mobile authentication calls.
Verify that
basePath: "/auth"is uncommented in the Better Auth configuration.The commented
basePath: "/auth"on line 11 must be active to ensure auth routes are accessible at/api/auth/*where the mobile client expects them.apps/mobile/src/components/screen.tsx (3)
25-25: Verify if a Legend State observable alternative exists for color scheme.The coding guidelines state: "Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)". The
useColorSchemehook is not a Better Auth hook. Please confirm whether a Legend State observable should be used instead for managing color scheme state.As per coding guidelines.
36-36: Verify that style override behavior is intentional.The style array places
{ flex: 1 }first, then spreadsKeyboardAvoidingViewProps?.style. This allows consumers to override theflexproperty, which could break the component's layout if unintended. Confirm whether this flexibility is desired or ifflex: 1should be enforced.If
flex: 1must always be applied, consider:- style={[{ flex: 1 }, KeyboardAvoidingViewProps?.style]} + style={[KeyboardAvoidingViewProps?.style, { flex: 1 }]}
1-42: Verify component location aligns with project structure.The retrieved learnings indicate: "Only truly reusable UI components belong in src/components/ui with proper TypeScript interfaces". This
Screencomponent appears to be a reusable UI primitive used across multiple screens. Should it be located inapps/mobile/src/components/ui/screen.tsxinstead?Based on learnings.
| ...(env.NODE_ENV === "development" ? [ | ||
| "exp://*/*", // Trust all Expo development URLs | ||
| "exp://10.0.0.*:*/*", // Trust 10.0.0.x IP range | ||
| "exp://192.168.*.*:*/*", // Trust 192.168.x.x IP range | ||
| "exp://172.*.*.*:*/*", // Trust 172.x.x.x IP range | ||
| "exp://localhost:*/*" // Trust localhost | ||
| ] : []) |
There was a problem hiding this comment.
Overly permissive development trusted origins.
The development-mode trusted origins (lines 21-27) are too broad and create security risks:
exp://*/*trusts all Expo development URLs without restrictionexp://172.*.*.*:*/*includes non-private IP ranges (172.16-31 are private, but 172.0-15 and 172.32-255 are public)- Wildcard patterns bypass origin validation entirely
Restrict to private IP ranges only:
// Development mode - Expo's exp:// scheme with local IP ranges
...(env.NODE_ENV === "development" ? [
- "exp://*/*", // Trust all Expo development URLs
- "exp://10.0.0.*:*/*", // Trust 10.0.0.x IP range
- "exp://192.168.*.*:*/*", // Trust 192.168.x.x IP range
- "exp://172.*.*.*:*/*", // Trust 172.x.x.x IP range
+ "exp://10.*.*.*:*/*", // Private: 10.0.0.0/8
+ "exp://192.168.*.*:*/*", // Private: 192.168.0.0/16
+ "exp://172.16.*.*:*/*", // Private: 172.16.0.0/12 (start)
+ "exp://172.17.*.*:*/*",
+ "exp://172.18.*.*:*/*",
+ "exp://172.19.*.*:*/*",
+ "exp://172.20.*.*:*/*",
+ "exp://172.21.*.*:*/*",
+ "exp://172.22.*.*:*/*",
+ "exp://172.23.*.*:*/*",
+ "exp://172.24.*.*:*/*",
+ "exp://172.25.*.*:*/*",
+ "exp://172.26.*.*:*/*",
+ "exp://172.27.*.*:*/*",
+ "exp://172.28.*.*:*/*",
+ "exp://172.29.*.*:*/*",
+ "exp://172.30.*.*:*/*",
+ "exp://172.31.*.*:*/*", // Private: 172.16.0.0/12 (end)
"exp://localhost:*/*" // Trust localhost
] : [])Alternatively, if you need the broader pattern, add a comment explaining the security trade-off and ensure this is never used in production.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/api/src/lib/auth.ts around lines 21 to 27, the development trusted
origins are overly permissive (exp://*/*, broad 172.* range and other
wildcards); replace the global wildcard and the broad 172.* pattern with
explicit private-range entries only (e.g. exp://10.*/*, exp://10.*.*:*/* or
equivalent for 10.0.0.*, exp://192.168.*.*:*/*, and the private
172.16.0.0–172.31.255.255 range narrowed to explicit patterns such as
exp://172.16.*.*:*/* through exp://172.31.*.*:*/*), remove exp://*/*, and drop
any other wildcard catch-alls; if you intentionally need broader patterns, add a
clear comment warning about the security trade-off and ensure the block is gated
to development-only (never enabled in production).
| <FontAwesome name="google" size={20} color="black" /> | ||
| <Text>Continue with Google</Text> | ||
| </Button> | ||
| <Button | ||
| variant="outline" | ||
| onPress={() => handleSocialLogin("facebook")} | ||
| className="flex-row items-center gap-2" | ||
| > | ||
| <FontAwesome name="facebook" size={20} color="black" /> | ||
| <Text>Continue with Facebook</Text> | ||
| </Button> | ||
| <Button | ||
| variant="outline" | ||
| onPress={() => handleSocialLogin("github")} | ||
| className="flex-row items-center gap-2" | ||
| > | ||
| <FontAwesome name="github" size={20} color="black" /> | ||
| <Text>Continue with Github</Text> | ||
| </Button> | ||
| <Button | ||
| variant="outline" | ||
| onPress={() => handleSocialLogin("apple")} | ||
| className="flex-row items-center gap-2" | ||
| > | ||
| <FontAwesome name="apple" size={20} color="black" /> | ||
| <Text>Continue with Apple</Text> | ||
| </Button> | ||
| <Button | ||
| variant="outline" | ||
| onPress={() => handleSocialLogin("linkedin")} | ||
| className="flex-row items-center gap-2" | ||
| > | ||
| <FontAwesome name="linkedin" size={20} color="black" /> | ||
| <Text>Continue with Linkedin</Text> | ||
| </Button> |
There was a problem hiding this comment.
Hardcoded icon colors break dark mode.
All FontAwesome icons use color="black" (lines 46, 54, 62, 70, 78), which will be invisible or have poor contrast in dark mode. The text color adapts via Tailwind classes, but icons remain black.
Use the theme-aware text-foreground color or extract the current color from the theme:
-<FontAwesome name="google" size={20} color="black" />
+<FontAwesome name="google" size={20} className="text-foreground" />Note: If FontAwesome doesn't support className, you may need to use useColorScheme() to conditionally set the color:
import { useColorScheme } from "~/lib/useColorScheme";
const { isDarkColorScheme } = useColorScheme();
const iconColor = isDarkColorScheme ? "white" : "black";
// Then use:
<FontAwesome name="google" size={20} color={iconColor} />🤖 Prompt for AI Agents
In apps/mobile/src/app/(public)/auth/index.tsx around lines 46 to 80 the
FontAwesome icons are hardcoded with color="black", which breaks dark mode;
update the component to use a theme-aware color instead — either apply the
shared text color (e.g., Tailwind's text-foreground) if the icon supports
className, or import and use useColorScheme to derive a boolean
isDarkColorScheme and set iconColor = isDarkColorScheme ? "white" : "black" (or
pull the appropriate foreground colors from your theme), then replace the
hardcoded "black" values with the theme-derived iconColor so icons match
light/dark modes.
| <Screen> | ||
| <View className="flex-row"> | ||
| {router.canGoBack() && ( | ||
| <Button | ||
| variant="ghost" | ||
| className="absolute top-0 left-0 z-10" | ||
| onPress={() => router.back()} | ||
| > | ||
| <ChevronLeft size={24} className="text-foreground" /> | ||
| </Button> | ||
| )} | ||
| </View> | ||
| <SignUpContainer /> | ||
| </Screen> | ||
| ); |
There was a problem hiding this comment.
Use Icon wrapper for className support.
Line 19 applies className directly to ChevronLeft, but Lucide icons don't natively support NativeWind's className. The new Icon component introduced in this PR (apps/mobile/src/components/ui/icon.tsx) provides this functionality via cssInterop.
Apply this diff to use the Icon wrapper:
+import { Icon } from "~/components/ui/icon";
import { useRouter } from "expo-router";
import { ChevronLeft } from "lucide-react-native";
import { View } from "react-native";
import { Screen } from "~/components/screen";
import { Button } from "~/components/ui/button";
import { SignUpContainer } from "~/containers/auth/sign-up.container";
export default function SignUp() {
const router = useRouter();
return (
<Screen>
<View className="flex-row">
{router.canGoBack() && (
<Button
variant="ghost"
className="absolute top-0 left-0 z-10"
onPress={() => router.back()}
>
- <ChevronLeft size={24} className="text-foreground" />
+ <Icon as={ChevronLeft} size={24} className="text-foreground" />
</Button>
)}
</View>
<SignUpContainer />
</Screen>
);
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/mobile/src/app/(public)/auth/sign-up.tsx around lines 11 to 25, the
Lucide ChevronLeft icon is receiving a NativeWind `className` directly; import
the new Icon wrapper from apps/mobile/src/components/ui/icon.tsx and replace the
direct ChevronLeft usage with the Icon wrapper (e.g., use Icon with the
ChevronLeft component passed as the icon prop and move
`className="text-foreground"` onto Icon while preserving the size prop), and
update the imports accordingly so the back button renders with
NativeWind-compatible styling.
…ation flows and add Buoy SDK dependencies.
|
CodeAnt AI is running Incremental review Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
apps/mobile/src/app/(public)/auth/_layout.tsx (1)
5-13: Session gating and redirect logic look solid; consider a non-null loading state.Using
authClient.useSession()to block rendering until auth state is known and redirect authenticated users straight into/(public)/(protected)/home/(tabs)is clean and avoids a flash of unauthenticated UI. For UX, you might later swap thereturn nullwhileisPendingfor a lightweight loading indicator or branded splash, but this is non-blocking.Please confirm that the current
authClient.useSession()API on mobile indeed exposes{ isPending, data }with the same semantics you rely on here, given any Better Auth version changes.apps/mobile/src/components/ui/password.tsx (1)
30-30: Simplify className template string.The fallback
|| ""is unnecessary sinceundefinedin a template string coerces to an empty string.Apply this diff:
- className={`pr-10 ${className || ""}`} + className={`pr-10 ${className ?? ""}`}Or even simpler:
- className={`pr-10 ${className || ""}`} + className={["pr-10", className].filter(Boolean).join(" ")}apps/mobile/src/components/screen.tsx (1)
14-24: Consider extracting the props type for reusability.The inline type definition works but extracting it would improve type reusability and documentation.
Apply this diff to extract the type:
+type ScreenProps = { + children: React.ReactNode; + className?: string; + SystemBarsProps?: SystemBarsProps; + KeyboardAvoidingViewProps?: KeyboardAvoidingViewProps; +}; + -export const Screen = ({ - children, - className, - SystemBarsProps: systemBarsProps, - KeyboardAvoidingViewProps: keyboardAvoidingViewProps, -}: { - children: React.ReactNode; - className?: string; - SystemBarsProps?: SystemBarsProps; - KeyboardAvoidingViewProps?: KeyboardAvoidingViewProps; -}) => { +export const Screen = ({ + children, + className, + SystemBarsProps: systemBarsProps, + KeyboardAvoidingViewProps: keyboardAvoidingViewProps, +}: ScreenProps) => {apps/mobile/src/app/_layout.tsx (1)
77-79: Prefer arrow function for consistency.The coding guidelines recommend using arrow functions over function declarations.
Apply this diff:
-function noop() { - // do nothing -} +const noop = () => { + // do nothing +};apps/mobile/src/components/dev-tools/tools.tsx (1)
2-2: Consider using styled UI components for consistency.The coding guidelines recommend importing UI components via path aliases (e.g.,
@/src/components/ui/). The custom Button and Text components from~/components/ui/provide consistent styling and better integration with the app's design system.Apply this diff to use the styled components:
-import { Button, Text, View } from "react-native"; +import { View } from "react-native"; +import { Button } from "~/components/ui/button"; +import { Text } from "~/components/ui/text";Then update the Button usage on Line 15:
- <Button onPress={onClose} title="Close" /> + <Button onPress={onClose}> + <Text>Close</Text> + </Button>As per coding guidelines, Import UI components via path aliases.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (16)
apps/mobile/package.json(2 hunks)apps/mobile/src/app/(public)/auth/_layout.tsx(1 hunks)apps/mobile/src/app/(public)/auth/forgot-password.tsx(2 hunks)apps/mobile/src/app/(public)/auth/index.tsx(1 hunks)apps/mobile/src/app/(public)/auth/reset-password.tsx(3 hunks)apps/mobile/src/app/(public)/auth/sign-in.tsx(2 hunks)apps/mobile/src/app/(public)/auth/sign-up.tsx(1 hunks)apps/mobile/src/app/_layout.tsx(1 hunks)apps/mobile/src/components/ThemeToggle.tsx(1 hunks)apps/mobile/src/components/auth/sign-up-form.tsx(1 hunks)apps/mobile/src/components/dev-tools/tools.tsx(1 hunks)apps/mobile/src/components/header.tsx(1 hunks)apps/mobile/src/components/screen.tsx(1 hunks)apps/mobile/src/components/ui/password.tsx(1 hunks)apps/mobile/src/containers/auth/sign-up.container.tsx(1 hunks)apps/mobile/src/containers/core/HeaderUser.tsx(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/mobile/src/components/ThemeToggle.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/mobile/src/app/(public)/auth/sign-up.tsx
- apps/mobile/src/containers/core/HeaderUser.tsx
- apps/mobile/src/app/(public)/auth/index.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use object destructuring for method parameters (wrap multiple parameters in an object; define shapes with TypeScript interfaces)
Use authClient.useSession() for session state
Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)
Import UI components via path aliases (e.g., @/src/components/ui/)
Prefer union string/number literals over TypeScript enums
Use export type and import type for types
Don't use non-null assertions (!) or implicit any
Avoid TypeScript namespaces; prefer ESM modules
Files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/_layout.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/components/dev-tools/tools.tsxapps/mobile/src/components/header.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/components/ui/password.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Platform.OS and process.env.EXPO_OS for conditional platform logic
Files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/_layout.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/components/dev-tools/tools.tsxapps/mobile/src/components/header.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/components/ui/password.tsx
**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.tsx: Use React Native primitives (View, Text, etc.) instead of HTML elements
Use Tailwind responsive prefixes (sm:, md:, lg:) and NativeWind responsive utilities
Use web: prefix for web-only styles; use conditional rendering for native-only components
Use IconSymbol to map SF Symbols on iOS to Material Icons on other platforms
Web a11y: ensure buttons have type, anchors are valid, SVGs/iframes have title, html has lang, inputs have valid autocomplete, ARIA roles/props/values are valid
Files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/_layout.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/components/dev-tools/tools.tsxapps/mobile/src/components/header.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/components/ui/password.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx,js,jsx}: Don't use the arguments object
Use for...of instead of Array.forEach
Use arrow functions instead of function expressions
Use Date.now() instead of new Date().getTime()
Use .flatMap() instead of map().flat() when possible
Prefer regex literals over RegExp constructor when possible
Use concise optional chaining instead of chained logical expressions
Always provide radix to parseInt()
Don't use var; use const/let and prefer const when single assignment
Use template literals over string concatenation
Use strict equality (===/!==)
Don't use console or debugger in committed code
Prevent import cycles and avoid namespace imports
Don't hardcode secrets (API keys/tokens) in source
Don't have unused vars, params, imports, labels, or private members
Avoid await inside loops; ensure Promise-like statements are handled
Disallow bitwise operators and comma operator
Ensure switch statements are exhaustive; default clause comes last; no fallthrough or duplicate cases
Use object spread over Object.assign when creating new objects
Prefer Array.isArray over instanceof Array; use at() instead of integer index access where appropriate
No unreachable code, duplicate conditions, or assignments in conditionals
Always use radix with parseInt; prefer Number.isNaN/Number.isFinite over globals
Disallow using global eval, with, var, and unsafe negation
Ensure typeof comparisons use valid strings; getters return values; constructors don’t return values
Files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/_layout.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/components/dev-tools/tools.tsxapps/mobile/src/components/header.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/components/ui/password.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{tsx,jsx}: Provide key props in lists; avoid array index as key
Don't define React components inside other components
Don't use event handlers on non-interactive elements; make interactive roles focusable
Don't use both children and dangerouslySetInnerHTML; avoid dangerous JSX props
Use <>...</> instead of ...
Files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/containers/auth/sign-up.container.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/_layout.tsxapps/mobile/src/app/(public)/auth/reset-password.tsxapps/mobile/src/components/dev-tools/tools.tsxapps/mobile/src/components/header.tsxapps/mobile/src/components/auth/sign-up-form.tsxapps/mobile/src/components/ui/password.tsx
🧠 Learnings (11)
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Use React Native primitives (View, Text, etc.) instead of HTML elements
Applied to files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/components/screen.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/_layout.tsxapps/mobile/src/components/ui/password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/containers/**/*.container.tsx : Create containers in src/containers/ mirroring Expo Router paths (e.g., admin/add-user.container.tsx)
Applied to files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/(public)/auth/reset-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Use authClient.useSession() for session state
Applied to files:
apps/mobile/src/app/(public)/auth/sign-in.tsxapps/mobile/src/app/(public)/auth/reset-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/app/**/_layout.{ts,tsx} : Ensure global.css is imported in the app entry layout for NativeWind setup
Applied to files:
apps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsxapps/mobile/src/app/_layout.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/app/** : Expo Router: keep all routes under src/app with route groups (e.g., (auth), (tabs))
Applied to files:
apps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/reset-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Follow Expo Router file-based routing conventions for navigation structure
Applied to files:
apps/mobile/src/app/(public)/auth/_layout.tsxapps/mobile/src/app/(public)/auth/forgot-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{tsx,ts} : Use Platform.OS and process.env.EXPO_OS for conditional platform logic
Applied to files:
apps/mobile/src/app/(public)/auth/forgot-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{tsx,jsx} : Don't define React components inside other components
Applied to files:
apps/mobile/src/app/(public)/auth/forgot-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Import UI components via path aliases (e.g., @/src/components/ui/)
Applied to files:
apps/mobile/src/app/(public)/auth/forgot-password.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Use web: prefix for web-only styles; use conditional rendering for native-only components
Applied to files:
apps/mobile/src/app/_layout.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)
Applied to files:
apps/mobile/src/components/ui/password.tsx
🧬 Code graph analysis (7)
apps/mobile/src/app/(public)/auth/_layout.tsx (3)
apps/mobile/src/lib/auth-client.ts (1)
authClient(21-28)apps/frontend/src/app/(public)/(protected)/home/(tabs)/index.tsx (2)
HomeScreen(7-18)router(12-12)apps/frontend/src/app/(public)/auth/sign-in.tsx (1)
SignIn(21-180)
apps/mobile/src/containers/auth/sign-up.container.tsx (2)
apps/mobile/src/components/auth/sign-up-success-card.tsx (1)
SignUpSuccessCard(16-78)apps/mobile/src/models/admin/user-detail.model.ts (1)
handleResendVerification(152-157)
apps/mobile/src/components/screen.tsx (2)
apps/mobile/src/hooks/useColorScheme.ts (1)
useColorScheme(9-64)apps/mobile/src/lib/utils.ts (1)
cn(4-6)
apps/mobile/src/app/(public)/auth/forgot-password.tsx (7)
apps/mobile/src/components/screen.tsx (1)
Screen(14-42)apps/mobile/src/components/header.tsx (1)
Header(7-19)apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)apps/mobile/src/components/ui/input.tsx (1)
Input(25-25)apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)apps/mobile/src/models/admin/user-detail.model.ts (1)
handleResetPassword(184-189)apps/mobile/src/components/ui/activity-indicator.tsx (1)
ActivityIndicator(12-12)
apps/mobile/src/components/dev-tools/tools.tsx (4)
apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)apps/mobile/src/components/ThemeToggle.tsx (1)
ThemeToggle(7-31)apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)apps/mobile/src/lib/icons/MoonStar.tsx (1)
MoonStar(5-5)
apps/mobile/src/components/header.tsx (2)
apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)apps/mobile/src/components/ui/icon.tsx (1)
Icon(54-54)
apps/mobile/src/components/auth/sign-up-form.tsx (6)
apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)apps/mobile/src/components/ui/input.tsx (1)
Input(25-25)apps/mobile/src/components/ui/password.tsx (1)
PasswordInput(51-51)apps/mobile/src/components/ui/progress.tsx (1)
Progress(32-32)apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)apps/mobile/src/components/ui/activity-indicator.tsx (1)
ActivityIndicator(12-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Sourcery review
🔇 Additional comments (21)
apps/mobile/src/app/(public)/auth/_layout.tsx (1)
15-23: Auth stack now correctly registers all relevant routes, including reset-password.Registering
index,sign-in,sign-up,forgot-password, andreset-passwordensures each auth screen has a defined route and fixes the earlier reset-password navigation gap;headerShown: falsealso matches a pattern where screens own their headers.Please double-check that each screen file under this layout (
index.tsx,sign-in.tsx,sign-up.tsx,forgot-password.tsx,reset-password.tsx) matches these route names so Expo Router resolves them as expected. Based on learnings, this aligns with the Expo Router file-based routing conventions.apps/mobile/package.json (1)
28-30: All dependencies verified as legitimate with no known security vulnerabilities or React 19 incompatibilities.The npm registry confirms all four packages are legitimate:
@react-buoy/core, @react-buoy/env, @react-buoy/network (all ^1.5.18): Published 7 hours ago by lovesworking; maintained at https://github.com/LovesWorking/react-native-buoy with Proprietary licenses. No known CVEs. These are React Native dev tools with no explicit React 19 peerDependency, but React Native 0.81.5 is compatible with React 19.1.0.
expo-clipboard (~8.0.7): MIT licensed, maintained by Expo team members. Well-established project (142 versions). React Native 0.81.5 is compatible (Expo SDK 54 targets RN 0.81). No known CVEs.
Version constraints (^ for @react-buoy, ~ for expo-clipboard) reflect standard npm practices—both are reasonable choices.
The PR's "Possible security concern" label does not appear substantiated by package analysis.
apps/mobile/src/components/header.tsx (1)
7-19: LGTM! Clean and focused header component.The Header component is well-structured with appropriate conditional rendering based on navigation history. The use of
router.canGoBack()ensures the back button only appears when navigation history exists.apps/mobile/src/containers/auth/sign-up.container.tsx (2)
35-35: LGTM! Layout adjustment adds consistent padding.The addition of
p-6padding and class reordering improves visual consistency with other auth screens.
42-43: LGTM! Prop reordering is cosmetic.Reordering props doesn't affect functionality since JavaScript object properties are unordered. The component interface remains unchanged.
apps/mobile/src/components/screen.tsx (1)
32-37: Verify intentional flex override behavior.The style array
[{ flex: 1 }, keyboardAvoidingViewProps?.style]allows consumers to overrideflex: 1by passing style props. This could break the Screen's layout contract if consumers accidentally override the flex behavior.If this is intentional (to allow full style control), consider documenting this behavior. Otherwise, apply this diff to prevent flex override:
<KeyboardAvoidingView behavior={isIos ? "padding" : "height"} keyboardVerticalOffset={keyboardOffset} {...keyboardAvoidingViewProps} - style={[{ flex: 1 }, keyboardAvoidingViewProps?.style]} + style={{ flex: 1, ...keyboardAvoidingViewProps?.style }} >Note: Using object spread
{ flex: 1, ...style }still allows override but makes the precedence more explicit. To prevent override entirely, you'd need to reverse the order or use StyleSheet.flatten.apps/mobile/src/components/auth/sign-up-form.tsx (2)
53-68: LGTM! Type alias follows coding guidelines.Converting from
interfacetotypealigns with the coding guideline to useexport typefor type definitions.
78-145: LGTM! Clean refactor from Card to View-based layout.The migration from Card components to View/Text primitives maintains all functionality while following React Native best practices. The form fields, password strength indicator, and navigation links are properly preserved.
apps/mobile/src/app/(public)/auth/forgot-password.tsx (2)
64-107: LGTM! Screen and Header integration is clean.The refactor from Card-based UI to Screen/Header layout is well-executed. The form maintains all functionality (email input, loading states, navigation) while gaining consistent safe area handling and keyboard avoidance.
4-4: Inconsistent path alias for authClient import.Line 4 uses
@/src/lib/auth-clientwhile other imports (lines 6-7, 13) use the~/alias pattern (~/components/,~/lib/). Mixing path aliases reduces consistency and can confuse developers about the canonical import style.Apply this diff to use consistent path aliasing:
-import { authClient } from "@/src/lib/auth-client"; +import { authClient } from "~/lib/auth-client";Verify this path resolves correctly, as other files in the PR use the same pattern.
⛔ Skipped due to learnings
Learnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to **/*.{ts,tsx} : Import UI components via path aliases (e.g., @/src/components/ui/)Learnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to **/*.{ts,tsx} : Use authClient.useSession() for session stateLearnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to src/lib/auth-client.ts : Initialize Better Auth client in src/lib/auth-client.ts with platform-specific pluginsLearnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to tsconfig.json : Configure TypeScript path aliases for @/* from project rootLearnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to **/*.{ts,tsx} : Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)apps/mobile/src/app/(public)/auth/sign-in.tsx (1)
91-161: LGTM! Screen integration and verification flow are well-implemented.The Screen/Header refactor maintains all sign-in functionality while adding consistent layout and safe area handling. The conditional verification prompt (lines 126-145) provides good UX for unverified users.
apps/mobile/src/app/(public)/auth/reset-password.tsx (4)
28-29: LGTM! Optional chaining prevents native runtime crash.The use of
window.location?.searchwith optional chaining correctly handles React Native environments wherewindow.locationis undefined, preventing the runtime crash mentioned in past review comments.
98-103: LGTM! Loading state uses Screen wrapper.The loading state is now wrapped in Screen with proper layout, addressing the past review comment about consistent Screen usage across auth flows.
107-154: LGTM! Screen/Header integration and password reset flow are solid.The refactor to Screen/Header layout maintains all password reset functionality (token validation, password matching, length validation) while providing consistent safe area handling and navigation.
4-4: Inconsistent path alias for authClient import.Line 4 uses
@/src/lib/auth-clientwhile other imports (lines 5-6, 11) use the~/alias pattern. This is the same inconsistency seen in sign-in.tsx and forgot-password.tsx.Apply this diff to use consistent path aliasing:
-import { authClient } from "@/src/lib/auth-client"; +import { authClient } from "~/lib/auth-client";⛔ Skipped due to learnings
Learnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to **/*.{ts,tsx} : Import UI components via path aliases (e.g., @/src/components/ui/)Learnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to **/*.{ts,tsx} : Use authClient.useSession() for session stateLearnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to src/lib/auth-client.ts : Initialize Better Auth client in src/lib/auth-client.ts with platform-specific pluginsLearnt from: CR Repo: fyndx/universal-starter PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-09-03T13:07:10.649Z Learning: Applies to tsconfig.json : Configure TypeScript path aliases for @/* from project rootapps/mobile/src/app/_layout.tsx (4)
4-4: LGTM!The import additions and path updates are appropriate for the new dev tools functionality.
Also applies to: 12-14
19-23: LGTM!The biome-ignore is appropriately justified for the required Expo Router ErrorBoundary re-export pattern.
25-29: LGTM!The Platform.select pattern for platform-specific setup is clean and follows the coding guidelines for conditional platform logic.
64-69: LGTM!The web-specific background class setup is correctly implemented using isomorphic layout effect.
apps/mobile/src/components/dev-tools/tools.tsx (2)
7-18: LGTM!The ThemeToggleTool component is well-structured with proper object destructuring, safe area handling, and NativeWind styling.
20-30: LGTM!The customTools export is correctly typed and structured for the @react-buoy/core dev tools API.
| import { Link, useRouter } from "expo-router"; | ||
| import { useState } from "react"; | ||
| import { View } from "react-native"; | ||
| import { authClient } from "@/src/lib/auth-client"; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Inconsistent path alias for authClient import.
Line 4 uses @/src/lib/auth-client while other imports (lines 5-6, 12) use the ~/ alias pattern. This inconsistency matches the same issue in forgot-password.tsx.
Apply this diff to use consistent path aliasing:
-import { authClient } from "@/src/lib/auth-client";
+import { authClient } from "~/lib/auth-client";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { authClient } from "@/src/lib/auth-client"; | |
| import { authClient } from "~/lib/auth-client"; |
🤖 Prompt for AI Agents
In apps/mobile/src/app/(public)/auth/sign-in.tsx around line 4, the import uses
the inconsistent alias "@/src/lib/auth-client"; change it to use the project's
consistent "~/" alias (e.g. "~/lib/auth-client") to match the other imports in
this file (and align with forgot-password.tsx). Update that single import path
so all imports in the file use the same alias pattern.
| @@ -1,50 +1,51 @@ | |||
| import { Eye, EyeOff } from "lucide-react-native"; | |||
| import * as React from "react"; | |||
| import { type RefObject, useState } from "react"; | |||
There was a problem hiding this comment.
Replace useState with Legend State observable.
The coding guidelines explicitly state to avoid React hooks and use Legend State observables directly (exception: Better Auth hooks). The useState hook on line 21 violates this guideline.
Based on learnings, the codebase standard is to use Legend State for component state management.
Apply this diff to replace useState with Legend State:
-import { type RefObject, useState } from "react";
+import { type RefObject } from "react";
+import { observable } from "@legendapp/state";
+import { Reactive } from "@legendapp/state/react";And update the component:
function PasswordInput({
className,
placeholderClassName,
...props
}: PasswordInputProps) {
- const [showPassword, setShowPassword] = useState(false);
+ const showPassword$ = observable(false);
const togglePasswordVisibility = () => {
- setShowPassword(!showPassword);
+ showPassword$.set(!showPassword$.get());
};
return (
- <View className="relative">
+ <Reactive.View className="relative">
<Input
className={`pr-10 ${className || ""}`}
placeholderClassName={placeholderClassName}
- secureTextEntry={!showPassword}
+ secureTextEntry={() => !showPassword$.get()}
{...props}
/>
<Pressable
- accessibilityLabel={showPassword ? "Hide password" : "Show password"}
+ accessibilityLabel={() => showPassword$.get() ? "Hide password" : "Show password"}
accessibilityRole="button"
className="absolute top-0 right-3 flex h-10 native:h-12 web:cursor-pointer items-center justify-center"
onPress={togglePasswordVisibility}
>
- {showPassword ? (
+ {() => showPassword$.get() ? (
<Icon as={EyeOff} className="h-4 w-4 text-muted-foreground" />
) : (
<Icon as={Eye} className="h-4 w-4 text-muted-foreground" />
- )}
+ )()}
</Pressable>
- </View>
+ </Reactive.View>
);
}Also applies to: 21-21
🤖 Prompt for AI Agents
In apps/mobile/src/components/ui/password.tsx (imports at line 2 and state usage
at line 21), replace the React useState usage with a Legend State observable:
remove useState from the import, add the appropriate Legend State observable
import, replace the useState declaration on line 21 with creation of a Legend
State observable for that piece of state, and update all reads/writes to use the
Legend State observable API (get/set/subscribe or the project-specific
accessors) instead of setState; ensure imports and any cleanup/subscription
follow the project's Legend State patterns.
| interface PasswordInputProps extends Omit<TextInputProps, "secureTextEntry"> { | ||
| ref?: React.RefObject<TextInput>; | ||
| ref?: RefObject<TextInput>; | ||
| } |
There was a problem hiding this comment.
Use forwardRef for proper ref forwarding.
The ref prop is defined as a regular prop in the interface, but React requires refs to be forwarded using React.forwardRef. The current pattern won't allow parent components to properly access the underlying TextInput instance.
Apply this diff to properly implement ref forwarding:
+import { type RefObject, forwardRef } from "react";
interface PasswordInputProps extends Omit<TextInputProps, "secureTextEntry"> {
- ref?: RefObject<TextInput>;
}
-function PasswordInput({
+const PasswordInput = forwardRef<TextInput, PasswordInputProps>(({
className,
placeholderClassName,
...props
-}: PasswordInputProps) {
+}, ref) => {
// ... component body ...
return (
<View className="relative">
<Input
+ ref={ref}
className={`pr-10 ${className || ""}`}
placeholderClassName={placeholderClassName}
secureTextEntry={!showPassword}
{...props}
/>
{/* ... rest of component ... */}
</View>
);
-}
+});
+
+PasswordInput.displayName = "PasswordInput";Also applies to: 16-20
🤖 Prompt for AI Agents
In apps/mobile/src/components/ui/password.tsx around lines 12-14 and 16-20, the
component currently declares a ref prop on the props interface which prevents
proper React ref forwarding; update the component to use React.forwardRef
instead: remove ref from the props interface (use Omit to exclude
"secureTextEntry" only), change the component to a forwardRef functional
component with the ref typed as Ref<TextInput> (or RefObject<TextInput> as
appropriate), accept (props, ref) in the forwardRef callback, pass that ref
through to the underlying TextInput element, and export the forwarded component
so parent components can access the TextInput instance.
| {!(isPending || data) && ( | ||
| <Button | ||
| onPress={() => bottomSheetModalRef.current?.present()} | ||
| variant={"ghost"} | ||
| > | ||
| <Menu className="text-base text-foreground" /> | ||
| </Button> | ||
| )} | ||
| {data && !isPending && ( | ||
| <Pressable onPress={() => bottomSheetModalRef.current?.present()}> | ||
| <Avatar alt={data?.user.name ?? "User"}> | ||
| <AvatarImage source={{ uri: data?.user?.image ?? undefined }} /> | ||
| <AvatarFallback> | ||
| <Text>{data?.user?.name.charAt(0) ?? "U"}</Text> | ||
| </AvatarFallback> | ||
| </Avatar> | ||
| </Pressable> |
There was a problem hiding this comment.
Suggestion: Wrapping the mobile view in a raw <div> crashes React Native because <div> is not a valid native component; the UI will fail to render on devices where the web DOM is unavailable. [possible bug]
Severity Level: Critical 🚨
| {!(isPending || data) && ( | |
| <Button | |
| onPress={() => bottomSheetModalRef.current?.present()} | |
| variant={"ghost"} | |
| > | |
| <Menu className="text-base text-foreground" /> | |
| </Button> | |
| )} | |
| {data && !isPending && ( | |
| <Pressable onPress={() => bottomSheetModalRef.current?.present()}> | |
| <Avatar alt={data?.user.name ?? "User"}> | |
| <AvatarImage source={{ uri: data?.user?.image ?? undefined }} /> | |
| <AvatarFallback> | |
| <Text>{data?.user?.name.charAt(0) ?? "U"}</Text> | |
| </AvatarFallback> | |
| </Avatar> | |
| </Pressable> | |
| <View className="flex md:hidden"> | |
| {!(isPending || data) && ( | |
| <Button | |
| onPress={() => bottomSheetModalRef.current?.present()} | |
| variant={"ghost"} | |
| > | |
| <Menu className="text-base text-foreground" /> | |
| </Button> | |
| )} | |
| {data && !isPending && ( | |
| <Pressable onPress={() => bottomSheetModalRef.current?.present()}> | |
| <Avatar alt={data?.user.name ?? "User"}> | |
| <AvatarImage source={{ uri: data?.user?.image ?? undefined }} /> | |
| <AvatarFallback> | |
| <Text>{data?.user?.name.charAt(0) ?? "U"}</Text> | |
| </AvatarFallback> | |
| </Avatar> | |
| </Pressable> | |
| )} | |
| </View> |
Why it matters? ⭐
The PR is strictly for a React Native screen; <div> is not a supported native component and would crash on device builds. Swapping it for <View> like the rest of the file keeps the layout functional.
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/mobile/src/containers/core/HeaderUser.tsx
**Line:** 144:160
**Comment:**
*Possible Bug: Wrapping the mobile view in a raw `<div>` crashes React Native because `<div>` is not a valid native component; the UI will fail to render on devices where the web DOM is unavailable.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.|
CodeAnt AI Incremental review completed. |
…tagging, and refactor mobile header UI with FontAwesome prop remapping.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
apps/api/src/lib/auth.ts (1)
21-29: Overly permissive development trusted origins remain unaddressed.The wildcard patterns (especially
exp://*/*andexp://172.*.*.*:*/*) are too broad. The172.*pattern includes public IP ranges (172.0-15 and 172.32-255 are not private). This was flagged in previous reviews.Consider restricting to explicit private ranges or verify that Better Auth supports this wildcard syntax as intended.
apps/api/src/env.ts (1)
119-124:z.flattenErroris not a valid Zod API - useparsed.error.flatten()instead.This will throw
TypeError: z.flattenError is not a functionwhen validation fails, preventing the formatted error output and clean exit.Apply this diff:
if (!parsed.success) { logger.error("❌ Invalid environment variables:"); - logger.error( - JSON.stringify(z.flattenError(parsed.error).fieldErrors, null, 2) - ); + logger.error( + JSON.stringify(parsed.error.flatten().fieldErrors, null, 2) + ); process.exit(1); }apps/mobile/src/containers/core/HeaderUser.tsx (1)
142-161: Mobile header UI is completely disabled.The entire mobile view section is commented out, which means mobile users have no visible header controls—no login button, no user avatar, and no way to access the menu that triggers the
BottomSheetModal. This breaks the mobile user experience.If this is work-in-progress code that should not be in this PR, remove it. If the mobile view should be active, uncomment and fix the
<div>element on line 142 to use<View>instead (React Native primitive per coding guidelines).If you intend to enable the mobile view, apply this fix:
- {/* <div className="flex md:hidden"> + <View className="flex md:hidden"> {!(isPending || data) && ( <Button onPress={() => bottomSheetModalRef.current?.present()} variant={"ghost"} > <Menu className="text-base text-foreground" /> </Button> )} {data && !isPending && ( <Pressable onPress={() => bottomSheetModalRef.current?.present()}> <Avatar alt={data?.user.name ?? "User"}> <AvatarImage source={{ uri: data?.user?.image ?? undefined }} /> <AvatarFallback> <Text>{data?.user?.name.charAt(0) ?? "U"}</Text> </AvatarFallback> </Avatar> </Pressable> )} - </div> */} + </View>
🧹 Nitpick comments (1)
apps/api/src/env.ts (1)
35-38:SMTP_SECUREtransform returnsundefinedfor non-"true" values when the field is present.The transform
(s) => s === "true"returnsfalsefor any non-"true" string, but when.optional()is chained after.transform(), an empty string or other falsy value still gets transformed rather than treated as absent. This is likely fine for boolean semantics, but consider using.default(false)if you want explicitfalsewhen the env var is set but not"true".SMTP_SECURE: z .string() .transform((s) => s === "true") - .optional(), + .default("false") + .transform((s) => s === "true"),Or keep as-is if the current behavior is intentional.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
.github/workflows/docker-build.yml(1 hunks)apps/api/src/env.test.ts(1 hunks)apps/api/src/env.ts(1 hunks)apps/api/src/lib/auth.ts(2 hunks)apps/mobile/src/app/(public)/auth/index.tsx(1 hunks)apps/mobile/src/app/_layout.tsx(1 hunks)apps/mobile/src/containers/core/HeaderUser.tsx(1 hunks)apps/mobile/src/utils/remap-props.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/mobile/src/app/(public)/auth/index.tsx
- apps/mobile/src/app/_layout.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use object destructuring for method parameters (wrap multiple parameters in an object; define shapes with TypeScript interfaces)
Use authClient.useSession() for session state
Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)
Import UI components via path aliases (e.g., @/src/components/ui/)
Prefer union string/number literals over TypeScript enums
Use export type and import type for types
Don't use non-null assertions (!) or implicit any
Avoid TypeScript namespaces; prefer ESM modules
Files:
apps/api/src/lib/auth.tsapps/api/src/env.test.tsapps/mobile/src/containers/core/HeaderUser.tsxapps/api/src/env.tsapps/mobile/src/utils/remap-props.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Platform.OS and process.env.EXPO_OS for conditional platform logic
Files:
apps/api/src/lib/auth.tsapps/api/src/env.test.tsapps/mobile/src/containers/core/HeaderUser.tsxapps/api/src/env.tsapps/mobile/src/utils/remap-props.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx,js,jsx}: Don't use the arguments object
Use for...of instead of Array.forEach
Use arrow functions instead of function expressions
Use Date.now() instead of new Date().getTime()
Use .flatMap() instead of map().flat() when possible
Prefer regex literals over RegExp constructor when possible
Use concise optional chaining instead of chained logical expressions
Always provide radix to parseInt()
Don't use var; use const/let and prefer const when single assignment
Use template literals over string concatenation
Use strict equality (===/!==)
Don't use console or debugger in committed code
Prevent import cycles and avoid namespace imports
Don't hardcode secrets (API keys/tokens) in source
Don't have unused vars, params, imports, labels, or private members
Avoid await inside loops; ensure Promise-like statements are handled
Disallow bitwise operators and comma operator
Ensure switch statements are exhaustive; default clause comes last; no fallthrough or duplicate cases
Use object spread over Object.assign when creating new objects
Prefer Array.isArray over instanceof Array; use at() instead of integer index access where appropriate
No unreachable code, duplicate conditions, or assignments in conditionals
Always use radix with parseInt; prefer Number.isNaN/Number.isFinite over globals
Disallow using global eval, with, var, and unsafe negation
Ensure typeof comparisons use valid strings; getters return values; constructors don’t return values
Files:
apps/api/src/lib/auth.tsapps/api/src/env.test.tsapps/mobile/src/containers/core/HeaderUser.tsxapps/api/src/env.tsapps/mobile/src/utils/remap-props.ts
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Don't nest describe() blocks too deeply; don't use focused/disabled tests; ensure expect is inside it()
Files:
apps/api/src/env.test.ts
**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.tsx: Use React Native primitives (View, Text, etc.) instead of HTML elements
Use Tailwind responsive prefixes (sm:, md:, lg:) and NativeWind responsive utilities
Use web: prefix for web-only styles; use conditional rendering for native-only components
Use IconSymbol to map SF Symbols on iOS to Material Icons on other platforms
Web a11y: ensure buttons have type, anchors are valid, SVGs/iframes have title, html has lang, inputs have valid autocomplete, ARIA roles/props/values are valid
Files:
apps/mobile/src/containers/core/HeaderUser.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{tsx,jsx}: Provide key props in lists; avoid array index as key
Don't define React components inside other components
Don't use event handlers on non-interactive elements; make interactive roles focusable
Don't use both children and dangerouslySetInnerHTML; avoid dangerous JSX props
Use <>...</> instead of ...
Files:
apps/mobile/src/containers/core/HeaderUser.tsx
🧠 Learnings (9)
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/lib/auth-client.ts : Initialize Better Auth client in src/lib/auth-client.ts with platform-specific plugins
Applied to files:
apps/api/src/lib/auth.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Use authClient.useSession() for session state
Applied to files:
apps/api/src/lib/auth.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't hardcode secrets (API keys/tokens) in source
Applied to files:
apps/api/src/lib/auth.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{tsx,ts} : Use Platform.OS and process.env.EXPO_OS for conditional platform logic
Applied to files:
apps/api/src/lib/auth.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Use React Native primitives (View, Text, etc.) instead of HTML elements
Applied to files:
apps/mobile/src/containers/core/HeaderUser.tsxapps/mobile/src/utils/remap-props.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{tsx,jsx} : Use <>...</> instead of <Fragment>...</Fragment>
Applied to files:
apps/mobile/src/containers/core/HeaderUser.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.{ts,tsx} : Avoid React hooks; use Legend State observables directly (exception: Better Auth hooks)
Applied to files:
apps/mobile/src/containers/core/HeaderUser.tsx
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to src/components/**/*.{ts,tsx} : Use NativeWind with className and Tailwind utilities for component styling
Applied to files:
apps/mobile/src/utils/remap-props.ts
📚 Learning: 2025-09-03T13:07:10.649Z
Learnt from: CR
Repo: fyndx/universal-starter PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-03T13:07:10.649Z
Learning: Applies to **/*.tsx : Use IconSymbol to map SF Symbols on iOS to Material Icons on other platforms
Applied to files:
apps/mobile/src/utils/remap-props.ts
🧬 Code graph analysis (5)
apps/api/src/lib/auth.ts (2)
apps/api/src/env.ts (1)
env(127-127)apps/api/src/infra/db.ts (1)
prisma(2-2)
apps/api/src/env.test.ts (1)
apps/api/src/env.ts (1)
envSchema(4-115)
apps/mobile/src/containers/core/HeaderUser.tsx (9)
apps/mobile/src/lib/icons/Shield.tsx (1)
Shield(5-5)apps/mobile/src/lib/auth-client.ts (1)
authClient(21-28)apps/mobile/src/components/ui/bottom-sheet/index.tsx (2)
BottomSheetModal(46-46)BottomSheetView(50-50)apps/mobile/src/models/core/impersonation.model.ts (1)
impersonationModel$(80-80)apps/mobile/src/components/ui/activity-indicator.tsx (1)
ActivityIndicator(12-12)apps/mobile/src/components/ui/dropdown-menu.tsx (6)
DropdownMenu(259-259)DropdownMenuTrigger(273-273)DropdownMenuContent(261-261)DropdownMenuLabel(264-264)DropdownMenuSeparator(268-268)DropdownMenuItem(263-263)apps/mobile/src/components/ui/avatar.tsx (3)
Avatar(47-47)AvatarImage(47-47)AvatarFallback(47-47)apps/mobile/src/components/ui/text.tsx (1)
Text(89-89)apps/mobile/src/components/ui/button.tsx (1)
Button(107-107)
apps/api/src/env.ts (1)
packages/logger/src/index.ts (1)
logger(26-26)
apps/mobile/src/utils/remap-props.ts (1)
apps/mobile/src/components/ui/bottom-sheet/index.tsx (1)
BottomSheetModal(46-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Sourcery review
🔇 Additional comments (9)
apps/api/src/lib/auth.ts (1)
34-76: Good implementation of conditional social provider configuration.The conditional spread pattern correctly omits providers when credentials are missing, preventing Better Auth from registering providers with invalid empty credentials. This addresses the previous review concern and follows best practices.
apps/api/src/env.test.ts (1)
4-86: Comprehensive test coverage for environment schema validation.The tests appropriately cover:
- Base configuration without social providers
- Fully configured single provider
- Incomplete provider configurations (both missing ID and missing Secret)
- Multiple providers with full and partial configurations
The assertions correctly verify both success/failure states and error messages.
.github/workflows/docker-build.yml (2)
76-78: Verify intent:latesttag generation is now disabled.The
type=raw,value=latest,enable={{is_default_branch}}line is commented out, which means pushes tomainwill no longer produce alatesttag. If this is intentional to prevent accidental deployments, consider adding a comment explaining why. Otherwise, this may break deployment workflows that rely on pulling thelatesttag.
116-117: Same concern for Workers image:latesttag disabled.Consistent with the API image changes, but ensure downstream deployments don't depend on the
latesttag for the workers image.apps/api/src/env.ts (1)
64-115: Well-designed cross-field validation for social provider credentials.The
superRefineimplementation correctly enforces that each OAuth provider must have bothCLIENT_IDandCLIENT_SECRETset together, or neither. The error messages are clear and point to the specific missing field. This addresses the previous review concern about partial provider configurations passing validation.apps/mobile/src/utils/remap-props.ts (2)
1-1: LGTM!The FontAwesome import is properly structured and aligns with the PR's goal of adding icon support for social login UI.
5-9: LGTM!The BottomSheetModal remapProps configuration is correct, and the formatting updates improve consistency with the newly added FontAwesome block.
apps/mobile/src/containers/core/HeaderUser.tsx (2)
163-224: Bottom sheet implementation looks correct.The bottom sheet modal for mobile correctly uses React Native primitives and maintains consistent navigation to
/auth(line 217), aligning with the desktop flow (line 132) and the new social login landing page introduced in this PR.
39-43: This review comment is incorrect. The useEffect cannot be replaced with Legend State reactive patterns.The
useEffect(lines 39-43) is necessary and appropriate for syncing external Better Auth session data into the Legend State observable. Legend State in this codebase provides only basicobservable()state containers andobservercomponents—it does not exposecomputed(),watch(), or reactive binding mechanisms.The
useEffectwith[data]dependency is the correct pattern for:
- Reacting to external data changes (Better Auth session updates)
- Syncing that external state into internal Legend State
- Tracking dependency changes over component lifecycle
Removing this effect would break impersonation state synchronization when the session changes. The
useMounthook used elsewhere triggers initial fetches, not external data syncing—these serve different lifecycle purposes.
| remapProps(FontAwesome, { | ||
| className: "style", | ||
| color: "color", | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
Script executed:
#!/bin/bash
# First, let's read the remap-props.ts file to understand context
cat -n apps/mobile/src/utils/remap-props.tsRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
1 import { FontAwesome } from "@expo/vector-icons";
2 import { remapProps } from "nativewind";
3 import { BottomSheetModal } from "~/components/ui/bottom-sheet";
4
5 remapProps(BottomSheetModal, {
6 className: "style",
7 handleClassName: "handleStyle",
8 containerClassName: "containerStyle",
9 });
10
11 remapProps(FontAwesome, {
12 className: "style",
13 color: "color",
14 });
</shell_result>
Script executed:
#!/bin/bash
# Search for remapProps function definition and usage
rg -n "remapProps" -A 3 -B 3 --type ts --type tsxRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 2
stderr:
unrecognized file type: tsx
</shell_result>
Script executed:
#!/bin/bash
# Search for FontAwesome imports and usage patterns
rg -n "FontAwesome" -A 2 -B 2 --type ts --type tsxRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 2
stderr:
unrecognized file type: tsx
</shell_result>
Script executed:
#!/bin/bash
# Search for FontAwesome usage in TypeScript files (without tsx flag issue)
rg -n "FontAwesome" -A 2 -B 2 --type tsRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
apps/mobile/src/utils/remap-props.ts:1:import { FontAwesome } from "@expo/vector-icons";
apps/mobile/src/utils/remap-props.ts-2-import { remapProps } from "nativewind";
apps/mobile/src/utils/remap-props.ts-3-import { BottomSheetModal } from "~/components/ui/bottom-sheet";
--
apps/mobile/src/utils/remap-props.ts-9-});
apps/mobile/src/utils/remap-props.ts-10-
apps/mobile/src/utils/remap-props.ts:11:remapProps(FontAwesome, {
apps/mobile/src/utils/remap-props.ts-12- className: "style",
apps/mobile/src/utils/remap-props.ts-13- color: "color",
--
apps/mobile/src/app/(public)/auth/index.tsx:1:import { FontAwesome } from "@expo/vector-icons";
apps/mobile/src/app/(public)/auth/index.tsx-2-import { useRouter } from "expo-router";
apps/mobile/src/app/(public)/auth/index.tsx-3-import { View } from "react-native";
--
apps/mobile/src/app/(public)/auth/index.tsx-45- >
apps/mobile/src/app/(public)/auth/index.tsx-46- <Text>
apps/mobile/src/app/(public)/auth/index.tsx:47: <FontAwesome name="google" size={20} />
apps/mobile/src/app/(public)/auth/index.tsx-48- </Text>
apps/mobile/src/app/(public)/auth/index.tsx-49- <Text>Continue with Google</Text>
--
apps/mobile/src/app/(public)/auth/index.tsx-55- >
apps/mobile/src/app/(public)/auth/index.tsx-56- <Text>
apps/mobile/src/app/(public)/auth/index.tsx:57: <FontAwesome name="facebook" size={20} />
apps/mobile/src/app/(public)/auth/index.tsx-58- </Text>
apps/mobile/src/app/(public)/auth/index.tsx-59- <Text>Continue with Facebook</Text>
--
apps/mobile/src/app/(public)/auth/index.tsx-65- >
apps/mobile/src/app/(public)/auth/index.tsx-66- <Text>
apps/mobile/src/app/(public)/auth/index.tsx:67: <FontAwesome name="github" size={20} />
apps/mobile/src/app/(public)/auth/index.tsx-68- </Text>
apps/mobile/src/app/(public)/auth/index.tsx-69- <Text>Continue with Github</Text>
--
apps/mobile/src/app/(public)/auth/index.tsx-75- >
apps/mobile/src/app/(public)/auth/index.tsx-76- <Text>
apps/mobile/src/app/(public)/auth/index.tsx:77: <FontAwesome name="apple" size={20} />
apps/mobile/src/app/(public)/auth/index.tsx-78- </Text>
apps/mobile/src/app/(public)/auth/index.tsx-79- <Text>Continue with Apple</Text>
--
apps/mobile/src/app/(public)/auth/index.tsx-85- >
apps/mobile/src/app/(public)/auth/index.tsx-86- <Text>
apps/mobile/src/app/(public)/auth/index.tsx:87: <FontAwesome name="linkedin" size={20} />
apps/mobile/src/app/(public)/auth/index.tsx-88- </Text>
apps/mobile/src/app/(public)/auth/index.tsx-89- <Text>Continue with Linkedin</Text>
</shell_result>
Script executed:
#!/bin/bash
# Search for remapProps patterns
rg -n "remapProps" -A 3 -B 1 --type tsRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
apps/mobile/src/utils/remap-props.ts-1-import { FontAwesome } from "@expo/vector-icons";
apps/mobile/src/utils/remap-props.ts:2:import { remapProps } from "nativewind";
apps/mobile/src/utils/remap-props.ts-3-import { BottomSheetModal } from "~/components/ui/bottom-sheet";
apps/mobile/src/utils/remap-props.ts-4-
apps/mobile/src/utils/remap-props.ts:5:remapProps(BottomSheetModal, {
apps/mobile/src/utils/remap-props.ts-6- className: "style",
apps/mobile/src/utils/remap-props.ts-7- handleClassName: "handleStyle",
apps/mobile/src/utils/remap-props.ts-8- containerClassName: "containerStyle",
--
apps/mobile/src/utils/remap-props.ts-10-
apps/mobile/src/utils/remap-props.ts:11:remapProps(FontAwesome, {
apps/mobile/src/utils/remap-props.ts-12- className: "style",
apps/mobile/src/utils/remap-props.ts-13- color: "color",
apps/mobile/src/utils/remap-props.ts-14-});
</shell_result>
Script executed:
#!/bin/bash
# Search for color prop usage on FontAwesome or similar icon components
rg -n "color\s*=" -A 1 -B 1 --type ts | head -50Repository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
apps/mobile/src/app/(public)/(protected)/home/(tabs)/_layout.tsx-26- tabBarIcon: ({ color }) => (
apps/mobile/src/app/(public)/(protected)/home/(tabs)/_layout.tsx:27: <IconSymbol size={28} name="house.fill" color={color} />
apps/mobile/src/app/(public)/(protected)/home/(tabs)/_layout.tsx-28- ),
--
apps/mobile/src/app/(public)/(protected)/home/(tabs)/_layout.tsx-35- tabBarIcon: ({ color }) => (
apps/mobile/src/app/(public)/(protected)/home/(tabs)/_layout.tsx:36: <IconSymbol size={28} name="paperplane.fill" color={color} />
apps/mobile/src/app/(public)/(protected)/home/(tabs)/_layout.tsx-37- ),
--
apps/mobile/src/components/layouts/default/Footer.tsx-35- <View className="w-8 h-8 bg-muted rounded-lg items-center justify-center">
apps/mobile/src/components/layouts/default/Footer.tsx:36: <AntDesign name="twitter" size={16} color="#6B7280" />
apps/mobile/src/components/layouts/default/Footer.tsx-37- </View>
--
apps/mobile/src/components/layouts/default/Footer.tsx-40- <View className="w-8 h-8 bg-muted rounded-lg items-center justify-center">
apps/mobile/src/components/layouts/default/Footer.tsx:41: <AntDesign name="github" size={16} color="#6B7280" />
apps/mobile/src/components/layouts/default/Footer.tsx-42- </View>
--
apps/mobile/src/components/layouts/default/Footer.tsx-45- <View className="w-8 h-8 bg-muted rounded-lg items-center justify-center">
apps/mobile/src/components/layouts/default/Footer.tsx:46: <AntDesign name="linkedin-square" size={16} color="#6B7280" />
apps/mobile/src/components/layouts/default/Footer.tsx-47- </View>
--
apps/mobile/src/components/layouts/default/Footer.tsx-50- <View className="w-8 h-8 bg-muted rounded-lg items-center justify-center">
apps/mobile/src/components/layouts/default/Footer.tsx:51: <Feather name="globe" size={16} color="#6B7280" />
apps/mobile/src/components/layouts/default/Footer.tsx-52- </View>
--
apps/mobile/src/components/layouts/default/Footer.tsx-128- <View className="w-6 h-6 items-center justify-center">
apps/mobile/src/components/layouts/default/Footer.tsx:129: <Feather name="globe" size={16} color="#6B7280" />
apps/mobile/src/components/layouts/default/Footer.tsx-130- </View>
--
apps/mobile/src/components/layouts/default/Footer.tsx-133- <View className="w-6 h-6 items-center justify-center">
apps/mobile/src/components/layouts/default/Footer.tsx:134: <MaterialIcons name="email" size={16} color="#6B7280" />
apps/mobile/src/components/layouts/default/Footer.tsx-135- </View>
--
apps/mobile/src/components/layouts/default/Footer.tsx-138- <View className="w-6 h-6 items-center justify-center">
apps/mobile/src/components/layouts/default/Footer.tsx:139: <MaterialIcons name="help-outline" size={16} color="#6B7280" />
apps/mobile/src/components/layouts/default/Footer.tsx-140- </View>
--
apps/mobile/src/components/ui/IconSymbol.tsx-39-}) {
apps/mobile/src/components/ui/IconSymbol.tsx:40: return <MaterialIcons color={color} size={size} name={MAPPING[name]} style={style} />;
apps/mobile/src/components/ui/IconSymbol.tsx-41-}
--
apps/mobile/src/components/ui/activity-indicator.tsx-8- const { colorScheme } = useColorScheme();
apps/mobile/src/components/ui/activity-indicator.tsx:9: return <RNActivityIndicator color={NAV_THEME[colorScheme].text} {...props} />;
apps/mobile/src/components/ui/activity-indicator.tsx-10-}
</shell_result>
Script executed:
#!/bin/bash
# Check if there are any comments or documentation about remapProps usage
rg -n "remapProps|NativeWind" -B 2 -A 5 --type ts | head -60Repository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
apps/mobile/src/utils/remap-props.ts-1-import { FontAwesome } from "@expo/vector-icons";
apps/mobile/src/utils/remap-props.ts:2:import { remapProps } from "nativewind";
apps/mobile/src/utils/remap-props.ts-3-import { BottomSheetModal } from "~/components/ui/bottom-sheet";
apps/mobile/src/utils/remap-props.ts-4-
apps/mobile/src/utils/remap-props.ts:5:remapProps(BottomSheetModal, {
apps/mobile/src/utils/remap-props.ts-6- className: "style",
apps/mobile/src/utils/remap-props.ts-7- handleClassName: "handleStyle",
apps/mobile/src/utils/remap-props.ts-8- containerClassName: "containerStyle",
apps/mobile/src/utils/remap-props.ts-9-});
apps/mobile/src/utils/remap-props.ts-10-
apps/mobile/src/utils/remap-props.ts:11:remapProps(FontAwesome, {
apps/mobile/src/utils/remap-props.ts-12- className: "style",
apps/mobile/src/utils/remap-props.ts-13- color: "color",
apps/mobile/src/utils/remap-props.ts-14-});
--
apps/mobile/src/components/landing/landing-page.tsx-180- title: "Lightning Fast Development",
apps/mobile/src/components/landing/landing-page.tsx-181- description:
apps/mobile/src/components/landing/landing-page.tsx:182: "Built with Expo Router, Legend State, and NativeWind for rapid development and optimal performance.",
apps/mobile/src/components/landing/landing-page.tsx-183- },
apps/mobile/src/components/landing/landing-page.tsx-184- {
apps/mobile/src/components/landing/landing-page.tsx-185- id: "production-ready",
apps/mobile/src/components/landing/landing-page.tsx-186- icon: Shield,
apps/mobile/src/components/landing/landing-page.tsx-187- title: "Production Ready",
--
apps/mobile/src/components/landing/landing-page.tsx-388- avatar: "👩🎨",
apps/mobile/src/components/landing/landing-page.tsx-389- quote:
apps/mobile/src/components/landing/landing-page.tsx:390: "The integration of Legend State and NativeWind makes state management and styling a breeze. Highly recommended!",
apps/mobile/src/components/landing/landing-page.tsx-391- rating: 5,
apps/mobile/src/components/landing/landing-page.tsx-392- },
apps/mobile/src/components/landing/landing-page.tsx-393- ];
apps/mobile/src/components/landing/landing-page.tsx-394-
apps/mobile/src/components/landing/landing-page.tsx-395- return (
--
apps/mobile/src/components/landing/landing-page.tsx-480- question: "Can I customize the UI components and styling?",
apps/mobile/src/components/landing/landing-page.tsx-481- answer:
apps/mobile/src/components/landing/landing-page.tsx:482: "Absolutely! The UI is built with NativeWind (Tailwind for React Native) and react-native-reusables, making it easy to customize colors, spacing, and components to match your brand.",
apps/mobile/src/components/landing/landing-page.tsx-483- },
apps/mobile/src/components/landing/landing-page.tsx-484- {
apps/mobile/src/components/landing/landing-page.tsx-485- id: "support",
apps/mobile/src/components/landing/landing-page.tsx-486- question: "Is there ongoing support and updates?",
apps/mobile/src/components/landing/landing-page.tsx-487- answer:
</shell_result>
Script executed:
#!/bin/bash
# Check if color prop is ever passed with className pattern
rg -n "color\s*=\s*['\"].*(?:text-|bg-)" --type tsRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Look for any NativeWind or remapProps related comments/documentation
rg -n "NativeWind|remap" --type ts --type js -B 2 -A 2Repository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
apps/mobile/src/utils/remap-props.ts-1-import { FontAwesome } from "@expo/vector-icons";
apps/mobile/src/utils/remap-props.ts:2:import { remapProps } from "nativewind";
apps/mobile/src/utils/remap-props.ts-3-import { BottomSheetModal } from "~/components/ui/bottom-sheet";
apps/mobile/src/utils/remap-props.ts-4-
apps/mobile/src/utils/remap-props.ts:5:remapProps(BottomSheetModal, {
apps/mobile/src/utils/remap-props.ts-6- className: "style",
apps/mobile/src/utils/remap-props.ts-7- handleClassName: "handleStyle",
--
apps/mobile/src/utils/remap-props.ts-9-});
apps/mobile/src/utils/remap-props.ts-10-
apps/mobile/src/utils/remap-props.ts:11:remapProps(FontAwesome, {
apps/mobile/src/utils/remap-props.ts-12- className: "style",
apps/mobile/src/utils/remap-props.ts-13- color: "color",
--
apps/mobile/src/components/landing/landing-page.tsx-180- title: "Lightning Fast Development",
apps/mobile/src/components/landing/landing-page.tsx-181- description:
apps/mobile/src/components/landing/landing-page.tsx:182: "Built with Expo Router, Legend State, and NativeWind for rapid development and optimal performance.",
apps/mobile/src/components/landing/landing-page.tsx-183- },
apps/mobile/src/components/landing/landing-page.tsx-184- {
--
apps/mobile/src/components/landing/landing-page.tsx-388- avatar: "👩🎨",
apps/mobile/src/components/landing/landing-page.tsx-389- quote:
apps/mobile/src/components/landing/landing-page.tsx:390: "The integration of Legend State and NativeWind makes state management and styling a breeze. Highly recommended!",
apps/mobile/src/components/landing/landing-page.tsx-391- rating: 5,
apps/mobile/src/components/landing/landing-page.tsx-392- },
--
apps/mobile/src/components/landing/landing-page.tsx-480- question: "Can I customize the UI components and styling?",
apps/mobile/src/components/landing/landing-page.tsx-481- answer:
apps/mobile/src/components/landing/landing-page.tsx:482: "Absolutely! The UI is built with NativeWind (Tailwind for React Native) and react-native-reusables, making it easy to customize colors, spacing, and components to match your brand.",
apps/mobile/src/components/landing/landing-page.tsx-483- },
apps/mobile/src/components/landing/landing-page.tsx-484- {
--
apps/mobile/index.ts-1-import "expo-router/entry";
apps/mobile/index.ts-2-
apps/mobile/index.ts:3:import "@/src/utils/remap-props";
apps/mobile/index.ts-4-import "./global.css";
--
apps/mobile/metro.config.js-1-// Learn more https://docs.expo.io/guides/customizing-metro
apps/mobile/metro.config.js-2-const { getDefaultConfig } = require("expo/metro-config");
apps/mobile/metro.config.js:3:const { withNativeWind } = require("nativewind/metro");
apps/mobile/metro.config.js-4-
apps/mobile/metro.config.js-5-/** @type {import('expo/metro-config').MetroConfig} */
apps/mobile/metro.config.js-6-const config = getDefaultConfig(__dirname);
apps/mobile/metro.config.js-7-
apps/mobile/metro.config.js:8:module.exports = withNativeWind(config, { input: "./global.css", inlineRem: 16 });
</shell_result>
Script executed:
#!/bin/bash
# Check package.json for NativeWind version and any related info
cat package.json | head -50Repository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
{
"name": "universal-starter",
"private": true,
"workspaces": {
"packages": [
"apps/*",
"packages/*"
]
},
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build"
},
"devDependencies": {
"@biomejs/biome": "catalog:devDeps",
"@types/bun": "latest",
"lefthook": "^1.12.3",
"turbo": "^2.6.1",
"typescript": "catalog:devDeps",
"ultracite": "6.3.6"
},
"engines": {
"bun": ">=1.0.0"
},
"packageManager": "pnpm@10.23.0"
}
</shell_result>
Script executed:
#!/bin/bash
# Search for any other remapProps calls in the codebase
fd -name "*.ts" -o -name "*.js" | xargs grep -l "remapProps" 2>/dev/nullRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 123
stderr:
error: Found argument '-n' which wasn't expected, or isn't valid in this context
If you tried to supply '-n' as a value rather than a flag, use '-- -n'
Usage: fd [OPTIONS] [pattern] [path]...
For more information try '--help'
</shell_result>
Script executed:
#!/bin/bash
# Find where remapProps is defined or used in node_modules check
fd "remap-props" --type fRepository: fyndx/universal-starter
<shell_result>
Repository: fyndx/universal-starter
Exit code: 0
stdout:
apps/mobile/src/utils/remap-props.ts
</shell_result>
Remove the redundant color: "color" mapping. FontAwesome's color prop accepts direct color values (hex codes, named colors), not Tailwind class strings, so it doesn't need to be included in the remapProps configuration.
remapProps(FontAwesome, {
className: "style",
- color: "color",
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| remapProps(FontAwesome, { | |
| className: "style", | |
| color: "color", | |
| }); | |
| remapProps(FontAwesome, { | |
| className: "style", | |
| }); |
🤖 Prompt for AI Agents
In apps/mobile/src/utils/remap-props.ts around lines 11 to 14, the remapProps
mapping includes a redundant entry mapping color: "color" for FontAwesome;
remove the color key from the remapProps configuration so only className maps to
"style" remains, and ensure the remapProps call is updated accordingly (no other
changes to FontAwesome usage required).
User description
PR Type
Enhancement, Configuration
Description
Implement comprehensive social login authentication with support for Google, Facebook, GitHub, Apple, and LinkedIn providers
Add environment variable validation using Zod schema for type-safe configuration management
Create new social login landing page (
/auth) replacing the previous sign-in redirect flowRefactor mobile authentication screens (sign-in, sign-up, forgot-password, reset-password) with improved layout structure using
Screenwrapper componentReplace
Cardcomponents with semanticViewcontainers throughout authentication pages for better maintainabilityAdd typography variants and accessibility support to
Textcomponent with semantic HTML rolesCreate reusable
Screenwrapper component combiningSafeAreaView,SystemBars, andKeyboardAvoidingViewwith platform-specific handlingAdd
Iconwrapper component for Lucide icons with Nativewind supportUpdate authentication redirect paths across the application to point to new
/authlanding pageUpdate development configuration with trusted origins for Expo's
exp://schemeUpdate Biome from 1.9.4 to 2.3.7 and TypeScript to 5.9.3
Update Turborepo configuration with TUI mode and new
db:resettaskUpdate VSCode default formatter from Prettier to Biome
Diagram Walkthrough
File Walkthrough
7 files
env.ts
Environment variable validation schema with Zodapps/api/src/env.ts
authentication, email services, and observability
logging if validation fails
envobject for type-safe access throughout theapplication
index.ts
Environment validation initializationapps/api/src/index.ts
@src/envmodule to ensure environment validation runsat application startup
turbo.json
Update Turborepo configuration and add db:reset taskturbo.json
"ui": "tui"configuration for Turborepo UI"interactive": trueto dev task configurationdb:resettask with cache disabled and persistent flag.env.example
Add social login provider environment variablesapps/api/.env.example
Facebook, GitHub, Apple, and LinkedIn
CLIENT_IDandCLIENT_SECRETenvironmentvariables
components.json
Add shadcn/ui configuration to components.jsonapps/mobile/components.json
$schemareference for shadcn/ui configurationutils,ui, andhookspathssettings.json
Update VSCode default formatter to Biome.vscode/settings.json
biome.jsonc
Update Biome configuration and schema versionbiome.jsonc
ultracite/coreandultracite/reactpresets19 files
auth.ts
Social login providers and development origin configurationapps/api/src/lib/auth.ts
envobject from new env configuration fileexp://scheme withlocal IP ranges
Apple, LinkedIn) with credentials from environment variables
basePathwith commented configurationconfig.ts
Email configuration using validated environment variablesapps/api/src/lib/email/config.ts
process.envaccess with validatedenvobject from newconfiguration
operator
variables
button.tsx
Button component styling and platform-specific improvementsapps/mobile/src/components/ui/button.tsx
handling using
Platform.select()refparameter from function signature and improves classNamehandling
reset-password.tsx
Reset password screen UI simplification and navigationapps/mobile/src/app/(public)/auth/reset-password.tsx
of Card subcomponents
sign-in.tsx
Refactor sign-in page layout and navigation structureapps/mobile/src/app/(public)/auth/sign-in.tsx
Cardcomponent withScreenwrapper and custom layout usingViewcomponentsChevronLefticon at the topViewcontainerswith gap-based spacing
Linkcomponents to useasChildprop for proper navigationbehavior
forgot-password.tsx
Refactor forgot-password page with Screen wrapperapps/mobile/src/app/(public)/auth/forgot-password.tsx
Cardcomponent withScreenwrapper and customView-basedlayout
ChevronLefticonViewcontainers with consistentspacing
useRouterhook for navigation functionalityindex.tsx
Implement social login authentication landing pageapps/mobile/src/app/(public)/auth/index.tsx
authentication page
LinkedIn providers
handleSocialLoginfunction usingauthClient.signIn.socialtext.tsx
Add typography variants and accessibility supportapps/mobile/src/components/ui/text.tsx
textVariantsCVA configuration with semantic typography variants(h1-h4, p, blockquote, code, etc.)
Platform.selectfor weband native
ROLEandARIA_LEVELmappings for accessibility supportTextcomponent to acceptvariantprop and apply semantic HTMLroles
sign-up-success-card.tsx
Replace Card component with semantic View layoutapps/mobile/src/components/auth/sign-up-success-card.tsx
Cardcomponent imports and replaced with semanticViewcontainers
CardHeader,CardContent,CardFootertoViewcomponents withgap-based spacing
Textcomponent with inline className fortypography
sign-up-form.tsx
Replace Card component with semantic View structureapps/mobile/src/components/auth/sign-up-form.tsx
Cardcomponent and replaced withViewcontainersViewcomponents
Textcomponent with font-bold andmuted-foreground classes
flex-1to maintain consistent sizingicon.tsx
Add Icon wrapper component for Lucide iconsapps/mobile/src/components/ui/icon.tsx
Iconwrapper component for Lucide icons with Nativewindsupport
cssInteropconfiguration to map className to icon sizeproperties
index.tsx
Update splash screen with safe area and auth redirectapps/mobile/src/app/index.tsx
SafeAreaViewfor proper screen insets/(public)/auth/sign-into/(public)/authreact-native-safe-area-contextimport for safe area handling_layout.tsx
Simplify auth layout and update routing structureapps/mobile/src/app/(public)/auth/_layout.tsx
SafeAreaViewwrapper andHeadercomponent from layoutsocial-sign-inscreen from Stack configurationindexscreen to Stack for social login landing page/(public)/(protected)/home/(tabs)screen.tsx
Create reusable Screen wrapper componentapps/mobile/src/components/screen.tsx
Screenwrapper component combiningSafeAreaView,SystemBars, andKeyboardAvoidingViewAndroid)
SystemBarsPropsandKeyboardAvoidingViewPropssign-up.tsx
Wrap sign-up page with Screen and add navigationapps/mobile/src/app/(public)/auth/sign-up.tsx
SignUpContainerwithScreencomponent for consistent layoutChevronLefticonuseRouterhook andScreencomponentsign-up.container.tsx
Add padding to sign-up containerapps/mobile/src/containers/auth/sign-up.container.tsx
p-6padding class to main containerViewfor consistent spacing_layout.tsx
Update admin layout auth redirect pathapps/mobile/src/app/(public)/(protected)/admin/_layout.tsx
/auth/sign-into/authHeaderUser.tsx
Update HeaderUser login redirect pathapps/mobile/src/containers/core/HeaderUser.tsx
/auth/sign-into/auth_layout.tsx
Update protected layout auth redirect pathapps/mobile/src/app/(public)/(protected)/_layout.tsx
/auth/sign-into/auth3 files
pnpm-lock.yaml
Dependency updates and cleanuppnpm-lock.yaml
@biomejs/biomefrom 1.9.4 to 2.3.7 with correspondingplatform-specific CLI packages
ultracitefrom 5.3.3 to 6.3.6 with new dependency structurepackage.json
Ultracite dependency version bumppackage.json
ultracitedependency from 5.3.3 to 6.3.6pnpm-workspace.yaml
Update Biome and TypeScript dependenciespnpm-workspace.yaml
@biomejs/biomeversion from 1.9.4 to 2.3.7typescriptversion from ^5.7.3 to ^5.9.32 files
CodeAnt-AI Description
Introduce social login landing page and refreshed auth screens
What Changed
/authnow shows a dedicated landing screen with Google, Facebook, GitHub, Apple, and LinkedIn buttons plus a safe-area-aware layout so users can pick social login or continue with email.Impact
✅ More social login choices on auth landing✅ Consistent auth flow layout across mobile screens✅ Grounded environment validation before auth starts💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.