feat(mobile): build out barebones mobile app#843
Conversation
📝 WalkthroughWalkthroughThis PR introduces a new Expo-based mobile application alongside dependency version updates across existing applications. It adds Expo authentication support to the auth server, creates mobile UI components and routing infrastructure, updates package dependencies, and modifies member query filtering. Changes
Sequence DiagramsequenceDiagram
participant MobileApp as Mobile App
participant AuthClient as Auth Client
participant AuthServer as Auth Server
participant Storage as Secure Storage
MobileApp->>AuthClient: useSession()
AuthClient->>Storage: Check stored session
Storage-->>AuthClient: Session data (or null)
alt No Session
AuthClient-->>MobileApp: null
MobileApp->>MobileApp: Redirect to /(auth)/sign-in
MobileApp->>MobileApp: Render SignInScreen
Note over MobileApp: User taps GitHub/Google
MobileApp->>AuthClient: signIn.social({provider})
AuthClient->>AuthServer: OAuth request + scheme:superset
AuthServer->>AuthServer: Validate & create session
AuthServer-->>AuthClient: Return session token
AuthClient->>Storage: Store session securely
AuthClient-->>MobileApp: useSession() returns session
MobileApp->>MobileApp: Redirect to home screen
else Session Exists
AuthClient-->>MobileApp: session object
MobileApp->>MobileApp: Render HomeScreen
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes The changes span multiple application modules with extensive new mobile app scaffold code (configuration, components, screens, utilities) and repetitive dependency updates across 9 package.json files. While dependency updates are homogeneous and low-risk, the new mobile app introduces a diverse set of new files following established patterns (Expo Router, React Native UI components, Zod validation). The auth server modification is straightforward (plugin registration), and the members query change is minimal. The primary review effort stems from the breadth of new mobile app code and ensuring consistency across components and configuration. Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 15
🤖 Fix all issues with AI agents
In `@apps/api/package.json`:
- Around line 32-33: The dependency version for `@types/react-dom` is mismatched
with react-dom (react-dom is set to "19.1.0" while `@types/react-dom` is pinned to
^19.2.3); update the `@types/react-dom` entry in package.json to a type version
aligned with React 19.1 (for example "~19.1.0") so it matches react-dom and
`@types/react`, ensuring consistent types across the project.
In `@apps/desktop/package.json`:
- Line 55: Update the `@types/react` dependency in package.json to satisfy
`@types/react-dom`'s peer requirement: change the version constraint for
"@types/react" from "~19.1.0" to a 19.2.x-compatible range (e.g., "~19.2.0" or
"^19.2.0") so it aligns with "@types/react-dom@19.2.3" and removes the peer
conflict while leaving other dependencies unchanged.
In `@apps/docs/package.json`:
- Around line 23-24: The dependency versions for TypeScript typings are
mismatched: update the `@types` packages in package.json so `@types/react` and
`@types/react-dom` use the same minor series; specifically change the `@types/react`
entry to ^19.2.x (to match `@types/react-dom`@^19.2.3) or alternatively set
`@types/react-dom` to ~19.1.x—edit the "@types/react" and "@types/react-dom"
entries accordingly to keep them aligned.
In `@apps/mobile/app.json`:
- Line 43: In app.json update the "owner" field value: locate the JSON key
"owner" (currently set to "supserset-sh") and correct the typo by replacing it
with "superset-sh" so the owner string matches the intended organization name.
In `@apps/mobile/components.json`:
- Around line 6-11: Update the tailwind entry in components.json to remove the
non-existent tailwind.config.js reference: either delete the "config":
"tailwind.config.js" key from the "tailwind" object in components.json or
replace it with a valid config path if you intend to use one; ensure the "css":
"global.css" and "cssVariables": true settings remain intact so the project
continues to use the CSS-first Tailwind v4 setup (refer to the "tailwind" object
and the "config" key when making the change).
In `@apps/mobile/components/ui/button.tsx`:
- Around line 102-117: The ButtonProps type is unnecessarily combining
React.ComponentProps and React.RefAttributes; replace the intersection with
React.ComponentPropsWithRef<typeof Pressable> to simplify and include refs
automatically. Update the type alias ButtonProps to use
ComponentPropsWithRef<typeof Pressable>, keeping the rest of the Button
component (function Button, the Pressable spread {...props}, and usage of
buttonVariants/buttonTextVariants and cn) unchanged so props and refs continue
to be forwarded correctly.
In `@apps/mobile/components/ui/card.tsx`:
- Around line 5-69: Split each component (Card, CardHeader, CardTitle,
CardDescription, CardContent, CardFooter) into its own file and update their
exports; remove the incorrect use of React.RefAttributes from props or,
preferably, implement proper ref forwarding by wrapping each functional
component with React.forwardRef and accepting (props, ref) to pass the ref to
the underlying View/Text element (e.g., forwardRef for Card should forward to
the inner View, CardTitle/CardDescription forward to Text, etc.), and update
their prop types to use React.ComponentProps<typeof View>/Text plus
React.Ref<HTMLDivElement | Text> as appropriate; ensure you export default each
component from its new file and update any imports where these components are
used.
In `@apps/mobile/components/ui/text.tsx`:
- Around line 55-62: The ROLE mapping uses forced type assertions for
Platform.select({ web: "blockquote" as Role }) and "code" which silence
TypeScript because React Native's Role type lacks these web-only ARIA roles;
either add a brief inline comment above the ROLE constant explaining the
web-only assertion and why it's safe (Platform.select guarantees runtime-only on
web), or create a proper type augmentation to extend react-native's Role with
'blockquote' and 'code' (e.g., add an ambient declaration module for
'react-native' in your types directory) and remove the as Role casts so ROLE
(and related types TextVariant/Role) are properly typed without assertions.
In `@apps/mobile/global.css`:
- Around line 10-11: Remove the inconsistent CSS custom property --color-radius
from the `@variant` light block and ensure the theme uses the established --radius
variable; locate the `@theme` block that defines --radius and the `@variant` light
block containing --color-radius, delete the --color-radius declaration, and
verify no other rules reference --color-radius so the layout relies on the
existing --radius: 0.5rem variable.
In `@apps/mobile/lib/auth/client.ts`:
- Around line 5-6: The code silently falls back to "http://localhost:3001" when
EXPO_PUBLIC_API_URL is missing; change the logic around the API_URL/BASE_URL
constant so that if process.env.EXPO_PUBLIC_API_URL is undefined and the app is
not in development (e.g., process.env.NODE_ENV !== 'development' or __DEV__),
you either throw an error or log a clear warning and fail fast instead of using
localhost; update the constant name (API_URL → BASE_URL) and ensure the new
BASE_URL is passed into createAuthClient where API_URL was previously used so
the client initialization uses the validated environment value.
In `@apps/mobile/lib/database.ts`:
- Around line 12-84: This module uses raw SQL in initDatabase, getTodos,
addTodo, toggleTodo, and deleteTodo; replace these with Drizzle ORM calls using
the centralized schema from packages/db/src (import the todos table and db
client types), initialize the Drizzle client in initDatabase (or reuse existing
exported db instance) instead of SQLite.execAsync, rewrite getTodos to run
db.select(todos).orderBy(todos.created_at.desc()), addTodo to use
db.insert(todos).values({ title }).returning(), toggleTodo to use
db.update(todos).set({ completed: sql`NOT ${todos.completed}` }) or fetch
current value then update, and deleteTodo to use
db.delete(todos).where(eq(todos.id, id)); ensure type mappings (completed
boolean, createdAt field) match your Todo type and adjust returned row property
names to createdAt, and remove raw SQL strings while importing helpers (eq, sql)
from drizzle-orm/sqlite as needed.
In `@apps/mobile/package.json`:
- Line 16: The dependency entry for "@electric-sql/client" has an empty version
string which is fragile; update the apps/mobile/package.json by either removing
the "@electric-sql/client" dependency if you rely on the root resolution
override, or replace the empty string with a concrete reference (e.g., a
workspace reference like "workspace:*", the PR tarball URL used in the root
resolution, or the published version) so package resolution is explicit and
predictable.
In `@apps/mobile/screens/index/HomeScreen.tsx`:
- Around line 3-30: Update the handleSignOut implementation in HomeScreen to
catch errors from signOut() instead of letting unhandled rejections occur: wrap
the await signOut() call in a try/catch, call console.error with a clear prefix
(e.g., "HomeScreen: signOut failed") and the caught error, and show user
feedback via an Alert (e.g., Alert.alert with a short message) so failures are
logged and surfaced to the user.
In `@apps/web/package.json`:
- Around line 36-37: Update package.json to mitigate CVE-2025-55182 by bumping
"react" from 19.1.0 to 19.1.2 and ensure "react-dom" is also set to 19.1.2
(replace the existing 19.1.0 entries), and align the `@types` entry for react-dom
to a matching ~19.1.x range instead of ^19.2.3; run package manager install and
lockfile update and run tests/build to verify nothing else breaks.
In `@packages/auth/package.json`:
- Line 21: Update the dependency version for "@better-auth/expo" in package.json
to a published release; locate the dependency entry for "@better-auth/expo" and
replace "1.4.15" with a valid npm version (e.g., "1.2.11" or a valid pre-release
like "1.3.8-beta.4") or align it with the version used elsewhere (apps/mobile)
after verifying that version exists on npm, then run npm/yarn install to confirm
the package resolves.
🧹 Nitpick comments (6)
packages/auth/src/server.ts (1)
20-37: Extract trusted origin literals into named constants.This block is getting policy-heavy; hoisting the new mobile/Expo origins into module-level constants makes the intent clearer and avoids magic strings inline.
As per coding guidelines, extract hardcoded values to named constants.♻️ Suggested refactor
+const MOBILE_APP_ORIGINS = ["superset://"]; +const EXPO_DEV_ORIGINS = ["exp://", "exp://**", "exp://192.168.*.*:*/**"]; + export const auth = betterAuth({ trustedOrigins: [ env.NEXT_PUBLIC_WEB_URL, env.NEXT_PUBLIC_API_URL, env.NEXT_PUBLIC_MARKETING_URL, env.NEXT_PUBLIC_ADMIN_URL, // Electron desktop app origins ...(env.NEXT_PUBLIC_DESKTOP_URL ? [env.NEXT_PUBLIC_DESKTOP_URL] : []), "superset://app", // Production Electron app // React Native mobile app origins - "superset://", // Production mobile app + ...MOBILE_APP_ORIGINS, // Production mobile app // Expo development mode - exp:// scheme with local IP ranges - ...(process.env.NODE_ENV === "development" - ? [ - "exp://", - "exp://**", - "exp://192.168.*.*:*/**", - ] - : []), + ...(process.env.NODE_ENV === "development" ? EXPO_DEV_ORIGINS : []), ],packages/ui/package.json (1)
89-91: Exact version inpeerDependenciesis overly restrictive.Using an exact version
"react": "19.1.0"inpeerDependenciesmeans consumers must use exactly this version. This could cause peer dependency warnings or failures for apps using React19.0.xor19.2.x.Consider using a range that accommodates minor version differences:
🔧 Proposed fix
"peerDependencies": { - "react": "19.1.0" + "react": "^19.0.0" }apps/mobile/components/ui/input.tsx (1)
4-32: Missing ref forwarding for TextInput.The component accepts
React.RefAttributes<TextInput>in its props type but doesn't actually forward the ref to the underlyingTextInput. This prevents parent components from accessing the input for programmatic focus, blur, or selection operations.♻️ Proposed fix to enable ref forwarding
+import * as React from "react"; import { Platform, TextInput, type TextInputProps } from "react-native"; import { cn } from "@/lib/utils"; -function Input({ +const Input = React.forwardRef<TextInput, TextInputProps>(function Input({ className, ...props -}: TextInputProps & React.RefAttributes<TextInput>) { +}, ref) { return ( <TextInput + ref={ref} className={cn( "dark:bg-input/30 border-input bg-background text-foreground flex h-10 w-full min-w-0 flex-row items-center rounded-md border px-3 py-1 text-base leading-5 shadow-sm shadow-black/5 sm:h-9", props.editable === false && cn( "opacity-50", Platform.select({ web: "disabled:pointer-events-none disabled:cursor-not-allowed", }), ), Platform.select({ web: cn( "placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground outline-none transition-[color,box-shadow] md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", ), native: "placeholder:text-muted-foreground/50", }), className, )} {...props} /> ); -} +}); export { Input };apps/mobile/components/ui/switch.tsx (1)
5-35: Missing ref forwarding for Switch primitive.Similar to the Input component, this accepts
React.RefAttributes<SwitchPrimitives.RootRef>but doesn't forward the ref to the underlyingSwitchPrimitives.Root. Consider usingReact.forwardRefif programmatic access to the switch is needed.♻️ Proposed fix
import * as SwitchPrimitives from "@rn-primitives/switch"; +import * as React from "react"; import { Platform } from "react-native"; import { cn } from "@/lib/utils"; -function Switch({ +const Switch = React.forwardRef<SwitchPrimitives.RootRef, SwitchPrimitives.RootProps>(function Switch({ className, ...props -}: SwitchPrimitives.RootProps & React.RefAttributes<SwitchPrimitives.RootRef>) { +}, ref) { return ( <SwitchPrimitives.Root + ref={ref} className={cn( // ... existing classes )} {...props} > {/* ... */} </SwitchPrimitives.Root> ); -} +});apps/mobile/screens/(auth)/sign-in/SignInScreen.tsx (1)
16-71: Extract provider strings and callback URL into module constants.This aligns with the project’s guidance on avoiding hardcoded values and improves reuse in the UI and handler.
♻️ Proposed refactor
+const CALLBACK_URL = "/"; +const GITHUB_PROVIDER = "github" as const; +const GOOGLE_PROVIDER = "google" as const; +type Provider = typeof GITHUB_PROVIDER | typeof GOOGLE_PROVIDER; + export default function SignInScreen() { - const [loading, setLoading] = useState<"github" | "google" | null>(null); + const [loading, setLoading] = useState<Provider | null>(null); const { data: session } = useSession(); // Redirect if already signed in if (session) { return <Redirect href="/" />; } - const handleSignIn = async (provider: "github" | "google") => { + const handleSignIn = async (provider: Provider) => { console.log("[sign-in] Button clicked:", provider); try { setLoading(provider); console.log("[sign-in] Calling signIn.social..."); await signIn.social({ provider, - callbackURL: "/", + callbackURL: CALLBACK_URL, }); } catch (error) { // ... } finally { setLoading(null); } }; @@ - onPress={() => handleSignIn("github")} + onPress={() => handleSignIn(GITHUB_PROVIDER)} @@ - onPress={() => handleSignIn("google")} + onPress={() => handleSignIn(GOOGLE_PROVIDER)}As per coding guidelines, extract hardcoded values to module-level constants.
apps/mobile/components/ui/card.tsx (1)
5-80: Split into one component per file.This file defines six components. Please move each component into its own file and re-export via an index to match the one-component-per-file standard. As per coding guidelines, one component per file.
| "react": "19.1.0", | ||
| "react-dom": "19.1.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n apps/docs/package.jsonRepository: superset-sh/superset
Length of output: 1316
🌐 Web query:
React 19.1.0 Next.js 16 compatibility
💡 Result:
Short answer: Yes — Next.js 16 is designed to work with React 19.x, so React 19.1.0 is generally compatible with Next.js 16. Install matching react and react-dom versions (exactly the same), and update any third‑party packages whose peerDependencies still restrict to React 18. (nextjs.org)
Notes / cautions:
- Next’s upgrade guide recommends using react@latest / react-dom@latest when moving to Next 16. (nextjs.org)
- Some ecosystem packages (or
@next/third‑parties helpers) may still list React 18 ranges and require bumping their peerDependencies; you may see peer‑dependency warnings and will need to update those packages or use --legacy-peer-deps temporarily. (github.com) - Security: several advisories in late 2025 affected React Server Components in certain 19.x releases — patch to a non‑vulnerable React 19 release if you rely on RSC. Verify you’re on a patched 19.x version. (techradar.com)
If you want, I can: (1) check your package.json for specific conflicts, or (2) recommend the exact react/react-dom version to install (including patched versions).
Citations:
- 1: https://nextjs.org/docs/app/guides/upgrading/version-16?utm_source=openai
- 2: https://nextjs.org/docs/app/guides/upgrading/version-16?utm_source=openai
- 3: @next/third-parties peerDependencies does not support Next 15 or React 19 RC vercel/next.js#71185
- 4: https://www.techradar.com/pro/security/experts-warn-this-worst-case-scenario-react-vulnerability-could-soon-be-exploited-so-patch-now?utm_source=openai
🌐 Web query:
tailwindcss 4.1.18 @tailwindcss/postcss 4.0.9 compatibility
💡 Result:
Yes — Tailwind CSS v4.1.18 is compatible with the @tailwindcss/postcss 4.x plugin (including 4.0.9). Tailwind v4 requires using the separate PostCSS package (@tailwindcss/postcss), and v4.1.18 is a v4 release. [1][2][3]
Sources:
- Tailwind v4 PostCSS install docs. [1]
@tailwindcss/postcssv4.0.9 npm page. [2]- tailwindcss v4.1.18 GitHub release notes. [3]
🌐 Web query:
@types/react-dom 19.2.3 @types/react 19.1.0 compatibility alignment
💡 Result:
Short answer: they can conflict — @types/react-dom 19.2.3 expects the React types from the 19.2.x line, so using @types/react 19.1.0 can produce TypeScript/JSX type errors. Align the @types/* minor versions (use @types/react 19.2.x to match @types/react-dom 19.2.3, or downgrade @types/react-dom to 19.1.x). [1][2][3]
Commands:
- to upgrade react types: npm install -D
@types/react@^19.2@types/react-dom@^19.2 - or to downgrade react-dom types: npm install -D
@types/react-dom@^19.1
Sources:
@types/react-dompackage info. [1]@types/reactreleases overview. [2]- DefinitelyTyped discussion showing JSX/type issues when versions are out of sync. [3]
Align @types/react and @types/react-dom to the same minor version.
Line 33 pins @types/react to ~19.1.0 while line 34 uses @types/react-dom at ^19.2.3. This version mismatch will cause TypeScript/JSX type conflicts. Update @types/react to ^19.2.x to match @types/react-dom@^19.2.3, or downgrade @types/react-dom to ~19.1.x.
React 19.1.0 is compatible with Next.js 16, and Tailwind CSS 4.1.18 is compatible with @tailwindcss/postcss 4.0.9, so no changes needed there.
🤖 Prompt for AI Agents
In `@apps/docs/package.json` around lines 23 - 24, The dependency versions for
TypeScript typings are mismatched: update the `@types` packages in package.json so
`@types/react` and `@types/react-dom` use the same minor series; specifically change
the `@types/react` entry to ^19.2.x (to match `@types/react-dom`@^19.2.3) or
alternatively set `@types/react-dom` to ~19.1.x—edit the "@types/react" and
"@types/react-dom" entries accordingly to keep them aligned.
| "projectId": "fa9332a8-896a-4d2a-be5b-d82469b46e5d" | ||
| } | ||
| }, | ||
| "owner": "supserset-sh" |
There was a problem hiding this comment.
Typo in the owner field.
The owner is set to "supserset-sh" but should likely be "superset-sh" (extra 's' removed).
🔤 Proposed fix
- "owner": "supserset-sh"
+ "owner": "superset-sh"📝 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.
| "owner": "supserset-sh" | |
| "owner": "superset-sh" |
🤖 Prompt for AI Agents
In `@apps/mobile/app.json` at line 43, In app.json update the "owner" field value:
locate the JSON key "owner" (currently set to "supserset-sh") and correct the
typo by replacing it with "superset-sh" so the owner string matches the intended
organization name.
| "tailwind": { | ||
| "config": "tailwind.config.js", | ||
| "css": "global.css", | ||
| "baseColor": "neutral", | ||
| "cssVariables": true | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify tailwind.config.js exists in apps/mobile/
fd -t f "tailwind.config" apps/mobile/
# Also check for CSS-based Tailwind config
if [ -f "apps/mobile/global.css" ]; then
echo "=== global.css content (first 30 lines) ==="
cat apps/mobile/global.css | head -30
else
echo "global.css not found"
fi
# Check directory structure of apps/mobile
echo "=== apps/mobile/ directory structure ==="
fd -t f . apps/mobile/ -x basename {} | head -20Repository: superset-sh/superset
Length of output: 1342
Remove or update the tailwind.config.js reference in components.json.
The tailwind.config.js file does not exist in apps/mobile/. The project is correctly using Tailwind CSS v4 with CSS-first configuration—global.css imports Tailwind via @import "tailwindcss" and defines theme variables. The reference to a non-existent config file in components.json may confuse tools or developers. Either remove the config reference or create the file if needed for your setup.
🤖 Prompt for AI Agents
In `@apps/mobile/components.json` around lines 6 - 11, Update the tailwind entry
in components.json to remove the non-existent tailwind.config.js reference:
either delete the "config": "tailwind.config.js" key from the "tailwind" object
in components.json or replace it with a valid config path if you intend to use
one; ensure the "css": "global.css" and "cssVariables": true settings remain
intact so the project continues to use the CSS-first Tailwind v4 setup (refer to
the "tailwind" object and the "config" key when making the change).
| export async function initDatabase() { | ||
| if (db) return db; | ||
|
|
||
| db = await SQLite.openDatabaseAsync("superset.db"); | ||
|
|
||
| // Create todos table | ||
| await db.execAsync(` | ||
| CREATE TABLE IF NOT EXISTS todos ( | ||
| id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
| title TEXT NOT NULL, | ||
| completed INTEGER DEFAULT 0, | ||
| created_at TEXT DEFAULT CURRENT_TIMESTAMP | ||
| ); | ||
| `); | ||
|
|
||
| return db; | ||
| } | ||
|
|
||
| export async function getTodos(): Promise<Todo[]> { | ||
| const database = await initDatabase(); | ||
| const result = await database.getAllAsync<{ | ||
| id: number; | ||
| title: string; | ||
| completed: number; | ||
| created_at: string; | ||
| }>("SELECT * FROM todos ORDER BY created_at DESC"); | ||
|
|
||
| return result.map((row) => ({ | ||
| id: row.id, | ||
| title: row.title, | ||
| completed: Boolean(row.completed), | ||
| createdAt: row.created_at, | ||
| })); | ||
| } | ||
|
|
||
| export async function addTodo(title: string): Promise<Todo> { | ||
| const database = await initDatabase(); | ||
| const result = await database.runAsync( | ||
| "INSERT INTO todos (title) VALUES (?)", | ||
| title, | ||
| ); | ||
|
|
||
| const newTodo = await database.getFirstAsync<{ | ||
| id: number; | ||
| title: string; | ||
| completed: number; | ||
| created_at: string; | ||
| }>("SELECT * FROM todos WHERE id = ?", result.lastInsertRowId); | ||
|
|
||
| if (!newTodo) { | ||
| throw new Error("Failed to create todo"); | ||
| } | ||
|
|
||
| return { | ||
| id: newTodo.id, | ||
| title: newTodo.title, | ||
| completed: Boolean(newTodo.completed), | ||
| createdAt: newTodo.created_at, | ||
| }; | ||
| } | ||
|
|
||
| export async function toggleTodo(id: number): Promise<void> { | ||
| const database = await initDatabase(); | ||
| await database.runAsync( | ||
| "UPDATE todos SET completed = NOT completed WHERE id = ?", | ||
| id, | ||
| ); | ||
| } | ||
|
|
||
| export async function deleteTodo(id: number): Promise<void> { | ||
| const database = await initDatabase(); | ||
| await database.runAsync("DELETE FROM todos WHERE id = ?", id); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if Drizzle ORM is in the project dependencies
find . -name "package.json" -type f | head -5 | xargs grep -l "drizzle" 2>/dev/null || echo "Searching root package.json..."
cat package.json | grep -i drizzleRepository: superset-sh/superset
Length of output: 141
🏁 Script executed:
# Check if packages/db/src/ exists and what's inside
ls -la packages/db/src/ 2>/dev/null | head -20Repository: superset-sh/superset
Length of output: 452
🏁 Script executed:
# Search for existing Drizzle ORM usage patterns in apps directory
rg "from.*drizzle" apps/ --type ts --type tsx -A 2 | head -50Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
# Check the file structure to confirm it's under apps/
ls -la apps/mobile/lib/ | grep databaseRepository: superset-sh/superset
Length of output: 124
🏁 Script executed:
# Check packages/db/src/client.ts to confirm Drizzle setup
cat -n packages/db/src/client.tsRepository: superset-sh/superset
Length of output: 766
🏁 Script executed:
# Search for drizzle imports in apps (without type restriction)
rg "from.*drizzle" apps/ -A 2 | head -50Repository: superset-sh/superset
Length of output: 3908
🏁 Script executed:
# Check root package.json for drizzle
cat package.json | grep -A 5 -B 5 drizzleRepository: superset-sh/superset
Length of output: 46
Replace raw SQL with Drizzle ORM in app code.
This module performs CRUD via raw SQL strings. The repository requires all database operations in apps/**/*.{ts,tsx} to use Drizzle ORM per project standards. Migrate these statements to Drizzle ORM to align with the existing pattern used in other app modules (apps/api, apps/desktop) and the centralized schema in packages/db/src/.
🤖 Prompt for AI Agents
In `@apps/mobile/lib/database.ts` around lines 12 - 84, This module uses raw SQL
in initDatabase, getTodos, addTodo, toggleTodo, and deleteTodo; replace these
with Drizzle ORM calls using the centralized schema from packages/db/src (import
the todos table and db client types), initialize the Drizzle client in
initDatabase (or reuse existing exported db instance) instead of
SQLite.execAsync, rewrite getTodos to run
db.select(todos).orderBy(todos.created_at.desc()), addTodo to use
db.insert(todos).values({ title }).returning(), toggleTodo to use
db.update(todos).set({ completed: sql`NOT ${todos.completed}` }) or fetch
current value then update, and deleteTodo to use
db.delete(todos).where(eq(todos.id, id)); ensure type mappings (completed
boolean, createdAt field) match your Todo type and adjust returned row property
names to createdAt, and remove raw SQL strings while importing helpers (eq, sql)
from drizzle-orm/sqlite as needed.
| import { ScrollView, View } from "react-native"; | ||
| import { Button } from "@/components/ui/button"; | ||
| import { | ||
| Card, | ||
| CardContent, | ||
| CardDescription, | ||
| CardFooter, | ||
| CardHeader, | ||
| CardTitle, | ||
| } from "@/components/ui/card"; | ||
| import { Input } from "@/components/ui/input"; | ||
| import { Switch } from "@/components/ui/switch"; | ||
| import { Text } from "@/components/ui/text"; | ||
| import { signOut, useSession } from "@/lib/auth/client"; | ||
|
|
||
| export default function HomeScreen() { | ||
| const [switchValue, setSwitchValue] = useState(false); | ||
| const [inputValue, setInputValue] = useState(""); | ||
| const { data: session } = useSession(); | ||
|
|
||
| // Redirect to sign in if not authenticated | ||
| if (!session) { | ||
| return <Redirect href="/(auth)/sign-in" />; | ||
| } | ||
|
|
||
| const handleSignOut = async () => { | ||
| await signOut(); | ||
| }; |
There was a problem hiding this comment.
Handle sign-out failures with logging + user feedback.
signOut() errors currently surface as unhandled rejections without context. Add a try/catch with a prefixed log and Alert for the user.
🐛 Proposed fix
-import { ScrollView, View } from "react-native";
+import { Alert, ScrollView, View } from "react-native";
@@
const handleSignOut = async () => {
- await signOut();
+ try {
+ await signOut();
+ } catch (error) {
+ console.error("[home/sign-out] Failed to sign out:", error);
+ Alert.alert(
+ "Sign Out Failed",
+ error instanceof Error ? error.message : String(error),
+ );
+ }
};As per coding guidelines, never swallow errors silently and use prefixed console logs.
📝 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 { ScrollView, View } from "react-native"; | |
| import { Button } from "@/components/ui/button"; | |
| import { | |
| Card, | |
| CardContent, | |
| CardDescription, | |
| CardFooter, | |
| CardHeader, | |
| CardTitle, | |
| } from "@/components/ui/card"; | |
| import { Input } from "@/components/ui/input"; | |
| import { Switch } from "@/components/ui/switch"; | |
| import { Text } from "@/components/ui/text"; | |
| import { signOut, useSession } from "@/lib/auth/client"; | |
| export default function HomeScreen() { | |
| const [switchValue, setSwitchValue] = useState(false); | |
| const [inputValue, setInputValue] = useState(""); | |
| const { data: session } = useSession(); | |
| // Redirect to sign in if not authenticated | |
| if (!session) { | |
| return <Redirect href="/(auth)/sign-in" />; | |
| } | |
| const handleSignOut = async () => { | |
| await signOut(); | |
| }; | |
| import { Alert, ScrollView, View } from "react-native"; | |
| import { Button } from "@/components/ui/button"; | |
| import { | |
| Card, | |
| CardContent, | |
| CardDescription, | |
| CardFooter, | |
| CardHeader, | |
| CardTitle, | |
| } from "@/components/ui/card"; | |
| import { Input } from "@/components/ui/input"; | |
| import { Switch } from "@/components/ui/switch"; | |
| import { Text } from "@/components/ui/text"; | |
| import { signOut, useSession } from "@/lib/auth/client"; | |
| export default function HomeScreen() { | |
| const [switchValue, setSwitchValue] = useState(false); | |
| const [inputValue, setInputValue] = useState(""); | |
| const { data: session } = useSession(); | |
| // Redirect to sign in if not authenticated | |
| if (!session) { | |
| return <Redirect href="/(auth)/sign-in" />; | |
| } | |
| const handleSignOut = async () => { | |
| try { | |
| await signOut(); | |
| } catch (error) { | |
| console.error("[home/sign-out] Failed to sign out:", error); | |
| Alert.alert( | |
| "Sign Out Failed", | |
| error instanceof Error ? error.message : String(error), | |
| ); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In `@apps/mobile/screens/index/HomeScreen.tsx` around lines 3 - 30, Update the
handleSignOut implementation in HomeScreen to catch errors from signOut()
instead of letting unhandled rejections occur: wrap the await signOut() call in
a try/catch, call console.error with a clear prefix (e.g., "HomeScreen: signOut
failed") and the caught error, and show user feedback via an Alert (e.g.,
Alert.alert with a short message) so failures are logged and surfaced to the
user.
| "react": "19.1.0", | ||
| "react-dom": "19.1.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd apps/web && cat -n package.json | head -60Repository: superset-sh/superset
Length of output: 1936
🌐 Web query:
Next.js 16 React 19.1.0 compatibility support
💡 Result:
Short answer: Next.js 16 is compatible with React 19, but React 19.1.0 is affected by a critical RSC remote‑code‑execution vulnerability (CVE‑2025‑55182). Do not run Next.js 16 with unpatched React 19.1.0 in production — upgrade React to one of the patched releases (e.g., 19.1.2) and upgrade Next.js to a patched 16.x release (16.0.7+). [1][2][3]
Sources
- Next.js 16 release/upgrading notes (React 19 support and React Compiler). [1]
- React security advisory — RSC RCE (CVE‑2025‑55182) and patched React releases (19.0.1, 19.1.2, 19.2.1). [2]
- Next.js / Vercel security advisory and patch guidance (Next.js 16 patched releases). [3]
🌐 Web query:
tailwindcss 4.1.18 @tailwindcss/postcss 4.0.9 compatibility
💡 Result:
Yes — @tailwindcss/postcss@4.0.9 is the PostCSS plugin for Tailwind v4 and is compatible with tailwindcss@4.1.18. Install both plus PostCSS (v8.x) and use @tailwindcss/postcss in your PostCSS config. [1][2][3][4]
References
- Tailwind docs: install Tailwind v4 with
@tailwindcss/postcssvia PostCSS. [1] - npm:
@tailwindcss/postcssv4.0.9 release/version page. [2] - npm/jsdocs: tailwindcss v4.1.18 release/version page. [3]
- Notes: Tailwind v4’s PostCSS plugin moved to
@tailwindcss/postcssand requires PostCSS 8.x. [4]
Would you like the exact install commands and a sample postcss.config.js?
🌐 Web query:
@types/react-dom 19.1.0 react-dom version alignment
💡 Result:
Short answer: @types/react-dom@19.1.0 is the TypeScript declarations for react-dom 19.x — you should use it with react-dom 19.x (and the matching @types/react 19.x). See the @types/react-dom package page and common guidance about matching major versions. [1][2]
Sources:
@types/react-domnpm (19.1.0) — package details/peer dependency info. [1]- Community guidance: pick
@typesversions that match your React/TS setup (examples). [2]
Upgrade React 19.1.0 to 19.1.2 immediately — CVE-2025-55182 remote code execution vulnerability in unpatched React 19.1.0. Also align @types/react-dom to ~19.1.x instead of ^19.2.3 to match react-dom 19.1.0. (Tailwindcss 4.1.18 and @tailwindcss/postcss 4.0.9 are compatible; no change needed there.)
🤖 Prompt for AI Agents
In `@apps/web/package.json` around lines 36 - 37, Update package.json to mitigate
CVE-2025-55182 by bumping "react" from 19.1.0 to 19.1.2 and ensure "react-dom"
is also set to 19.1.2 (replace the existing 19.1.0 entries), and align the
`@types` entry for react-dom to a matching ~19.1.x range instead of ^19.2.3; run
package manager install and lockfile update and run tests/build to verify
nothing else breaks.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@plans/mobile-app-structure-comparison.md`:
- Around line 14-65: Add language identifiers to the fenced code blocks that
contain the directory tree examples in the
plans/mobile-app-structure-comparison.md file (replace the opening ``` with
```text or ```tree for each directory layout block so markdownlint MD040 is
satisfied); specifically update each triple-backtick fence that wraps the
directory-layout snippets (the blocks beginning with "apps/mobile/" and the
other two similar tree blocks) to include a language tag like text or tree.
| ``` | ||
| apps/mobile/ | ||
| ├── src/ # Source root | ||
| │ ├── app/ # Expo Router - ROUTING LOGIC ONLY | ||
| │ │ ├── _layout.tsx # Root providers & navigation config (STAYS HERE) | ||
| │ │ ├── index.tsx # Redirect logic only (STAYS HERE) | ||
| │ │ └── (tabs)/ | ||
| │ │ ├── _layout.tsx # Tab navigation config (STAYS HERE) | ||
| │ │ ├── chat/ | ||
| │ │ │ ├── _layout.tsx # Stack navigation config (STAYS HERE) | ||
| │ │ │ ├── index.tsx # exports from screens/ (ROUTING ONLY) | ||
| │ │ │ ├── new.tsx # exports from screens/ (ROUTING ONLY) | ||
| │ │ │ └── [id].tsx # exports from screens/ (ROUTING ONLY) | ||
| │ │ └── today/ | ||
| │ │ └── index.tsx # exports from screens/ (ROUTING ONLY) | ||
| │ │ | ||
| │ ├── screens/ # BUSINESS LOGIC & UI | ||
| │ │ ├── (tabs)/ | ||
| │ │ │ ├── chat/ | ||
| │ │ │ │ ├── chats/ | ||
| │ │ │ │ │ └── ChatListScreen/ | ||
| │ │ │ │ │ ├── ChatListScreen.tsx | ||
| │ │ │ │ │ ├── index.ts | ||
| │ │ │ │ │ └── components/ # Colocated components | ||
| │ │ │ │ │ └── ChatItem/ | ||
| │ │ │ │ │ ├── ChatItem.tsx | ||
| │ │ │ │ │ ├── index.ts | ||
| │ │ │ │ │ └── components/ | ||
| │ │ │ │ │ └── ChatItemRightActions/ | ||
| │ │ │ │ │ ├── ChatItemRightActions.tsx | ||
| │ │ │ │ │ └── index.ts | ||
| │ │ │ │ ├── new/ | ||
| │ │ │ │ │ ├── NewChatScreen.tsx | ||
| │ │ │ │ │ └── index.ts | ||
| │ │ │ │ └── [id]/ | ||
| │ │ │ │ ├── ChatScreen.tsx | ||
| │ │ │ │ └── index.ts | ||
| │ │ │ └── today/ | ||
| │ │ │ └── index/ | ||
| │ │ │ ├── TodayScreen.tsx | ||
| │ │ │ └── index.ts | ||
| │ │ └── components/ # Shared screen components | ||
| │ │ ├── OfflineScreen/ | ||
| │ │ └── PosthogTracker/ | ||
| │ │ | ||
| │ ├── components/ # Global UI components | ||
| │ ├── hooks/ # Shared hooks | ||
| │ ├── providers/ # Context providers | ||
| │ ├── stores/ # State management | ||
| │ ├── utils/ # Utility functions | ||
| │ └── globals.css | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to fenced code blocks.
markdownlint MD040 will flag these fences. Please specify a language (e.g., text or tree for directory layouts).
✅ Suggested fix
-```
+```text(Apply to the fences starting at Lines 14, 68, 283, 318.)
</details>
Also applies to: 68-92, 283-298, 318-344
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
14-14: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In @plans/mobile-app-structure-comparison.md around lines 14 - 65, Add language
identifiers to the fenced code blocks that contain the directory tree examples
in the plans/mobile-app-structure-comparison.md file (replace the opening withtext or ```tree for each directory layout block so markdownlint MD040 is
satisfied); specifically update each triple-backtick fence that wraps the
directory-layout snippets (the blocks beginning with "apps/mobile/" and the
other two similar tree blocks) to include a language tag like text or tree.
</details>
<!-- fingerprinting:phantom:triton:eagle -->
<!-- This is an auto-generated comment by CodeRabbit -->
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/admin/package.json`:
- Around line 46-50: The package.json pins "@types/react" to "~19.1.0" which
conflicts with "@types/react-dom@^19.2.3" that expects "^19.2.0"; update the
"@types/react" entry in package.json to a compatible version (e.g. "^19.2.0" or
matching "^19.2.x") to satisfy the peer requirement, then reinstall dependencies
and regenerate the lockfile (run npm/yarn install) so types and lockfile are
consistent; locate the dependency line for "@types/react" in package.json to
make this change.
In `@apps/mobile/screens/`(auth)/sign-in/SignInScreen.tsx:
- Around line 18-29: Wrap the verbose console.log/console.error calls around the
signIn.social flow with an environment check (e.g., __DEV__) so only
non-sensitive result/error details are printed in development; keep the minimal
console.error("[sign-in] Error caught:", error) for production but move the
JSON.stringify(error, null, 2) and detailed result logging into an if (__DEV__)
block around the signIn.social call results and catch block (references:
signIn.social, setLoading, provider, result, error).
♻️ Duplicate comments (10)
apps/api/package.json (1)
41-42: Align@types/react-domwith react-dom 19.1.0.
@types/react-domis pinned to ^19.2.3 whilereact-domis 19.1.0, which risks type drift and typecheck failures. Consider aligning it to ~19.1.0.🔧 Suggested change
- "@types/react-dom": "^19.2.3", + "@types/react-dom": "~19.1.0",plans/mobile-app-structure-comparison.md (1)
14-14: Add language identifiers to fenced code blocks.The directory tree code blocks are missing language identifiers, which triggers markdownlint MD040. Please specify a language (e.g.,
textortree) for each fence.✅ Suggested fix
-``` +```textApply this change to the opening fences at lines 14, 68, 283, and 318.
Also applies to: 68-68, 283-283, 318-318
apps/desktop/package.json (1)
143-158: Resolve@types/react/@types/react-dompeer mismatch; verify Tailwind plugin compatibility.This repeats a previously flagged issue:
@types/react-dom@^19.2.3requires@types/react^19.2.0, but it’s pinned to~19.1.0. Also confirm@tailwindcss/vite@^4.0.9is compatible withtailwindcss@^4.1.18.🐛 Suggested fix for the types mismatch
- "@types/react": "~19.1.0", + "@types/react": "~19.2.0",#!/bin/bash # Verify `@types/react-dom` peer requirement and Tailwind plugin compatibility. npm view `@types/react-dom`@19.2.3 peerDependencies npm view tailwindcss@4.1.18 peerDependencies npm view `@tailwindcss/vite`@4.0.9 peerDependenciesapps/mobile/app.json (1)
43-43: Fix the Expo owner typo to avoid mis-attribution.The owner value appears misspelled and should match the organization name.
🔧 Proposed fix
- "owner": "supserset-sh" + "owner": "superset-sh"apps/mobile/lib/auth/client.ts (1)
5-10: Avoid silent localhost fallback outside dev.If
EXPO_PUBLIC_API_URLis missing in production, the client will quietly point to localhost, leading to confusing failures. Prefer a dev-only fallback and fail fast in non-dev builds.As per coding guidelines, use prefixed console logs.🔧 Proposed fix
-// Get API URL from env -const API_URL = process.env.EXPO_PUBLIC_API_URL || "http://localhost:3001"; +const LOG_PREFIX = "[auth/client]"; +const API_URL = process.env.EXPO_PUBLIC_API_URL; + +if (!API_URL) { + if (__DEV__) { + console.warn(`${LOG_PREFIX} EXPO_PUBLIC_API_URL not set, using localhost fallback`); + } else { + throw new Error(`${LOG_PREFIX} EXPO_PUBLIC_API_URL must be set in production`); + } +} + +const BASE_URL = API_URL || "http://localhost:3001"; export const authClient = createAuthClient({ - baseURL: API_URL, + baseURL: BASE_URL, plugins: [ expoClient({ scheme: "superset",apps/mobile/package.json (1)
15-17: Pin@electric-sql/clientto an explicit version or workspace reference.An empty version string is brittle and can resolve unpredictably.
🔧 Example fix (adjust to match root resolution)
"dependencies": { "@better-auth/expo": "^1.4.15", - "@electric-sql/client": "", + "@electric-sql/client": "workspace:*",Run this to confirm how the root workspace resolves the package and align the version accordingly:
#!/bin/bash rg -n '"@electric-sql/client"' package.json rg -n '"@electric-sql/client"' -g 'pnpm-lock.yaml' -g 'yarn.lock' -g 'package-lock.json'apps/mobile/global.css (1)
10-12: Remove stray--color-radiustoken.You already define
--radiusin@theme; this looks like a typo/unused variable.🔧 Proposed fix
`@variant` light { - --color-radius: 0.5rem; --color-background: hsl(0 0% 100%);apps/mobile/components/ui/text.tsx (1)
55-61: Avoid untyped casts for web-only roles.
Consider a local type augmentation or inline comment to justify the web-only Role values so typing stays safe.apps/mobile/screens/index/HomeScreen.tsx (1)
21-23: Handle sign-out failures explicitly.
WrapsignOut()in try/catch and surface/log errors so failures aren’t silent. As per coding guidelines, ...apps/mobile/lib/database.ts (1)
12-84: Replace raw SQL with Drizzle ORM.
This module uses raw SQL for schema creation and CRUD; app code should use Drizzle instead. Based on learnings, ...
🧹 Nitpick comments (2)
packages/auth/src/server.ts (1)
32-38: Consolidate redundant Expo origin patterns.The three Expo development patterns are redundant. According to Better Auth's matching behavior,
"exp://"without wildcards uses prefix matching and already matches any URL starting with"exp://"(including all IP ranges, ports, and paths). The patterns"exp://**"and"exp://192.168.*.*:*/**"are unnecessary. Use only"exp://"for clarity and reduced complexity.apps/mobile/app/(auth)/sign-in.tsx (1)
3-3: Prefer direct import to reduce barrel coupling.
Import the screen from its concrete file (e.g.,@/screens/(auth)/sign-in/SignInScreen) to avoid barrel indirection. As per coding guidelines, ...
| "@types/react": "~19.1.0", | ||
| "@types/react-dom": "^19.2.3", | ||
| "babel-plugin-react-compiler": "^1.0.0", | ||
| "dotenv": "^17.2.3", | ||
| "tailwindcss": "^4.0.9", | ||
| "tailwindcss": "^4.1.18", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
npm view `@types/react-dom`@19.2.3 peerDependenciesRepository: superset-sh/superset
Length of output: 93
Align @types/react with @types/react-dom peer requirements.
@types/react-dom@^19.2.3 requires @types/react ^19.2.0, but it's pinned to ~19.1.0. This creates a peer dependency conflict and can break type compatibility.
🐛 Suggested fix
- "@types/react": "~19.1.0",
+ "@types/react": "~19.2.0",📝 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.
| "@types/react": "~19.1.0", | |
| "@types/react-dom": "^19.2.3", | |
| "babel-plugin-react-compiler": "^1.0.0", | |
| "dotenv": "^17.2.3", | |
| "tailwindcss": "^4.0.9", | |
| "tailwindcss": "^4.1.18", | |
| "@types/react": "~19.2.0", | |
| "@types/react-dom": "^19.2.3", | |
| "babel-plugin-react-compiler": "^1.0.0", | |
| "dotenv": "^17.2.3", | |
| "tailwindcss": "^4.1.18", |
🤖 Prompt for AI Agents
In `@apps/admin/package.json` around lines 46 - 50, The package.json pins
"@types/react" to "~19.1.0" which conflicts with "@types/react-dom@^19.2.3" that
expects "^19.2.0"; update the "@types/react" entry in package.json to a
compatible version (e.g. "^19.2.0" or matching "^19.2.x") to satisfy the peer
requirement, then reinstall dependencies and regenerate the lockfile (run
npm/yarn install) so types and lockfile are consistent; locate the dependency
line for "@types/react" in package.json to make this change.
| console.log("[sign-in] Button clicked:", provider); | ||
| try { | ||
| setLoading(provider); | ||
| console.log("[sign-in] Calling signIn.social..."); | ||
| const result = await signIn.social({ | ||
| provider, | ||
| callbackURL: "/", | ||
| }); | ||
| console.log("[sign-in] signIn.social result:", result); | ||
| } catch (error) { | ||
| console.error("[sign-in] Error caught:", error); | ||
| console.error("[sign-in] Error details:", JSON.stringify(error, null, 2)); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat apps/mobile/screens/\(auth\)/sign-in/SignInScreen.tsxRepository: superset-sh/superset
Length of output: 2241
🏁 Script executed:
fd "signIn" --type f -e ts -e tsx | head -20Repository: superset-sh/superset
Length of output: 46
🏁 Script executed:
rg "signIn\.social" -A 10 -B 5 --type ts --type tsx | head -100Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
find . -path "*/lib/auth/client*" -type fRepository: superset-sh/superset
Length of output: 96
🏁 Script executed:
cat lib/auth/client.ts 2>/dev/null || cat lib/auth/client.js 2>/dev/null || find . -name "client.ts" -o -name "client.js" | grep authRepository: superset-sh/superset
Length of output: 126
🏁 Script executed:
rg "export.*signIn" -A 15 -B 2 --type ts --type js | head -150Repository: superset-sh/superset
Length of output: 228
🏁 Script executed:
cat apps/mobile/lib/auth/client.tsRepository: superset-sh/superset
Length of output: 575
🏁 Script executed:
cat packages/auth/src/client.ts | head -200Repository: superset-sh/superset
Length of output: 568
🏁 Script executed:
rg "signIn\.social" -A 5 --type ts --type tsx | head -100Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
rg "better-auth" package.jsonRepository: superset-sh/superset
Length of output: 46
🏁 Script executed:
rg "__DEV__\|NODE_ENV\|isDev" apps/mobile --type ts --type tsx | head -20Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
rg "signIn.social" -A 5 | head -100Repository: superset-sh/superset
Length of output: 3051
🏁 Script executed:
rg "__DEV__|NODE_ENV" apps/mobile | head -20Repository: superset-sh/superset
Length of output: 46
🏁 Script executed:
cat package.json | grep -A 5 "better-auth"Repository: superset-sh/superset
Length of output: 46
🏁 Script executed:
rg "better-auth" apps/mobile/package.json 2>/dev/null || rg "better-auth" package.jsonRepository: superset-sh/superset
Length of output: 124
🏁 Script executed:
rg "import.*better-auth" --type ts | head -20Repository: superset-sh/superset
Length of output: 848
🏁 Script executed:
find . -type f -name "*.json" | xargs grep -l "better-auth" 2>/dev/null | head -5Repository: superset-sh/superset
Length of output: 192
🏁 Script executed:
rg "const result" apps/mobile --type ts -B 3 -A 3 | head -50Repository: superset-sh/superset
Length of output: 1384
🏁 Script executed:
web_search
better-auth signIn.social return type response tokensRepository: superset-sh/superset
Length of output: 164
🌐 Web query:
better-auth signIn.social return type response tokens sensitive data
💡 Result:
Short answer — authClient.signIn.social returns a client response object (typically { data, error }) and does NOT hand you the social provider's raw access/refresh tokens in that response for the normal redirect flow. Instead:
-
For the normal redirect flow you get a response with data.url (the provider redirect URL) or an object indicating success; the provider tokens are exchanged/kept server-side and session cookies are set by Better Auth. Sensitive provider tokens are not exposed to the client in that response. [1][2]
-
If you use the idToken / idToken.accessToken option (client obtains the provider token and you send it to Better Auth), you supply the token to signIn.social so the server can validate it; the call still does not return raw provider credentials back to the client — the server uses them to create the session. [2]
-
The client API uses the { data, error } pattern and also supports asResponse/asResponse-style options for lower-level responses; check for data.url when using disableRedirect or proxy flows. [1][3]
If you want exact TypeScript types or the full response shape, point me to the version of better-auth you’re using (package version) and I’ll fetch the precise client types.
Sources: Better Auth docs (Basic Usage / Social Sign-On, Google social idToken example) and client reference. [1] [2] [3]
References
[1] Better Auth — Basic Usage / Social Sign‑On.
[2] Better Auth — Google social sign‑in (idToken example).
[3] Better Auth docs — client response shape ({ data, error }, asResponse, data.url).
🏁 Script executed:
rg "console.log|console.error" apps/mobile/screens --type ts -B 2 -A 1 | head -80Repository: superset-sh/superset
Length of output: 1295
Guard verbose logging with environment checks.
The signIn.social() response does not expose raw OAuth tokens (better-auth keeps provider tokens server-side), but the result and error objects may contain user data or error details that shouldn't be logged in production. Wrap the detailed logging statements with __DEV__ or environment checks, while keeping basic error logging for debugging:
if (__DEV__) {
console.log("[sign-in] signIn.social result:", result);
console.error("[sign-in] Error details:", JSON.stringify(error, null, 2));
}
🤖 Prompt for AI Agents
In `@apps/mobile/screens/`(auth)/sign-in/SignInScreen.tsx around lines 18 - 29,
Wrap the verbose console.log/console.error calls around the signIn.social flow
with an environment check (e.g., __DEV__) so only non-sensitive result/error
details are printed in development; keep the minimal console.error("[sign-in]
Error caught:", error) for production but move the JSON.stringify(error, null,
2) and detailed result logging into an if (__DEV__) block around the
signIn.social call results and catch block (references: signIn.social,
setLoading, provider, result, error).
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/auth/package.json`:
- Around line 21-26: Replace the non-existent dependency version for the
`@better-auth/expo` entry in package.json: locate the "@better-auth/expo"
dependency and update its version string from "1.4.16" to a published version
(e.g., a 1.3.x release such as "1.3.8-beta.4" or another confirmed npm version)
so installs won't fail; ensure the updated version matches the package registry
and run a quick install to verify.
♻️ Duplicate comments (3)
apps/api/package.json (1)
41-42: Align@types/react-domto match@types/reactat~19.1.0.
@types/reactis pinned to~19.1.0but@types/react-domremains at^19.2.3. This version mismatch can cause TypeScript/JSX type conflicts since react-dom types 19.2.x expect React types from the 19.2.x line.Suggested fix
"@types/react": "~19.1.0", - "@types/react-dom": "^19.2.3", + "@types/react-dom": "~19.1.0",apps/docs/package.json (1)
37-38: Align@types/react-domto match@types/reactat~19.1.0.Same issue as in
apps/api/package.json:@types/reactis~19.1.0while@types/react-domis^19.2.3. Update to~19.1.0for consistency.Suggested fix
"@types/react": "~19.1.0", - "@types/react-dom": "^19.2.3", + "@types/react-dom": "~19.1.0",apps/desktop/package.json (1)
143-144: Update@types/reactto align with@types/react-dompeer dependency.
@types/reactat~19.1.0is incompatible with@types/react-dom@^19.2.3, which requires@types/react^19.2.0as a peer dependency. Either update@types/reactto~19.2.0or downgrade@types/react-domto a version compatible with the 19.1.x types.🛠️ Suggested fix
Option 1 (Preferred): Update
@types/reactto match@types/react-dompeer requirement:- "@types/react": "~19.1.0", + "@types/react": "~19.2.0",Option 2: Downgrade
@types/react-domto align with React 19.1.0:- "@types/react-dom": "^19.2.3", + "@types/react-dom": "~19.1.0",
🧹 Nitpick comments (3)
packages/auth/tsconfig.json (1)
4-5: Reasonable workaround for dependency type conflicts.Adding
skipLibCheck: trueto resolve the Better-Auth/Expo duplicate type conflicts is a pragmatic fix. This is a common pattern when dealing with complex dependency graphs that have conflicting.d.tsfiles.Consider adding a brief comment above this option explaining why it's needed, so future maintainers know it can potentially be removed if upstream type conflicts are resolved.
apps/mobile/lib/env.ts (1)
16-24: Consider wrapping parse with a descriptive error for better DX.If
EXPO_PUBLIC_API_URLis missing, Zod throws a generic validation error. Adding a try-catch with a clearer message would help developers troubleshoot faster.Optional improvement
-export const env = envSchema.parse({ +const parsed = envSchema.safeParse({ NODE_ENV: process.env.NODE_ENV as unknown, EXPO_PUBLIC_API_URL: process.env.EXPO_PUBLIC_API_URL as unknown, EXPO_PUBLIC_WEB_URL: process.env.EXPO_PUBLIC_WEB_URL as unknown, EXPO_PUBLIC_DEEP_LINK_SCHEME: process.env .EXPO_PUBLIC_DEEP_LINK_SCHEME as unknown, EXPO_PUBLIC_DEEP_LINK_DOMAIN: process.env .EXPO_PUBLIC_DEEP_LINK_DOMAIN as unknown, }); + +if (!parsed.success) { + console.error("[env] Invalid environment configuration:", parsed.error.flatten()); + throw new Error("[env] Missing or invalid environment variables. Check EXPO_PUBLIC_API_URL is set."); +} + +export const env = parsed.data;apps/mobile/lib/base-url.ts (1)
34-39: Consider using URL object consistently for hostname replacement.Creating a URL object but then using
string.replace()could miss edge cases (e.g., hostname appearing in path). Using the URL object's properties directly would be more robust.More robust URL manipulation
if (devServerIp) { const urlObj = new URL(apiUrl); - const replacedUrl = apiUrl.replace(urlObj.hostname, devServerIp); + urlObj.hostname = devServerIp; + const replacedUrl = urlObj.toString().replace(/\/$/, ""); console.log( `[base-url] Auto-detected dev server IP: ${devServerIp}, using ${replacedUrl}`, ); return replacedUrl; }
| "@better-auth/expo": "1.4.16", | ||
| "@superset/db": "workspace:*", | ||
| "@superset/shared": "workspace:*", | ||
| "@t3-oss/env-core": "^0.13.8", | ||
| "@t3-oss/env-nextjs": "^0.13.8", | ||
| "better-auth": "^1.4.9", | ||
| "better-auth": "1.4.16", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify both better-auth packages exist at version 1.4.16
echo "Checking better-auth@1.4.16..."
curl -s "https://registry.npmjs.org/better-auth/1.4.16" | jq -r '.version // "NOT FOUND"'
echo "Checking `@better-auth/expo`@1.4.16..."
curl -s "https://registry.npmjs.org/@better-auth%2Fexpo/1.4.16" | jq -r '.version // "NOT FOUND"'Repository: superset-sh/superset
Length of output: 184
🌐 Web query:
better-auth@1.4.16 npm package version
💡 Result:
Yes — better-auth version 1.4.16 is published. You can install it with:
npm install better-auth@1.4.16. [1][2]
Sources:
- Release/archive (tarball) listing for better-auth 1.4.16. [1]
- Snyk / package metadata showing latest 1.4.16. [2]
🌐 Web query:
@better-auth/expo@1.4.16 npm package version
💡 Result:
I couldn't find @better-auth/expo published on npm as version 1.4.16. The Better Auth monorepo has a 1.4.16 release archive, but the @better-auth/expo package versions published to npm appear to be in the 1.0–1.3 range (examples: 1.3.0-beta.11 / 1.3.8-beta.4). [1][2]
Sources:
- npm package pages for
@better-auth/expo(published versions). [1] - better-auth v1.4.16 archive (monorepo release contents). [2]
Fix @better-auth/expo version: 1.4.16 does not exist on npm.
better-auth@1.4.16 is published and valid, but @better-auth/expo@1.4.16 does not exist on npm. Published versions of @better-auth/expo are in the 1.0–1.3 range (e.g., 1.3.8-beta.4). Update line 21 to a version that actually exists on npm to prevent install failures.
🤖 Prompt for AI Agents
In `@packages/auth/package.json` around lines 21 - 26, Replace the non-existent
dependency version for the `@better-auth/expo` entry in package.json: locate the
"@better-auth/expo" dependency and update its version string from "1.4.16" to a
published version (e.g., a 1.3.x release such as "1.3.8-beta.4" or another
confirmed npm version) so installs won't fail; ensure the updated version
matches the package registry and run a quick install to verify.
- Add zod-based env validation in lib/env.ts for type-safe environment variables - Implement auto dev server IP detection in lib/base-url.ts following T3 pattern - Automatically replaces localhost with Expo dev server IP in development - Fails fast if localhost is used in production - Logs auto-detected IP for debugging - Update auth client to use getBaseUrl() for automatic localhost handling - Remove unused database.ts and expo-sqlite dependency - Remove inline comments from theme.ts - Add @types/node for TypeScript process.env support - Update uniwind types (auto-generated)
- Add @react-navigation/native dependency to mobile app - Update better-auth packages to 1.4.16 for consistency - Add skipLibCheck to auth package to work around bun cache path issues - Clear and reinstall node_modules/.bun to resolve duplicate dependency caches - Format uniwind-types.d.ts This fixes TypeScript errors caused by bun caching multiple versions of drizzle-orm and @better-auth/core with different hashes, which prevented portable type references.
- Update @tanstack/db from ^0.5.16 to 0.5.22 - Add ts-expect-error for RefLeaf<string> comparison type inference issue - Add null check before querying members - Remove unnecessary comment from mobile app/index.tsx The TanStack DB eq() function has a type inference issue when comparing a RefLeaf<string> (column reference) to a string literal in where clauses. The functionality works correctly at runtime per TanStack DB docs, but TypeScript can't match the overload signatures. Added @ts-expect-error with explanation.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/mobile/app/`(auth)/sign-in.tsx:
- Around line 5-12: The SignInRoute is not checking useSession's isPending flag,
causing a flicker of SignInScreen during hydration; update SignInRoute to
destructure isPending from useSession (e.g., const { data: session, isPending }
= useSession()) and return early (null or a loader) while isPending is true,
then keep the existing session check to Redirect to "/" when session exists
before rendering SignInScreen; modify the function containing SignInRoute, which
renders SignInScreen and Redirect, to implement this gating behavior.
In `@apps/mobile/components/ui/text.tsx`:
- Around line 73-93: The Text component currently ignores refs; wrap the
functional component with React.forwardRef and accept a ref parameter (e.g.,
function Text(props, ref) or const Text = React.forwardRef(function Text(props,
ref) { ... } ) ), keep the existing props/types (including
React.RefAttributes<RNText>), and pass the ref through to the rendered Component
(Component ref={ref}). Update the exported symbol (Text) to be the forwarded-ref
version so consumers can attach refs to RNText.
♻️ Duplicate comments (4)
apps/desktop/package.json (1)
143-144: Peer dependency mismatch between@types/reactand@types/react-dom.
@types/react-dom@^19.2.3requires@types/reactversion^19.2.0as a peer dependency, but line 143 pins@types/reactto~19.1.0. This will cause peer dependency warnings and potential type incompatibilities.Update
@types/reactto~19.2.0to satisfy the peer dependency constraint, or downgrade@types/react-domto a 19.1.x version.plans/mobile-app-structure-comparison.md (1)
14-14: Add language identifiers to fenced code blocks.The fenced code blocks at lines 14, 68, 283, and 318 are missing language identifiers, which violates markdownlint MD040. Specify
textortreefor directory layout blocks.✅ Suggested fix
Apply to all four blocks:
-``` +```textAlso applies to: 68-68, 283-283, 318-318
apps/mobile/components/ui/text.tsx (1)
55-62: Web-only role casts still bypass RN Role typing.
This was already called out in a previous review; keeping it here as a duplicate reminder.packages/auth/package.json (1)
21-26: Verify@better-auth/expo@1.4.16is published (install blocker if not).Earlier review notes flagged this version as unpublished; if that’s still true, installs will fail. Please confirm the version exists and is compatible with
better-auth@1.4.16, and adjust to a published release if needed.#!/bin/bash # Verify versions exist on npm registry curl -s "https://registry.npmjs.org/better-auth/1.4.16" | jq -r '.version // "NOT FOUND"' curl -s "https://registry.npmjs.org/@better-auth%2Fexpo/1.4.16" | jq -r '.version // "NOT FOUND"'
🧹 Nitpick comments (3)
apps/mobile/lib/theme.ts (1)
3-45: Extract shared token literals to top-level constants.
Several values (surface/foreground/muted/border and radius) are repeated across light/dark; centralizing them reduces drift and aligns with repo guidance. As per coding guidelines, extract hardcoded values to named constants.♻️ Suggested refactor
import { DarkTheme, DefaultTheme, type Theme } from "@react-navigation/native"; +const RADIUS = "0.5rem"; +const LIGHT_SURFACE = "hsl(0 0% 100%)"; +const LIGHT_FOREGROUND = "hsl(240 10% 3.9%)"; +const LIGHT_MUTED = "hsl(240 4.8% 95.9%)"; +const LIGHT_BORDER = "hsl(240 5.9% 90%)"; +const DARK_SURFACE = "hsl(240 10% 3.9%)"; +const DARK_FOREGROUND = "hsl(0 0% 98%)"; +const DARK_MUTED = "hsl(240 3.7% 15.9%)"; + export const THEME = { light: { - background: "hsl(0 0% 100%)", - foreground: "hsl(240 10% 3.9%)", - card: "hsl(0 0% 100%)", - cardForeground: "hsl(240 10% 3.9%)", - popover: "hsl(0 0% 100%)", - popoverForeground: "hsl(240 10% 3.9%)", + background: LIGHT_SURFACE, + foreground: LIGHT_FOREGROUND, + card: LIGHT_SURFACE, + cardForeground: LIGHT_FOREGROUND, + popover: LIGHT_SURFACE, + popoverForeground: LIGHT_FOREGROUND, primary: "hsl(240 5.9% 10%)", primaryForeground: "hsl(0 0% 98%)", - secondary: "hsl(240 4.8% 95.9%)", + secondary: LIGHT_MUTED, secondaryForeground: "hsl(240 5.9% 10%)", - muted: "hsl(240 4.8% 95.9%)", + muted: LIGHT_MUTED, mutedForeground: "hsl(240 3.8% 46.1%)", - accent: "hsl(240 4.8% 95.9%)", + accent: LIGHT_MUTED, accentForeground: "hsl(240 5.9% 10%)", destructive: "hsl(0 84.2% 60.2%)", - border: "hsl(240 5.9% 90%)", - input: "hsl(240 5.9% 90%)", + border: LIGHT_BORDER, + input: LIGHT_BORDER, ring: "hsl(240 5.9% 10%)", - radius: "0.5rem", + radius: RADIUS, }, dark: { - background: "hsl(240 10% 3.9%)", - foreground: "hsl(0 0% 98%)", - card: "hsl(240 10% 3.9%)", - cardForeground: "hsl(0 0% 98%)", - popover: "hsl(240 10% 3.9%)", - popoverForeground: "hsl(0 0% 98%)", + background: DARK_SURFACE, + foreground: DARK_FOREGROUND, + card: DARK_SURFACE, + cardForeground: DARK_FOREGROUND, + popover: DARK_SURFACE, + popoverForeground: DARK_FOREGROUND, primary: "hsl(0 0% 98%)", primaryForeground: "hsl(240 5.9% 10%)", - secondary: "hsl(240 3.7% 15.9%)", + secondary: DARK_MUTED, secondaryForeground: "hsl(0 0% 98%)", - muted: "hsl(240 3.7% 15.9%)", + muted: DARK_MUTED, mutedForeground: "hsl(240 5% 64.9%)", - accent: "hsl(240 3.7% 15.9%)", + accent: DARK_MUTED, accentForeground: "hsl(0 0% 98%)", destructive: "hsl(0 62.8% 30.6%)", - border: "hsl(240 3.7% 15.9%)", - input: "hsl(240 3.7% 15.9%)", + border: DARK_MUTED, + input: DARK_MUTED, ring: "hsl(240 4.9% 83.9%)", - radius: "0.5rem", + radius: RADIUS, }, };apps/mobile/app/(auth)/sign-in.tsx (1)
3-3: Prefer concrete import over barrel export.Guidelines recommend importing the file directly to avoid barrel‑induced cycles.
♻️ Proposed change
-import SignInScreen from "@/screens/(auth)/sign-in"; +import SignInScreen from "@/screens/(auth)/sign-in/SignInScreen";apps/mobile/lib/auth/client.ts (1)
9-16: Extract magic string values to module constants.The hardcoded
"superset"values should be extracted to named constants at the top of the module for consistency and to avoid drift.♻️ Proposed refactor
+const AUTH_SCHEME = "superset"; +const AUTH_STORAGE_PREFIX = "superset"; + export const authClient = createAuthClient({ baseURL: BASE_URL, plugins: [ expoClient({ - scheme: "superset", - storagePrefix: "superset", + scheme: AUTH_SCHEME, + storagePrefix: AUTH_STORAGE_PREFIX, storage: SecureStore, }), ], });
| export default function SignInRoute() { | ||
| const { data: session } = useSession(); | ||
|
|
||
| if (session) { | ||
| return <Redirect href="/" />; | ||
| } | ||
|
|
||
| return <SignInScreen />; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
better-auth useSession hook loading status documentation
💡 Result:
Summary — useSession loading status
- The useSession hook (from the React client) returns an isPending boolean that represents the loading state (true while session fetch is pending). [1] (better-auth.com)
- Example return shape shown in the docs: { data: session, isPending, error, refetch }. Use isPending to show loading UI. [2] (better-auth.com)
- Note: there are open GitHub issues about isPending/hydration and cases where useSession doesn’t update automatically after server-side auth changes — these can cause isPending or session state to behave unexpectedly in some SSR/React 19 setups. Check the linked issues if you see stale or always-true isPending. [3] (github.com)
Sources
- Better Auth docs — Basic Usage (useSession example). [1] (better-auth.com)
- Better Auth docs — Client / Hooks (useSession usage). [2] (better-auth.com)
- GitHub issues discussing isPending/hydration and useSession update problems. [3] (github.com)
Do you want the exact code snippet from the docs or links to the issues?
Citations:
- 1: https://www.better-auth.com/docs/basic-usage?utm_source=openai
- 2: https://www.better-auth.com/docs/concepts/client?utm_source=openai
- 3: useSession runs on server & produces hydration errors better-auth/better-auth#2462
- 4: https://www.better-auth.com/docs/basic-usage?utm_source=openai
- 5: https://www.better-auth.com/docs/concepts/client?utm_source=openai
- 6: useSession runs on server & produces hydration errors better-auth/better-auth#2462
🏁 Script executed:
# Search for useSession usage in the codebase
rg "useSession" --type tsx --type ts -B 2 -A 5Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
# Look for isPending usage specifically
rg "isPending" --type tsx --type ts -B 2 -A 2Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
# Check if there are other auth route files for comparison
fd "auth|sign" --type f -e tsx -e tsRepository: superset-sh/superset
Length of output: 897
🏁 Script executed:
# Search for useSession usage
rg "useSession" -B 2 -A 5Repository: superset-sh/superset
Length of output: 16935
🏁 Script executed:
# Search for isPending usage
rg "isPending" -B 2 -A 2Repository: superset-sh/superset
Length of output: 47630
🏁 Script executed:
# Read the sign-in route file
cat -n apps/mobile/app/\(auth\)/sign-in.tsxRepository: superset-sh/superset
Length of output: 458
🏁 Script executed:
# Read the SignInScreen component
cat -n apps/mobile/screens/\(auth\)/sign-in/SignInScreen.tsxRepository: superset-sh/superset
Length of output: 2794
Gate on isPending to prevent sign-in screen flicker during hydration.
The useSession() hook returns an isPending flag that's true while the session is loading. Without checking it, this route may briefly render the sign-in screen before redirecting an already-authenticated user. Use the isPending flag to avoid this flicker:
const { data: session, isPending } = useSession();
if (isPending) {
return null; // or a loading indicator
}
if (session) {
return <Redirect href="/" />;
}
return <SignInScreen />;The desktop app implements this pattern correctly in apps/desktop/src/renderer/routes/sign-in/page.tsx.
🤖 Prompt for AI Agents
In `@apps/mobile/app/`(auth)/sign-in.tsx around lines 5 - 12, The SignInRoute is
not checking useSession's isPending flag, causing a flicker of SignInScreen
during hydration; update SignInRoute to destructure isPending from useSession
(e.g., const { data: session, isPending } = useSession()) and return early (null
or a loader) while isPending is true, then keep the existing session check to
Redirect to "/" when session exists before rendering SignInScreen; modify the
function containing SignInRoute, which renders SignInScreen and Redirect, to
implement this gating behavior.
| function Text({ | ||
| className, | ||
| asChild = false, | ||
| variant = "default", | ||
| ...props | ||
| }: React.ComponentProps<typeof RNText> & | ||
| TextVariantProps & | ||
| React.RefAttributes<RNText> & { | ||
| asChild?: boolean; | ||
| }) { | ||
| const textClass = React.useContext(TextClassContext); | ||
| const Component = asChild ? Slot.Text : RNText; | ||
| return ( | ||
| <Component | ||
| className={cn(textVariants({ variant }), textClass, className)} | ||
| role={variant ? ROLE[variant] : undefined} | ||
| aria-level={variant ? ARIA_LEVEL[variant] : undefined} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n apps/mobile/components/ui/text.tsxRepository: superset-sh/superset
Length of output: 3181
🏁 Script executed:
rg -A 5 "Slot\.Text" apps/mobile/components/ui/Repository: superset-sh/superset
Length of output: 516
🌐 Web query:
@rn-primitives/slot Slot.Text ref forwarding support
💡 Result:
Short answer: No — Slot.Text itself does not provide special ref-forwarding; it merges and passes props to its child but doesn't convert a forwarded ref into a child's ref for you. If you need a forwarded ref on a slottable primitive, use the library's ref helpers (e.g., useAugmentedRef / forwardRef in your wrapper) to attach/compose refs. See the Slot docs and the hooks (useAugmentedRef) docs. [1][2][3]
Sources
- Slot primitive docs (usage/props). [1]
- Hooks docs — useAugmentedRef (for composing/using forwarded refs). [2]
- rn-primitives GitHub (primitives include slot + hooks). [3]
Forward refs using React.forwardRef; current implementation silently ignores them.
React.RefAttributes<RNText> is declared in the type signature (line 80), but Text is not wrapped in forwardRef. Spreading {...props} does not forward the special ref prop—it is filtered out by React. This means any refs passed by consumers are dropped.
Proposed fix
- function Text({
- className,
- asChild = false,
- variant = "default",
- ...props
- }: React.ComponentProps<typeof RNText> &
- TextVariantProps &
- React.RefAttributes<RNText> & {
- asChild?: boolean;
- }) {
- const textClass = React.useContext(TextClassContext);
- const Component = asChild ? Slot.Text : RNText;
- return (
- <Component
- className={cn(textVariants({ variant }), textClass, className)}
- role={variant ? ROLE[variant] : undefined}
- aria-level={variant ? ARIA_LEVEL[variant] : undefined}
- {...props}
- />
- );
- }
+ const Text = React.forwardRef<
+ RNText,
+ React.ComponentProps<typeof RNText> &
+ TextVariantProps & {
+ asChild?: boolean;
+ }
+ >(function Text(
+ { className, asChild = false, variant = "default", ...props },
+ ref,
+ ) {
+ const textClass = React.useContext(TextClassContext);
+ const Component = asChild ? Slot.Text : RNText;
+ return (
+ <Component
+ ref={ref}
+ className={cn(textVariants({ variant }), textClass, className)}
+ role={variant ? ROLE[variant] : undefined}
+ aria-level={variant ? ARIA_LEVEL[variant] : undefined}
+ {...props}
+ />
+ );
+ });
+
+ Text.displayName = "Text";📝 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.
| function Text({ | |
| className, | |
| asChild = false, | |
| variant = "default", | |
| ...props | |
| }: React.ComponentProps<typeof RNText> & | |
| TextVariantProps & | |
| React.RefAttributes<RNText> & { | |
| asChild?: boolean; | |
| }) { | |
| const textClass = React.useContext(TextClassContext); | |
| const Component = asChild ? Slot.Text : RNText; | |
| return ( | |
| <Component | |
| className={cn(textVariants({ variant }), textClass, className)} | |
| role={variant ? ROLE[variant] : undefined} | |
| aria-level={variant ? ARIA_LEVEL[variant] : undefined} | |
| {...props} | |
| /> | |
| ); | |
| } | |
| const Text = React.forwardRef< | |
| RNText, | |
| React.ComponentProps<typeof RNText> & | |
| TextVariantProps & { | |
| asChild?: boolean; | |
| } | |
| >(function Text( | |
| { className, asChild = false, variant = "default", ...props }, | |
| ref, | |
| ) { | |
| const textClass = React.useContext(TextClassContext); | |
| const Component = asChild ? Slot.Text : RNText; | |
| return ( | |
| <Component | |
| ref={ref} | |
| className={cn(textVariants({ variant }), textClass, className)} | |
| role={variant ? ROLE[variant] : undefined} | |
| aria-level={variant ? ARIA_LEVEL[variant] : undefined} | |
| {...props} | |
| /> | |
| ); | |
| }); | |
| Text.displayName = "Text"; |
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/text.tsx` around lines 73 - 93, The Text component
currently ignores refs; wrap the functional component with React.forwardRef and
accept a ref parameter (e.g., function Text(props, ref) or const Text =
React.forwardRef(function Text(props, ref) { ... } ) ), keep the existing
props/types (including React.RefAttributes<RNText>), and pass the ref through to
the rendered Component (Component ref={ref}). Update the exported symbol (Text)
to be the forwarded-ref version so consumers can attach refs to RNText.
Summary
Reanimated doesn't work yet, has some hacky stuff, but is at least a good checkpoint to build from.
Changes
Better-Auth Expo Integration ✅
expo()server plugin import - changed frombetter-auth/pluginsto@better-auth/expo(this was the critical bug causing 403 errors)@better-auth/expodependency topackages/authtrustedOrigins:exp://- Trust all Expo URLs (prefix matching)exp://**- Trust all Expo URLs (wildcard matching)exp://192.168.*.*:*/**- Trust local IP ranges with any portbiome.jsonfrom mobile app (Biome runs at root level only per monorepo guidelines)Mobile App Structure Refactoring ✅
screens/directory that mirrorsapp/structure 1:1screens/with proper colocation support:screens/RootLayout/RootLayout.tsx(fromapp/_layout.tsx)screens/index/HomeScreen.tsx(fromapp/index.tsx)screens/(auth)/sign-in/SignInScreen.tsx(fromapp/(auth)/sign-in.tsx)app/files to just export fromscreens/directoryindex.ts) for each screen directoryscreens/can be properly colocated with their dependencies following monorepo guidelinesTest Plan
Configuration Verified
expo()plugin from correct import pathexpoClientwith correct scheme ("superset")unstable_enablePackageExports = truesuperset://) and development (exp://) patternsScreenshots
OAuth redirect URLs are being generated successfully (see Expo dev server logs).
Summary by CodeRabbit
New Features
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.