React Native
@potalab/base/rn re-exports everything from @potalab/base and adds native session storage, background-aware token refresh and PKCE that works without crypto.subtle (Hermes). Native modules are passed in by your app, so the package has no hard native dependency.
npx expo install expo-secure-store expo-crypto expo-web-browserpnpm add @potalab/baseimport { AppState } from "react-native"import * as SecureStore from "expo-secure-store"import * as ExpoCrypto from "expo-crypto"import { createClient, secureStoreAdapter, expoCrypto } from "@potalab/base/rn"import type { Database } from "./db"
export const base = createClient<Database>({ url: process.env.EXPO_PUBLIC_POTALAB_BASE_URL!, key: process.env.EXPO_PUBLIC_POTALAB_BASE_KEY!, auth: { storage: secureStoreAdapter(SecureStore), crypto: expoCrypto(ExpoCrypto) }, appState: AppState, // pauses refresh in the background, refreshes on return if due})import "react-native-get-random-values" // must be the first importimport AsyncStorage from "@react-native-async-storage/async-storage"import { AppState } from "react-native"import { createClient, asyncStorageAdapter } from "@potalab/base/rn"
export const base = createClient({ url, key, auth: { storage: asyncStorageAdapter(AsyncStorage) }, appState: AppState,})OAuth, SSO and magic links
Section titled “OAuth, SSO and magic links”Open the provider in an in-app browser and parse the callback:
import * as WebBrowser from "expo-web-browser"import { parseAuthCallback } from "@potalab/base/rn"
const redirectTo = "myapp://auth/callback"const { data } = await base.auth.signInWithOAuth({ provider: "google", redirectTo, skipBrowserRedirect: true })const res = await WebBrowser.openAuthSessionAsync(data.url!, redirectTo)if (res.type === "success") { const { code, error } = parseAuthCallback(res.url) if (code) await base.auth.exchangeCodeForSession(code)}redirectTo must be on the project’s redirect allowlist. Custom app schemes such as myapp://auth are allowed.
What it handles
Section titled “What it handles”- PKCE without
crypto.subtle:expoCrypto(), or the globalgetRandomValueswith a pure-JS SHA-256. expo-secure-storekeys are sanitized and values over about 2 KB are split into chunks.- The client avoids
URL.hostandURL.searchParams.set, which React Native’sURLpolyfill rejects. - Realtime uses React Native’s global
WebSocket. - The returned client has a
dispose()method to stop its timers and listeners.