@rebasepro/client 0.9.1-canary.ff338b5 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","names":[],"sources":["../src/reviver.ts","../src/transport.ts","../src/auth.ts","../src/admin.ts","../src/cron.ts","../src/backups.ts","../src/api-keys.ts","../src/sdk_query_builder.ts","../src/collection.ts","../src/functions.ts","../src/storage.ts","../src/storage-registry.ts","../src/websocket.ts","../src/realtime-channel.ts","../src/index.ts"],"sourcesContent":["import { EntityReference, EntityRelation, GeoPoint, Vector } from \"@rebasepro/types\";\n\nexport function rebaseReviver(_key: string, value: unknown): unknown {\n if (value && typeof value === \"object\" && \"__type\" in value) {\n const record = value as Record<string, unknown>;\n switch (record.__type) {\n case \"date\":\n case \"Date\": {\n if (typeof record.value !== \"string\") {\n return value;\n }\n const date = new Date(record.value);\n return isNaN(date.getTime()) ? null : date;\n }\n case \"reference\":\n case \"EntityReference\":\n return new EntityReference({\n id: String(record.id),\n path: record.path as string,\n driver: record.driver as string | undefined,\n databaseId: record.databaseId as string | undefined\n });\n case \"relation\":\n case \"EntityRelation\":\n return new EntityRelation(\n record.id as string | number,\n record.path as string,\n record.data as Record<string, unknown> | undefined\n );\n case \"GeoPoint\":\n return new GeoPoint(record.latitude as number, record.longitude as number);\n case \"Vector\":\n return new Vector(record.value as number[]);\n default:\n return value;\n }\n }\n return value;\n}\n","import { FindParams as TypesFindParams, FindResponse as TypesFindResponse, RebaseApiError } from \"@rebasepro/types\";\nimport { serializeFilter, serializeLogicalCondition, serializeOrderBy } from \"@rebasepro/common\";\nimport { rebaseReviver } from \"./reviver\";\n\n// The canonical client error now lives in `@rebasepro/types` so every package\n// (client, auth, …) throws one type. Re-exported here to preserve the historical\n// `import { RebaseApiError } from \".../transport\"` path used across the SDK.\nexport { RebaseApiError } from \"@rebasepro/types\";\nexport type { RebaseErrorInit } from \"@rebasepro/types\";\n\nexport interface RebaseClientConfig {\n /**\n * Origin of the Rebase server — scheme, host and port **only**.\n *\n * {@link apiPath} is appended to this, so do not include it here:\n * `\"http://localhost:3001\"` is correct, while `\"http://localhost:3001/api\"`\n * silently builds `/api/api/…` and every request 404s. Omit entirely for\n * same-origin requests from the browser.\n */\n baseUrl?: string;\n /**\n * Bearer token sent as `Authorization` on every request.\n *\n * In the browser this is the signed-in user's access token, so row-level\n * security applies. Server-side callers — scripts, cron jobs, ETL — pass the\n * service key instead, which resolves to `{ uid: \"service\", roles: [\"admin\"] }`\n * and **bypasses RLS**: there is no user to constrain those queries, so scope\n * them explicitly.\n */\n token?: string;\n /**\n * Path the API is mounted under, appended to {@link baseUrl}.\n * Defaults to `\"/api\"`; override only if the server mounts it elsewhere.\n */\n apiPath?: string;\n fetch?: typeof globalThis.fetch;\n onUnauthorized?: () => Promise<boolean>;\n websocketUrl?: string; // Optional real-time WebSocket connection\n /**\n * Open the realtime WebSocket. **Defaults to `true`.**\n *\n * The socket connects as soon as the client is constructed and keeps the\n * Node event loop alive, so a one-shot script (CLI, cron job, ETL) will not\n * exit on its own. Set this to `false` for any process that reads or writes\n * and then terminates — `.listen()` and `.listenById()` then throw instead\n * of silently doing nothing.\n *\n * Long-lived processes that do want realtime can instead call\n * `client.close()` when shutting down.\n */\n realtime?: boolean;\n}\n\n/**\n * Re-export from `@rebasepro/types` for backward compatibility.\n */\nexport type FindParams = TypesFindParams;\nexport type FindResponse<T> = TypesFindResponse<T extends Record<string, unknown> ? T : Record<string, unknown>>;\n\nexport function buildQueryString(params?: FindParams): string {\n if (!params) return \"\";\n const parts: string[] = [];\n\n if (params.limit != null) parts.push(`limit=${params.limit}`);\n if (params.offset != null) parts.push(`offset=${params.offset}`);\n if (params.page != null) parts.push(`page=${params.page}`);\n\n if (params.orderBy) {\n const wire = serializeOrderBy(params.orderBy);\n if (wire) parts.push(`orderBy=${encodeURIComponent(wire)}`);\n }\n\n if (params.searchString) {\n parts.push(`searchString=${encodeURIComponent(params.searchString)}`);\n }\n\n if (params.include && params.include.length > 0) {\n parts.push(`include=${encodeURIComponent(params.include.join(\",\"))}`);\n }\n\n if (params.logical) {\n const root = params.logical;\n const serialized = (root.conditions ?? []).map(serializeLogicalCondition).join(\",\");\n parts.push(`${root.type}=${encodeURIComponent(`(${serialized})`)}`);\n }\n\n if (params.where) {\n const serialized = serializeFilter(params.where);\n for (const [field, value] of Object.entries(serialized)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(v)}`);\n }\n } else {\n parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(value)}`);\n }\n }\n }\n\n return parts.length > 0 ? \"?\" + parts.join(\"&\") : \"\";\n}\n\nexport interface Transport {\n request: <T = unknown>(path: string, init?: RequestInit) => Promise<T>;\n setToken: (newToken: string | null) => void;\n setAuthTokenGetter: (getter: () => Promise<string | null>) => void;\n setOnUnauthorized: (handler: () => Promise<boolean>) => void;\n readonly baseUrl: string;\n readonly apiPath: string;\n readonly fetchFn: typeof globalThis.fetch;\n getHeaders: (init?: RequestInit) => Record<string, string>;\n resolveToken: () => Promise<string | null>;\n}\n\nexport function createTransport(config: RebaseClientConfig): Transport {\n const fetchFn = config.fetch || globalThis.fetch;\n const apiPath = config.apiPath || \"/api\";\n let token = config.token;\n let tokenGetter: (() => Promise<string | null>) | undefined;\n let onUnauthorizedHandler = config.onUnauthorized;\n\n function getHeaders(activeToken: string | undefined, init?: RequestInit) {\n return {\n \"Content-Type\": \"application/json\",\n ...(activeToken ? { Authorization: `Bearer ${activeToken}` } : {}),\n ...((init?.headers as Record<string, string>) || {})\n };\n }\n\n async function request<T = unknown>(path: string, init?: RequestInit): Promise<T> {\n const base = config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"\";\n const url = base + apiPath + path;\n\n let activeToken = token;\n if (tokenGetter) {\n try {\n const fetched = await tokenGetter();\n if (fetched !== null && fetched !== undefined) {\n activeToken = fetched;\n }\n } catch (e) {\n // Ignore error, fallback to static token if any\n }\n }\n\n const headers = getHeaders(activeToken, init);\n\n // If passing FormData, we MUST let fetch set the boundary, so remove Content-Type\n if (init?.body instanceof FormData) {\n delete (headers as Record<string, string>)[\"Content-Type\"];\n }\n\n const res = await fetchFn(url, { ...init,\nheaders });\n\n if (res.status === 204) return undefined as T; // SAFETY: HTTP 204 No Content has no body\n\n const text = await res.text().catch(() => \"\");\n let body: Record<string, unknown> = {};\n if (text) {\n try {\n body = JSON.parse(text, rebaseReviver) as Record<string, unknown>;\n } catch (e) {\n // If not valid JSON, fallback\n }\n }\n\n // The server always emits the canonical `{ error: { message, code, details? } }`\n // envelope (formatted by the central errorHandler), so we read strictly\n // from `body.error.*`.\n const getErrorField = (obj: Record<string, unknown>, field: string): unknown => {\n const err = obj?.error;\n if (err && typeof err === \"object\" && err !== null) {\n return (err as Record<string, unknown>)[field];\n }\n return undefined;\n };\n\n if (res.status === 401 && onUnauthorizedHandler) {\n const retried = await onUnauthorizedHandler();\n if (retried) {\n let retryToken = token;\n if (tokenGetter) {\n try {\n const fetched = await tokenGetter();\n if (fetched !== null && fetched !== undefined) {\n retryToken = fetched;\n }\n } catch (e) { /* ignore */ }\n }\n const retryHeaders = getHeaders(retryToken, init) as Record<string, string>;\n const retryRes = await fetchFn(url, { ...init,\nheaders: retryHeaders });\n if (retryRes.status === 204) return undefined as T; // SAFETY: HTTP 204 No Content has no body\n const retryText = await retryRes.text().catch(() => \"\");\n let retryBody: Record<string, unknown> = {};\n if (retryText) {\n try {\n retryBody = JSON.parse(retryText, rebaseReviver);\n } catch (e) { /* ignore */ }\n }\n if (!retryRes.ok) {\n let fallbackMessage = retryRes.statusText;\n if (retryRes.status === 404 && !fallbackMessage) {\n const method = init?.method || \"GET\";\n fallbackMessage = `Endpoint not found (${method} ${path}). This usually means the collection is not registered on the backend, or the frontend API URL configuration (e.g. VITE_API_URL) is missing or pointing to the wrong host.`;\n }\n throw new RebaseApiError(\n String(getErrorField(retryBody, \"message\") || fallbackMessage || `Request failed with status ${retryRes.status}`),\n {\n status: retryRes.status,\n code: getErrorField(retryBody, \"code\") as string | undefined,\n details: getErrorField(retryBody, \"details\")\n }\n );\n }\n return retryBody as T;\n }\n }\n\n if (!res.ok) {\n let fallbackMessage = res.statusText;\n if (res.status === 404 && !fallbackMessage) {\n const method = init?.method || \"GET\";\n fallbackMessage = `Endpoint not found (${method} ${path}). This usually means the collection is not registered on the backend, or the frontend API URL configuration (e.g. VITE_API_URL) is missing or pointing to the wrong host.`;\n }\n throw new RebaseApiError(\n String(getErrorField(body, \"message\") || fallbackMessage || `Request failed with status ${res.status}`),\n {\n status: res.status,\n code: getErrorField(body, \"code\") as string | undefined,\n details: getErrorField(body, \"details\")\n }\n );\n }\n\n return body as T;\n }\n\n return {\n request,\n setToken(newToken: string | null) { token = newToken || undefined; },\n setAuthTokenGetter(getter: () => Promise<string | null>) { tokenGetter = getter; },\n setOnUnauthorized(handler: () => Promise<boolean>) { onUnauthorizedHandler = handler; },\n get baseUrl() { return config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"\"; },\n get apiPath() { return apiPath; },\n get fetchFn() { return fetchFn; },\n getHeaders: (init?: RequestInit) => getHeaders(token, init) as Record<string, string>,\n resolveToken: async () => {\n if (tokenGetter) {\n try {\n const fetched = await tokenGetter();\n if (fetched !== null && fetched !== undefined) {\n return fetched;\n }\n } catch (e) { /* ignore */ }\n }\n return token || null;\n }\n };\n}\n","import { RebaseApiError, Transport } from \"./transport\";\nimport type { AuthChangeEvent, RebaseSession, AuthTokens, DeviceSession, User } from \"@rebasepro/types\";\n\n// Re-export canonical types so `import { RebaseSession } from \"@rebasepro/client\"` keeps working\nexport type { RebaseSession, AuthTokens, AuthChangeEvent, DeviceSession } from \"@rebasepro/types\";\n\n/** @deprecated Use `User` from `@rebasepro/types` instead. */\nexport type RebaseUser = User;\n/** @deprecated Use `AuthTokens` from `@rebasepro/types` instead. */\nexport type RebaseTokens = AuthTokens;\n\n/** Minimal, non-sensitive user profile returned by {@link findUserByEmail}. */\nexport interface PublicUserProfile {\n uid: string;\n displayName: string | null;\n photoURL: string | null;\n}\n\n/** Map a raw user object from an auth response (`/login`, `/refresh`, `/me`) to a `User`. */\nfunction mapRawUser(raw: Record<string, unknown>): User {\n return {\n uid: raw.uid as string,\n email: (raw.email as string | null) ?? null,\n displayName: (raw.displayName as string | null) ?? null,\n photoURL: (raw.photoURL as string | null) ?? null,\n providerId: (raw.providerId as string | undefined) ?? \"password\",\n isAnonymous: (raw.isAnonymous as boolean | undefined) ?? false,\n emailVerified: raw.emailVerified as boolean | undefined,\n roles: raw.roles as string[] | undefined,\n metadata: raw.metadata as Record<string, unknown> | undefined,\n };\n}\n\n/** Placeholder user, used only as a last resort when none can be resolved. */\nconst EMPTY_USER: User = { uid: \"\", email: null, displayName: null, photoURL: null, providerId: \"password\", isAnonymous: false };\n\n\nexport interface AuthConfig {\n needsSetup: boolean;\n registrationEnabled: boolean;\n emailServiceEnabled?: boolean;\n passwordReset?: boolean;\n emailVerification?: boolean;\n magicLink?: boolean;\n enabledProviders: string[];\n}\n\nexport interface AuthStorage {\n getItem: (key: string) => string | null;\n setItem: (key: string, value: string) => void;\n removeItem: (key: string) => void;\n}\n\nexport function createMemoryStorage(): AuthStorage {\n const store: Record<string, string> = {};\n return {\n getItem(key) { return store[key] ?? null; },\n setItem(key, value) { store[key] = value; },\n removeItem(key) { delete store[key]; }\n };\n}\n\nfunction detectStorage(): AuthStorage {\n try {\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(\"__rebase_test__\", \"1\");\n localStorage.removeItem(\"__rebase_test__\");\n return localStorage;\n }\n } catch (e) { /* ignore */ }\n return createMemoryStorage();\n}\n\nexport interface CreateAuthOptions {\n storage?: AuthStorage;\n authPath?: string;\n autoRefresh?: boolean;\n persistSession?: boolean;\n /**\n * Authentication flow mode.\n * - 'json' (default): Tokens are sent/received in JSON bodies. Refresh token is stored in local storage.\n * - 'cookie': Refresh token is sent/received via httpOnly cookies. Access token remains in memory.\n */\n authFlowMode?: \"json\" | \"cookie\";\n}\n\nexport function createAuth(transport: Transport, options?: CreateAuthOptions) {\n const opts = options || {};\n const storage = opts.storage || detectStorage();\n const authPath = opts.authPath || \"/auth\";\n const autoRefresh = opts.autoRefresh !== false;\n const persistSession = opts.persistSession !== false;\n const authFlowMode = opts.authFlowMode || \"json\";\n\n const STORAGE_KEY = \"rebase_auth\";\n const REFRESH_BUFFER_MS = 120000;\n // Auto-refresh resilience: retry transient failures with exponential backoff\n // (1s, 2s, 4s, … capped) before giving up and signing out.\n const MAX_REFRESH_RETRIES = 5;\n const REFRESH_RETRY_BASE_MS = 1000;\n const REFRESH_RETRY_MAX_MS = 30000;\n\n let currentSession: RebaseSession | null = null;\n const listeners = new Set<(event: AuthChangeEvent, session: RebaseSession | null) => void>();\n let refreshTimeout: ReturnType<typeof setTimeout> | null = null;\n // De-dupe concurrent refreshes. On boot (esp. cookie mode + React StrictMode)\n // multiple callers can trigger refresh at once; without this they race — the\n // server rotates the refresh token twice and the browser can end up with a\n // cookie the DB no longer matches. A single in-flight promise is shared.\n let inFlightRefresh: Promise<RebaseSession> | null = null;\n let resolveInitialized: (value: void | PromiseLike<void>) => void;\n const isInitialized = new Promise<void>((resolve) => {\n resolveInitialized = resolve;\n });\n\n function authUrl(endpoint: string) {\n return transport.baseUrl + transport.apiPath + authPath + endpoint;\n }\n\n function getFetch() {\n return transport.fetchFn || globalThis.fetch;\n }\n\n function throwApiError(status: number, body: { error?: { message?: string; code?: string; details?: unknown }; message?: string; code?: string; details?: unknown } | undefined, statusText: string): never {\n throw new RebaseApiError(\n body?.error?.message || body?.message || statusText,\n {\n status,\n code: body?.error?.code || body?.code,\n details: body?.error?.details || body?.details\n }\n );\n }\n\n function emit(event: AuthChangeEvent, session: RebaseSession | null) {\n for (const fn of listeners) {\n try { fn(event, session); } catch (e) { /* ignore */ }\n }\n }\n\n function saveSession(session: RebaseSession) {\n if (!persistSession || authFlowMode === \"cookie\") return;\n try {\n storage.setItem(STORAGE_KEY, JSON.stringify(session));\n } catch (e) { /* ignore */ }\n }\n\n function clearStoredSession() {\n try {\n storage.removeItem(STORAGE_KEY);\n } catch (e) { /* ignore */ }\n }\n\n function loadStoredSession(): RebaseSession | null {\n try {\n const raw = storage.getItem(STORAGE_KEY);\n if (raw) return JSON.parse(raw) as RebaseSession;\n } catch (e) { /* ignore */ }\n return null;\n }\n\n /**\n * A refresh failure is only fatal if the refresh token itself is rejected\n * (expired / invalid / forbidden). Network blips, timeouts, and 5xx (e.g. a\n * backend restart mid-session) are transient and must NOT log the user out.\n */\n function isFatalRefreshError(err: unknown): boolean {\n if (!(err instanceof RebaseApiError)) return false; // network/other → transient\n if (err.code === \"INVALID_TOKEN\" || err.code === \"TOKEN_EXPIRED\") return true;\n // 401/403 are auth failures; other statuses (incl. 5xx, 0) are transient.\n return err.status === 401 || err.status === 403;\n }\n\n async function attemptScheduledRefresh(attempt: number) {\n try {\n await refreshSession();\n // On success, refreshSession() re-schedules the next refresh itself.\n } catch (err) {\n if (isFatalRefreshError(err)) {\n signOut();\n return;\n }\n if (attempt >= MAX_REFRESH_RETRIES) {\n signOut();\n return;\n }\n // Transient failure — back off and retry rather than dropping the session.\n const backoff = Math.min(REFRESH_RETRY_BASE_MS * 2 ** attempt, REFRESH_RETRY_MAX_MS);\n refreshTimeout = setTimeout(() => { void attemptScheduledRefresh(attempt + 1); }, backoff);\n }\n }\n\n function scheduleRefresh(expiresAt: number) {\n if (refreshTimeout) clearTimeout(refreshTimeout);\n if (!autoRefresh) return;\n\n const delay = (expiresAt - REFRESH_BUFFER_MS) - Date.now();\n\n if (delay <= 0) {\n void attemptScheduledRefresh(0);\n return;\n }\n\n refreshTimeout = setTimeout(() => { void attemptScheduledRefresh(0); }, delay);\n }\n\n function handleAuthResponse(data: { tokens: AuthTokens, user: Record<string, unknown> }, event?: AuthChangeEvent): RebaseSession {\n const user: User = mapRawUser(data.user);\n const session: RebaseSession = {\n accessToken: data.tokens.accessToken,\n refreshToken: data.tokens.refreshToken || (currentSession?.refreshToken) || \"\",\n expiresAt: data.tokens.accessTokenExpiresAt,\n user\n };\n currentSession = session;\n saveSession(session);\n transport.setToken(session.accessToken);\n scheduleRefresh(session.expiresAt);\n emit(event || \"SIGNED_IN\", session);\n return session;\n }\n\n async function signInWithEmail(email: string, password: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/login\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email,\npassword }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n async function signUp(email: string, password: string, displayName?: string) {\n const fetchFn = getFetch();\n const payload: Record<string, string> = { email,\npassword };\n if (displayName !== undefined) payload.displayName = displayName;\n const res = await fetchFn(authUrl(\"/register\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n /**\n * Sign in with Google.\n *\n * Supports three invocation styles:\n * - `signInWithGoogle({ idToken })` — ID-token flow (One Tap / Sign In button)\n * - `signInWithGoogle({ accessToken })` — Access-token flow (popup)\n * - `signInWithGoogle({ code, redirectUri })` — Authorization code flow (most secure)\n */\n async function signInWithGoogle(\n payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }\n ) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/google\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const responseBody = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, responseBody, res.statusText);\n const session = handleAuthResponse(responseBody, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n async function signInWithLinkedin(code: string, redirectUri: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/linkedin\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ code,\nredirectUri }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n /**\n * Generic OAuth sign-in. Posts the given payload to `/auth/{providerId}`.\n * Use this for any provider registered on the backend.\n */\n async function signInWithOAuth(providerId: string, payload: Record<string, unknown>) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(`/${providerId}`), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n // Convenience wrappers for all supported OAuth providers\n\n async function signInWithGitHub(code: string, redirectUri: string) {\n return signInWithOAuth(\"github\", { code,\nredirectUri });\n }\n\n async function signInWithMicrosoft(code: string, redirectUri: string) {\n return signInWithOAuth(\"microsoft\", { code,\nredirectUri });\n }\n\n async function signInWithApple(code: string, redirectUri: string, user?: { name?: { firstName?: string; lastName?: string }; email?: string }) {\n return signInWithOAuth(\"apple\", { code,\nredirectUri,\nuser });\n }\n\n async function signInWithFacebook(code: string, redirectUri: string) {\n return signInWithOAuth(\"facebook\", { code,\nredirectUri });\n }\n\n async function signInWithTwitter(code: string, redirectUri: string, codeVerifier: string) {\n return signInWithOAuth(\"twitter\", { code,\nredirectUri,\ncodeVerifier });\n }\n\n async function signInWithDiscord(code: string, redirectUri: string) {\n return signInWithOAuth(\"discord\", { code,\nredirectUri });\n }\n\n async function signInWithGitLab(code: string, redirectUri: string) {\n return signInWithOAuth(\"gitlab\", { code,\nredirectUri });\n }\n\n async function signInWithBitbucket(code: string, redirectUri: string) {\n return signInWithOAuth(\"bitbucket\", { code,\nredirectUri });\n }\n\n async function signInWithSlack(code: string, redirectUri: string) {\n return signInWithOAuth(\"slack\", { code,\nredirectUri });\n }\n\n async function signInWithSpotify(code: string, redirectUri: string) {\n return signInWithOAuth(\"spotify\", { code,\nredirectUri });\n }\n\n async function signOut() {\n const fetchFn = getFetch();\n try {\n if (authFlowMode === \"cookie\" || currentSession?.refreshToken) {\n await fetchFn(authUrl(\"/logout\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: currentSession?.refreshToken }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n }\n } catch (e) { /* ignore */ }\n currentSession = null;\n clearStoredSession();\n if (refreshTimeout) {\n clearTimeout(refreshTimeout);\n refreshTimeout = null;\n }\n transport.setToken(null);\n emit(\"SIGNED_OUT\", null);\n }\n\n function refreshSession(): Promise<RebaseSession> {\n // Share a single in-flight refresh across concurrent callers.\n if (inFlightRefresh) return inFlightRefresh;\n inFlightRefresh = doRefreshSession().finally(() => {\n inFlightRefresh = null;\n });\n return inFlightRefresh;\n }\n\n async function doRefreshSession(): Promise<RebaseSession> {\n if (authFlowMode !== \"cookie\" && !currentSession?.refreshToken) {\n throw new Error(\"No active session to refresh\");\n }\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/refresh\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: currentSession?.refreshToken }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n\n const accessToken = body.tokens.accessToken;\n transport.setToken(accessToken);\n\n // Resolve the user, in order of preference:\n // 1. the user returned by /refresh (modern backends include it),\n // 2. the user already in memory,\n // 3. a fetch of /me — required to restore a session from an httpOnly\n // cookie alone (cold start in cookie mode), where there is no\n // in-memory user and the backend didn't echo one.\n let user = currentSession?.user;\n if (body.user && typeof body.user.uid === \"string\") {\n user = mapRawUser(body.user as Record<string, unknown>);\n } else if (!user || !user.uid) {\n try {\n user = await getUser();\n } catch { /* fall through to the empty stub below */ }\n }\n\n const session: RebaseSession = {\n accessToken,\n refreshToken: body.tokens.refreshToken || currentSession?.refreshToken || \"\",\n expiresAt: body.tokens.accessTokenExpiresAt,\n user: user ?? EMPTY_USER\n };\n currentSession = session;\n saveSession(session);\n transport.setToken(session.accessToken);\n scheduleRefresh(session.expiresAt);\n emit(\"TOKEN_REFRESHED\", session);\n return session;\n }\n\n async function getUser() {\n const data = await transport.request<{ user: User }>(authPath + \"/me\", { method: \"GET\" });\n return data.user;\n }\n\n /**\n * Resolve an email to a minimal public profile (`uid`, `displayName`,\n * `photoURL`) for invite-by-email flows. Returns `null` when no account\n * matches. Requires the backend to opt in via `auth.allowUserLookup`;\n * otherwise the endpoint is absent and this rejects.\n */\n async function findUserByEmail(email: string): Promise<PublicUserProfile | null> {\n const data = await transport.request<{ user: PublicUserProfile | null }>(authPath + \"/find-user\", {\n method: \"POST\",\n body: JSON.stringify({ email })\n });\n return data.user;\n }\n\n async function updateUser(updates: { displayName?: string, photoURL?: string }) {\n const data = await transport.request<{ user: User }>(authPath + \"/me\", {\n method: \"PATCH\",\n body: JSON.stringify(updates)\n });\n if (currentSession) {\n currentSession = { ...currentSession,\nuser: data.user };\n saveSession(currentSession);\n emit(\"USER_UPDATED\", currentSession);\n }\n return data.user;\n }\n\n async function resetPasswordForEmail(email: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/forgot-password\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email })\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function resetPassword(token: string, password: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/reset-password\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token,\npassword })\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function changePassword(oldPassword: string, newPassword: string) {\n return transport.request<{ success: boolean; message: string; }>(authPath + \"/change-password\", {\n method: \"POST\",\n body: JSON.stringify({ oldPassword,\nnewPassword })\n });\n }\n\n async function sendVerificationEmail() {\n return transport.request<{ success: boolean; message: string; }>(authPath + \"/send-verification\", {\n method: \"POST\"\n });\n }\n\n async function verifyEmail(token: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/verify-email?token=\" + encodeURIComponent(token)), {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" }\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function sendMagicLink(email: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/magic-link\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email })\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function verifyMagicLink(token: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/magic-link/verify\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n async function getSessions(): Promise<DeviceSession[]> {\n const data = await transport.request<{ sessions: DeviceSession[] }>(authPath + \"/sessions\", { method: \"GET\" });\n return data.sessions;\n }\n\n async function revokeSession(sessionId: string) {\n return transport.request<{ success: boolean }>(authPath + \"/sessions/\" + encodeURIComponent(sessionId), {\n method: \"DELETE\"\n });\n }\n\n async function revokeAllSessions() {\n const result = await transport.request<{ success: boolean }>(authPath + \"/sessions\", {\n method: \"DELETE\"\n });\n currentSession = null;\n clearStoredSession();\n if (refreshTimeout) {\n clearTimeout(refreshTimeout);\n refreshTimeout = null;\n }\n transport.setToken(null);\n emit(\"SIGNED_OUT\", null);\n return result;\n }\n\n async function getAuthConfig() {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/config\"), {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" }\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as AuthConfig;\n }\n\n function getSession() {\n return currentSession;\n }\n\n function onAuthStateChange(callback: (event: AuthChangeEvent, session: RebaseSession | null) => void) {\n listeners.add(callback);\n return () => listeners.delete(callback);\n }\n\n if (persistSession) {\n const stored = loadStoredSession();\n if (stored && stored.accessToken) {\n if (stored.expiresAt > Date.now()) {\n currentSession = stored;\n transport.setToken(stored.accessToken);\n scheduleRefresh(stored.expiresAt);\n resolveInitialized!();\n } else if (authFlowMode === \"cookie\" || stored.refreshToken) {\n currentSession = stored;\n refreshSession().then(() => {\n resolveInitialized!();\n }).catch(() => {\n currentSession = null;\n clearStoredSession();\n transport.setToken(null);\n resolveInitialized!();\n });\n } else {\n resolveInitialized!();\n }\n } else if (authFlowMode === \"cookie\") {\n // Silent refresh on boot to pick up httpOnly session\n refreshSession().then(() => {\n resolveInitialized!();\n }).catch(() => {\n resolveInitialized!();\n });\n } else {\n resolveInitialized!();\n }\n } else {\n resolveInitialized!();\n }\n\n return {\n signInWithEmail,\n signUp,\n signInWithGoogle,\n signInWithLinkedin,\n signInWithOAuth,\n signInWithGitHub,\n signInWithMicrosoft,\n signInWithApple,\n signInWithFacebook,\n signInWithTwitter,\n signInWithDiscord,\n signInWithGitLab,\n signInWithBitbucket,\n signInWithSlack,\n signInWithSpotify,\n signOut,\n refreshSession,\n getUser,\n findUserByEmail,\n updateUser,\n resetPasswordForEmail,\n resetPassword,\n changePassword,\n sendVerificationEmail,\n verifyEmail,\n sendMagicLink,\n verifyMagicLink,\n getSessions,\n revokeSession,\n revokeAllSessions,\n getAuthConfig,\n getSession,\n onAuthStateChange,\n isInitialized: () => isInitialized\n };\n}\n\nexport interface CookieStorageOptions {\n path?: string;\n domain?: string;\n secure?: boolean;\n sameSite?: \"Lax\" | \"Strict\" | \"None\";\n maxAge?: number;\n}\n\nexport function createCookieStorage(options: CookieStorageOptions = {}): AuthStorage {\n const defaultOptions = {\n path: \"/\",\n sameSite: \"Lax\" as const,\n ...options\n };\n\n return {\n getItem(key: string): string | null {\n if (typeof document === \"undefined\") return null;\n const nameEQ = encodeURIComponent(key) + \"=\";\n const ca = document.cookie.split(\";\");\n for (let i = 0; i < ca.length; i++) {\n let c = ca[i];\n while (c.charAt(0) === \" \") c = c.substring(1, c.length);\n if (c.indexOf(nameEQ) === 0) {\n return decodeURIComponent(c.substring(nameEQ.length, c.length));\n }\n }\n return null;\n },\n setItem(key: string, value: string): void {\n if (typeof document === \"undefined\") return;\n let cookieStr = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n\n if (defaultOptions.path) {\n cookieStr += `; path=${defaultOptions.path}`;\n }\n if (defaultOptions.domain) {\n cookieStr += `; domain=${defaultOptions.domain}`;\n }\n if (defaultOptions.maxAge !== undefined) {\n cookieStr += `; max-age=${defaultOptions.maxAge}`;\n } else {\n cookieStr += `; max-age=${365 * 24 * 60 * 60}`;\n }\n if (defaultOptions.secure) {\n cookieStr += \"; secure\";\n }\n if (defaultOptions.sameSite) {\n cookieStr += `; samesite=${defaultOptions.sameSite}`;\n }\n\n document.cookie = cookieStr;\n },\n removeItem(key: string): void {\n if (typeof document === \"undefined\") return;\n let cookieStr = `${encodeURIComponent(key)}=; path=${defaultOptions.path || \"/\"}; max-age=-1`;\n if (defaultOptions.domain) {\n cookieStr += `; domain=${defaultOptions.domain}`;\n }\n document.cookie = cookieStr;\n }\n };\n}\n","import type { Transport } from \"./transport\";\nimport { AdminUser } from \"@rebasepro/types\";\n\nexport type { AdminUser };\n\n\nexport interface CreateAdminOptions {\n adminPath?: string;\n}\n\nexport function createAdmin(transport: Transport, options?: CreateAdminOptions) {\n const opts = options || {};\n const adminPath = opts.adminPath || \"/admin\";\n\n async function listUsers() {\n return transport.request<{ users: AdminUser[] }>(adminPath + \"/users\", { method: \"GET\" });\n }\n\n async function listUsersPaginated(options?: { search?: string; limit?: number; offset?: number; orderBy?: string; orderDir?: \"asc\" | \"desc\" }) {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined) params.set(\"offset\", String(options.offset));\n if (options?.search) params.set(\"search\", options.search);\n if (options?.orderBy) params.set(\"orderBy\", options.orderBy);\n if (options?.orderDir) params.set(\"orderDir\", options.orderDir);\n const qs = params.toString();\n return transport.request<{ users: AdminUser[]; total: number; limit: number; offset: number }>(\n adminPath + \"/users\" + (qs ? \"?\" + qs : \"\"), { method: \"GET\" }\n );\n }\n\n async function getUser(userId: string) {\n return transport.request<{ user: AdminUser }>(adminPath + \"/users/\" + encodeURIComponent(userId), { method: \"GET\" });\n }\n\n async function createUser(data: { email: string, displayName?: string, password?: string, roles?: string[] }) {\n return transport.request<{ user: AdminUser }>(adminPath + \"/users\", {\n method: \"POST\",\n body: JSON.stringify(data)\n });\n }\n\n async function updateUser(userId: string, data: { email?: string, displayName?: string, password?: string, roles?: string[] }) {\n return transport.request<{ user: AdminUser }>(adminPath + \"/users/\" + encodeURIComponent(userId), {\n method: \"PUT\",\n body: JSON.stringify(data)\n });\n }\n\n async function deleteUser(userId: string) {\n return transport.request<{ success: boolean }>(adminPath + \"/users/\" + encodeURIComponent(userId), {\n method: \"DELETE\"\n });\n }\n\n async function resetPassword(userId: string, options?: { password?: string }) {\n return transport.request<{ user: AdminUser; temporaryPassword?: string; invitationSent?: boolean; emailDeliveryFailed?: boolean }>(\n adminPath + \"/users/\" + encodeURIComponent(userId) + \"/reset-password\",\n {\n method: \"POST\",\n ...(options?.password ? { body: JSON.stringify({ password: options.password }) } : {})\n }\n );\n }\n\n async function listRoles() {\n return transport.request<{ roles: Array<{ id: string; name: string }> }>(\n adminPath + \"/roles\",\n { method: \"GET\" }\n );\n }\n\n async function bootstrap() {\n return transport.request<{ success: boolean; message: string; user: { uid: string; roles: string[] } }>(adminPath + \"/bootstrap\", {\n method: \"POST\"\n });\n }\n\n return {\n listUsers,\n listUsersPaginated,\n getUser,\n createUser,\n updateUser,\n deleteUser,\n resetPassword,\n listRoles,\n bootstrap\n };\n}\n","import { Transport } from \"./transport\";\nimport type { CronJobStatus, CronJobLogEntry } from \"@rebasepro/types\";\n\nexport interface CreateCronOptions {\n cronPath?: string;\n}\n\nexport function createCron(transport: Transport, options?: CreateCronOptions) {\n const cronPath = options?.cronPath || \"/cron\";\n\n async function listJobs(): Promise<{ jobs: CronJobStatus[] }> {\n return transport.request<{ jobs: CronJobStatus[] }>(cronPath, { method: \"GET\" });\n }\n\n async function getJob(jobId: string): Promise<{ job: CronJobStatus }> {\n return transport.request<{ job: CronJobStatus }>(\n cronPath + \"/\" + encodeURIComponent(jobId),\n { method: \"GET\" }\n );\n }\n\n async function triggerJob(jobId: string): Promise<{ log: CronJobLogEntry; job: CronJobStatus }> {\n return transport.request<{ log: CronJobLogEntry; job: CronJobStatus }>(\n cronPath + \"/\" + encodeURIComponent(jobId) + \"/trigger\",\n { method: \"POST\" }\n );\n }\n\n async function getJobLogs(\n jobId: string,\n options?: { limit?: number }\n ): Promise<{ logs: CronJobLogEntry[] }> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n const qs = params.toString();\n return transport.request<{ logs: CronJobLogEntry[] }>(\n cronPath + \"/\" + encodeURIComponent(jobId) + \"/logs\" + (qs ? \"?\" + qs : \"\"),\n { method: \"GET\" }\n );\n }\n\n async function toggleJob(\n jobId: string,\n enabled: boolean\n ): Promise<{ job: CronJobStatus }> {\n return transport.request<{ job: CronJobStatus }>(\n cronPath + \"/\" + encodeURIComponent(jobId),\n {\n method: \"PUT\",\n body: JSON.stringify({ enabled })\n }\n );\n }\n\n return {\n listJobs,\n getJob,\n triggerJob,\n getJobLogs,\n toggleJob\n };\n}\n","import { Transport } from \"./transport\";\nimport type { BackupInfo, BackupDestinationKind } from \"@rebasepro/types\";\n\nexport interface CreateBackupsOptions {\n backupsPath?: string;\n}\n\nexport function createBackups(transport: Transport, options?: CreateBackupsOptions) {\n const backupsPath = options?.backupsPath || \"/admin/backups\";\n\n async function list(): Promise<{\n backups: BackupInfo[];\n destinationKind: BackupDestinationKind;\n configured: boolean;\n }> {\n return transport.request(backupsPath, { method: \"GET\" });\n }\n\n /**\n * Download a backup's bytes. Uses an authenticated fetch (not the JSON\n * transport) so the octet-stream response comes back as a Blob.\n */\n async function download(key: string): Promise<Blob> {\n const token = await transport.resolveToken();\n // Mirror transport.request's URL construction (baseUrl + apiPath + path)\n // — this endpoint returns an octet-stream, so we fetch it directly\n // instead of going through the JSON transport.\n const url = `${transport.baseUrl}${transport.apiPath}${backupsPath}/download?key=${encodeURIComponent(key)}`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: token ? { Authorization: `Bearer ${token}` } : {}\n });\n if (!res.ok) {\n throw new Error(`Failed to download backup (${res.status})`);\n }\n return res.blob();\n }\n\n return { list, download };\n}\n","import type { Transport } from \"./transport\";\n\n// Re-define the types locally since they live in server, not in @rebasepro/types.\n// These match the server-side types exactly.\n\n/** A single permission entry scoping an API key to a collection and its allowed operations. */\nexport interface ApiKeyPermission {\n collection: string;\n operations: (\"read\" | \"write\" | \"delete\")[];\n}\n\n/** An API key with the secret portion masked (returned by list / get / update). */\nexport interface ApiKeyMasked {\n id: string;\n name: string;\n key_prefix: string;\n permissions: ApiKeyPermission[];\n admin: boolean;\n rate_limit: number | null;\n created_by: string;\n created_at: string;\n updated_at: string;\n last_used_at: string | null;\n expires_at: string | null;\n revoked_at: string | null;\n}\n\n/** An API key including the full secret (returned only on creation). */\nexport interface ApiKeyWithSecret extends ApiKeyMasked {\n key: string;\n}\n\n/** Payload for creating a new API key. */\nexport interface CreateApiKeyRequest {\n name: string;\n permissions: ApiKeyPermission[];\n rate_limit?: number | null;\n expires_at?: string | null;\n}\n\n/** Payload for updating an existing API key. */\nexport interface UpdateApiKeyRequest {\n name?: string;\n permissions?: ApiKeyPermission[];\n rate_limit?: number | null;\n expires_at?: string | null;\n}\n\n/** Options for the `createApiKeys` factory. */\nexport interface CreateApiKeysOptions {\n apiKeysPath?: string;\n}\n\n/**\n * Creates a client for managing API keys via the admin routes.\n *\n * @param transport - The shared HTTP transport created by `createTransport`.\n * @param options - Optional overrides (e.g. a custom base path).\n */\nexport function createApiKeys(transport: Transport, options?: CreateApiKeysOptions) {\n const apiKeysPath = options?.apiKeysPath || \"/admin/api-keys\";\n\n /** List all API keys (masked). */\n async function listKeys(): Promise<{ keys: ApiKeyMasked[] }> {\n return transport.request<{ keys: ApiKeyMasked[] }>(apiKeysPath, { method: \"GET\" });\n }\n\n /** Get a single API key by ID (masked). */\n async function getKey(id: string): Promise<{ key: ApiKeyMasked }> {\n return transport.request<{ key: ApiKeyMasked }>(\n apiKeysPath + \"/\" + encodeURIComponent(id),\n { method: \"GET\" }\n );\n }\n\n /** Create a new API key. The full secret is included in the response. */\n async function createKey(data: CreateApiKeyRequest): Promise<{ key: ApiKeyWithSecret }> {\n return transport.request<{ key: ApiKeyWithSecret }>(apiKeysPath, {\n method: \"POST\",\n body: JSON.stringify(data)\n });\n }\n\n /** Update an existing API key. */\n async function updateKey(id: string, data: UpdateApiKeyRequest): Promise<{ key: ApiKeyMasked }> {\n return transport.request<{ key: ApiKeyMasked }>(\n apiKeysPath + \"/\" + encodeURIComponent(id),\n {\n method: \"PUT\",\n body: JSON.stringify(data)\n }\n );\n }\n\n /** Revoke (soft-delete) an API key. */\n async function revokeKey(id: string): Promise<{ success: boolean }> {\n return transport.request<{ success: boolean }>(\n apiKeysPath + \"/\" + encodeURIComponent(id),\n { method: \"DELETE\" }\n );\n }\n\n return {\n listKeys,\n getKey,\n createKey,\n updateKey,\n revokeKey\n };\n}\n","import {\n FindParams,\n FindResult,\n LogicalCondition,\n SDKCollectionClient,\n SDKQueryBuilderInterface,\n WhereFilterOp,\n WhereValue\n} from \"@rebasepro/types\";\n\n/**\n * SDK Query Builder — returns flat rows (`FindResult<M>`) instead of\n * Entity-wrapped results (`FindResponse<M>`).\n *\n * @example\n * const { data } = await rebase.data.posts\n * .where(\"status\", \"==\", \"published\")\n * .orderBy(\"created_at\", \"desc\")\n * .limit(10)\n * .find();\n *\n * console.log(data[0].title); // flat access\n */\nexport class SDKQueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements SDKQueryBuilderInterface<M> {\n private params: FindParams = { where: {} };\n\n constructor(private collection: SDKCollectionClient<M>) {}\n\n /**\n * Add a filter condition to your query.\n * @example\n * client.data.users.where('age', '>=', 18).find()\n */\n where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): this;\n where(logicalCondition: LogicalCondition): this;\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, value?: unknown): this {\n if (typeof columnOrCondition === \"object\" && columnOrCondition !== null && \"type\" in columnOrCondition) {\n this.params.logical = columnOrCondition as LogicalCondition;\n return this;\n }\n\n if (!this.params.where) {\n this.params.where = {};\n }\n\n const column = columnOrCondition as string;\n const condition: [WhereFilterOp, unknown] = [operator!, value];\n const existing = this.params.where[column];\n\n if (existing === undefined) {\n this.params.where[column] = condition;\n } else if (Array.isArray(existing) && existing.length > 0 && Array.isArray(existing[0])) {\n (this.params.where[column] as [WhereFilterOp, unknown][]).push(condition);\n } else {\n let firstCondition: [WhereFilterOp, unknown];\n if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === \"string\") {\n firstCondition = existing as [WhereFilterOp, unknown];\n } else {\n firstCondition = [\"==\", existing];\n }\n this.params.where[column] = [firstCondition, condition];\n }\n\n return this;\n }\n\n /**\n * Order the results by a specific column.\n */\n orderBy(column: keyof M & string, direction: \"asc\" | \"desc\" = \"asc\"): this {\n this.params.orderBy = [column, direction];\n return this;\n }\n\n /**\n * Limit the number of results returned.\n */\n limit(count: number): this {\n this.params.limit = count;\n return this;\n }\n\n /**\n * Skip the first N results.\n */\n offset(count: number): this {\n this.params.offset = count;\n return this;\n }\n\n /**\n * Set a free-text search string if supported by the backend.\n */\n search(searchString: string): this {\n this.params.searchString = searchString;\n return this;\n }\n\n /**\n * Include related entities in the response.\n * Relations will be populated with full data instead of just IDs.\n *\n * @param relations - Relation names to include, or \"*\" for all.\n * @example\n * client.data.posts.include(\"tags\", \"author\").find()\n */\n include(...relations: string[]): this {\n this.params.include = relations;\n return this;\n }\n\n /**\n * Execute the find query and return the results as flat rows.\n */\n async find(): Promise<FindResult<M>> {\n return this.collection.find(this.params);\n }\n\n /**\n * Count the records matching this query.\n */\n async count(): Promise<number> {\n if (!this.collection.count) {\n throw new Error(\"count() is not supported by this collection client.\");\n }\n return this.collection.count(this.params);\n }\n\n /**\n * Listen to realtime updates matching this query.\n */\n listen(onUpdate: (data: FindResult<M>) => void, onError?: (error: Error) => void): () => void {\n if (!this.collection.listen) {\n throw new Error(\n \"Listen is only available when RebaseClient is configured with a websocketUrl, \" +\n \"and not when it was created with realtime: false.\"\n );\n }\n return this.collection.listen(this.params, onUpdate, onError);\n }\n}\n","import { buildQueryString, FindParams, RebaseApiError, Transport } from \"./transport\";\nimport { RebaseWebSocketClient } from \"./websocket\";\nimport {\n FindResult,\n LogicalCondition,\n SDKCollectionClient,\n SDKQueryBuilderInterface,\n WhereFilterOp,\n WhereValue\n} from \"@rebasepro/types\";\n\nimport { SDKQueryBuilder } from \"./sdk_query_builder\";\n\n/**\n * The concrete, HTTP-backed implementation of the public\n * {@link SDKCollectionClient} contract — flat rows (no Entity wrapper), plus\n * fluent query-builder methods (`.where()`, `.orderBy()`, …).\n *\n * This is what `createRebaseClient().data.<collection>` returns. It is not a\n * separate API from {@link SDKCollectionClient}; it only widens it with\n * `count()`. Program against {@link SDKCollectionClient} when you want a\n * transport-agnostic type.\n */\nexport interface CollectionClient<\n M extends Record<string, unknown> = Record<string, unknown>,\n I = Partial<M>,\n U = Partial<M>\n> extends SDKCollectionClient<M, I, U> {\n count(params?: FindParams): Promise<number>;\n}\n\nexport function createCollectionClient<M extends Record<string, unknown> = Record<string, unknown>>(transport: Transport, slug: string, ws?: RebaseWebSocketClient): CollectionClient<M> {\n const basePath = `/data/${slug}`;\n\n const client: CollectionClient<M> = {\n async find(params?: FindParams): Promise<FindResult<M>> {\n const qs = buildQueryString(params);\n const raw = await transport.request<{\n data: Record<string, unknown>[];\n meta: FindResult<M>[\"meta\"]\n }>(basePath + qs, { method: \"GET\" });\n return {\n data: (raw.data || []) as M[],\n meta: raw.meta\n };\n },\n\n async findById(id: string | number) {\n try {\n const raw = await transport.request<Record<string, unknown>>(`${basePath}/${encodeURIComponent(String(id))}`, { method: \"GET\" });\n if (!raw) return undefined;\n return raw as M;\n } catch (err) {\n if (err instanceof RebaseApiError && err.status === 404) {\n return undefined;\n }\n throw err;\n }\n },\n\n async create(data: Partial<M>, id?: string | number) {\n const body: Record<string, unknown> = { ...data };\n if (id !== undefined) {\n body.id = id;\n }\n const raw = await transport.request<Record<string, unknown>>(basePath, {\n method: \"POST\",\n body: JSON.stringify(body)\n });\n return raw as M;\n },\n\n async createMany(data: Partial<M>[], options?: { upsert?: boolean }) {\n if (!Array.isArray(data)) {\n throw new TypeError(\"createMany expects an array of records.\");\n }\n if (data.length === 0) return [];\n\n const raw = await transport.request<{ data: Record<string, unknown>[] }>(`${basePath}/bulk`, {\n method: \"POST\",\n body: JSON.stringify({\n rows: data,\n ...(options?.upsert ? { upsert: true } : {})\n })\n });\n return (raw.data || []) as M[];\n },\n\n async update(id: string | number, data: Partial<M>) {\n const raw = await transport.request<Record<string, unknown>>(`${basePath}/${encodeURIComponent(String(id))}`, {\n method: \"PUT\",\n body: JSON.stringify(data)\n });\n return raw as M;\n },\n\n async delete(id: string | number) {\n await transport.request<void>(`${basePath}/${encodeURIComponent(String(id))}`, {\n method: \"DELETE\"\n });\n },\n\n async count(params?: FindParams): Promise<number> {\n const countParams: FindParams = {\n ...params,\n limit: undefined,\n offset: undefined\n };\n const qs = buildQueryString(countParams);\n const raw = await transport.request<{ count: number }>(basePath + \"/count\" + qs, { method: \"GET\" });\n return raw.count ?? 0;\n },\n\n // Fluent builder instantiation\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, value?: unknown) {\n const builder = new SDKQueryBuilder<M>(client);\n if (typeof columnOrCondition === \"object\") {\n return builder.where(columnOrCondition);\n }\n return builder.where(columnOrCondition as keyof M & string, operator!, value as WhereValue<M[keyof M & string]>);\n },\n orderBy(column: keyof M & string, direction?: \"asc\" | \"desc\") {\n return new SDKQueryBuilder<M>(client).orderBy(column, direction);\n },\n limit(count: number) {\n return new SDKQueryBuilder<M>(client).limit(count);\n },\n offset(count: number) {\n return new SDKQueryBuilder<M>(client).offset(count);\n },\n search(searchString: string) {\n return new SDKQueryBuilder<M>(client).search(searchString);\n },\n include(...relations: string[]) {\n return new SDKQueryBuilder<M>(client).include(...relations);\n }\n };\n\n if (ws) {\n client.listen = (params: FindParams | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void) => {\n let active = true;\n let lastUpdateId = 0;\n const unsub = ws.listenCollection(\n {\n path: slug,\n filter: params?.where,\n limit: params?.limit,\n startAfter: params?.offset ? String(params.offset) : undefined,\n orderBy: params?.orderBy?.[0],\n order: params?.orderBy?.[1],\n searchString: params?.searchString\n },\n (incomingRows: Record<string, unknown>[]) => {\n const currentUpdateId = ++lastUpdateId;\n const requestedLimit = params?.limit || 20;\n const offset = params?.offset || 0;\n\n // WS client already delivers flat rows — just cast\n const rows = incomingRows as M[];\n\n // Heuristic metadata (used as fallback if count call fails)\n const heuristicTotal = rows.length;\n const heuristicHasMore = rows.length >= requestedLimit;\n\n // Try to get authoritative count; fall back to heuristic\n if (client.count) {\n client.count(params)\n .then((total) => {\n if (active && currentUpdateId === lastUpdateId) {\n onUpdate({\n data: rows,\n meta: {\n total,\n limit: requestedLimit,\n offset,\n hasMore: offset + rows.length < total\n }\n });\n }\n })\n .catch(() => {\n // Count failed — use heuristic meta\n if (active && currentUpdateId === lastUpdateId) {\n onUpdate({\n data: rows,\n meta: {\n total: heuristicTotal,\n limit: requestedLimit,\n offset,\n hasMore: heuristicHasMore\n }\n });\n }\n });\n } else {\n // No count method — fire immediately with heuristic meta\n onUpdate({\n data: rows,\n meta: {\n total: heuristicTotal,\n limit: requestedLimit,\n offset,\n hasMore: heuristicHasMore\n }\n });\n }\n },\n onError\n );\n\n return () => {\n active = false;\n unsub();\n };\n };\n\n client.listenById = (id: string | number, onUpdate: (data: M | undefined) => void, onError?: (error: Error) => void) => {\n return ws.listenOne(\n {\n path: slug,\n id: String(id)\n },\n (row: Record<string, unknown> | null) => {\n if (row) {\n onUpdate(row as M);\n } else {\n onUpdate(undefined);\n }\n },\n onError\n );\n };\n }\n\n return client;\n}\n","import type { Transport } from \"./transport\";\n\n/**\n * Client interface for invoking custom backend functions.\n *\n * Custom functions are Hono route files auto-mounted by the Rebase backend\n * at `/api/functions/{name}`. The `FunctionsClient` wraps the shared\n * transport so callers never need to manually construct URLs or inject\n * auth tokens.\n *\n * @example\n * ```ts\n * const result = await client.functions.invoke<{ job: Job }>('extract-job', {\n * url: 'https://example.com/posting',\n * html: htmlContent,\n * });\n * ```\n */\nexport interface FunctionsClient {\n /**\n * Invoke a custom backend function by name.\n *\n * @typeParam T - Expected shape of the response payload.\n * @param name - Function name (the filename without extension, e.g. `\"extract-job\"`).\n * @param payload - Optional JSON-serialisable body sent as `POST`.\n * @param options - Optional overrides (HTTP method, sub-path, extra headers).\n * @returns The parsed JSON response from the function.\n */\n invoke<T = unknown>(\n name: string,\n payload?: unknown,\n options?: FunctionInvokeOptions,\n ): Promise<T>;\n}\n\nexport interface FunctionInvokeOptions {\n /** HTTP method — defaults to `\"POST\"`. */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n /** Sub-path appended after the function name, e.g. `\"status/123\"`. */\n path?: string;\n /** Extra headers merged into the request (auth is still injected automatically). */\n headers?: Record<string, string>;\n}\n\n/**\n * Create a `FunctionsClient` backed by the given transport.\n *\n * The transport already handles:\n * - Base URL resolution\n * - JWT injection via `Authorization: Bearer`\n * - 401 retry / `onUnauthorized` flow\n * - Consistent error throwing via `RebaseApiError`\n *\n * @internal\n */\nexport function createFunctionsClient(transport: Transport): FunctionsClient {\n return {\n async invoke<T = unknown>(\n name: string,\n payload?: unknown,\n options?: FunctionInvokeOptions\n ): Promise<T> {\n const method = options?.method ?? \"POST\";\n const subPath = options?.path ? `/${options.path.replace(/^\\//, \"\")}` : \"\";\n const routePath = `/functions/${encodeURIComponent(name)}${subPath}`;\n\n const init: RequestInit = { method };\n\n if (payload !== undefined && method !== \"GET\") {\n init.body = JSON.stringify(payload);\n }\n\n if (options?.headers) {\n init.headers = options.headers;\n }\n\n return transport.request<T>(routePath, init);\n }\n };\n}\n","import { StorageSource, UploadFileProps, UploadFileResult, DownloadConfig, StorageListResult, DownloadMetadata, PUBLIC_STORAGE_PREFIX, isPublicStoragePath } from \"@rebasepro/types\";\nimport { Transport } from \"./transport\";\n\n/**\n * Create a StorageSource that talks to the Rebase backend REST API.\n *\n * @param transport - HTTP transport instance\n * @param storageId - Optional storage-source key for multi-backend routing.\n * When set, it is forwarded to the server so the correct\n * `StorageController` is resolved from the registry.\n */\nexport function createStorage(transport: Transport, storageId?: string): StorageSource {\n const urlsCache = new Map<string, { config: DownloadConfig; expiresAt?: number }>();\n\n /** Append ?storageId=... to a path when multi-backend routing is active. */\n const withStorageId = (path: string): string => {\n if (!storageId) return path;\n const sep = path.includes(\"?\") ? \"&\" : \"?\";\n return `${path}${sep}storageId=${encodeURIComponent(storageId)}`;\n };\n\n async function putObject({\n file,\n key,\n metadata,\n bucket,\n public: isPublic\n }: UploadFileProps): Promise<UploadFileResult> {\n const formData = new FormData();\n formData.append(\"file\", file);\n\n // Public objects live under the public prefix so they can be served\n // token-less via a stable, permanent URL. Normalize the key here so the\n // stored path is self-describing (no server round-trip needed to know\n // it's public).\n let effectiveKey = key;\n if (isPublic && effectiveKey && !isPublicStoragePath(effectiveKey)) {\n effectiveKey = `${PUBLIC_STORAGE_PREFIX}${effectiveKey.replace(/^\\/+/, \"\")}`;\n }\n\n if (effectiveKey) formData.append(\"key\", effectiveKey);\n if (bucket) formData.append(\"bucket\", bucket);\n if (storageId) formData.append(\"storageId\", storageId);\n\n if (metadata) {\n for (const [key, value] of Object.entries(metadata)) {\n if (value !== undefined && value !== null) {\n formData.append(\n `metadata_${key}`,\n typeof value === \"string\" ? value : JSON.stringify(value)\n );\n }\n }\n }\n\n const result = await transport.request<{ data: UploadFileResult }>(withStorageId(\"/storage/upload\"), {\n method: \"POST\",\n body: formData,\n headers: {}\n });\n\n return result.data;\n }\n\n async function getSignedUrl(\n keyOrUrl: string,\n bucket?: string\n ): Promise<DownloadConfig> {\n const cacheKey = bucket ? `${bucket}/${keyOrUrl}` : keyOrUrl;\n const cachedEntry = urlsCache.get(cacheKey);\n if (cachedEntry) {\n if (!cachedEntry.expiresAt || cachedEntry.expiresAt > Date.now()) {\n return cachedEntry.config;\n }\n urlsCache.delete(cacheKey);\n }\n\n let filePath = keyOrUrl;\n\n if (filePath && (filePath.startsWith(\"local://\") || filePath.startsWith(\"s3://\") || filePath.startsWith(\"gs://\"))) {\n filePath = filePath.substring(filePath.indexOf(\"://\") + 3);\n }\n\n if (bucket && filePath && !filePath.startsWith(bucket)) {\n filePath = `${bucket}/${filePath}`;\n }\n\n if (!filePath || filePath.trim() === \"\" || filePath === \"/\") {\n return { url: null, fileNotFound: true };\n }\n\n // ── Public objects ────────────────────────────────────────────────\n // A public file (under the public prefix) is served token-less via a\n // stable, permanent, CDN-cacheable URL. No metadata round-trip and no\n // token are needed — build the URL directly and cache it forever.\n if (isPublicStoragePath(filePath)) {\n const publicConfig: DownloadConfig = {\n url: withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}`)\n };\n urlsCache.set(cacheKey, { config: publicConfig }); // no expiry\n return publicConfig;\n }\n\n try {\n const result = await transport.request<{ data: DownloadMetadata }>(withStorageId(`/storage/metadata/${filePath}`));\n\n // Public object (server-confirmed): token-less permanent URL.\n if (result.data.public) {\n const publicConfig: DownloadConfig = {\n url: withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}`),\n metadata: result.data\n };\n urlsCache.set(cacheKey, { config: publicConfig }); // no expiry\n return publicConfig;\n }\n\n // Private object: use the short-lived, file-scoped download token\n // minted by the server. We deliberately do NOT fall back to the\n // caller's access token — a URL must never carry a full-privilege\n // credential. If no scoped token is present the URL fails closed.\n const scopedToken = result.data.token;\n const tokenQuery = scopedToken ? `?token=${scopedToken}` : \"\";\n\n const downloadConfig: DownloadConfig = {\n // `withStorageId` picks `?` or `&` based on whether the token\n // query is already present, so the URL stays valid even when\n // there is no token.\n url: withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}${tokenQuery}`),\n metadata: result.data\n };\n\n const expiresAt = result.data.tokenExpiresIn\n ? Date.now() + (result.data.tokenExpiresIn - 10) * 1000 // subtract 10s buffer\n : undefined;\n\n urlsCache.set(cacheKey, { config: downloadConfig, expiresAt });\n return downloadConfig;\n } catch (e: unknown) {\n if (e instanceof Error && \"status\" in e && (e as { status: number }).status === 404) {\n return { url: null, fileNotFound: true };\n }\n throw e;\n }\n }\n\n async function getObject(\n key: string,\n bucket?: string\n ): Promise<File | null> {\n const downloadConfig = await getSignedUrl(key, bucket);\n if (downloadConfig.fileNotFound || !downloadConfig.url) {\n return null;\n }\n\n // Fetch using the signed URL directly. Since the scoped token is in the ?token= query param,\n // we explicitly omit any Authorization headers to prevent passing full access tokens to file serving routes.\n const response = await transport.fetchFn(downloadConfig.url, {\n headers: {}\n });\n\n if (response.status === 404) return null;\n if (!response.ok) throw new Error(\"Failed to get file\");\n\n const blob = await response.blob();\n const fileName = (bucket ? `${bucket}/${key}` : key).split(\"/\").pop() || \"file\";\n return new File([blob], fileName, { type: blob.type });\n }\n\n async function deleteObject(\n key: string,\n bucket?: string\n ): Promise<void> {\n let filePath = key;\n\n if (filePath && (filePath.startsWith(\"local://\") || filePath.startsWith(\"s3://\") || filePath.startsWith(\"gs://\"))) {\n filePath = filePath.substring(filePath.indexOf(\"://\") + 3);\n }\n\n if (bucket && filePath && !filePath.startsWith(bucket)) {\n filePath = `${bucket}/${filePath}`;\n }\n\n if (!filePath || filePath.trim() === \"\" || filePath === \"/\") {\n return;\n }\n\n try {\n await transport.request(withStorageId(`/storage/file/${filePath}`), { method: \"DELETE\" });\n } catch (e: unknown) {\n if (!(e instanceof Error && \"status\" in e && (e as { status: number }).status === 404)) throw e;\n }\n\n urlsCache.delete(bucket ? `${bucket}/${key}` : key);\n }\n\n async function listObjects(\n prefix: string,\n options?: {\n bucket?: string;\n maxResults?: number;\n pageToken?: string;\n }\n ): Promise<StorageListResult> {\n const params = new URLSearchParams();\n if (prefix) params.set(\"prefix\", prefix);\n if (options?.bucket) params.set(\"bucket\", options.bucket);\n if (options?.maxResults) params.set(\"maxResults\", String(options.maxResults));\n if (options?.pageToken) params.set(\"pageToken\", options.pageToken);\n\n if (storageId) params.set(\"storageId\", storageId);\n\n const result = await transport.request<{ data: StorageListResult }>(`/storage/list?${params.toString()}`);\n return result.data;\n }\n\n return {\n putObject,\n getSignedUrl,\n getObject,\n deleteObject,\n listObjects\n };\n}\n","/**\n * Client-side storage source registry.\n *\n * Manages multiple `StorageSource` instances keyed by\n * `StorageSourceDefinition.key`. Collection properties reference\n * a source by key via `StorageConfig.storageSource`.\n *\n * Typical bootstrap flow:\n * 1. Fetch definitions from `GET /api/storage/sources`\n * 2. Build server-backed sources automatically via `createStorage(transport, key)`\n * 3. Register \"direct\" sources manually (e.g. Firebase Storage hook)\n */\n\nimport type { StorageSource, StorageSourceRegistry, StorageSourceDefinition } from \"@rebasepro/types\";\nimport { DEFAULT_STORAGE_SOURCE_KEY } from \"@rebasepro/types\";\nimport { createStorage } from \"./storage\";\nimport type { Transport } from \"./transport\";\n\n/**\n * Default implementation of the client-side `StorageSourceRegistry`.\n */\nexport class ClientStorageSourceRegistry implements StorageSourceRegistry {\n private sources = new Map<string, StorageSource>();\n\n /**\n * Register a storage source.\n * @param key - Unique key matching a `StorageSourceDefinition.key`\n * @param source - The `StorageSource` instance\n */\n register(key: string, source: StorageSource): void {\n this.sources.set(key, source);\n }\n\n getDefault(): StorageSource {\n const source = this.sources.get(DEFAULT_STORAGE_SOURCE_KEY);\n if (!source) {\n throw new Error(\n `[StorageSourceRegistry] No default storage source registered. ` +\n `Register one with key \"${DEFAULT_STORAGE_SOURCE_KEY}\".`\n );\n }\n return source;\n }\n\n get(key: string | undefined | null): StorageSource | undefined {\n if (key === undefined || key === null) {\n return this.sources.get(DEFAULT_STORAGE_SOURCE_KEY);\n }\n return this.sources.get(key);\n }\n\n getOrDefault(key: string | undefined | null): StorageSource {\n if (key === undefined || key === null) {\n return this.getDefault();\n }\n const source = this.sources.get(key);\n if (source) return source;\n\n // Fallback to default\n console.warn(\n `[StorageSourceRegistry] Storage source \"${key}\" not found, ` +\n `falling back to \"${DEFAULT_STORAGE_SOURCE_KEY}\".`\n );\n return this.getDefault();\n }\n\n has(key: string): boolean {\n return this.sources.has(key);\n }\n\n list(): string[] {\n return Array.from(this.sources.keys());\n }\n\n /**\n * Build a registry from `StorageSourceDefinition[]` and an HTTP transport.\n *\n * - Sources with `transport: \"server\"` are auto-wired via `createStorage(transport, key)`.\n * - Sources with `transport: \"direct\"` are **not** auto-wired — they must\n * be registered manually after this call (e.g. via a Firebase hook).\n *\n * @param definitions - Array of storage source definitions\n * @param transport - HTTP transport for server-backed sources\n */\n static fromDefinitions(\n definitions: StorageSourceDefinition[],\n transport: Transport\n ): ClientStorageSourceRegistry {\n const registry = new ClientStorageSourceRegistry();\n\n for (const def of definitions) {\n if (def.transport === \"server\") {\n // Auto-create a server-backed StorageSource for this key\n const source = createStorage(transport, def.key === DEFAULT_STORAGE_SOURCE_KEY ? undefined : def.key);\n registry.register(def.key, source);\n }\n // \"direct\" sources must be registered manually\n }\n\n return registry;\n }\n}\n","import {\n DeleteProps,\n CollectionConfig,\n FetchCollectionProps,\n FetchOneProps,\n SaveProps,\n WebSocketMessage,\n WebSocketErrorPayload,\n CollectionUpdateMessage,\n SingleUpdateMessage,\n TableMetadata,\n BranchInfo,\n RebaseApiError\n} from \"@rebasepro/types\";\nimport { buildCompositeId, COMPOSITE_ID_SEPARATOR, type PrimaryKeyInfo } from \"@rebasepro/common\";\nimport { rebaseReviver } from \"./reviver\";\n\n\n\n/**\n * Extract error message and code from a WebSocket message payload.\n * Handles both `{ error: string }` and `{ error: { message, code } }` shapes.\n */\nfunction extractMessageError(message: WebSocketMessage): { errorMessage: string; errorCode?: string } {\n const payload = message.payload as WebSocketErrorPayload | undefined;\n const errPayload = payload?.error;\n const errorMessage = typeof errPayload === \"object\"\n ? errPayload.message\n : payload?.message || (typeof errPayload === \"string\" ? errPayload : undefined) || message.error || \"Unknown error\";\n const errorCode = typeof errPayload === \"object\"\n ? errPayload.code\n : payload?.code;\n // Callers treat this as a string (`.toLowerCase()` in isAuthError). A frame\n // carrying a non-string here would throw inside the message handler, where\n // the surrounding try/catch would swallow it — and a subscription error that\n // never reaches its listener is a view stuck loading forever.\n const safeMessage = typeof errorMessage === \"string\"\n ? errorMessage\n : (errorMessage == null ? \"Unknown error\" : JSON.stringify(errorMessage));\n return { errorMessage: safeMessage,\nerrorCode };\n}\n\nexport interface RebaseWebSocketConfig {\n websocketUrl: string;\n /** Optional auth token getter for WebSocket authentication */\n getAuthToken?: () => Promise<string | null>;\n /** Optional WebSocket constructor to override globalThis.WebSocket (e.g. for Node environments) */\n WebSocket?: typeof WebSocket;\n /** Callback to handle unauthorized requests or token expiration (refreshes auth session) */\n onUnauthorized?: () => Promise<boolean>;\n}\n\n\n/**\n * Broadcast and presence frames.\n *\n * Fire-and-forget (the server sends no response envelope), and exempt from the\n * client-side auth gate — a public channel is usable without an account.\n */\nconst CHANNEL_MESSAGE_TYPES = new Set([\n \"join_channel\",\n \"leave_channel\",\n \"broadcast\",\n \"presence_track\",\n \"presence_untrack\",\n \"presence_state\"\n]);\n\n/**\n * Low-level realtime WebSocket client.\n *\n * @internal Not a stable app-facing API. `createRebaseClient()` constructs and\n * manages this internally (exposed as `client.ws`, typed by the minimal\n * `RebaseWebSocket` contract in `@rebasepro/types`). It is re-exported from the\n * package root only because the `@rebasepro/client-postgres` driver\n * instantiates it directly; its surface may change without a major bump.\n */\nexport class RebaseWebSocketClient {\n private websocketUrl: string;\n private ws: WebSocket | null = null;\n public getAuthToken?: () => Promise<string | null>;\n private subscriptions = new Map<string, {\n onUpdate: (data: WebSocketMessage) => void,\n onError?: (error: Error) => void\n }>();\n\n private listeners = new Map<string, Set<(...args: unknown[]) => void>>();\n\n /** Channel-name → handlers, for broadcast and presence frames. */\n private channelHandlers = new Map<string, Set<(message: Record<string, unknown>) => void>>();\n\n /** Set by `close()`. Blocks any later operation from silently redialling. */\n private closedByCaller = false;\n\n /**\n * Whether a socket exists at all (open or still opening).\n *\n * Lets callers distinguish \"authenticate the live socket\" from \"there is\n * nothing to authenticate yet\", without that question forcing a dial.\n */\n public get hasSocket(): boolean {\n return this.ws !== null;\n }\n\n /** So the \"no WebSocket in this environment\" warning is said once, not per call. */\n private warnedNoWebSocket = false;\n\n /** Subscribe to broadcast/presence frames for one channel. */\n public onChannelMessage(channel: string, handler: (message: Record<string, unknown>) => void): () => void {\n if (!this.channelHandlers.has(channel)) this.channelHandlers.set(channel, new Set());\n this.channelHandlers.get(channel)!.add(handler);\n return () => {\n const handlers = this.channelHandlers.get(channel);\n if (!handlers) return;\n handlers.delete(handler);\n if (handlers.size === 0) this.channelHandlers.delete(channel);\n };\n }\n\n /** Notified after the socket comes back, so channels can re-join. */\n public onReconnect(handler: () => void): () => void {\n return this.on(\"reconnect\", handler);\n }\n\n public on(event: \"connect\" | \"disconnect\" | \"reconnect\" | \"error\", cb: (...args: unknown[]) => void) {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(cb);\n return () => this.listeners.get(event)!.delete(cb);\n }\n\n private emit(event: string, ...args: unknown[]) {\n if (this.listeners.has(event)) {\n this.listeners.get(event)!.forEach(cb => cb(...args));\n }\n }\n\n // New: Subscription deduplication management with optimizations\n private collectionSubscriptions = new Map<string, {\n backendSubscriptionId: string;\n callbacks: Map<string, {\n onUpdate: (rows: Record<string, unknown>[]) => void;\n onError?: (error: Error) => void;\n }>;\n props: FetchCollectionProps;\n latestData?: Record<string, unknown>[]; // Cache the latest flat rows\n lastUpdated?: number; // Timestamp for cache invalidation\n isInitialDataReceived?: boolean; // Track if we got initial data\n /**\n * A `subscribe_collection` frame is on the wire and its initial payload\n * has not arrived yet. Without this, a subscription whose subscribe\n * failed is indistinguishable from one still loading, and every later\n * listener attaches to it and waits forever.\n */\n subscribeInFlight?: boolean;\n /**\n * Watchdog for the above. `subscribe_collection` expects no response\n * envelope, so it is not covered by `pendingRequests`' timeout — a lost\n * initial payload would otherwise hang the subscription indefinitely.\n */\n subscribeTimeout?: ReturnType<typeof setTimeout>;\n /**\n * The key columns of this collection, as told by the server on a patch.\n * Rows are columns only, and the SDK holds no collection config, so\n * without this there is nothing to derive an address from.\n */\n pks?: PrimaryKeyInfo[];\n }>();\n\n private singleSubscriptions = new Map<string, {\n backendSubscriptionId: string;\n callbacks: Map<string, {\n onUpdate: (row: Record<string, unknown> | null) => void;\n onError?: (error: Error) => void;\n }>;\n props: FetchOneProps;\n latestData?: Record<string, unknown> | null; // Cache the latest flat row\n lastUpdated?: number; // Timestamp for cache invalidation\n isInitialDataReceived?: boolean; // Track if we got initial data\n /** See the collection subscription counterparts. */\n subscribeInFlight?: boolean;\n subscribeTimeout?: ReturnType<typeof setTimeout>;\n }>();\n\n // Maps to quickly find subscription by backend subscription ID\n private backendToCollectionKey = new Map<string, string>();\n private backendToEntityKey = new Map<string, string>();\n\n\n private pendingRequests = new Map<string, {\n resolve: (p: unknown) => void;\n reject: (p: Error) => void;\n message?: Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void }\n }>();\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n private isConnected = false;\n private messageQueue: Record<string, unknown>[] = [];\n private requestTimeoutMs = 30000;\n private subscriptionTimeoutMs = 30000;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n\n private isAuthenticated = false;\n private authPromise: Promise<void> | null = null;\n private WebSocketConstructor: typeof WebSocket | undefined;\n public onUnauthorized?: () => Promise<boolean>;\n private refreshInProgress: Promise<boolean> | null = null;\n\n constructor(config: RebaseWebSocketConfig) {\n this.websocketUrl = config.websocketUrl;\n this.getAuthToken = config.getAuthToken;\n this.onUnauthorized = config.onUnauthorized;\n this.WebSocketConstructor = config.WebSocket || (typeof WebSocket !== \"undefined\" ? WebSocket : undefined);\n\n // Deliberately does NOT dial here. Constructing the client is not a\n // statement that the app wants a socket — `createRebaseClient` builds\n // one whenever realtime is not explicitly disabled, so connecting here\n // opened a socket on every page load of every app that merely *might*\n // subscribe later. Anonymous-first apps paid that on every visit, to\n // authenticate with nothing, which left them choosing between \"socket\n // on every page load\" and \"no channels at all\".\n //\n // The environment warning is also deferred: an app that never\n // subscribes should say nothing at all. See `ensureConnected`.\n }\n\n /**\n * Open the socket if it is not open (or opening) already.\n *\n * Idempotent, synchronous, and safe to call on every operation that needs a\n * live socket — `initWebSocket` already no-ops on an open socket and is\n * re-entrant, since the reconnect path has always called it.\n */\n public ensureConnected(): void {\n // An explicit `close()` is final. Without this, one queued frame could\n // redial a socket the caller just released and keep a Node process\n // alive forever.\n if (this.closedByCaller) return;\n if (!this.WebSocketConstructor) {\n if (!this.warnedNoWebSocket) {\n this.warnedNoWebSocket = true;\n console.warn(\"WebSocket is not defined in this environment. Realtime subscriptions will not work unless you provide a WebSocket implementation in the config.\");\n }\n return;\n }\n if (this.ws || this.reconnectTimeout) return;\n this.initWebSocket();\n }\n\n /**\n * Authenticate the WebSocket connection\n */\n async authenticate(token: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const requestId = `auth_${Date.now()}`;\n\n const timeout = setTimeout(() => {\n this.pendingRequests.delete(requestId);\n this.authPromise = null; // Clear promise so we can retry later\n reject(new Error(\"Authentication timeout\"));\n }, 30000);\n\n this.pendingRequests.set(requestId, {\n resolve: () => {\n clearTimeout(timeout);\n this.isAuthenticated = true;\n resolve();\n },\n reject: (error) => {\n clearTimeout(timeout);\n reject(error);\n }\n });\n\n const message = {\n type: \"AUTHENTICATE\",\n requestId,\n payload: { token }\n };\n\n if (!this.isConnected || !this.ws) {\n this.messageQueue.unshift(message); // Auth should be first\n } else {\n this.ws.send(JSON.stringify(message));\n }\n });\n }\n\n /**\n * Set the auth token getter function\n */\n setAuthTokenGetter(getAuthToken: () => Promise<string | null>): void {\n this.getAuthToken = getAuthToken;\n // Auto-authenticate if we are already connected but didn't have the token getter yet\n if (this.isConnected && !this.isAuthenticated && !this.authPromise) {\n console.debug(\"WebSocket auto-authenticating after token getter set\");\n this.getAuthToken().then(token => {\n if (!this.ws) return; // Prevent memory leaks / actions after disconnect\n if (token) {\n this.authenticate(token).catch(e => {\n if (this.ws) console.debug(\"WebSocket auto-auth skipped:\", e?.message || e);\n });\n }\n }).catch(e => {\n // User not logged in or auth still loading — this is expected,\n // the WebSocket will authenticate on-demand when a request is made.\n if (this.ws) console.debug(\"WebSocket auto-auth skipped:\", e?.message || e);\n });\n }\n }\n\n /**\n * Drop the socket.\n *\n * `permanent` distinguishes the two callers. Signing out drops the socket\n * but the client stays usable — a later subscribe should reconnect\n * anonymously. `client.close()` is the caller saying they are done, and\n * must not be undone by a stray queued frame.\n */\n public disconnect(permanent = false): void {\n if (permanent) this.closedByCaller = true;\n this.isAuthenticated = false;\n this.authPromise = null;\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n if (this.ws) {\n this.ws.onclose = null; // Prevent reconnect on explicit disconnect\n this.ws.onerror = null; // Prevent errors on explicit disconnect\n this.ws.onopen = null;\n this.ws.onmessage = null;\n this.ws.close();\n this.ws = null;\n }\n }\n\n // Initialize WebSocket connection\n private initWebSocket() {\n if (!this.WebSocketConstructor) return;\n if (this.ws?.readyState === this.WebSocketConstructor.OPEN) return;\n\n // Guard against race condition: if a previous socket is still connecting, tear it down\n if (this.ws) {\n this.ws.onclose = null;\n this.ws.close();\n this.ws = null;\n }\n\n try {\n this.ws = new this.WebSocketConstructor(this.websocketUrl);\n\n this.ws!.onopen = async () => {\n console.debug(\"Connected to PostgreSQL backend\");\n const wasReconnect = this.reconnectAttempts > 0;\n this.isConnected = true;\n this.reconnectAttempts = 0;\n\n // Auto-authenticate if token getter is available\n if (this.getAuthToken && !this.isAuthenticated) {\n try {\n const token = await this.getAuthToken();\n if (token) {\n await this.authenticate(token);\n console.debug(\"WebSocket auto-authenticated\");\n }\n } catch (error) {\n // User not logged in or auth still loading — this is expected.\n // Authentication will happen on-demand when the user logs in.\n console.debug(\"WebSocket connected without auth:\", (error as Error)?.message || error);\n }\n }\n\n this.emit(wasReconnect ? \"reconnect\" : \"connect\");\n this.processMessageQueue();\n\n // Re-subscribe all active subscriptions after reconnect.\n // The server-side subscription state was lost when the connection dropped,\n // so we need to re-register every active subscription.\n if (wasReconnect) {\n this.resubscribeAll();\n }\n\n // Subscribes requested while offline have just gone out; they\n // could not be watchdogged at request time.\n this.armPendingSubscribeWatchdogs();\n };\n\n this.ws!.onmessage = (event) => {\n try {\n const message = JSON.parse(event.data, rebaseReviver);\n this.handleWebSocketMessage(message);\n } catch (error) {\n console.error(\"Error parsing WebSocket message:\", error);\n }\n };\n\n this.ws!.onclose = () => {\n console.debug(\"Disconnected from PostgreSQL backend\");\n this.isConnected = false;\n this.isAuthenticated = false;\n this.authPromise = null;\n // The reconnect path re-subscribes everything; a watchdog firing\n // in the meantime would tear down healthy subscriptions.\n this.suspendSubscribeWatchdogs();\n this.emit(\"disconnect\");\n\n // Re-queue pending requests so the UI doesn't hang indefinitely or crash\n for (const [reqId, request] of this.pendingRequests.entries()) {\n if (reqId.startsWith(\"auth_\")) {\n request.reject(new Error(\"Connection closed during authentication\"));\n } else if (request.message) {\n request.message._queuedResolve = request.resolve;\n request.message._queuedReject = request.reject;\n this.messageQueue.push(request.message);\n } else {\n request.reject(new RebaseApiError(\"Connection closed\"));\n }\n this.pendingRequests.delete(reqId);\n }\n\n this.attemptReconnect();\n };\n\n this.ws!.onerror = (error) => {\n console.error(\"WebSocket error:\", error);\n this.isConnected = false;\n this.emit(\"error\", error);\n };\n } catch (error) {\n console.error(\"Failed to initialize WebSocket:\", error);\n this.attemptReconnect();\n }\n }\n\n private processMessageQueue() {\n while (this.messageQueue.length > 0 && this.isConnected) {\n const message = this.messageQueue.shift();\n if (message) this.sendMessage(message);\n }\n }\n\n private attemptReconnect() {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n console.error(\"Max reconnection attempts reached\");\n // Nothing will re-subscribe now, so stop every subscription that\n // never loaded from spinning forever.\n this.failAllPendingSubscriptions(\n new RebaseApiError(\"Connection lost\", { code: \"CONNECTION_LOST\" })\n );\n return;\n }\n\n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n\n console.debug(`Attempting to reconnect in ${delay}ms (attempt ${this.reconnectAttempts})`);\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n }\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null;\n this.initWebSocket();\n }, delay);\n }\n\n private isAuthError(message: WebSocketMessage): boolean {\n if (message.type === \"AUTH_ERROR\") return true;\n const { errorMessage, errorCode } = extractMessageError(message);\n if (errorCode === \"UNAUTHORIZED\" || errorCode === \"JWT_EXPIRED\" || errorCode === \"AUTH_ERROR\") return true;\n const lowerMessage = errorMessage.toLowerCase();\n return lowerMessage.includes(\"unauthorized\") || lowerMessage.includes(\"token expired\") || lowerMessage.includes(\"token is expired\") || lowerMessage.includes(\"invalid token\") || lowerMessage.includes(\"session expired\") || lowerMessage.includes(\"auth error\");\n }\n\n private async handleAuthFailure(): Promise<boolean> {\n if (this.refreshInProgress) {\n return this.refreshInProgress;\n }\n this.refreshInProgress = (async () => {\n this.isAuthenticated = false;\n this.authPromise = null;\n if (this.onUnauthorized) {\n try {\n const refreshed = await this.onUnauthorized();\n if (refreshed && this.getAuthToken) {\n const token = await this.getAuthToken();\n if (token) {\n await this.authenticate(token);\n return true;\n }\n }\n } catch (error) {\n console.error(\"WebSocket auth refresh failed:\", error);\n }\n }\n return false;\n })();\n try {\n return await this.refreshInProgress;\n } finally {\n this.refreshInProgress = null;\n }\n }\n\n /**\n * Shared logic for re-subscribing a collection or row subscription\n * after an auth error is resolved by refreshing credentials.\n */\n private resubscribeAfterAuthRefresh(\n message: WebSocketMessage,\n subscription: {\n backendSubscriptionId: string;\n callbacks: Map<string, { onUpdate: (...args: never[]) => void; onError?: (error: Error) => void }>;\n props: FetchCollectionProps | FetchOneProps;\n },\n subscriptionKey: string,\n idPrefix: \"collection\" | \"row\",\n backendKeyMap: Map<string, string>,\n messageType: \"subscribe_collection\" | \"subscribe_one\"\n ): void {\n this.handleAuthFailure().then(refreshed => {\n if (refreshed) {\n const oldBackendId = subscription.backendSubscriptionId;\n const newBackendId = `${idPrefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n subscription.backendSubscriptionId = newBackendId;\n backendKeyMap.delete(oldBackendId);\n backendKeyMap.set(newBackendId, subscriptionKey);\n\n // Route through the helpers so the retry is watchdogged too.\n if (messageType === \"subscribe_collection\") {\n this.sendCollectionSubscribe(subscriptionKey);\n } else {\n this.sendEntitySubscribe(subscriptionKey);\n }\n return;\n }\n\n // The refresh did not produce usable credentials. Report the original\n // error and drop the registration, so a later mount can try again\n // rather than attaching to a subscription that will never load.\n const { errorMessage, errorCode } = extractMessageError(message);\n const error = new RebaseApiError(errorMessage, { code: errorCode });\n if (messageType === \"subscribe_collection\") {\n this.failCollectionSubscription(subscriptionKey, error);\n } else {\n this.failEntitySubscription(subscriptionKey, error);\n }\n }).catch(err => {\n const error = err instanceof Error ? err : new Error(String(err));\n if (messageType === \"subscribe_collection\") {\n this.failCollectionSubscription(subscriptionKey, error);\n } else {\n this.failEntitySubscription(subscriptionKey, error);\n }\n });\n }\n\n private handleWebSocketMessage(message: WebSocketMessage) {\n const {\n type,\n requestId,\n subscriptionId\n } = message;\n\n // Handle responses to pending requests\n if (requestId && this.pendingRequests.has(requestId)) {\n const pendingReq = this.pendingRequests.get(requestId)!;\n if (type === \"ERROR\" || type === \"AUTH_ERROR\" || message.error) {\n if (this.isAuthError(message)) {\n this.pendingRequests.delete(requestId);\n this.handleAuthFailure().then(refreshed => {\n if (refreshed && pendingReq.message) {\n this.doSendMessage(pendingReq.message, pendingReq.resolve, pendingReq.reject).catch(pendingReq.reject);\n } else {\n const { errorMessage, errorCode } = extractMessageError(message);\n pendingReq.reject(new RebaseApiError(errorMessage, { code: errorCode }));\n }\n }).catch(err => {\n pendingReq.reject(err);\n });\n } else {\n this.pendingRequests.delete(requestId);\n const { errorMessage, errorCode } = extractMessageError(message);\n pendingReq.reject(new RebaseApiError(errorMessage, { code: errorCode }));\n }\n } else {\n this.pendingRequests.delete(requestId);\n pendingReq.resolve(message.payload || message);\n }\n return;\n }\n\n // Channel traffic (broadcast / presence) is addressed by channel name\n // rather than by requestId or subscriptionId, so it is dispatched\n // before the subscription paths — none of which would match it, and\n // the message would otherwise fall through and be dropped silently.\n if (typeof message.channel === \"string\" &&\n (type === \"broadcast\" || type === \"presence_state\" || type === \"presence_diff\")) {\n const handlers = this.channelHandlers.get(message.channel);\n if (handlers) {\n for (const handler of [...handlers]) {\n try {\n handler(message as unknown as Record<string, unknown>);\n } catch (error) {\n console.error(\"Error in channel handler:\", error);\n }\n }\n }\n return;\n }\n\n // Handle subscription updates for collection subscriptions\n if (subscriptionId && type === \"collection_update\") {\n const subscriptionKey = this.backendToCollectionKey.get(subscriptionId);\n if (subscriptionKey) {\n const collectionSub = this.collectionSubscriptions.get(subscriptionKey);\n if (collectionSub) {\n const wireEntities = (message.rows || []) as unknown as Record<string, unknown>[];\n const incomingRows = wireEntities;\n\n // The keys arrive with the rows, so they are known before the\n // first merge — a CDC-driven change never sends a patch, and\n // learning them from patches alone would leave every\n // externally-written collection unable to match a thing.\n const updatePks = (message as unknown as { pks?: PrimaryKeyInfo[] }).pks;\n if (updatePks) collectionSub.pks = updatePks;\n\n // Structural merge: preserve cached row references for rows\n // whose values haven't changed. This prevents downstream React components\n // from re-rendering (VirtualTableCell uses deepEqual on rowData —\n // same reference = instant true, avoiding expensive deep comparison).\n const rows = this.mergeRows(collectionSub.latestData, incomingRows, collectionSub.pks);\n\n // Cache the latest data with optimizations\n collectionSub.latestData = rows;\n collectionSub.lastUpdated = Date.now();\n collectionSub.isInitialDataReceived = true;\n // The subscribe landed — stand the watchdog down.\n if (collectionSub.subscribeTimeout) clearTimeout(collectionSub.subscribeTimeout);\n collectionSub.subscribeTimeout = undefined;\n collectionSub.subscribeInFlight = false;\n\n // Notify all callbacks for this subscription\n collectionSub.callbacks.forEach(callback => {\n try {\n callback.onUpdate(rows);\n } catch (error) {\n console.error(\"Error in collection subscription callback:\", error);\n if (callback.onError) {\n callback.onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n });\n return;\n }\n }\n }\n\n // Handle instant row-level patches for collection subscriptions.\n // These arrive before the full refetch and give immediate cross-tab feedback.\n if (subscriptionId && type === \"collection_patch\") {\n const subscriptionKey = this.backendToCollectionKey.get(subscriptionId);\n if (subscriptionKey) {\n const collectionSub = this.collectionSubscriptions.get(subscriptionKey);\n if (collectionSub && collectionSub.isInitialDataReceived && collectionSub.latestData) {\n const patchWireEntity = message.row ?? null;\n const patchMessage = message as unknown as { id: string; pks?: PrimaryKeyInfo[] };\n const patchEntityId = patchMessage.id;\n // The server knows the key columns; remember them, because the\n // refetch reconciliation needs them too and carries no id.\n if (patchMessage.pks) collectionSub.pks = patchMessage.pks;\n const patchRow = patchWireEntity ? (patchWireEntity as unknown as Record<string, unknown>) : null;\n let updated: Record<string, unknown>[];\n\n if (patchRow === null) {\n // Row was deleted — remove it from the cached list\n updated = collectionSub.latestData.filter(\n e => this.rowAddress(e, collectionSub.pks) !== String(patchEntityId)\n );\n } else {\n // Row was created or updated — merge into the cached list.\n // Matched against the patch's own address rather than\n // anything read off the row: `patchRow.id` is undefined\n // for a table not keyed on `id`, so every update looked\n // like a new row and was prepended as a duplicate.\n const idx = collectionSub.latestData.findIndex(\n e => this.rowAddress(e, collectionSub.pks) === String(patchEntityId)\n );\n if (idx >= 0) {\n // Update in place (preserve array position)\n updated = [...collectionSub.latestData];\n updated[idx] = patchRow;\n } else {\n // New row — prepend (most recently created first)\n updated = [patchRow, ...collectionSub.latestData];\n }\n }\n\n collectionSub.latestData = updated;\n collectionSub.lastUpdated = Date.now();\n\n // Fire all callbacks with the patched data\n collectionSub.callbacks.forEach(callback => {\n try {\n callback.onUpdate(updated);\n } catch (error) {\n console.error(\"Error in collection patch callback:\", error);\n if (callback.onError) {\n callback.onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n });\n return;\n }\n }\n }\n\n // Handle subscription updates for row subscriptions\n if (subscriptionId && type === \"single_update\") {\n const subscriptionKey = this.backendToEntityKey.get(subscriptionId);\n if (subscriptionKey) {\n const entitySub = this.singleSubscriptions.get(subscriptionKey);\n if (entitySub) {\n const wireEntity = message.row ?? null;\n const row = wireEntity ? (wireEntity as unknown as Record<string, unknown>) : null;\n // Cache the latest data with optimizations\n entitySub.latestData = row;\n entitySub.lastUpdated = Date.now();\n entitySub.isInitialDataReceived = true;\n if (entitySub.subscribeTimeout) clearTimeout(entitySub.subscribeTimeout);\n entitySub.subscribeTimeout = undefined;\n entitySub.subscribeInFlight = false;\n\n // Notify all callbacks for this subscription\n entitySub.callbacks.forEach(callback => {\n try {\n callback.onUpdate(row);\n } catch (error) {\n console.error(\"Error in row subscription callback:\", error);\n if (callback.onError) {\n callback.onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n });\n return;\n }\n }\n }\n\n // Handle subscription errors\n if (subscriptionId && (type === \"ERROR\" || message.error)) {\n const collectionKey = this.backendToCollectionKey.get(subscriptionId);\n if (collectionKey) {\n const collectionSub = this.collectionSubscriptions.get(collectionKey);\n if (collectionSub) {\n if (this.isAuthError(message)) {\n this.resubscribeAfterAuthRefresh(\n message,\n collectionSub,\n collectionKey,\n \"collection\",\n this.backendToCollectionKey,\n \"subscribe_collection\"\n );\n return;\n }\n\n // The server answered, so nothing is in flight any more. Leave\n // the registration in place (its listeners are still mounted\n // and have been told), but marked idle so the next listener\n // re-subscribes instead of attaching to a dead entry.\n if (collectionSub.subscribeTimeout) clearTimeout(collectionSub.subscribeTimeout);\n collectionSub.subscribeTimeout = undefined;\n collectionSub.subscribeInFlight = false;\n\n const { errorMessage, errorCode } = extractMessageError(message);\n const error = new RebaseApiError(errorMessage, { code: errorCode });\n collectionSub.callbacks.forEach(callback => {\n if (callback.onError) {\n callback.onError(error);\n }\n });\n return;\n }\n }\n\n const entityKey = this.backendToEntityKey.get(subscriptionId);\n if (entityKey) {\n const entitySub = this.singleSubscriptions.get(entityKey);\n if (entitySub) {\n if (this.isAuthError(message)) {\n this.resubscribeAfterAuthRefresh(\n message,\n entitySub,\n entityKey,\n \"row\",\n this.backendToEntityKey,\n \"subscribe_one\"\n );\n return;\n }\n\n if (entitySub.subscribeTimeout) clearTimeout(entitySub.subscribeTimeout);\n entitySub.subscribeTimeout = undefined;\n entitySub.subscribeInFlight = false;\n\n const { errorMessage, errorCode } = extractMessageError(message);\n const error = new RebaseApiError(errorMessage, { code: errorCode });\n entitySub.callbacks.forEach(callback => {\n if (callback.onError) {\n callback.onError(error);\n }\n });\n return;\n }\n }\n }\n\n // Legacy subscription handling (for backward compatibility)\n if (subscriptionId && this.subscriptions.has(subscriptionId)) {\n const callback = this.subscriptions.get(subscriptionId);\n if (!callback) {\n throw new Error(`Subscription callback not found for subscriptionId: ${subscriptionId}`);\n }\n if (message.type === \"ERROR\" || message.error) {\n if (callback.onError) {\n const { errorMessage, errorCode } = extractMessageError(message);\n callback.onError(new RebaseApiError(errorMessage, { code: errorCode }));\n }\n } else {\n callback.onUpdate(message);\n }\n }\n }\n\n private async ensureAuthenticated(retryCount = 3): Promise<void> {\n // If already authenticated or no token getter, skip\n if (this.isAuthenticated || !this.getAuthToken) return;\n\n // If auth is in progress, wait for it\n if (this.authPromise) {\n await this.authPromise;\n return;\n }\n\n // Try to authenticate with retries\n let lastError: unknown = null;\n\n for (let attempt = 0; attempt < retryCount; attempt++) {\n try {\n const token = await this.getAuthToken();\n if (!token) throw new Error(\"user not logged in\");\n this.authPromise = this.authenticate(token);\n await this.authPromise;\n this.authPromise = null;\n console.debug(\"WebSocket authenticated on demand\");\n return; // Success\n } catch (error: unknown) {\n this.authPromise = null;\n lastError = error;\n\n const errMsg = error instanceof Error ? error.message : String(error);\n // \"not logged in\" / \"Session expired\" are definitive - don't retry\n if (errMsg.includes(\"not logged in\") || errMsg.includes(\"Session expired\")) {\n console.warn(\"WebSocket auth failed: user not logged in\");\n throw error;\n }\n\n // \"still loading\" is transient - retry with backoff (auth controller\n // is restoring tokens from localStorage; it will resolve shortly)\n if (errMsg.includes(\"still loading\")) {\n if (attempt < retryCount - 1) {\n const delay = Math.min(500 * (attempt + 1), 2000);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n }\n\n // For other errors, retry with backoff\n if (attempt < retryCount - 1) {\n const delay = Math.min(1000 * (attempt + 1), 3000);\n console.debug(`WebSocket auth attempt ${attempt + 1} failed, retrying in ${delay}ms...`);\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n\n console.warn(\"WebSocket on-demand auth failed after retries:\", lastError);\n throw lastError;\n }\n\n async reauthenticate(): Promise<void> {\n if (!this.getAuthToken) return;\n\n this.isAuthenticated = false;\n try {\n const token = await this.getAuthToken();\n if (!token) throw new Error(\"user not logged in\");\n await this.authenticate(token);\n console.debug(\"WebSocket reauthenticated successfully\");\n } catch (error) {\n console.error(\"WebSocket reauthentication failed:\", error);\n throw error;\n }\n }\n\n /**\n * Public because `RebaseRealtimeChannel` sends channel frames through it.\n * Not part of the stable surface — prefer `client.realtime.channel(name)`.\n */\n public sendMessage(message: Record<string, unknown>): Promise<unknown> {\n // If already has a requestId (re-sending from queue), use the stored promise handlers\n const queuedMsg = message as Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void };\n if (queuedMsg._queuedResolve && queuedMsg._queuedReject) {\n return this.doSendMessage(message, queuedMsg._queuedResolve, queuedMsg._queuedReject);\n }\n\n if (!this.isConnected || !this.ws) {\n // The queue is only ever drained by a socket opening, so something\n // has to open one. Before lazy connect this was guaranteed by the\n // constructor; now the first frame is what asks for it.\n this.ensureConnected();\n // Queue the message and return a promise that will be resolved when actually sent\n return new Promise<unknown>((resolve, reject) => {\n const queueable = message as Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void };\n queueable._queuedResolve = resolve;\n queueable._queuedReject = reject;\n this.messageQueue.push(message);\n });\n }\n\n return new Promise<unknown>((resolve, reject) => {\n this.doSendMessage(message, resolve, reject);\n });\n }\n\n private async doSendMessage(message: Record<string, unknown>, resolve: (value: unknown) => void, reject: (error: Error) => void): Promise<void> {\n // Ensure authenticated before sending non-auth messages.\n //\n // Channel traffic is exempt. `ensureAuthenticated` throws \"user not\n // logged in\" when there is no token, which rejects the frame before it\n // is ever sent — so on an anonymous-first app (the kind this API was\n // added for) *every* channel operation failed client-side, and the\n // server never got to decide. Presence in a public room does not\n // require an account. A signed-in caller still authenticates: the\n // socket does it from `getAuthToken` on open, and the server authorizes\n // these frames either way.\n if (message.type !== \"AUTHENTICATE\"\n && !CHANNEL_MESSAGE_TYPES.has(message.type as string)\n && this.getAuthToken && !this.isAuthenticated) {\n try {\n await this.ensureAuthenticated();\n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : \"Authentication required\";\n reject(new RebaseApiError(errorMessage));\n return;\n }\n }\n\n const requestId = (message.requestId as string) || `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n message.requestId = requestId;\n\n const expectsResponse = !(\n message.type === \"subscribe_collection\"\n || message.type === \"subscribe_one\"\n || message.type === \"unsubscribe\"\n || CHANNEL_MESSAGE_TYPES.has(message.type as string)\n );\n\n if (expectsResponse && !this.pendingRequests.has(requestId)) {\n const timeoutHandle = setTimeout(() => {\n if (this.pendingRequests.has(requestId)) {\n this.pendingRequests.delete(requestId);\n reject(new RebaseApiError(\"Request timed out\"));\n }\n }, this.requestTimeoutMs);\n\n this.pendingRequests.set(requestId, {\n resolve: (value: unknown) => {\n clearTimeout(timeoutHandle);\n resolve(value);\n },\n reject: (error: Error) => {\n clearTimeout(timeoutHandle);\n reject(error);\n },\n message: message as Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void }\n });\n }\n\n try {\n this.ws!.send(JSON.stringify(message));\n if (!expectsResponse) {\n resolve(undefined);\n }\n } catch (error) {\n if (expectsResponse) {\n this.pendingRequests.delete(requestId);\n }\n reject(new RebaseApiError(\"Failed to send message\", { cause: error }));\n }\n }\n\n // Data source methods\n async fetchCollection<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> {\n const response = await this.sendMessage({\n type: \"FETCH_COLLECTION\",\n payload: props\n }) as { rows?: Record<string, unknown>[] };\n return (response.rows || []);\n }\n\n async fetchOne<M extends Record<string, unknown>>(props: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> {\n const response = await this.sendMessage({\n type: \"FETCH_ONE\",\n payload: props\n }) as { row?: Record<string, unknown> };\n const wireEntity = response.row;\n return wireEntity ?? undefined;\n }\n\n async save<M extends Record<string, unknown>>(props: SaveProps<M>): Promise<Record<string, unknown>> {\n const response = await this.sendMessage({\n type: \"SAVE\",\n payload: props\n }) as { row: Record<string, unknown> };\n return response.row;\n }\n\n async delete<M extends Record<string, unknown>>(props: DeleteProps<M>): Promise<void> {\n await this.sendMessage({\n type: \"DELETE\",\n payload: props\n });\n }\n\n async executeSql(sql: string, options?: { database?: string, role?: string }): Promise<Record<string, unknown>[]> {\n const response = await this.sendMessage({\n type: \"EXECUTE_SQL\",\n payload: { sql,\noptions }\n }) as { result?: Record<string, unknown>[] };\n return response.result || [];\n }\n\n async fetchAvailableDatabases(): Promise<string[]> {\n const response = await this.sendMessage({\n type: \"FETCH_DATABASES\",\n payload: {}\n }) as { databases?: string[] };\n return response.databases || [];\n }\n\n async fetchAvailableRoles(): Promise<string[]> {\n const response = await this.sendMessage({\n type: \"FETCH_ROLES\"\n }) as { roles?: string[] };\n return response.roles || [];\n }\n\n async fetchCurrentDatabase(): Promise<string | undefined> {\n const response = await this.sendMessage({\n type: \"FETCH_CURRENT_DATABASE\"\n }) as { database?: string };\n return response.database;\n }\n\n async checkUniqueField(path: string, name: string, value: unknown, id?: string, collection?: CollectionConfig): Promise<boolean> {\n const response = await this.sendMessage({\n type: \"CHECK_UNIQUE_FIELD\",\n payload: {\n path,\n name,\n value,\n id,\n collection\n }\n }) as { isUnique: boolean };\n return response.isUnique;\n }\n\n async count<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number> {\n const response = await this.sendMessage({\n type: \"COUNT\",\n payload: props\n }) as { count: number };\n return response.count;\n }\n\n async fetchUnmappedTables(mappedPaths?: string[]): Promise<string[]> {\n const response = await this.sendMessage({\n type: \"FETCH_UNMAPPED_TABLES\",\n payload: { mappedPaths }\n }) as { tables?: string[] };\n return response.tables || [];\n }\n\n async fetchTableMetadata(tableName: string): Promise<TableMetadata> {\n const response = await this.sendMessage({\n type: \"FETCH_TABLE_METADATA\",\n payload: { tableName }\n }) as { metadata?: TableMetadata };\n\n return response.metadata || ({ columns: [],\nforeignKeys: [],\njunctions: [],\npolicies: [] } as TableMetadata);\n }\n\n async createBranch(name: string, options?: { source?: string }): Promise<BranchInfo> {\n const response = await this.sendMessage({\n type: \"CREATE_BRANCH\",\n payload: { name,\noptions }\n }) as { branch: BranchInfo };\n return response.branch;\n }\n\n async deleteBranch(name: string): Promise<void> {\n await this.sendMessage({\n type: \"DELETE_BRANCH\",\n payload: { name }\n });\n }\n\n async listBranches(): Promise<BranchInfo[]> {\n const response = await this.sendMessage({\n type: \"LIST_BRANCHES\",\n payload: {}\n }) as { branches?: BranchInfo[] };\n return response.branches || [];\n }\n\n /**\n * Recursively compare two values for structural equality.\n * Handles primitives, null, undefined, Date, RegExp, arrays, and plain objects.\n */\n private deepEqual(a: unknown, b: unknown): boolean {\n // Same reference or same primitive\n if (a === b) return true;\n\n // Handle null/undefined\n if (a === null || b === null || a === undefined || b === undefined) return false;\n\n // Different types\n if (typeof a !== typeof b) return false;\n\n // Non-object primitives (number, string, boolean, bigint, symbol)\n // that weren't caught by === above (e.g. NaN !== NaN)\n if (typeof a !== \"object\") return false;\n\n // Date comparison\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n if (a instanceof Date || b instanceof Date) return false;\n\n // RegExp comparison\n if (a instanceof RegExp && b instanceof RegExp) {\n return a.source === b.source && a.flags === b.flags;\n }\n if (a instanceof RegExp || b instanceof RegExp) return false;\n\n // Array comparison\n const aIsArray = Array.isArray(a);\n const bIsArray = Array.isArray(b);\n if (aIsArray !== bIsArray) return false;\n\n if (aIsArray && bIsArray) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!this.deepEqual(a[i], b[i])) return false;\n }\n return true;\n }\n\n // Plain object comparison\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n\n if (aKeys.length !== bKeys.length) return false;\n\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(bObj, key)) return false;\n if (!this.deepEqual(aObj[key], bObj[key])) return false;\n }\n\n return true;\n }\n\n private normalizeForComparison(val: unknown): unknown {\n if (!val) return val;\n\n if (Array.isArray(val)) {\n return val.map(item => this.normalizeForComparison(item));\n }\n\n if (typeof val === \"object\") {\n if (val instanceof Date) return val;\n if (val instanceof RegExp) return val;\n\n const obj = val as Record<string, unknown>;\n if (obj.__type === \"relation\") {\n const { data, ...rest } = obj;\n return rest;\n }\n\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n result[k] = this.normalizeForComparison(v);\n }\n return result;\n }\n\n return val;\n }\n\n /**\n * The address of a row, for matching it against another copy of itself.\n *\n * A row is exactly its columns and carries no address, so it is derived\n * from the key columns the server named — including the ordinary case where\n * that key is `id`, which the server reports like any other.\n *\n * Undefined when there are no keys, which means the server could not\n * resolve any: such rows genuinely cannot be recognised, and guessing at a\n * column called `id` would be inventing an identity for a table that has\n * none.\n */\n private rowAddress(row: Record<string, unknown>, pks: PrimaryKeyInfo[] | undefined): string | undefined {\n if (!pks || pks.length === 0) return undefined;\n const address = buildCompositeId(row, pks);\n if (!address || address.split(COMPOSITE_ID_SEPARATOR).every(part => part === \"\")) return undefined;\n return address;\n }\n\n /**\n * Merge incoming rows with cached data, preserving cached references\n * for rows whose values haven't changed. This avoids unnecessary\n * React re-renders when the server refetches all rows but most\n * haven't actually changed.\n */\n private mergeRows(\n cached: Record<string, unknown>[] | undefined,\n incoming: Record<string, unknown>[],\n pks?: PrimaryKeyInfo[]\n ): Record<string, unknown>[] {\n if (!cached || cached.length === 0) return incoming;\n\n // Build a lookup from cached rows by address for O(1) access\n const cachedById = new Map<string, Record<string, unknown>>();\n for (const row of cached) {\n const address = this.rowAddress(row, pks);\n if (address !== undefined) cachedById.set(address, row);\n }\n\n return incoming.map(incomingRow => {\n const address = this.rowAddress(incomingRow, pks);\n const cachedRow = address === undefined ? undefined : cachedById.get(address);\n if (!cachedRow) return incomingRow;\n\n // Compare flat rows directly (no more path/values nesting)\n const normCached = this.normalizeForComparison(cachedRow) as Record<string, unknown>;\n const normIncoming = this.normalizeForComparison(incomingRow) as Record<string, unknown>;\n\n if (this.deepEqual(normCached, normIncoming)) {\n return cachedRow;\n } else {\n // Deep debug: Why did it fail?\n const mismatches: Record<string, { cached: unknown, incoming: unknown }> = {};\n const allKeys = new Set([...Object.keys(normCached), ...Object.keys(normIncoming)]);\n for (const key of allKeys) {\n if (!this.deepEqual(normCached[key], normIncoming[key])) {\n mismatches[key] = { cached: normCached[key],\nincoming: normIncoming[key] };\n }\n }\n console.debug(`[RebaseWS] Row ${address} refetch mismatch:\\n`, JSON.stringify(mismatches, null, 2));\n }\n return incomingRow;\n });\n }\n\n // Subscription methods\n listenCollection<M extends Record<string, unknown>>(\n props: FetchCollectionProps<M>,\n onUpdate: (rows: Record<string, unknown>[]) => void,\n onError?: (error: Error) => void\n ): () => void {\n // A subscription is the app asking for live data, so this is where the\n // socket is wanted. Called before the dedup check below: joining an\n // existing subscription must still work if the socket has since gone.\n this.ensureConnected();\n\n const subscriptionKey = this.createCollectionSubscriptionKey(props);\n const callbackId = `callback_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n // Check if we already have a subscription for these exact parameters\n const existingSubscription = this.collectionSubscriptions.get(subscriptionKey);\n\n if (existingSubscription) {\n // Reuse existing subscription - just add the new callback\n const callbackMap = existingSubscription.callbacks as Map<string, {\n onUpdate: (rows: Record<string, unknown>[]) => void;\n onError?: (error: Error) => void;\n }>;\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n // Immediately fire the callback with cached data if available\n if (existingSubscription.latestData !== undefined && existingSubscription.isInitialDataReceived) {\n try {\n onUpdate(existingSubscription.latestData);\n } catch (error) {\n console.error(\"Error in collection subscription callback:\", error);\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n } else if (!existingSubscription.subscribeInFlight) {\n // Registered but idle: its subscribe never landed (the send failed,\n // or the server answered with an error). Nothing is coming, so\n // re-issue it — otherwise this listener waits forever.\n this.sendCollectionSubscribe(subscriptionKey);\n }\n\n // Return unsubscribe function\n return () => {\n callbackMap.delete(callbackId);\n if (callbackMap.size === 0) {\n // Only tear down if this is still the same registration — a\n // failed subscribe may have replaced it in the meantime.\n if (this.collectionSubscriptions.get(subscriptionKey) !== existingSubscription) return;\n if (existingSubscription.subscribeTimeout) clearTimeout(existingSubscription.subscribeTimeout);\n this.collectionSubscriptions.delete(subscriptionKey);\n this.backendToCollectionKey.delete(existingSubscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: existingSubscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n };\n }\n\n // Create new subscription\n const backendSubscriptionId = `collection_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n const callbackMap = new Map<string, {\n onUpdate: (rows: Record<string, unknown>[]) => void;\n onError?: (error: Error) => void;\n }>();\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n this.collectionSubscriptions.set(subscriptionKey, {\n backendSubscriptionId,\n callbacks: callbackMap,\n props\n });\n\n // Add reverse lookup\n this.backendToCollectionKey.set(backendSubscriptionId, subscriptionKey);\n\n // Send subscription request to backend. A failure here drops the\n // registration and notifies every listener, so the next mount retries.\n this.sendCollectionSubscribe(subscriptionKey);\n\n // Return unsubscribe function\n return () => {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (subscription) {\n const callbacks = subscription.callbacks;\n callbacks.delete(callbackId);\n if (callbacks.size === 0) {\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n this.collectionSubscriptions.delete(subscriptionKey);\n this.backendToCollectionKey.delete(subscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: subscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n }\n };\n }\n\n listenOne<M extends Record<string, unknown>>(\n props: FetchOneProps<M>,\n onUpdate: (row: Record<string, unknown> | null) => void,\n onError?: (error: Error) => void\n ): () => void {\n this.ensureConnected();\n\n const subscriptionKey = this.createSingleSubscriptionKey(props);\n const callbackId = `callback_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n // Check if we already have a subscription for these exact parameters\n const existingSubscription = this.singleSubscriptions.get(subscriptionKey);\n\n if (existingSubscription) {\n // Reuse existing subscription - just add the new callback\n const callbackMap = existingSubscription.callbacks as Map<string, {\n onUpdate: (row: Record<string, unknown> | null) => void;\n onError?: (error: Error) => void;\n }>;\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n // Immediately fire the callback with cached data if available\n if (existingSubscription.latestData !== undefined && existingSubscription.isInitialDataReceived) {\n try {\n onUpdate(existingSubscription.latestData);\n } catch (error) {\n console.error(\"Error in row subscription callback:\", error);\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n } else if (!existingSubscription.subscribeInFlight) {\n // See listenCollection: a registration with nothing in flight is\n // dead, and attaching to it silently would hang this listener.\n this.sendEntitySubscribe(subscriptionKey);\n }\n\n // Return unsubscribe function\n return () => {\n callbackMap.delete(callbackId);\n if (callbackMap.size === 0) {\n if (this.singleSubscriptions.get(subscriptionKey) !== existingSubscription) return;\n if (existingSubscription.subscribeTimeout) clearTimeout(existingSubscription.subscribeTimeout);\n // No more callbacks, unsubscribe from backend\n this.singleSubscriptions.delete(subscriptionKey);\n this.backendToEntityKey.delete(existingSubscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: existingSubscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n };\n }\n\n // Create new subscription\n const backendSubscriptionId = `entity_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n const callbackMap = new Map<string, {\n onUpdate: (row: Record<string, unknown> | null) => void;\n onError?: (error: Error) => void;\n }>();\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n this.singleSubscriptions.set(subscriptionKey, {\n backendSubscriptionId,\n callbacks: callbackMap,\n props\n });\n\n // Add reverse lookup\n this.backendToEntityKey.set(backendSubscriptionId, subscriptionKey);\n\n // Send subscription request to backend\n this.sendEntitySubscribe(subscriptionKey);\n\n // Return unsubscribe function\n return () => {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (subscription) {\n const callbacks = subscription.callbacks;\n callbacks.delete(callbackId);\n if (callbacks.size === 0) {\n this.singleSubscriptions.delete(subscriptionKey);\n this.backendToEntityKey.delete(subscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: subscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n }\n };\n }\n\n /**\n * Send a `subscribe_collection` for an already-registered subscription and\n * arm its watchdog.\n *\n * Every path that registers a collection subscription goes through here, so\n * that a subscribe which never lands — a rejected send, or a server that\n * never answers — always ends up in `failCollectionSubscription` rather than\n * leaving the entry parked with `isInitialDataReceived === false` forever.\n */\n private sendCollectionSubscribe(subscriptionKey: string): void {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeInFlight = true;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeTimeout = undefined;\n // Only time out a frame that is actually on the wire. While offline the\n // message just sits in the queue, and reconnect backoff can exceed the\n // timeout — `armPendingSubscribeWatchdogs` picks these up on connect.\n if (this.isConnected) this.sendCollectionSubscribeWatchdog(subscriptionKey);\n\n this.sendMessage({\n type: \"subscribe_collection\",\n payload: {\n ...subscription.props,\n subscriptionId: backendSubscriptionId\n }\n }).catch(error => {\n const current = this.collectionSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n this.failCollectionSubscription(\n subscriptionKey,\n error instanceof Error ? error : new Error(String(error))\n );\n });\n }\n\n /** The `listenOne` counterpart of {@link sendCollectionSubscribe}. */\n private sendEntitySubscribe(subscriptionKey: string): void {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeInFlight = true;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeTimeout = undefined;\n if (this.isConnected) this.sendEntitySubscribeWatchdog(subscriptionKey);\n\n this.sendMessage({\n type: \"subscribe_one\",\n payload: {\n ...subscription.props,\n subscriptionId: backendSubscriptionId\n }\n }).catch(error => {\n const current = this.singleSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n this.failEntitySubscription(\n subscriptionKey,\n error instanceof Error ? error : new Error(String(error))\n );\n });\n }\n\n /**\n * Report a subscribe failure to every listener and drop the registration.\n *\n * Dropping it is the point: the callbacks stay live (their components are\n * still mounted and have been told), but the next `listenCollection` for\n * these params finds no entry and issues a fresh subscribe instead of\n * silently attaching to a dead one.\n */\n private failCollectionSubscription(subscriptionKey: string, error: Error): void {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeInFlight = false;\n\n this.collectionSubscriptions.delete(subscriptionKey);\n this.backendToCollectionKey.delete(subscription.backendSubscriptionId);\n\n subscription.callbacks.forEach(callback => {\n if (callback.onError) {\n try {\n callback.onError(error);\n } catch (callbackError) {\n console.error(\"Error in collection subscription error callback:\", callbackError);\n }\n }\n });\n }\n\n /** The `listenOne` counterpart of {@link failCollectionSubscription}. */\n private failEntitySubscription(subscriptionKey: string, error: Error): void {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeInFlight = false;\n\n this.singleSubscriptions.delete(subscriptionKey);\n this.backendToEntityKey.delete(subscription.backendSubscriptionId);\n\n subscription.callbacks.forEach(callback => {\n if (callback.onError) {\n try {\n callback.onError(error);\n } catch (callbackError) {\n console.error(\"Error in row subscription error callback:\", callbackError);\n }\n }\n });\n }\n\n /**\n * Stop the watchdogs without failing anything — used when the socket drops,\n * since the reconnect path re-subscribes everything anyway and a watchdog\n * firing mid-reconnect would tear down healthy subscriptions.\n */\n private suspendSubscribeWatchdogs(): void {\n for (const sub of this.collectionSubscriptions.values()) {\n if (sub.subscribeTimeout) clearTimeout(sub.subscribeTimeout);\n sub.subscribeTimeout = undefined;\n sub.subscribeInFlight = false;\n }\n for (const sub of this.singleSubscriptions.values()) {\n if (sub.subscribeTimeout) clearTimeout(sub.subscribeTimeout);\n sub.subscribeTimeout = undefined;\n sub.subscribeInFlight = false;\n }\n }\n\n /**\n * Arm watchdogs for subscribes that were requested while offline and have\n * just been flushed to the socket. Their timers were deliberately not set at\n * request time, so without this they would have no timeout at all.\n */\n private armPendingSubscribeWatchdogs(): void {\n for (const [key, sub] of this.collectionSubscriptions.entries()) {\n if (sub.subscribeInFlight && !sub.subscribeTimeout) this.sendCollectionSubscribeWatchdog(key);\n }\n for (const [key, sub] of this.singleSubscriptions.entries()) {\n if (sub.subscribeInFlight && !sub.subscribeTimeout) this.sendEntitySubscribeWatchdog(key);\n }\n }\n\n private sendCollectionSubscribeWatchdog(subscriptionKey: string): void {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeTimeout = setTimeout(() => {\n const current = this.collectionSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n if (!current.subscribeInFlight) return;\n this.failCollectionSubscription(\n subscriptionKey,\n new RebaseApiError(\"Subscription timed out\", { code: \"SUBSCRIPTION_TIMEOUT\" })\n );\n }, this.subscriptionTimeoutMs);\n }\n\n private sendEntitySubscribeWatchdog(subscriptionKey: string): void {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeTimeout = setTimeout(() => {\n const current = this.singleSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n if (!current.subscribeInFlight) return;\n this.failEntitySubscription(\n subscriptionKey,\n new RebaseApiError(\"Subscription timed out\", { code: \"SUBSCRIPTION_TIMEOUT\" })\n );\n }, this.subscriptionTimeoutMs);\n }\n\n /**\n * Fail every subscription that never received data. Called when reconnection\n * is given up on, so views surface an error instead of spinning forever.\n */\n private failAllPendingSubscriptions(error: Error): void {\n for (const key of [...this.collectionSubscriptions.keys()]) {\n const sub = this.collectionSubscriptions.get(key);\n if (sub && !sub.isInitialDataReceived) this.failCollectionSubscription(key, error);\n }\n for (const key of [...this.singleSubscriptions.keys()]) {\n const sub = this.singleSubscriptions.get(key);\n if (sub && !sub.isInitialDataReceived) this.failEntitySubscription(key, error);\n }\n }\n\n /**\n * Re-send all active subscriptions to the backend after a reconnect.\n * The server wipes subscription state when a client disconnects, so\n * we need to re-register everything to resume receiving updates.\n */\n private resubscribeAll(): void {\n console.debug(`[WS] Re-subscribing: ${this.collectionSubscriptions.size} collection(s), ${this.singleSubscriptions.size} row(ies)`);\n\n // Re-subscribe collection subscriptions\n for (const [key, sub] of this.collectionSubscriptions.entries()) {\n // Generate a fresh backend ID since the old one is no longer valid on the server\n const oldBackendId = sub.backendSubscriptionId;\n const newBackendId = `collection_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n sub.backendSubscriptionId = newBackendId;\n\n // Update reverse lookup\n this.backendToCollectionKey.delete(oldBackendId);\n this.backendToCollectionKey.set(newBackendId, key);\n\n this.sendCollectionSubscribe(key);\n }\n\n // Re-subscribe row subscriptions\n for (const [key, sub] of this.singleSubscriptions.entries()) {\n const oldBackendId = sub.backendSubscriptionId;\n const newBackendId = `entity_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n sub.backendSubscriptionId = newBackendId;\n\n this.backendToEntityKey.delete(oldBackendId);\n this.backendToEntityKey.set(newBackendId, key);\n\n this.sendEntitySubscribe(key);\n }\n }\n\n private createCollectionSubscriptionKey(props: FetchCollectionProps): string {\n // Create a deterministic key based on subscription parameters\n const key = {\n path: props.path,\n filter: props.filter,\n limit: props.limit,\n startAfter: props.startAfter,\n orderBy: props.orderBy,\n order: props.order,\n searchString: props.searchString,\n collection: props.collection?.name\n };\n // Use replacer function (not array) to sort keys at all levels for deterministic output\n return JSON.stringify(key, (_, value) => {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n return Object.keys(value).sort().reduce((sorted: Record<string, unknown>, k) => {\n sorted[k] = value[k];\n return sorted;\n }, {});\n }\n return value;\n });\n }\n\n private createSingleSubscriptionKey(props: FetchOneProps): string {\n return `${props.path}|${props.id}`;\n }\n}\n","/**\n * Broadcast channels and presence, as an SDK surface.\n *\n * The realtime engine has supported `join_channel`, `broadcast`,\n * `presence_track`, `presence_untrack` and `presence_state` for a while, but\n * the client only recognised those types well enough to send them\n * fire-and-forget: there were no methods to call and no way to receive channel\n * or broadcast events, since `on()` handles only connect / disconnect /\n * reconnect / error. Anything wanting presence therefore opened a *second*\n * socket and reimplemented the AUTHENTICATE → AUTH_SUCCESS handshake, the\n * reconnect backoff, and the presence heartbeat — a couple of hundred lines\n * per app, all of it duplicating this package.\n *\n * Two protocol details this hides, because both are easy to get wrong and\n * neither is discoverable from the message list:\n *\n * - **A joining client is told only about its own join.** The `presence_diff`\n * it receives after `presence_track` contains just itself. The existing\n * roster arrives only in response to an explicit `presence_state` request,\n * so `join()` sends one.\n * - **Presence expires after 30s** (`PRESENCE_TIMEOUT_MS` server-side). A\n * client that tracks once and goes quiet silently vanishes from everyone\n * else's roster while still sitting in the document, so `track()` starts a\n * heartbeat and `leave()` stops it.\n */\n\n/** Presence state keyed by the server's client id. */\nexport type PresenceState = Record<string, Record<string, unknown>>;\n\nexport interface PresenceDiff {\n joins: PresenceState;\n leaves: PresenceState;\n}\n\nexport interface BroadcastEvent {\n event: string;\n payload: unknown;\n}\n\n/** The socket operations a channel needs; satisfied by RebaseWebSocketClient. */\nexport interface ChannelTransport {\n sendMessage(message: Record<string, unknown>): Promise<unknown>;\n onChannelMessage(channel: string, handler: (message: Record<string, unknown>) => void): () => void;\n onReconnect(handler: () => void): () => void;\n}\n\n/**\n * Re-send presence comfortably inside the server's 30s expiry.\n *\n * Two-thirds of the window: one lost heartbeat still leaves time for the next\n * before the entry is reaped, so a single dropped frame is not a disappearance.\n */\nconst PRESENCE_HEARTBEAT_MS = 20_000;\n\nexport class RebaseRealtimeChannel {\n private presenceHandlers = new Set<(state: PresenceState, diff?: PresenceDiff) => void>();\n private broadcastHandlers = new Set<(event: BroadcastEvent) => void>();\n private unsubscribers: (() => void)[] = [];\n\n /** Last known roster, kept so handlers always get a full picture. */\n private presences: PresenceState = {};\n /** What this client last tracked, replayed on reconnect and heartbeat. */\n private trackedState: Record<string, unknown> | null = null;\n private heartbeat: ReturnType<typeof setInterval> | null = null;\n private joined = false;\n\n constructor(\n public readonly name: string,\n private transport: ChannelTransport\n ) {}\n\n /**\n * Join the channel and ask for the current roster.\n *\n * Called automatically by `track`, `broadcast`, `onPresence` and\n * `onBroadcast`; calling it directly is only needed to start receiving\n * before there is anything to send.\n */\n /**\n * Send a channel message.\n *\n * Every channel message is read by the server out of a `payload` envelope\n * (`payload?.channel`, `payload?.state`, `payload?.event`). Sending those\n * fields flat does not error: `payload?.channel` simply reads as\n * `undefined`, so the client is registered into channel `undefined` with\n * empty state, and the echo comes back with no `channel` for\n * `onChannelMessage` to match — presence and broadcast both go quiet with\n * nothing logged. Funnelled through one place so a new message type cannot\n * reintroduce that.\n */\n private send(type: string, fields: Record<string, unknown> = {}): Promise<unknown> {\n return this.transport.sendMessage({ type, payload: { channel: this.name, ...fields } });\n }\n\n async join(): Promise<void> {\n if (this.joined) return;\n this.joined = true;\n\n this.unsubscribers.push(\n this.transport.onChannelMessage(this.name, (message) => this.handle(message))\n );\n\n // A reconnect drops server-side channel membership and presence, so\n // both have to be re-established. Nothing else notices this: the\n // socket comes back, and the client just stops receiving.\n this.unsubscribers.push(\n this.transport.onReconnect(() => {\n void this.rejoin();\n })\n );\n\n await this.send(\"join_channel\");\n // Not optional. Joining does not push the roster — without this the\n // channel believes it is alone until somebody else happens to move.\n await this.send(\"presence_state\");\n }\n\n private async rejoin(): Promise<void> {\n try {\n await this.send(\"join_channel\");\n await this.send(\"presence_state\");\n if (this.trackedState) {\n await this.send(\"presence_track\", { state: this.trackedState });\n }\n } catch {\n // The socket is down again; the next reconnect will retry.\n }\n }\n\n /**\n * Publish this client's presence state, and keep publishing it.\n *\n * Calling `track` again replaces the state (and restarts the heartbeat),\n * which is how you update e.g. a cursor position.\n */\n async track(state: Record<string, unknown>): Promise<void> {\n await this.join();\n this.trackedState = state;\n\n await this.send(\"presence_track\", { state });\n\n if (!this.heartbeat) {\n this.heartbeat = setInterval(() => {\n if (!this.trackedState) return;\n void this.send(\"presence_track\", { state: this.trackedState })\n .catch(() => { /* a dropped beat is recoverable; the next one carries the same state */ });\n }, PRESENCE_HEARTBEAT_MS);\n // Do not hold a Node process open just to say \"still here\".\n (this.heartbeat as unknown as { unref?: () => void }).unref?.();\n }\n }\n\n /** Stop publishing presence, without leaving the channel. */\n async untrack(): Promise<void> {\n this.stopHeartbeat();\n this.trackedState = null;\n if (this.joined) {\n await this.send(\"presence_untrack\");\n }\n }\n\n /**\n * Observe the roster. The handler fires immediately with what is already\n * known, then on every change.\n */\n onPresence(handler: (state: PresenceState, diff?: PresenceDiff) => void): () => void {\n this.presenceHandlers.add(handler);\n void this.join();\n if (Object.keys(this.presences).length > 0) handler({ ...this.presences });\n return () => this.presenceHandlers.delete(handler);\n }\n\n /** Send a broadcast. The sender does not receive its own message. */\n async broadcast(event: string, payload: unknown): Promise<void> {\n await this.join();\n await this.send(\"broadcast\", { event, payload });\n }\n\n /** Observe broadcasts. Pass an event name to filter. */\n onBroadcast(handler: (event: BroadcastEvent) => void): () => void;\n onBroadcast(event: string, handler: (payload: unknown) => void): () => void;\n onBroadcast(\n eventOrHandler: string | ((event: BroadcastEvent) => void),\n maybeHandler?: (payload: unknown) => void\n ): () => void {\n const wrapped: (event: BroadcastEvent) => void = typeof eventOrHandler === \"string\"\n ? (e) => { if (e.event === eventOrHandler) maybeHandler!(e.payload); }\n : eventOrHandler;\n\n this.broadcastHandlers.add(wrapped);\n void this.join();\n return () => this.broadcastHandlers.delete(wrapped);\n }\n\n /** Leave the channel and release every listener and timer. */\n async leave(): Promise<void> {\n this.stopHeartbeat();\n this.trackedState = null;\n this.presences = {};\n this.presenceHandlers.clear();\n this.broadcastHandlers.clear();\n\n for (const off of this.unsubscribers) off();\n this.unsubscribers = [];\n\n if (this.joined) {\n this.joined = false;\n await this.send(\"leave_channel\");\n }\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeat) {\n clearInterval(this.heartbeat);\n this.heartbeat = null;\n }\n }\n\n /** Fold an incoming frame into the roster and fan it out. */\n private handle(message: Record<string, unknown>): void {\n switch (message.type) {\n case \"presence_state\": {\n this.presences = (message.presences as PresenceState) ?? {};\n this.emitPresence();\n break;\n }\n case \"presence_diff\": {\n const joins = (message.joins as PresenceState) ?? {};\n const leaves = (message.leaves as PresenceState) ?? {};\n // A diff carries only what moved, so the roster is maintained\n // here rather than handed to callers to reassemble.\n for (const [id, state] of Object.entries(joins)) this.presences[id] = state;\n for (const id of Object.keys(leaves)) delete this.presences[id];\n this.emitPresence({ joins, leaves });\n break;\n }\n case \"broadcast\": {\n const event = { event: message.event as string, payload: message.payload };\n for (const handler of this.broadcastHandlers) handler(event);\n break;\n }\n }\n }\n\n private emitPresence(diff?: PresenceDiff): void {\n const snapshot = { ...this.presences };\n for (const handler of this.presenceHandlers) handler(snapshot, diff);\n }\n}\n","import { createTransport, RebaseClientConfig } from \"./transport\";\nimport { RebaseClientError } from \"./errors\";\nimport { createAuth, CreateAuthOptions } from \"./auth\";\nimport { createAdmin, CreateAdminOptions } from \"./admin\";\nimport { createCron, CreateCronOptions } from \"./cron\";\nimport { createBackups } from \"./backups\";\nimport { createApiKeys, CreateApiKeysOptions } from \"./api-keys\";\nimport { CollectionClient, createCollectionClient } from \"./collection\";\nimport { createFunctionsClient } from \"./functions\";\nimport { createStorage } from \"./storage\";\nimport { ClientStorageSourceRegistry } from \"./storage-registry\";\nimport { RebaseWebSocketClient } from \"./websocket\";\nimport { RebaseRealtimeChannel } from \"./realtime-channel\";\nimport {\n DEFAULT_STORAGE_SOURCE_KEY,\n InsertOf,\n RebaseClient,\n RebaseSdkData,\n RowOf,\n StorageSource,\n StorageSourceDefinition,\n StorageSourceRegistry,\n UpdateOf\n} from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\n\n// ─── Public API surface ──────────────────────────────────────────────────────\n//\n// This barrel is the public API of `@rebasepro/client`. It is an explicit,\n// curated list — NOT `export *` — so that adding an export to a module below\n// does not silently republish it to app developers. Internal factories\n// (`createTransport`, `createAuth`, `createCollectionClient`, …), the raw\n// `Transport`, the storage-source registry impl, the JSON reviver, and the\n// concrete `SDKQueryBuilder` class are intentionally NOT re-exported: they are\n// implementation details of `createRebaseClient()` and have no external\n// consumers. App developers reach them through the client instance, never by\n// importing the factory. To add something to the public surface, add it here\n// deliberately.\n\n// Errors — the single error type thrown by SDK HTTP calls, plus the\n// data-proxy's unknown-collection error.\nexport { RebaseApiError } from \"./transport\";\nexport { RebaseClientError } from \"./errors\";\n\n// Query + collection types (annotate SDK results; construct via the fluent API).\nexport type { RebaseClientConfig, FindParams, FindResponse } from \"./transport\";\nexport type { CollectionClient } from \"./collection\";\nexport type { FindResult, SDKCollectionClient, SDKQueryBuilderInterface, PaginationMeta } from \"@rebasepro/types\";\n\n// Logical-condition helpers for `.where(or(...), and(...))`.\nexport { QueryBuilder, or, and, cond } from \"@rebasepro/common\";\n\n// Auth: session/token types, config, and the pluggable storage strategies.\nexport { createCookieStorage, createMemoryStorage } from \"./auth\";\nexport type { AuthConfig, AuthStorage, CookieStorageOptions, CreateAuthOptions } from \"./auth\";\nexport type { RebaseSession, AuthTokens, AuthChangeEvent, DeviceSession } from \"@rebasepro/types\";\n/** @deprecated Import `User` / `AuthTokens` from `@rebasepro/types` instead. */\nexport type { RebaseUser, RebaseTokens } from \"./auth\";\n\n// Control-plane client option/DTO types (the client instance exposes the impls).\nexport type { CreateAdminOptions } from \"./admin\";\nexport type { AdminUser } from \"./admin\";\nexport type { CreateCronOptions } from \"./cron\";\nexport { createBackups } from \"./backups\";\nexport type { CreateBackupsOptions } from \"./backups\";\nexport type {\n ApiKeyMasked,\n ApiKeyPermission,\n ApiKeyWithSecret,\n CreateApiKeyRequest,\n CreateApiKeysOptions,\n UpdateApiKeyRequest\n} from \"./api-keys\";\nexport type { FunctionInvokeOptions, FunctionsClient } from \"./functions\";\n\n// Realtime: the WebSocket client class is internal to `createRebaseClient()`,\n// but re-exported (see @internal on the class) because the `client-postgres`\n// driver constructs it directly. Not a stable app-facing API.\nexport { RebaseWebSocketClient } from \"./websocket\";\nexport { RebaseRealtimeChannel } from \"./realtime-channel\";\nexport type { PresenceState, PresenceDiff, BroadcastEvent, ChannelTransport } from \"./realtime-channel\";\n\nexport interface CreateRebaseClientOptions extends RebaseClientConfig {\n auth?: CreateAuthOptions;\n admin?: CreateAdminOptions;\n cron?: CreateCronOptions;\n apiKeys?: CreateApiKeysOptions;\n /**\n * Declared storage sources for multi-backend support. Server-transport\n * entries are auto-wired into `client.storageRegistry`; `direct` sources\n * are registered app-side (e.g. via a Firebase Storage hook). The default\n * source (`storage`) is always registered under\n * {@link DEFAULT_STORAGE_SOURCE_KEY}.\n */\n storageSources?: StorageSourceDefinition[];\n /**\n * Maps camelCase property names / safe identifiers to the actual\n * collection slugs on the server (e.g. `{ companyMembers: \"company-members\" }`).\n * If provided, the data layer proxy will resolve property accessors to their\n * correct slugs via this map before falling back to automatic snake_casing.\n */\n collections?: Record<string, string>;\n}\n\n// ─── Typed Data Proxy ────────────────────────────────────────────────────────\n// Adds typed collection accessors when `DB` is provided via the SDK generator.\n\ntype KebabToCamelCase<S extends string> =\n S extends `${infer T}-${infer U}`\n ? `${T}${Capitalize<KebabToCamelCase<U>>}`\n : S;\n\n// Resolve a generated `Database` entry from a (kebab-case) slug literal,\n// or `unknown` when the slug isn't in the schema — the extractors below\n// then fall back to the open row / partial shapes.\ntype DBEntry<DB, S extends string> =\n KebabToCamelCase<S> extends keyof DB ? DB[KebabToCamelCase<S>] : unknown;\n\ntype TypedDataLayer<DB> = {\n collection<S extends string>(slug: S): CollectionClient<\n RowOf<DBEntry<DB, S>>,\n InsertOf<DBEntry<DB, S>>,\n UpdateOf<DBEntry<DB, S>>\n >;\n} & {\n [K in keyof DB]: CollectionClient<RowOf<DB[K]>, InsertOf<DB[K]>, UpdateOf<DB[K]>>;\n} & RebaseSdkData;\n\n/**\n * The return type of `createRebaseClient<DB>()`.\n *\n * This is `RebaseClient` (from `@rebasepro/types`) with all optional\n * capabilities populated and the `data` layer narrowed to provide\n * typed collection accessors when a `DB` schema generic is supplied.\n */\nexport type CreateRebaseClientResult<DB = Record<string, unknown>> = Omit<RebaseClient<DB>, \"data\" | \"email\"> & {\n setToken: (token: string | null) => void;\n setAuthTokenGetter: (getter: () => Promise<string | null>) => void;\n setOnUnauthorized: (handler: () => Promise<boolean>) => void;\n resolveToken: () => Promise<string | null>;\n auth: ReturnType<typeof createAuth>;\n admin: ReturnType<typeof createAdmin>;\n cron: ReturnType<typeof createCron>;\n backups: ReturnType<typeof createBackups>;\n apiKeys: ReturnType<typeof createApiKeys>;\n functions: ReturnType<typeof createFunctionsClient>;\n ws?: RebaseWebSocketClient;\n /**\n * Broadcast and presence channels.\n *\n * Was missing from this type while present on the returned object, which\n * made `client.realtime.channel(...)` a type error and forced every adopter\n * to cast around the feature before they could reach it.\n */\n realtime: {\n /**\n * Join a broadcast/presence channel. Repeated calls with the same name\n * return the same channel object. Throws only when the client was\n * created with `realtime: false`.\n */\n channel: (name: string) => RebaseRealtimeChannel;\n };\n /**\n * Release the realtime socket and its reconnect timer.\n *\n * An open socket keeps the Node event loop alive, so a script that does not\n * call this will not exit on its own. Safe when realtime was never started\n * (`realtime: false`), and safe to call twice.\n */\n close: () => void;\n storage: StorageSource;\n storageRegistry: StorageSourceRegistry;\n createStorageSource: (storageId: string) => StorageSource;\n fetchStorageSources: () => Promise<StorageSourceDefinition[]>;\n call: <T = unknown>(endpoint: string, payload?: unknown) => Promise<T>;\n collection: <M extends Record<string, unknown> = Record<string, unknown>>(slug: string) => CollectionClient<M>;\n data: TypedDataLayer<DB>;\n};\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\n/**\n * Derive a WebSocket URL from an HTTP base URL.\n * `http://` → `ws://`, `https://` → `wss://`.\n */\nfunction deriveWebSocketUrl(baseUrl?: string): string {\n if (typeof window !== \"undefined\") {\n let absoluteUrl = \"\";\n if (!baseUrl) {\n absoluteUrl = window.location.origin;\n } else if (/^https?:\\/\\//i.test(baseUrl) || /^wss?:\\/\\//i.test(baseUrl)) {\n absoluteUrl = baseUrl;\n } else {\n try {\n absoluteUrl = new URL(baseUrl, window.location.href).origin;\n } catch {\n absoluteUrl = window.location.origin;\n }\n }\n const protocol = absoluteUrl.startsWith(\"https:\") || absoluteUrl.startsWith(\"wss:\") ? \"wss:\" : \"ws:\";\n return absoluteUrl\n .replace(/^https?:\\/\\//i, `${protocol}//`)\n .replace(/^wss?:\\/\\//i, `${protocol}//`)\n .replace(/\\/$/, \"\");\n }\n\n if (!baseUrl) return \"\";\n if (!/^https?:\\/\\//i.test(baseUrl) && !/^wss?:\\/\\//i.test(baseUrl)) {\n return \"\";\n }\n return baseUrl\n .replace(/^https?:\\/\\//i, (match) => match.toLowerCase() === \"https://\" ? \"wss://\" : \"ws://\")\n .replace(/\\/$/, \"\");\n}\n\nexport function createRebaseClient<DB = Record<string, unknown>>(options: CreateRebaseClientOptions): CreateRebaseClientResult<DB> {\n const transport = createTransport(options);\n const auth = createAuth(transport, options.auth);\n const admin = createAdmin(transport, options.admin);\n const cron = createCron(transport, options.cron);\n const backups = createBackups(transport);\n const apiKeys = createApiKeys(transport, options.apiKeys);\n const storage = createStorage(transport);\n const functions = createFunctionsClient(transport);\n\n // Build a server-backed StorageSource for a given storage-source key.\n const createStorageSource = (storageId: string): StorageSource =>\n storageId === DEFAULT_STORAGE_SOURCE_KEY ? storage : createStorage(transport, storageId);\n\n // Storage registry: always holds the default source, plus any declared\n // server-transport sources. `direct` sources are registered app-side.\n const storageRegistry = new ClientStorageSourceRegistry();\n storageRegistry.register(DEFAULT_STORAGE_SOURCE_KEY, storage);\n for (const def of options.storageSources ?? []) {\n if (def.transport === \"server\" && def.key !== DEFAULT_STORAGE_SOURCE_KEY) {\n storageRegistry.register(def.key, createStorageSource(def.key));\n }\n }\n\n // Discover storage sources from the backend, making the server the single\n // source of truth. Server-transport sources are auto-wired into the\n // registry; `direct` sources are returned for the app to register. The\n // promise is cached on success and reset on failure so it can be retried\n // (e.g. once the user authenticates).\n let storageSourcesPromise: Promise<StorageSourceDefinition[]> | undefined;\n const fetchStorageSources = (): Promise<StorageSourceDefinition[]> => {\n if (storageSourcesPromise) return storageSourcesPromise;\n storageSourcesPromise = transport\n .request<{ data: StorageSourceDefinition[] }>(\"/storage/sources\")\n .then((res) => {\n const defs = res.data ?? [];\n for (const def of defs) {\n if (def.transport === \"server\"\n && def.key !== DEFAULT_STORAGE_SOURCE_KEY\n && !storageRegistry.has(def.key)) {\n storageRegistry.register(def.key, createStorageSource(def.key));\n }\n }\n return defs;\n })\n .catch((e) => {\n storageSourcesPromise = undefined; // allow retry\n throw e;\n });\n return storageSourcesPromise;\n };\n\n // Opting out has to happen before the URL is derived: `deriveWebSocketUrl`\n // always produces one, so a truthy check alone can never leave the socket\n // closed.\n const realtimeEnabled = options.realtime !== false;\n const resolvedWsUrl = realtimeEnabled\n ? (options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl))\n : undefined;\n\n let ws: RebaseWebSocketClient | undefined;\n /** One channel object per name — see `realtime.channel`. */\n const realtimeChannels = new Map<string, RebaseRealtimeChannel>();\n if (resolvedWsUrl) {\n const wsOnUnauthorized = options.onUnauthorized || (async () => {\n try {\n await auth.refreshSession();\n return true;\n } catch (e) {\n return false;\n }\n });\n\n ws = new RebaseWebSocketClient({\n websocketUrl: resolvedWsUrl,\n getAuthToken: async () => {\n let session = auth.getSession();\n if (session && session.expiresAt <= Date.now() + 10000) {\n try {\n session = await auth.refreshSession();\n } catch (e) { /* ignore */ }\n }\n return session?.accessToken || options.token || \"\";\n },\n onUnauthorized: wsOnUnauthorized\n });\n\n auth.onAuthStateChange((event, session) => {\n if (!ws) return;\n if (event === \"SIGNED_OUT\") {\n // Not permanent: the client stays usable, and a later subscribe\n // should reconnect anonymously.\n ws.disconnect();\n } else if (event === \"SIGNED_IN\" || event === \"TOKEN_REFRESHED\") {\n // Only re-authenticate a socket that already exists. Signing in\n // is not a request for realtime, and dialling here would undo\n // lazy connect for every app with a login. A socket opened\n // later authenticates itself from `getAuthToken` on open.\n if (session?.accessToken && ws.hasSocket) {\n ws.authenticate(session.accessToken).catch(console.warn);\n }\n }\n });\n }\n\n // Register transport callback for 401s after auth is instantiated.\n // IMPORTANT: We must use transport.setOnUnauthorized() here — NOT set\n // options.onUnauthorized — because the transport was already created above\n // and captured the (undefined) value from the config closure.\n if (!options.onUnauthorized) {\n transport.setOnUnauthorized(async () => {\n try {\n await auth.refreshSession();\n return true;\n } catch (e) {\n return false;\n }\n });\n }\n\n /**\n * Suggest the closest known collection key for a mistyped accessor.\n * Uses edit-distance-1 and prefix matching — no external dependency.\n */\n function suggestCollection(prop: string, knownKeys: string[]): string | undefined {\n // Prefix match (e.g. \"prod\" → \"products\")\n const prefixMatch = knownKeys.find(k => k.startsWith(prop) || prop.startsWith(k));\n if (prefixMatch) return prefixMatch;\n\n // Edit-distance-1: deletions, insertions, substitutions, transpositions\n for (const key of knownKeys) {\n if (Math.abs(key.length - prop.length) > 1) continue;\n let diffs = 0;\n const longer = key.length >= prop.length ? key : prop;\n const shorter = key.length >= prop.length ? prop : key;\n if (longer.length === shorter.length) {\n // Same length: allow 1 substitution or 1 transposition\n for (let i = 0; i < longer.length; i++) {\n if (longer[i] !== shorter[i]) {\n // Check for transposition\n if (\n i + 1 < longer.length &&\n longer[i] === shorter[i + 1] &&\n longer[i + 1] === shorter[i]\n ) {\n diffs++;\n i++; // skip next char (already accounted for)\n if (diffs > 1) break;\n continue;\n }\n diffs++;\n }\n if (diffs > 1) break;\n }\n } else {\n // Length differs by 1: allow 1 insertion/deletion\n let li = 0;\n let si = 0;\n while (li < longer.length) {\n if (si < shorter.length && longer[li] === shorter[si]) {\n si++;\n } else {\n diffs++;\n }\n li++;\n if (diffs > 1) break;\n }\n }\n if (diffs <= 1) return key;\n }\n\n return undefined;\n }\n\n const collectionClients = new Map<string, CollectionClient<Record<string, unknown>>>();\n let untypedWarned = false;\n\n function collection(slug: string): CollectionClient<Record<string, unknown>> {\n if (!collectionClients.has(slug)) {\n collectionClients.set(slug, createCollectionClient(transport, slug, ws));\n }\n return collectionClients.get(slug)!;\n }\n\n const dataTarget = { collection } as Record<string, unknown>;\n\n const dataProxy = new Proxy(dataTarget, {\n get(_target, prop: string | symbol) {\n if (prop === \"collection\") {\n return collection;\n }\n if (typeof prop === \"symbol\") return undefined;\n if (typeof prop === \"string\" && prop !== \"then\" && prop !== \"toJSON\" && prop !== \"$$typeof\") {\n if (options.collections) {\n if (prop in options.collections) {\n return collection(options.collections[prop]);\n }\n // Strict mode: the developer supplied a typed dictionary,\n // so we know the full set of valid accessors.\n const knownKeys = Object.keys(options.collections);\n const suggestion = suggestCollection(prop, knownKeys);\n const knownList = knownKeys.join(\", \");\n let msg = `Unknown collection accessor \"${prop}\". Known collections: ${knownList}.`;\n if (suggestion) msg += ` Did you mean \"${suggestion}\"?`;\n msg += ` Use data.collection(\"<slug>\") for dynamic slugs.`;\n throw new RebaseClientError(msg);\n }\n // Untyped fallback: convert camelCase property names to snake_case slugs.\n // e.g. `companyMembers` → `company_members`\n if (!untypedWarned) {\n untypedWarned = true;\n console.warn(\n `[Rebase] Untyped data access detected (client.data.${prop}). ` +\n `Collection names are resolved via snake_case conversion, which may cause silent 404s at request time. ` +\n `Pass a \\`collections\\` dictionary to createRebaseClient() or use the generated SDK for type-safe access.`\n );\n }\n const slug = toSnakeCase(prop);\n return collection(slug);\n }\n return undefined;\n }\n });\n\n const target = {\n auth,\n admin,\n cron,\n backups,\n apiKeys,\n functions,\n storage,\n storageRegistry,\n createStorageSource,\n fetchStorageSources,\n ws,\n realtime: {\n /**\n * Join a broadcast/presence channel.\n *\n * Repeated calls with the same name return the same channel, so\n * separate components can attach handlers without each opening its\n * own membership — and `leave()` from one would otherwise silently\n * cut off the others.\n */\n channel: (name: string): RebaseRealtimeChannel => {\n // Only `realtime: false` gets here — a hard opt-out, so this\n // stays an error. Being merely *unconnected* does not: the\n // socket opens on the first channel operation, which is the\n // whole point of asking for a channel before you use one.\n if (!ws) {\n throw new RebaseClientError(\n \"Realtime is disabled on this client (realtime: false), so channels are unavailable.\"\n );\n }\n let existing = realtimeChannels.get(name);\n if (!existing) {\n existing = new RebaseRealtimeChannel(name, ws);\n realtimeChannels.set(name, existing);\n }\n return existing;\n }\n },\n /**\n * Release the realtime socket and its reconnect timer.\n *\n * Until this returns, the open socket keeps the Node event loop alive\n * and the process will not exit on its own. Safe to call when realtime\n * was never started, and safe to call twice.\n */\n close: () => {\n // Channels hold presence heartbeat timers, which would otherwise\n // keep firing (and keep a Node process alive) after the socket\n // they publish over is gone.\n for (const channel of realtimeChannels.values()) void channel.leave();\n realtimeChannels.clear();\n // Permanent: nothing queued afterwards may redial and keep the\n // event loop alive, which is the reason this method exists.\n ws?.disconnect(true);\n },\n setToken: transport.setToken,\n setAuthTokenGetter: transport.setAuthTokenGetter,\n setOnUnauthorized: transport.setOnUnauthorized,\n resolveToken: transport.resolveToken,\n baseUrl: transport.baseUrl,\n collection,\n call: async <T = unknown>(endpoint: string, payload?: unknown): Promise<T> => {\n const prefix = endpoint.startsWith(\"/\") ? \"\" : \"/\";\n const res = await transport.request<{ data: T }>(`${prefix}${endpoint}`, {\n method: \"POST\",\n body: payload ? JSON.stringify(payload) : undefined\n });\n return res.data ?? (res as T);\n },\n data: dataProxy,\n } as unknown as CreateRebaseClientResult<DB>;\n\n return target;\n}\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","names":[],"sources":["../src/reviver.ts","../src/transport.ts","../src/auth.ts","../src/admin.ts","../src/cron.ts","../src/backups.ts","../src/api-keys.ts","../src/sdk_query_builder.ts","../src/collection.ts","../src/functions.ts","../src/storage.ts","../src/storage-registry.ts","../src/websocket.ts","../src/realtime-channel.ts","../src/index.ts"],"sourcesContent":["import { EntityReference, EntityRelation, GeoPoint, Vector } from \"@rebasepro/types\";\n\nexport function rebaseReviver(_key: string, value: unknown): unknown {\n if (value && typeof value === \"object\" && \"__type\" in value) {\n const record = value as Record<string, unknown>;\n switch (record.__type) {\n case \"date\":\n case \"Date\": {\n if (typeof record.value !== \"string\") {\n return value;\n }\n const date = new Date(record.value);\n return isNaN(date.getTime()) ? null : date;\n }\n case \"reference\":\n case \"EntityReference\":\n return new EntityReference({\n id: String(record.id),\n path: record.path as string,\n driver: record.driver as string | undefined,\n databaseId: record.databaseId as string | undefined\n });\n case \"relation\":\n case \"EntityRelation\":\n return new EntityRelation(\n record.id as string | number,\n record.path as string,\n record.data as Record<string, unknown> | undefined\n );\n case \"GeoPoint\":\n return new GeoPoint(record.latitude as number, record.longitude as number);\n case \"Vector\":\n return new Vector(record.value as number[]);\n default:\n return value;\n }\n }\n return value;\n}\n","import { FindParams as TypesFindParams, FindResponse as TypesFindResponse, RebaseApiError } from \"@rebasepro/types\";\nimport { serializeFilter, serializeLogicalCondition, serializeOrderBy } from \"@rebasepro/common\";\nimport { rebaseReviver } from \"./reviver\";\n\n// The canonical client error now lives in `@rebasepro/types` so every package\n// (client, auth, …) throws one type. Re-exported here to preserve the historical\n// `import { RebaseApiError } from \".../transport\"` path used across the SDK.\nexport { RebaseApiError } from \"@rebasepro/types\";\nexport type { RebaseErrorInit } from \"@rebasepro/types\";\n\nexport interface RebaseClientConfig {\n /**\n * Origin of the Rebase server — scheme, host and port **only**.\n *\n * {@link apiPath} is appended to this, so do not include it here:\n * `\"http://localhost:3001\"` is correct, while `\"http://localhost:3001/api\"`\n * silently builds `/api/api/…` and every request 404s. Omit entirely for\n * same-origin requests from the browser.\n */\n baseUrl?: string;\n /**\n * Bearer token sent as `Authorization` on every request.\n *\n * In the browser this is the signed-in user's access token, so row-level\n * security applies. Server-side callers — scripts, cron jobs, ETL — pass the\n * service key instead, which resolves to `{ uid: \"service\", roles: [\"admin\"] }`\n * and **bypasses RLS**: there is no user to constrain those queries, so scope\n * them explicitly.\n */\n token?: string;\n /**\n * Path the API is mounted under, appended to {@link baseUrl}.\n * Defaults to `\"/api\"`; override only if the server mounts it elsewhere.\n */\n apiPath?: string;\n fetch?: typeof globalThis.fetch;\n onUnauthorized?: () => Promise<boolean>;\n websocketUrl?: string; // Optional real-time WebSocket connection\n /**\n * Open the realtime WebSocket. **Defaults to `true`.**\n *\n * The socket connects as soon as the client is constructed and keeps the\n * Node event loop alive, so a one-shot script (CLI, cron job, ETL) will not\n * exit on its own. Set this to `false` for any process that reads or writes\n * and then terminates — `.listen()` and `.listenById()` then throw instead\n * of silently doing nothing.\n *\n * Long-lived processes that do want realtime can instead call\n * `client.close()` when shutting down.\n */\n realtime?: boolean;\n}\n\n/**\n * Re-export from `@rebasepro/types` for backward compatibility.\n */\nexport type FindParams = TypesFindParams;\nexport type FindResponse<T> = TypesFindResponse<T extends Record<string, unknown> ? T : Record<string, unknown>>;\n\nexport function buildQueryString(params?: FindParams): string {\n if (!params) return \"\";\n const parts: string[] = [];\n\n if (params.limit != null) parts.push(`limit=${params.limit}`);\n if (params.offset != null) parts.push(`offset=${params.offset}`);\n if (params.page != null) parts.push(`page=${params.page}`);\n\n if (params.orderBy) {\n const wire = serializeOrderBy(params.orderBy);\n if (wire) parts.push(`orderBy=${encodeURIComponent(wire)}`);\n }\n\n if (params.searchString) {\n parts.push(`searchString=${encodeURIComponent(params.searchString)}`);\n }\n\n if (params.include && params.include.length > 0) {\n parts.push(`include=${encodeURIComponent(params.include.join(\",\"))}`);\n }\n\n if (params.logical) {\n const root = params.logical;\n const serialized = (root.conditions ?? []).map(serializeLogicalCondition).join(\",\");\n parts.push(`${root.type}=${encodeURIComponent(`(${serialized})`)}`);\n }\n\n if (params.where) {\n const serialized = serializeFilter(params.where);\n for (const [field, value] of Object.entries(serialized)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(v)}`);\n }\n } else {\n parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(value)}`);\n }\n }\n }\n\n return parts.length > 0 ? \"?\" + parts.join(\"&\") : \"\";\n}\n\nexport interface Transport {\n request: <T = unknown>(path: string, init?: RequestInit) => Promise<T>;\n setToken: (newToken: string | null) => void;\n setAuthTokenGetter: (getter: () => Promise<string | null>) => void;\n setOnUnauthorized: (handler: () => Promise<boolean>) => void;\n readonly baseUrl: string;\n readonly apiPath: string;\n readonly fetchFn: typeof globalThis.fetch;\n getHeaders: (init?: RequestInit) => Record<string, string>;\n resolveToken: () => Promise<string | null>;\n}\n\n/**\n * The base every request and every caller-built URL resolves against.\n *\n * `baseUrl` is optional because the common production shape is a Rebase\n * backend serving its own SPA, where the API is simply the page's origin.\n * Leaving it unset is therefore the *correct* configuration there — and the\n * one that keeps working when a second hostname (a custom domain) points at\n * the same app.\n *\n * When unset in a browser this resolves to the page origin rather than \"\".\n * Requests behave identically either way, but the empty string is a trap for\n * anything that builds a URL from `client.baseUrl`: `new URL(\"\" + path)`\n * throws, so apps \"fixed\" it by baking an absolute host into their bundle —\n * which is exactly what breaks the day a custom domain is added, and which no\n * amount of CORS configuration repairs, because a SameSite=Lax auth cookie is\n * not sent cross-site either.\n */\nfunction resolveBaseUrl(configured?: string): string {\n if (configured) return configured.replace(/\\/$/, \"\");\n if (typeof window !== \"undefined\" && window.location?.origin) return window.location.origin;\n return \"\";\n}\n\nexport function createTransport(config: RebaseClientConfig): Transport {\n const fetchFn = config.fetch || globalThis.fetch;\n const apiPath = config.apiPath || \"/api\";\n let token = config.token;\n let tokenGetter: (() => Promise<string | null>) | undefined;\n let onUnauthorizedHandler = config.onUnauthorized;\n\n function getHeaders(activeToken: string | undefined, init?: RequestInit) {\n return {\n \"Content-Type\": \"application/json\",\n ...(activeToken ? { Authorization: `Bearer ${activeToken}` } : {}),\n ...((init?.headers as Record<string, string>) || {})\n };\n }\n\n async function request<T = unknown>(path: string, init?: RequestInit): Promise<T> {\n const url = resolveBaseUrl(config.baseUrl) + apiPath + path;\n\n let activeToken = token;\n if (tokenGetter) {\n try {\n const fetched = await tokenGetter();\n if (fetched !== null && fetched !== undefined) {\n activeToken = fetched;\n }\n } catch (e) {\n // Ignore error, fallback to static token if any\n }\n }\n\n const headers = getHeaders(activeToken, init);\n\n // If passing FormData, we MUST let fetch set the boundary, so remove Content-Type\n if (init?.body instanceof FormData) {\n delete (headers as Record<string, string>)[\"Content-Type\"];\n }\n\n const res = await fetchFn(url, { ...init,\nheaders });\n\n if (res.status === 204) return undefined as T; // SAFETY: HTTP 204 No Content has no body\n\n const text = await res.text().catch(() => \"\");\n let body: Record<string, unknown> = {};\n if (text) {\n try {\n body = JSON.parse(text, rebaseReviver) as Record<string, unknown>;\n } catch (e) {\n // If not valid JSON, fallback\n }\n }\n\n // The server always emits the canonical `{ error: { message, code, details? } }`\n // envelope (formatted by the central errorHandler), so we read strictly\n // from `body.error.*`.\n const getErrorField = (obj: Record<string, unknown>, field: string): unknown => {\n const err = obj?.error;\n if (err && typeof err === \"object\" && err !== null) {\n return (err as Record<string, unknown>)[field];\n }\n return undefined;\n };\n\n if (res.status === 401 && onUnauthorizedHandler) {\n const retried = await onUnauthorizedHandler();\n if (retried) {\n let retryToken = token;\n if (tokenGetter) {\n try {\n const fetched = await tokenGetter();\n if (fetched !== null && fetched !== undefined) {\n retryToken = fetched;\n }\n } catch (e) { /* ignore */ }\n }\n const retryHeaders = getHeaders(retryToken, init) as Record<string, string>;\n const retryRes = await fetchFn(url, { ...init,\nheaders: retryHeaders });\n if (retryRes.status === 204) return undefined as T; // SAFETY: HTTP 204 No Content has no body\n const retryText = await retryRes.text().catch(() => \"\");\n let retryBody: Record<string, unknown> = {};\n if (retryText) {\n try {\n retryBody = JSON.parse(retryText, rebaseReviver);\n } catch (e) { /* ignore */ }\n }\n if (!retryRes.ok) {\n let fallbackMessage = retryRes.statusText;\n if (retryRes.status === 404 && !fallbackMessage) {\n const method = init?.method || \"GET\";\n fallbackMessage = `Endpoint not found (${method} ${path}). This usually means the collection is not registered on the backend, or the frontend API URL configuration (e.g. VITE_API_URL) is missing or pointing to the wrong host.`;\n }\n throw new RebaseApiError(\n String(getErrorField(retryBody, \"message\") || fallbackMessage || `Request failed with status ${retryRes.status}`),\n {\n status: retryRes.status,\n code: getErrorField(retryBody, \"code\") as string | undefined,\n details: getErrorField(retryBody, \"details\")\n }\n );\n }\n return retryBody as T;\n }\n }\n\n if (!res.ok) {\n let fallbackMessage = res.statusText;\n if (res.status === 404 && !fallbackMessage) {\n const method = init?.method || \"GET\";\n fallbackMessage = `Endpoint not found (${method} ${path}). This usually means the collection is not registered on the backend, or the frontend API URL configuration (e.g. VITE_API_URL) is missing or pointing to the wrong host.`;\n }\n throw new RebaseApiError(\n String(getErrorField(body, \"message\") || fallbackMessage || `Request failed with status ${res.status}`),\n {\n status: res.status,\n code: getErrorField(body, \"code\") as string | undefined,\n details: getErrorField(body, \"details\")\n }\n );\n }\n\n return body as T;\n }\n\n return {\n request,\n setToken(newToken: string | null) { token = newToken || undefined; },\n setAuthTokenGetter(getter: () => Promise<string | null>) { tokenGetter = getter; },\n setOnUnauthorized(handler: () => Promise<boolean>) { onUnauthorizedHandler = handler; },\n get baseUrl() { return resolveBaseUrl(config.baseUrl); },\n get apiPath() { return apiPath; },\n get fetchFn() { return fetchFn; },\n getHeaders: (init?: RequestInit) => getHeaders(token, init) as Record<string, string>,\n resolveToken: async () => {\n if (tokenGetter) {\n try {\n const fetched = await tokenGetter();\n if (fetched !== null && fetched !== undefined) {\n return fetched;\n }\n } catch (e) { /* ignore */ }\n }\n return token || null;\n }\n };\n}\n","import { RebaseApiError, Transport } from \"./transport\";\nimport type { AuthChangeEvent, RebaseSession, AuthTokens, DeviceSession, User } from \"@rebasepro/types\";\n\n// Re-export canonical types so `import { RebaseSession } from \"@rebasepro/client\"` keeps working\nexport type { RebaseSession, AuthTokens, AuthChangeEvent, DeviceSession } from \"@rebasepro/types\";\n\n/** @deprecated Use `User` from `@rebasepro/types` instead. */\nexport type RebaseUser = User;\n/** @deprecated Use `AuthTokens` from `@rebasepro/types` instead. */\nexport type RebaseTokens = AuthTokens;\n\n/** Minimal, non-sensitive user profile returned by {@link findUserByEmail}. */\nexport interface PublicUserProfile {\n uid: string;\n displayName: string | null;\n photoURL: string | null;\n}\n\n/** Map a raw user object from an auth response (`/login`, `/refresh`, `/me`) to a `User`. */\nfunction mapRawUser(raw: Record<string, unknown>): User {\n return {\n uid: raw.uid as string,\n email: (raw.email as string | null) ?? null,\n displayName: (raw.displayName as string | null) ?? null,\n photoURL: (raw.photoURL as string | null) ?? null,\n providerId: (raw.providerId as string | undefined) ?? \"password\",\n isAnonymous: (raw.isAnonymous as boolean | undefined) ?? false,\n emailVerified: raw.emailVerified as boolean | undefined,\n roles: raw.roles as string[] | undefined,\n metadata: raw.metadata as Record<string, unknown> | undefined,\n };\n}\n\n/** Placeholder user, used only as a last resort when none can be resolved. */\nconst EMPTY_USER: User = { uid: \"\", email: null, displayName: null, photoURL: null, providerId: \"password\", isAnonymous: false };\n\n\nexport interface AuthConfig {\n needsSetup: boolean;\n registrationEnabled: boolean;\n emailServiceEnabled?: boolean;\n passwordReset?: boolean;\n emailVerification?: boolean;\n magicLink?: boolean;\n enabledProviders: string[];\n}\n\nexport interface AuthStorage {\n getItem: (key: string) => string | null;\n setItem: (key: string, value: string) => void;\n removeItem: (key: string) => void;\n}\n\nexport function createMemoryStorage(): AuthStorage {\n const store: Record<string, string> = {};\n return {\n getItem(key) { return store[key] ?? null; },\n setItem(key, value) { store[key] = value; },\n removeItem(key) { delete store[key]; }\n };\n}\n\nfunction detectStorage(): AuthStorage {\n try {\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(\"__rebase_test__\", \"1\");\n localStorage.removeItem(\"__rebase_test__\");\n return localStorage;\n }\n } catch (e) { /* ignore */ }\n return createMemoryStorage();\n}\n\nexport interface CreateAuthOptions {\n storage?: AuthStorage;\n authPath?: string;\n autoRefresh?: boolean;\n persistSession?: boolean;\n /**\n * Authentication flow mode.\n * - 'json' (default): Tokens are sent/received in JSON bodies. Refresh token is stored in local storage.\n * - 'cookie': Refresh token is sent/received via httpOnly cookies. Access token remains in memory.\n */\n authFlowMode?: \"json\" | \"cookie\";\n}\n\nexport function createAuth(transport: Transport, options?: CreateAuthOptions) {\n const opts = options || {};\n const storage = opts.storage || detectStorage();\n const authPath = opts.authPath || \"/auth\";\n const autoRefresh = opts.autoRefresh !== false;\n const persistSession = opts.persistSession !== false;\n const authFlowMode = opts.authFlowMode || \"json\";\n\n const STORAGE_KEY = \"rebase_auth\";\n const REFRESH_BUFFER_MS = 120000;\n // Auto-refresh resilience: retry transient failures with exponential backoff\n // (1s, 2s, 4s, … capped) before giving up and signing out.\n const MAX_REFRESH_RETRIES = 5;\n const REFRESH_RETRY_BASE_MS = 1000;\n const REFRESH_RETRY_MAX_MS = 30000;\n\n let currentSession: RebaseSession | null = null;\n const listeners = new Set<(event: AuthChangeEvent, session: RebaseSession | null) => void>();\n let refreshTimeout: ReturnType<typeof setTimeout> | null = null;\n // De-dupe concurrent refreshes. On boot (esp. cookie mode + React StrictMode)\n // multiple callers can trigger refresh at once; without this they race — the\n // server rotates the refresh token twice and the browser can end up with a\n // cookie the DB no longer matches. A single in-flight promise is shared.\n let inFlightRefresh: Promise<RebaseSession> | null = null;\n let resolveInitialized: (value: void | PromiseLike<void>) => void;\n const isInitialized = new Promise<void>((resolve) => {\n resolveInitialized = resolve;\n });\n\n function authUrl(endpoint: string) {\n return transport.baseUrl + transport.apiPath + authPath + endpoint;\n }\n\n function getFetch() {\n return transport.fetchFn || globalThis.fetch;\n }\n\n function throwApiError(status: number, body: { error?: { message?: string; code?: string; details?: unknown }; message?: string; code?: string; details?: unknown } | undefined, statusText: string): never {\n throw new RebaseApiError(\n body?.error?.message || body?.message || statusText,\n {\n status,\n code: body?.error?.code || body?.code,\n details: body?.error?.details || body?.details\n }\n );\n }\n\n function emit(event: AuthChangeEvent, session: RebaseSession | null) {\n for (const fn of listeners) {\n try { fn(event, session); } catch (e) { /* ignore */ }\n }\n }\n\n function saveSession(session: RebaseSession) {\n if (!persistSession || authFlowMode === \"cookie\") return;\n try {\n storage.setItem(STORAGE_KEY, JSON.stringify(session));\n } catch (e) { /* ignore */ }\n }\n\n function clearStoredSession() {\n try {\n storage.removeItem(STORAGE_KEY);\n } catch (e) { /* ignore */ }\n }\n\n function loadStoredSession(): RebaseSession | null {\n try {\n const raw = storage.getItem(STORAGE_KEY);\n if (raw) return JSON.parse(raw) as RebaseSession;\n } catch (e) { /* ignore */ }\n return null;\n }\n\n /**\n * A refresh failure is only fatal if the refresh token itself is rejected\n * (expired / invalid / forbidden). Network blips, timeouts, and 5xx (e.g. a\n * backend restart mid-session) are transient and must NOT log the user out.\n */\n function isFatalRefreshError(err: unknown): boolean {\n if (!(err instanceof RebaseApiError)) return false; // network/other → transient\n if (err.code === \"INVALID_TOKEN\" || err.code === \"TOKEN_EXPIRED\") return true;\n // 401/403 are auth failures; other statuses (incl. 5xx, 0) are transient.\n return err.status === 401 || err.status === 403;\n }\n\n async function attemptScheduledRefresh(attempt: number) {\n try {\n await refreshSession();\n // On success, refreshSession() re-schedules the next refresh itself.\n } catch (err) {\n if (isFatalRefreshError(err)) {\n signOut();\n return;\n }\n if (attempt >= MAX_REFRESH_RETRIES) {\n signOut();\n return;\n }\n // Transient failure — back off and retry rather than dropping the session.\n const backoff = Math.min(REFRESH_RETRY_BASE_MS * 2 ** attempt, REFRESH_RETRY_MAX_MS);\n refreshTimeout = setTimeout(() => { void attemptScheduledRefresh(attempt + 1); }, backoff);\n }\n }\n\n function scheduleRefresh(expiresAt: number) {\n if (refreshTimeout) clearTimeout(refreshTimeout);\n if (!autoRefresh) return;\n\n const delay = (expiresAt - REFRESH_BUFFER_MS) - Date.now();\n\n if (delay <= 0) {\n void attemptScheduledRefresh(0);\n return;\n }\n\n refreshTimeout = setTimeout(() => { void attemptScheduledRefresh(0); }, delay);\n }\n\n function handleAuthResponse(data: { tokens: AuthTokens, user: Record<string, unknown> }, event?: AuthChangeEvent): RebaseSession {\n const user: User = mapRawUser(data.user);\n const session: RebaseSession = {\n accessToken: data.tokens.accessToken,\n refreshToken: data.tokens.refreshToken || (currentSession?.refreshToken) || \"\",\n expiresAt: data.tokens.accessTokenExpiresAt,\n user\n };\n currentSession = session;\n saveSession(session);\n transport.setToken(session.accessToken);\n scheduleRefresh(session.expiresAt);\n emit(event || \"SIGNED_IN\", session);\n return session;\n }\n\n async function signInWithEmail(email: string, password: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/login\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email,\npassword }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n async function signUp(email: string, password: string, displayName?: string) {\n const fetchFn = getFetch();\n const payload: Record<string, string> = { email,\npassword };\n if (displayName !== undefined) payload.displayName = displayName;\n const res = await fetchFn(authUrl(\"/register\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n /**\n * Sign in with Google.\n *\n * Supports three invocation styles:\n * - `signInWithGoogle({ idToken })` — ID-token flow (One Tap / Sign In button)\n * - `signInWithGoogle({ accessToken })` — Access-token flow (popup)\n * - `signInWithGoogle({ code, redirectUri })` — Authorization code flow (most secure)\n */\n async function signInWithGoogle(\n payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }\n ) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/google\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const responseBody = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, responseBody, res.statusText);\n const session = handleAuthResponse(responseBody, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n async function signInWithLinkedin(code: string, redirectUri: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/linkedin\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ code,\nredirectUri }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n /**\n * Generic OAuth sign-in. Posts the given payload to `/auth/{providerId}`.\n * Use this for any provider registered on the backend.\n */\n async function signInWithOAuth(providerId: string, payload: Record<string, unknown>) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(`/${providerId}`), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n // Convenience wrappers for all supported OAuth providers\n\n async function signInWithGitHub(code: string, redirectUri: string) {\n return signInWithOAuth(\"github\", { code,\nredirectUri });\n }\n\n async function signInWithMicrosoft(code: string, redirectUri: string) {\n return signInWithOAuth(\"microsoft\", { code,\nredirectUri });\n }\n\n async function signInWithApple(code: string, redirectUri: string, user?: { name?: { firstName?: string; lastName?: string }; email?: string }) {\n return signInWithOAuth(\"apple\", { code,\nredirectUri,\nuser });\n }\n\n async function signInWithFacebook(code: string, redirectUri: string) {\n return signInWithOAuth(\"facebook\", { code,\nredirectUri });\n }\n\n async function signInWithTwitter(code: string, redirectUri: string, codeVerifier: string) {\n return signInWithOAuth(\"twitter\", { code,\nredirectUri,\ncodeVerifier });\n }\n\n async function signInWithDiscord(code: string, redirectUri: string) {\n return signInWithOAuth(\"discord\", { code,\nredirectUri });\n }\n\n async function signInWithGitLab(code: string, redirectUri: string) {\n return signInWithOAuth(\"gitlab\", { code,\nredirectUri });\n }\n\n async function signInWithBitbucket(code: string, redirectUri: string) {\n return signInWithOAuth(\"bitbucket\", { code,\nredirectUri });\n }\n\n async function signInWithSlack(code: string, redirectUri: string) {\n return signInWithOAuth(\"slack\", { code,\nredirectUri });\n }\n\n async function signInWithSpotify(code: string, redirectUri: string) {\n return signInWithOAuth(\"spotify\", { code,\nredirectUri });\n }\n\n async function signOut() {\n const fetchFn = getFetch();\n try {\n if (authFlowMode === \"cookie\" || currentSession?.refreshToken) {\n await fetchFn(authUrl(\"/logout\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: currentSession?.refreshToken }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n }\n } catch (e) { /* ignore */ }\n currentSession = null;\n clearStoredSession();\n if (refreshTimeout) {\n clearTimeout(refreshTimeout);\n refreshTimeout = null;\n }\n transport.setToken(null);\n emit(\"SIGNED_OUT\", null);\n }\n\n function refreshSession(): Promise<RebaseSession> {\n // Share a single in-flight refresh across concurrent callers.\n if (inFlightRefresh) return inFlightRefresh;\n inFlightRefresh = doRefreshSession().finally(() => {\n inFlightRefresh = null;\n });\n return inFlightRefresh;\n }\n\n async function doRefreshSession(): Promise<RebaseSession> {\n if (authFlowMode !== \"cookie\" && !currentSession?.refreshToken) {\n throw new Error(\"No active session to refresh\");\n }\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/refresh\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refreshToken: currentSession?.refreshToken }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n\n const accessToken = body.tokens.accessToken;\n transport.setToken(accessToken);\n\n // Resolve the user, in order of preference:\n // 1. the user returned by /refresh (modern backends include it),\n // 2. the user already in memory,\n // 3. a fetch of /me — required to restore a session from an httpOnly\n // cookie alone (cold start in cookie mode), where there is no\n // in-memory user and the backend didn't echo one.\n let user = currentSession?.user;\n if (body.user && typeof body.user.uid === \"string\") {\n user = mapRawUser(body.user as Record<string, unknown>);\n } else if (!user || !user.uid) {\n try {\n user = await getUser();\n } catch { /* fall through to the empty stub below */ }\n }\n\n const session: RebaseSession = {\n accessToken,\n refreshToken: body.tokens.refreshToken || currentSession?.refreshToken || \"\",\n expiresAt: body.tokens.accessTokenExpiresAt,\n user: user ?? EMPTY_USER\n };\n currentSession = session;\n saveSession(session);\n transport.setToken(session.accessToken);\n scheduleRefresh(session.expiresAt);\n emit(\"TOKEN_REFRESHED\", session);\n return session;\n }\n\n async function getUser() {\n const data = await transport.request<{ user: User }>(authPath + \"/me\", { method: \"GET\" });\n return data.user;\n }\n\n /**\n * Resolve an email to a minimal public profile (`uid`, `displayName`,\n * `photoURL`) for invite-by-email flows. Returns `null` when no account\n * matches. Requires the backend to opt in via `auth.allowUserLookup`;\n * otherwise the endpoint is absent and this rejects.\n */\n async function findUserByEmail(email: string): Promise<PublicUserProfile | null> {\n const data = await transport.request<{ user: PublicUserProfile | null }>(authPath + \"/find-user\", {\n method: \"POST\",\n body: JSON.stringify({ email })\n });\n return data.user;\n }\n\n async function updateUser(updates: { displayName?: string, photoURL?: string }) {\n const data = await transport.request<{ user: User }>(authPath + \"/me\", {\n method: \"PATCH\",\n body: JSON.stringify(updates)\n });\n if (currentSession) {\n currentSession = { ...currentSession,\nuser: data.user };\n saveSession(currentSession);\n emit(\"USER_UPDATED\", currentSession);\n }\n return data.user;\n }\n\n async function resetPasswordForEmail(email: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/forgot-password\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email })\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function resetPassword(token: string, password: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/reset-password\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token,\npassword })\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function changePassword(oldPassword: string, newPassword: string) {\n return transport.request<{ success: boolean; message: string; }>(authPath + \"/change-password\", {\n method: \"POST\",\n body: JSON.stringify({ oldPassword,\nnewPassword })\n });\n }\n\n /**\n * Link an OAuth provider to the **currently signed-in** account.\n *\n * Use this when `signIn*` failed with `EMAIL_NOT_VERIFIED` — an account\n * with that email already exists under a different sign-in method — or to\n * attach a provider whose email differs from the account's.\n *\n * The payload is the same one the provider's sign-in method takes, e.g.\n * `linkProvider(\"google\", { idToken })`.\n *\n * Unlike sign-in, this does not require the provider to have verified the\n * email, and the emails need not match: the active session already proves\n * account ownership.\n *\n * Throws `IDENTITY_ALREADY_LINKED` (409) if that provider identity is\n * attached to a different user. Succeeds idempotently (`alreadyLinked:\n * true`) if it is already attached to the current one.\n */\n async function linkProvider(\n providerId: string,\n payload: Record<string, unknown>\n ) {\n return transport.request<{ success: boolean; provider: string; alreadyLinked: boolean; }>(\n authPath + \"/link/\" + providerId,\n {\n method: \"POST\",\n body: JSON.stringify(payload)\n }\n );\n }\n\n async function sendVerificationEmail() {\n return transport.request<{ success: boolean; message: string; }>(authPath + \"/send-verification\", {\n method: \"POST\"\n });\n }\n\n async function verifyEmail(token: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/verify-email?token=\" + encodeURIComponent(token)), {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" }\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function sendMagicLink(email: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/magic-link\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email })\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as { success: boolean; message: string; };\n }\n\n async function verifyMagicLink(token: string) {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/magic-link/verify\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n credentials: authFlowMode === \"cookie\" ? \"include\" : undefined\n } as RequestInit);\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n const session = handleAuthResponse(body, \"SIGNED_IN\");\n return { user: session.user,\naccessToken: session.accessToken,\nrefreshToken: session.refreshToken };\n }\n\n async function getSessions(): Promise<DeviceSession[]> {\n const data = await transport.request<{ sessions: DeviceSession[] }>(authPath + \"/sessions\", { method: \"GET\" });\n return data.sessions;\n }\n\n async function revokeSession(sessionId: string) {\n return transport.request<{ success: boolean }>(authPath + \"/sessions/\" + encodeURIComponent(sessionId), {\n method: \"DELETE\"\n });\n }\n\n async function revokeAllSessions() {\n const result = await transport.request<{ success: boolean }>(authPath + \"/sessions\", {\n method: \"DELETE\"\n });\n currentSession = null;\n clearStoredSession();\n if (refreshTimeout) {\n clearTimeout(refreshTimeout);\n refreshTimeout = null;\n }\n transport.setToken(null);\n emit(\"SIGNED_OUT\", null);\n return result;\n }\n\n async function getAuthConfig() {\n const fetchFn = getFetch();\n const res = await fetchFn(authUrl(\"/config\"), {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" }\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) throwApiError(res.status, body, res.statusText);\n return body as AuthConfig;\n }\n\n function getSession() {\n return currentSession;\n }\n\n function onAuthStateChange(callback: (event: AuthChangeEvent, session: RebaseSession | null) => void) {\n listeners.add(callback);\n return () => listeners.delete(callback);\n }\n\n if (persistSession) {\n const stored = loadStoredSession();\n if (stored && stored.accessToken) {\n if (stored.expiresAt > Date.now()) {\n currentSession = stored;\n transport.setToken(stored.accessToken);\n scheduleRefresh(stored.expiresAt);\n resolveInitialized!();\n } else if (authFlowMode === \"cookie\" || stored.refreshToken) {\n currentSession = stored;\n refreshSession().then(() => {\n resolveInitialized!();\n }).catch(() => {\n currentSession = null;\n clearStoredSession();\n transport.setToken(null);\n resolveInitialized!();\n });\n } else {\n resolveInitialized!();\n }\n } else if (authFlowMode === \"cookie\") {\n // Silent refresh on boot to pick up httpOnly session\n refreshSession().then(() => {\n resolveInitialized!();\n }).catch(() => {\n resolveInitialized!();\n });\n } else {\n resolveInitialized!();\n }\n } else {\n resolveInitialized!();\n }\n\n return {\n signInWithEmail,\n signUp,\n signInWithGoogle,\n signInWithLinkedin,\n signInWithOAuth,\n signInWithGitHub,\n signInWithMicrosoft,\n signInWithApple,\n signInWithFacebook,\n signInWithTwitter,\n signInWithDiscord,\n signInWithGitLab,\n signInWithBitbucket,\n signInWithSlack,\n signInWithSpotify,\n signOut,\n refreshSession,\n getUser,\n findUserByEmail,\n updateUser,\n resetPasswordForEmail,\n resetPassword,\n changePassword,\n linkProvider,\n sendVerificationEmail,\n verifyEmail,\n sendMagicLink,\n verifyMagicLink,\n getSessions,\n revokeSession,\n revokeAllSessions,\n getAuthConfig,\n getSession,\n onAuthStateChange,\n isInitialized: () => isInitialized\n };\n}\n\nexport interface CookieStorageOptions {\n path?: string;\n domain?: string;\n secure?: boolean;\n sameSite?: \"Lax\" | \"Strict\" | \"None\";\n maxAge?: number;\n}\n\nexport function createCookieStorage(options: CookieStorageOptions = {}): AuthStorage {\n const defaultOptions = {\n path: \"/\",\n sameSite: \"Lax\" as const,\n ...options\n };\n\n return {\n getItem(key: string): string | null {\n if (typeof document === \"undefined\") return null;\n const nameEQ = encodeURIComponent(key) + \"=\";\n const ca = document.cookie.split(\";\");\n for (let i = 0; i < ca.length; i++) {\n let c = ca[i];\n while (c.charAt(0) === \" \") c = c.substring(1, c.length);\n if (c.indexOf(nameEQ) === 0) {\n return decodeURIComponent(c.substring(nameEQ.length, c.length));\n }\n }\n return null;\n },\n setItem(key: string, value: string): void {\n if (typeof document === \"undefined\") return;\n let cookieStr = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n\n if (defaultOptions.path) {\n cookieStr += `; path=${defaultOptions.path}`;\n }\n if (defaultOptions.domain) {\n cookieStr += `; domain=${defaultOptions.domain}`;\n }\n if (defaultOptions.maxAge !== undefined) {\n cookieStr += `; max-age=${defaultOptions.maxAge}`;\n } else {\n cookieStr += `; max-age=${365 * 24 * 60 * 60}`;\n }\n if (defaultOptions.secure) {\n cookieStr += \"; secure\";\n }\n if (defaultOptions.sameSite) {\n cookieStr += `; samesite=${defaultOptions.sameSite}`;\n }\n\n document.cookie = cookieStr;\n },\n removeItem(key: string): void {\n if (typeof document === \"undefined\") return;\n let cookieStr = `${encodeURIComponent(key)}=; path=${defaultOptions.path || \"/\"}; max-age=-1`;\n if (defaultOptions.domain) {\n cookieStr += `; domain=${defaultOptions.domain}`;\n }\n document.cookie = cookieStr;\n }\n };\n}\n","import type { Transport } from \"./transport\";\nimport { AdminUser } from \"@rebasepro/types\";\n\nexport type { AdminUser };\n\n\nexport interface CreateAdminOptions {\n adminPath?: string;\n}\n\nexport function createAdmin(transport: Transport, options?: CreateAdminOptions) {\n const opts = options || {};\n const adminPath = opts.adminPath || \"/admin\";\n\n async function listUsers() {\n return transport.request<{ users: AdminUser[] }>(adminPath + \"/users\", { method: \"GET\" });\n }\n\n async function listUsersPaginated(options?: { search?: string; limit?: number; offset?: number; orderBy?: string; orderDir?: \"asc\" | \"desc\" }) {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined) params.set(\"offset\", String(options.offset));\n if (options?.search) params.set(\"search\", options.search);\n if (options?.orderBy) params.set(\"orderBy\", options.orderBy);\n if (options?.orderDir) params.set(\"orderDir\", options.orderDir);\n const qs = params.toString();\n return transport.request<{ users: AdminUser[]; total: number; limit: number; offset: number }>(\n adminPath + \"/users\" + (qs ? \"?\" + qs : \"\"), { method: \"GET\" }\n );\n }\n\n async function getUser(userId: string) {\n return transport.request<{ user: AdminUser }>(adminPath + \"/users/\" + encodeURIComponent(userId), { method: \"GET\" });\n }\n\n async function createUser(data: { email: string, displayName?: string, password?: string, roles?: string[] }) {\n return transport.request<{ user: AdminUser }>(adminPath + \"/users\", {\n method: \"POST\",\n body: JSON.stringify(data)\n });\n }\n\n async function updateUser(userId: string, data: { email?: string, displayName?: string, password?: string, roles?: string[] }) {\n return transport.request<{ user: AdminUser }>(adminPath + \"/users/\" + encodeURIComponent(userId), {\n method: \"PUT\",\n body: JSON.stringify(data)\n });\n }\n\n async function deleteUser(userId: string) {\n return transport.request<{ success: boolean }>(adminPath + \"/users/\" + encodeURIComponent(userId), {\n method: \"DELETE\"\n });\n }\n\n async function resetPassword(userId: string, options?: { password?: string }) {\n return transport.request<{ user: AdminUser; temporaryPassword?: string; invitationSent?: boolean; emailDeliveryFailed?: boolean }>(\n adminPath + \"/users/\" + encodeURIComponent(userId) + \"/reset-password\",\n {\n method: \"POST\",\n ...(options?.password ? { body: JSON.stringify({ password: options.password }) } : {})\n }\n );\n }\n\n async function listRoles() {\n return transport.request<{ roles: Array<{ id: string; name: string }> }>(\n adminPath + \"/roles\",\n { method: \"GET\" }\n );\n }\n\n async function bootstrap() {\n return transport.request<{ success: boolean; message: string; user: { uid: string; roles: string[] } }>(adminPath + \"/bootstrap\", {\n method: \"POST\"\n });\n }\n\n return {\n listUsers,\n listUsersPaginated,\n getUser,\n createUser,\n updateUser,\n deleteUser,\n resetPassword,\n listRoles,\n bootstrap\n };\n}\n","import { Transport } from \"./transport\";\nimport type { CronJobStatus, CronJobLogEntry } from \"@rebasepro/types\";\n\nexport interface CreateCronOptions {\n cronPath?: string;\n}\n\nexport function createCron(transport: Transport, options?: CreateCronOptions) {\n const cronPath = options?.cronPath || \"/cron\";\n\n async function listJobs(): Promise<{ jobs: CronJobStatus[] }> {\n return transport.request<{ jobs: CronJobStatus[] }>(cronPath, { method: \"GET\" });\n }\n\n async function getJob(jobId: string): Promise<{ job: CronJobStatus }> {\n return transport.request<{ job: CronJobStatus }>(\n cronPath + \"/\" + encodeURIComponent(jobId),\n { method: \"GET\" }\n );\n }\n\n async function triggerJob(jobId: string): Promise<{ log: CronJobLogEntry; job: CronJobStatus }> {\n return transport.request<{ log: CronJobLogEntry; job: CronJobStatus }>(\n cronPath + \"/\" + encodeURIComponent(jobId) + \"/trigger\",\n { method: \"POST\" }\n );\n }\n\n async function getJobLogs(\n jobId: string,\n options?: { limit?: number }\n ): Promise<{ logs: CronJobLogEntry[] }> {\n const params = new URLSearchParams();\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n const qs = params.toString();\n return transport.request<{ logs: CronJobLogEntry[] }>(\n cronPath + \"/\" + encodeURIComponent(jobId) + \"/logs\" + (qs ? \"?\" + qs : \"\"),\n { method: \"GET\" }\n );\n }\n\n async function toggleJob(\n jobId: string,\n enabled: boolean\n ): Promise<{ job: CronJobStatus }> {\n return transport.request<{ job: CronJobStatus }>(\n cronPath + \"/\" + encodeURIComponent(jobId),\n {\n method: \"PUT\",\n body: JSON.stringify({ enabled })\n }\n );\n }\n\n return {\n listJobs,\n getJob,\n triggerJob,\n getJobLogs,\n toggleJob\n };\n}\n","import { Transport } from \"./transport\";\nimport type { BackupInfo, BackupDestinationKind } from \"@rebasepro/types\";\n\nexport interface CreateBackupsOptions {\n backupsPath?: string;\n}\n\nexport function createBackups(transport: Transport, options?: CreateBackupsOptions) {\n const backupsPath = options?.backupsPath || \"/admin/backups\";\n\n async function list(): Promise<{\n backups: BackupInfo[];\n destinationKind: BackupDestinationKind;\n configured: boolean;\n }> {\n return transport.request(backupsPath, { method: \"GET\" });\n }\n\n /**\n * Download a backup's bytes. Uses an authenticated fetch (not the JSON\n * transport) so the octet-stream response comes back as a Blob.\n */\n async function download(key: string): Promise<Blob> {\n const token = await transport.resolveToken();\n // Mirror transport.request's URL construction (baseUrl + apiPath + path)\n // — this endpoint returns an octet-stream, so we fetch it directly\n // instead of going through the JSON transport.\n const url = `${transport.baseUrl}${transport.apiPath}${backupsPath}/download?key=${encodeURIComponent(key)}`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: token ? { Authorization: `Bearer ${token}` } : {}\n });\n if (!res.ok) {\n throw new Error(`Failed to download backup (${res.status})`);\n }\n return res.blob();\n }\n\n return { list, download };\n}\n","import type { Transport } from \"./transport\";\n\n// Re-define the types locally since they live in server, not in @rebasepro/types.\n// These match the server-side types exactly.\n\n/** A single permission entry scoping an API key to a collection and its allowed operations. */\nexport interface ApiKeyPermission {\n collection: string;\n operations: (\"read\" | \"write\" | \"delete\")[];\n}\n\n/** An API key with the secret portion masked (returned by list / get / update). */\nexport interface ApiKeyMasked {\n id: string;\n name: string;\n key_prefix: string;\n permissions: ApiKeyPermission[];\n admin: boolean;\n rate_limit: number | null;\n created_by: string;\n created_at: string;\n updated_at: string;\n last_used_at: string | null;\n expires_at: string | null;\n revoked_at: string | null;\n}\n\n/** An API key including the full secret (returned only on creation). */\nexport interface ApiKeyWithSecret extends ApiKeyMasked {\n key: string;\n}\n\n/** Payload for creating a new API key. */\nexport interface CreateApiKeyRequest {\n name: string;\n permissions: ApiKeyPermission[];\n rate_limit?: number | null;\n expires_at?: string | null;\n}\n\n/** Payload for updating an existing API key. */\nexport interface UpdateApiKeyRequest {\n name?: string;\n permissions?: ApiKeyPermission[];\n rate_limit?: number | null;\n expires_at?: string | null;\n}\n\n/** Options for the `createApiKeys` factory. */\nexport interface CreateApiKeysOptions {\n apiKeysPath?: string;\n}\n\n/**\n * Creates a client for managing API keys via the admin routes.\n *\n * @param transport - The shared HTTP transport created by `createTransport`.\n * @param options - Optional overrides (e.g. a custom base path).\n */\nexport function createApiKeys(transport: Transport, options?: CreateApiKeysOptions) {\n const apiKeysPath = options?.apiKeysPath || \"/admin/api-keys\";\n\n /** List all API keys (masked). */\n async function listKeys(): Promise<{ keys: ApiKeyMasked[] }> {\n return transport.request<{ keys: ApiKeyMasked[] }>(apiKeysPath, { method: \"GET\" });\n }\n\n /** Get a single API key by ID (masked). */\n async function getKey(id: string): Promise<{ key: ApiKeyMasked }> {\n return transport.request<{ key: ApiKeyMasked }>(\n apiKeysPath + \"/\" + encodeURIComponent(id),\n { method: \"GET\" }\n );\n }\n\n /** Create a new API key. The full secret is included in the response. */\n async function createKey(data: CreateApiKeyRequest): Promise<{ key: ApiKeyWithSecret }> {\n return transport.request<{ key: ApiKeyWithSecret }>(apiKeysPath, {\n method: \"POST\",\n body: JSON.stringify(data)\n });\n }\n\n /** Update an existing API key. */\n async function updateKey(id: string, data: UpdateApiKeyRequest): Promise<{ key: ApiKeyMasked }> {\n return transport.request<{ key: ApiKeyMasked }>(\n apiKeysPath + \"/\" + encodeURIComponent(id),\n {\n method: \"PUT\",\n body: JSON.stringify(data)\n }\n );\n }\n\n /** Revoke (soft-delete) an API key. */\n async function revokeKey(id: string): Promise<{ success: boolean }> {\n return transport.request<{ success: boolean }>(\n apiKeysPath + \"/\" + encodeURIComponent(id),\n { method: \"DELETE\" }\n );\n }\n\n return {\n listKeys,\n getKey,\n createKey,\n updateKey,\n revokeKey\n };\n}\n","import {\n FindParams,\n FindResult,\n LogicalCondition,\n SDKCollectionClient,\n SDKQueryBuilderInterface,\n WhereFilterOp,\n WhereValue\n} from \"@rebasepro/types\";\n\n/**\n * SDK Query Builder — returns flat rows (`FindResult<M>`) instead of\n * Entity-wrapped results (`FindResponse<M>`).\n *\n * @example\n * const { data } = await rebase.data.posts\n * .where(\"status\", \"==\", \"published\")\n * .orderBy(\"created_at\", \"desc\")\n * .limit(10)\n * .find();\n *\n * console.log(data[0].title); // flat access\n */\nexport class SDKQueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements SDKQueryBuilderInterface<M> {\n private params: FindParams = { where: {} };\n\n constructor(private collection: SDKCollectionClient<M>) {}\n\n /**\n * Add a filter condition to your query.\n * @example\n * client.data.users.where('age', '>=', 18).find()\n */\n where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): this;\n where(logicalCondition: LogicalCondition): this;\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, value?: unknown): this {\n if (typeof columnOrCondition === \"object\" && columnOrCondition !== null && \"type\" in columnOrCondition) {\n this.params.logical = columnOrCondition as LogicalCondition;\n return this;\n }\n\n if (!this.params.where) {\n this.params.where = {};\n }\n\n const column = columnOrCondition as string;\n const condition: [WhereFilterOp, unknown] = [operator!, value];\n const existing = this.params.where[column];\n\n if (existing === undefined) {\n this.params.where[column] = condition;\n } else if (Array.isArray(existing) && existing.length > 0 && Array.isArray(existing[0])) {\n (this.params.where[column] as [WhereFilterOp, unknown][]).push(condition);\n } else {\n let firstCondition: [WhereFilterOp, unknown];\n if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === \"string\") {\n firstCondition = existing as [WhereFilterOp, unknown];\n } else {\n firstCondition = [\"==\", existing];\n }\n this.params.where[column] = [firstCondition, condition];\n }\n\n return this;\n }\n\n /**\n * Order the results by a specific column.\n */\n orderBy(column: keyof M & string, direction: \"asc\" | \"desc\" = \"asc\"): this {\n this.params.orderBy = [column, direction];\n return this;\n }\n\n /**\n * Limit the number of results returned.\n */\n limit(count: number): this {\n this.params.limit = count;\n return this;\n }\n\n /**\n * Skip the first N results.\n */\n offset(count: number): this {\n this.params.offset = count;\n return this;\n }\n\n /**\n * Set a free-text search string if supported by the backend.\n */\n search(searchString: string): this {\n this.params.searchString = searchString;\n return this;\n }\n\n /**\n * Include related entities in the response.\n * Relations will be populated with full data instead of just IDs.\n *\n * @param relations - Relation names to include, or \"*\" for all.\n * @example\n * client.data.posts.include(\"tags\", \"author\").find()\n */\n include(...relations: string[]): this {\n this.params.include = relations;\n return this;\n }\n\n /**\n * Execute the find query and return the results as flat rows.\n */\n async find(): Promise<FindResult<M>> {\n return this.collection.find(this.params);\n }\n\n /**\n * Count the records matching this query.\n */\n async count(): Promise<number> {\n if (!this.collection.count) {\n throw new Error(\"count() is not supported by this collection client.\");\n }\n return this.collection.count(this.params);\n }\n\n /**\n * Listen to realtime updates matching this query.\n */\n listen(onUpdate: (data: FindResult<M>) => void, onError?: (error: Error) => void): () => void {\n if (!this.collection.listen) {\n throw new Error(\n \"Listen is only available when RebaseClient is configured with a websocketUrl, \" +\n \"and not when it was created with realtime: false.\"\n );\n }\n return this.collection.listen(this.params, onUpdate, onError);\n }\n}\n","import { buildQueryString, FindParams, RebaseApiError, Transport } from \"./transport\";\nimport { RebaseWebSocketClient } from \"./websocket\";\nimport {\n FindResult,\n LogicalCondition,\n SDKCollectionClient,\n SDKQueryBuilderInterface,\n WhereFilterOp,\n WhereValue\n} from \"@rebasepro/types\";\n\nimport { SDKQueryBuilder } from \"./sdk_query_builder\";\n\n/**\n * The concrete, HTTP-backed implementation of the public\n * {@link SDKCollectionClient} contract — flat rows (no Entity wrapper), plus\n * fluent query-builder methods (`.where()`, `.orderBy()`, …).\n *\n * This is what `createRebaseClient().data.<collection>` returns. It is not a\n * separate API from {@link SDKCollectionClient}; it only widens it with\n * `count()`. Program against {@link SDKCollectionClient} when you want a\n * transport-agnostic type.\n */\nexport interface CollectionClient<\n M extends Record<string, unknown> = Record<string, unknown>,\n I = Partial<M>,\n U = Partial<M>\n> extends SDKCollectionClient<M, I, U> {\n count(params?: FindParams): Promise<number>;\n}\n\nexport function createCollectionClient<M extends Record<string, unknown> = Record<string, unknown>>(transport: Transport, slug: string, ws?: RebaseWebSocketClient): CollectionClient<M> {\n const basePath = `/data/${slug}`;\n\n const client: CollectionClient<M> = {\n async find(params?: FindParams): Promise<FindResult<M>> {\n const qs = buildQueryString(params);\n const raw = await transport.request<{\n data: Record<string, unknown>[];\n meta: FindResult<M>[\"meta\"]\n }>(basePath + qs, { method: \"GET\" });\n return {\n data: (raw.data || []) as M[],\n meta: raw.meta\n };\n },\n\n async findById(id: string | number) {\n try {\n const raw = await transport.request<Record<string, unknown>>(`${basePath}/${encodeURIComponent(String(id))}`, { method: \"GET\" });\n if (!raw) return undefined;\n return raw as M;\n } catch (err) {\n if (err instanceof RebaseApiError && err.status === 404) {\n return undefined;\n }\n throw err;\n }\n },\n\n async create(data: Partial<M>, id?: string | number) {\n const body: Record<string, unknown> = { ...data };\n if (id !== undefined) {\n body.id = id;\n }\n const raw = await transport.request<Record<string, unknown>>(basePath, {\n method: \"POST\",\n body: JSON.stringify(body)\n });\n return raw as M;\n },\n\n async createMany(data: Partial<M>[], options?: { upsert?: boolean }) {\n if (!Array.isArray(data)) {\n throw new TypeError(\"createMany expects an array of records.\");\n }\n if (data.length === 0) return [];\n\n const raw = await transport.request<{ data: Record<string, unknown>[] }>(`${basePath}/bulk`, {\n method: \"POST\",\n body: JSON.stringify({\n rows: data,\n ...(options?.upsert ? { upsert: true } : {})\n })\n });\n return (raw.data || []) as M[];\n },\n\n async update(id: string | number, data: Partial<M>) {\n const raw = await transport.request<Record<string, unknown>>(`${basePath}/${encodeURIComponent(String(id))}`, {\n method: \"PUT\",\n body: JSON.stringify(data)\n });\n return raw as M;\n },\n\n async delete(id: string | number) {\n await transport.request<void>(`${basePath}/${encodeURIComponent(String(id))}`, {\n method: \"DELETE\"\n });\n },\n\n async count(params?: FindParams): Promise<number> {\n const countParams: FindParams = {\n ...params,\n limit: undefined,\n offset: undefined\n };\n const qs = buildQueryString(countParams);\n const raw = await transport.request<{ count: number }>(basePath + \"/count\" + qs, { method: \"GET\" });\n return raw.count ?? 0;\n },\n\n // Fluent builder instantiation\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, value?: unknown) {\n const builder = new SDKQueryBuilder<M>(client);\n if (typeof columnOrCondition === \"object\") {\n return builder.where(columnOrCondition);\n }\n return builder.where(columnOrCondition as keyof M & string, operator!, value as WhereValue<M[keyof M & string]>);\n },\n orderBy(column: keyof M & string, direction?: \"asc\" | \"desc\") {\n return new SDKQueryBuilder<M>(client).orderBy(column, direction);\n },\n limit(count: number) {\n return new SDKQueryBuilder<M>(client).limit(count);\n },\n offset(count: number) {\n return new SDKQueryBuilder<M>(client).offset(count);\n },\n search(searchString: string) {\n return new SDKQueryBuilder<M>(client).search(searchString);\n },\n include(...relations: string[]) {\n return new SDKQueryBuilder<M>(client).include(...relations);\n }\n };\n\n if (ws) {\n client.listen = (params: FindParams | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void) => {\n let active = true;\n let lastUpdateId = 0;\n const unsub = ws.listenCollection(\n {\n path: slug,\n filter: params?.where,\n limit: params?.limit,\n startAfter: params?.offset ? String(params.offset) : undefined,\n orderBy: params?.orderBy?.[0],\n order: params?.orderBy?.[1],\n searchString: params?.searchString\n },\n (incomingRows: Record<string, unknown>[]) => {\n const currentUpdateId = ++lastUpdateId;\n const requestedLimit = params?.limit || 20;\n const offset = params?.offset || 0;\n\n // WS client already delivers flat rows — just cast\n const rows = incomingRows as M[];\n\n // Heuristic metadata (used as fallback if count call fails)\n const heuristicTotal = rows.length;\n const heuristicHasMore = rows.length >= requestedLimit;\n\n // Try to get authoritative count; fall back to heuristic\n if (client.count) {\n client.count(params)\n .then((total) => {\n if (active && currentUpdateId === lastUpdateId) {\n onUpdate({\n data: rows,\n meta: {\n total,\n limit: requestedLimit,\n offset,\n hasMore: offset + rows.length < total\n }\n });\n }\n })\n .catch(() => {\n // Count failed — use heuristic meta\n if (active && currentUpdateId === lastUpdateId) {\n onUpdate({\n data: rows,\n meta: {\n total: heuristicTotal,\n limit: requestedLimit,\n offset,\n hasMore: heuristicHasMore\n }\n });\n }\n });\n } else {\n // No count method — fire immediately with heuristic meta\n onUpdate({\n data: rows,\n meta: {\n total: heuristicTotal,\n limit: requestedLimit,\n offset,\n hasMore: heuristicHasMore\n }\n });\n }\n },\n onError\n );\n\n return () => {\n active = false;\n unsub();\n };\n };\n\n client.listenById = (id: string | number, onUpdate: (data: M | undefined) => void, onError?: (error: Error) => void) => {\n return ws.listenOne(\n {\n path: slug,\n id: String(id)\n },\n (row: Record<string, unknown> | null) => {\n if (row) {\n onUpdate(row as M);\n } else {\n onUpdate(undefined);\n }\n },\n onError\n );\n };\n }\n\n return client;\n}\n","import type { Transport } from \"./transport\";\n\n/**\n * Client interface for invoking custom backend functions.\n *\n * Custom functions are Hono route files auto-mounted by the Rebase backend\n * at `/api/functions/{name}`. The `FunctionsClient` wraps the shared\n * transport so callers never need to manually construct URLs or inject\n * auth tokens.\n *\n * @example\n * ```ts\n * const result = await client.functions.invoke<{ job: Job }>('extract-job', {\n * url: 'https://example.com/posting',\n * html: htmlContent,\n * });\n * ```\n */\nexport interface FunctionsClient {\n /**\n * Invoke a custom backend function by name.\n *\n * @typeParam T - Expected shape of the response payload.\n * @param name - Function name (the filename without extension, e.g. `\"extract-job\"`).\n * @param payload - Optional JSON-serialisable body sent as `POST`.\n * @param options - Optional overrides (HTTP method, sub-path, extra headers).\n * @returns The parsed JSON response from the function.\n */\n invoke<T = unknown>(\n name: string,\n payload?: unknown,\n options?: FunctionInvokeOptions,\n ): Promise<T>;\n}\n\nexport interface FunctionInvokeOptions {\n /** HTTP method — defaults to `\"POST\"`. */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n /** Sub-path appended after the function name, e.g. `\"status/123\"`. */\n path?: string;\n /** Extra headers merged into the request (auth is still injected automatically). */\n headers?: Record<string, string>;\n}\n\n/**\n * Create a `FunctionsClient` backed by the given transport.\n *\n * The transport already handles:\n * - Base URL resolution\n * - JWT injection via `Authorization: Bearer`\n * - 401 retry / `onUnauthorized` flow\n * - Consistent error throwing via `RebaseApiError`\n *\n * @internal\n */\nexport function createFunctionsClient(transport: Transport): FunctionsClient {\n return {\n async invoke<T = unknown>(\n name: string,\n payload?: unknown,\n options?: FunctionInvokeOptions\n ): Promise<T> {\n const method = options?.method ?? \"POST\";\n const subPath = options?.path ? `/${options.path.replace(/^\\//, \"\")}` : \"\";\n const routePath = `/functions/${encodeURIComponent(name)}${subPath}`;\n\n const init: RequestInit = { method };\n\n if (payload !== undefined && method !== \"GET\") {\n init.body = JSON.stringify(payload);\n }\n\n if (options?.headers) {\n init.headers = options.headers;\n }\n\n return transport.request<T>(routePath, init);\n }\n };\n}\n","import { StorageSource, UploadFileProps, UploadFileResult, DownloadConfig, StorageListResult, DownloadMetadata, PUBLIC_STORAGE_PREFIX, isPublicStoragePath } from \"@rebasepro/types\";\nimport { Transport } from \"./transport\";\n\n/**\n * Create a StorageSource that talks to the Rebase backend REST API.\n *\n * @param transport - HTTP transport instance\n * @param storageId - Optional storage-source key for multi-backend routing.\n * When set, it is forwarded to the server so the correct\n * `StorageController` is resolved from the registry.\n */\nexport function createStorage(transport: Transport, storageId?: string): StorageSource {\n const urlsCache = new Map<string, { config: DownloadConfig; expiresAt?: number }>();\n\n /** Append ?storageId=... to a path when multi-backend routing is active. */\n const withStorageId = (path: string): string => {\n if (!storageId) return path;\n const sep = path.includes(\"?\") ? \"&\" : \"?\";\n return `${path}${sep}storageId=${encodeURIComponent(storageId)}`;\n };\n\n async function putObject({\n file,\n key,\n metadata,\n bucket,\n public: isPublic\n }: UploadFileProps): Promise<UploadFileResult> {\n const formData = new FormData();\n formData.append(\"file\", file);\n\n // Public objects live under the public prefix so they can be served\n // token-less via a stable, permanent URL. Normalize the key here so the\n // stored path is self-describing (no server round-trip needed to know\n // it's public).\n let effectiveKey = key;\n if (isPublic && effectiveKey && !isPublicStoragePath(effectiveKey)) {\n effectiveKey = `${PUBLIC_STORAGE_PREFIX}${effectiveKey.replace(/^\\/+/, \"\")}`;\n }\n\n if (effectiveKey) formData.append(\"key\", effectiveKey);\n if (bucket) formData.append(\"bucket\", bucket);\n if (storageId) formData.append(\"storageId\", storageId);\n\n if (metadata) {\n for (const [key, value] of Object.entries(metadata)) {\n if (value !== undefined && value !== null) {\n formData.append(\n `metadata_${key}`,\n typeof value === \"string\" ? value : JSON.stringify(value)\n );\n }\n }\n }\n\n const result = await transport.request<{ data: UploadFileResult }>(withStorageId(\"/storage/upload\"), {\n method: \"POST\",\n body: formData,\n headers: {}\n });\n\n return result.data;\n }\n\n async function getSignedUrl(\n keyOrUrl: string,\n bucket?: string\n ): Promise<DownloadConfig> {\n const cacheKey = bucket ? `${bucket}/${keyOrUrl}` : keyOrUrl;\n const cachedEntry = urlsCache.get(cacheKey);\n if (cachedEntry) {\n if (!cachedEntry.expiresAt || cachedEntry.expiresAt > Date.now()) {\n return cachedEntry.config;\n }\n urlsCache.delete(cacheKey);\n }\n\n let filePath = keyOrUrl;\n\n if (filePath && (filePath.startsWith(\"local://\") || filePath.startsWith(\"s3://\") || filePath.startsWith(\"gs://\"))) {\n filePath = filePath.substring(filePath.indexOf(\"://\") + 3);\n }\n\n if (bucket && filePath && !filePath.startsWith(bucket)) {\n filePath = `${bucket}/${filePath}`;\n }\n\n if (!filePath || filePath.trim() === \"\" || filePath === \"/\") {\n return { url: null, fileNotFound: true };\n }\n\n // ── Public objects ────────────────────────────────────────────────\n // A public file (under the public prefix) is served token-less via a\n // stable, permanent, CDN-cacheable URL. No metadata round-trip and no\n // token are needed — build the URL directly and cache it forever.\n if (isPublicStoragePath(filePath)) {\n const publicConfig: DownloadConfig = {\n url: withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}`)\n };\n urlsCache.set(cacheKey, { config: publicConfig }); // no expiry\n return publicConfig;\n }\n\n try {\n const result = await transport.request<{ data: DownloadMetadata }>(withStorageId(`/storage/metadata/${filePath}`));\n\n // Public object (server-confirmed): token-less permanent URL.\n if (result.data.public) {\n const publicConfig: DownloadConfig = {\n url: withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}`),\n metadata: result.data\n };\n urlsCache.set(cacheKey, { config: publicConfig }); // no expiry\n return publicConfig;\n }\n\n // Private object: use the short-lived, file-scoped download token\n // minted by the server. We deliberately do NOT fall back to the\n // caller's access token — a URL must never carry a full-privilege\n // credential. If no scoped token is present the URL fails closed.\n const scopedToken = result.data.token;\n const tokenQuery = scopedToken ? `?token=${scopedToken}` : \"\";\n\n const downloadConfig: DownloadConfig = {\n // `withStorageId` picks `?` or `&` based on whether the token\n // query is already present, so the URL stays valid even when\n // there is no token.\n url: withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}${tokenQuery}`),\n metadata: result.data\n };\n\n const expiresAt = result.data.tokenExpiresIn\n ? Date.now() + (result.data.tokenExpiresIn - 10) * 1000 // subtract 10s buffer\n : undefined;\n\n urlsCache.set(cacheKey, { config: downloadConfig, expiresAt });\n return downloadConfig;\n } catch (e: unknown) {\n if (e instanceof Error && \"status\" in e && (e as { status: number }).status === 404) {\n return { url: null, fileNotFound: true };\n }\n throw e;\n }\n }\n\n async function getObject(\n key: string,\n bucket?: string\n ): Promise<File | null> {\n const downloadConfig = await getSignedUrl(key, bucket);\n if (downloadConfig.fileNotFound || !downloadConfig.url) {\n return null;\n }\n\n // Fetch using the signed URL directly. Since the scoped token is in the ?token= query param,\n // we explicitly omit any Authorization headers to prevent passing full access tokens to file serving routes.\n const response = await transport.fetchFn(downloadConfig.url, {\n headers: {}\n });\n\n if (response.status === 404) return null;\n if (!response.ok) throw new Error(\"Failed to get file\");\n\n const blob = await response.blob();\n const fileName = (bucket ? `${bucket}/${key}` : key).split(\"/\").pop() || \"file\";\n return new File([blob], fileName, { type: blob.type });\n }\n\n async function deleteObject(\n key: string,\n bucket?: string\n ): Promise<void> {\n let filePath = key;\n\n if (filePath && (filePath.startsWith(\"local://\") || filePath.startsWith(\"s3://\") || filePath.startsWith(\"gs://\"))) {\n filePath = filePath.substring(filePath.indexOf(\"://\") + 3);\n }\n\n if (bucket && filePath && !filePath.startsWith(bucket)) {\n filePath = `${bucket}/${filePath}`;\n }\n\n if (!filePath || filePath.trim() === \"\" || filePath === \"/\") {\n return;\n }\n\n try {\n await transport.request(withStorageId(`/storage/file/${filePath}`), { method: \"DELETE\" });\n } catch (e: unknown) {\n if (!(e instanceof Error && \"status\" in e && (e as { status: number }).status === 404)) throw e;\n }\n\n urlsCache.delete(bucket ? `${bucket}/${key}` : key);\n }\n\n async function listObjects(\n prefix: string,\n options?: {\n bucket?: string;\n maxResults?: number;\n pageToken?: string;\n }\n ): Promise<StorageListResult> {\n const params = new URLSearchParams();\n if (prefix) params.set(\"prefix\", prefix);\n if (options?.bucket) params.set(\"bucket\", options.bucket);\n if (options?.maxResults) params.set(\"maxResults\", String(options.maxResults));\n if (options?.pageToken) params.set(\"pageToken\", options.pageToken);\n\n if (storageId) params.set(\"storageId\", storageId);\n\n const result = await transport.request<{ data: StorageListResult }>(`/storage/list?${params.toString()}`);\n return result.data;\n }\n\n return {\n putObject,\n getSignedUrl,\n getObject,\n deleteObject,\n listObjects\n };\n}\n","/**\n * Client-side storage source registry.\n *\n * Manages multiple `StorageSource` instances keyed by\n * `StorageSourceDefinition.key`. Collection properties reference\n * a source by key via `StorageConfig.storageSource`.\n *\n * Typical bootstrap flow:\n * 1. Fetch definitions from `GET /api/storage/sources`\n * 2. Build server-backed sources automatically via `createStorage(transport, key)`\n * 3. Register \"direct\" sources manually (e.g. Firebase Storage hook)\n */\n\nimport type { StorageSource, StorageSourceRegistry, StorageSourceDefinition } from \"@rebasepro/types\";\nimport { DEFAULT_STORAGE_SOURCE_KEY } from \"@rebasepro/types\";\nimport { createStorage } from \"./storage\";\nimport type { Transport } from \"./transport\";\n\n/**\n * Default implementation of the client-side `StorageSourceRegistry`.\n */\nexport class ClientStorageSourceRegistry implements StorageSourceRegistry {\n private sources = new Map<string, StorageSource>();\n\n /**\n * Register a storage source.\n * @param key - Unique key matching a `StorageSourceDefinition.key`\n * @param source - The `StorageSource` instance\n */\n register(key: string, source: StorageSource): void {\n this.sources.set(key, source);\n }\n\n getDefault(): StorageSource {\n const source = this.sources.get(DEFAULT_STORAGE_SOURCE_KEY);\n if (!source) {\n throw new Error(\n `[StorageSourceRegistry] No default storage source registered. ` +\n `Register one with key \"${DEFAULT_STORAGE_SOURCE_KEY}\".`\n );\n }\n return source;\n }\n\n get(key: string | undefined | null): StorageSource | undefined {\n if (key === undefined || key === null) {\n return this.sources.get(DEFAULT_STORAGE_SOURCE_KEY);\n }\n return this.sources.get(key);\n }\n\n getOrDefault(key: string | undefined | null): StorageSource {\n if (key === undefined || key === null) {\n return this.getDefault();\n }\n const source = this.sources.get(key);\n if (source) return source;\n\n // Fallback to default\n console.warn(\n `[StorageSourceRegistry] Storage source \"${key}\" not found, ` +\n `falling back to \"${DEFAULT_STORAGE_SOURCE_KEY}\".`\n );\n return this.getDefault();\n }\n\n has(key: string): boolean {\n return this.sources.has(key);\n }\n\n list(): string[] {\n return Array.from(this.sources.keys());\n }\n\n /**\n * Build a registry from `StorageSourceDefinition[]` and an HTTP transport.\n *\n * - Sources with `transport: \"server\"` are auto-wired via `createStorage(transport, key)`.\n * - Sources with `transport: \"direct\"` are **not** auto-wired — they must\n * be registered manually after this call (e.g. via a Firebase hook).\n *\n * @param definitions - Array of storage source definitions\n * @param transport - HTTP transport for server-backed sources\n */\n static fromDefinitions(\n definitions: StorageSourceDefinition[],\n transport: Transport\n ): ClientStorageSourceRegistry {\n const registry = new ClientStorageSourceRegistry();\n\n for (const def of definitions) {\n if (def.transport === \"server\") {\n // Auto-create a server-backed StorageSource for this key\n const source = createStorage(transport, def.key === DEFAULT_STORAGE_SOURCE_KEY ? undefined : def.key);\n registry.register(def.key, source);\n }\n // \"direct\" sources must be registered manually\n }\n\n return registry;\n }\n}\n","import {\n DeleteProps,\n CollectionConfig,\n FetchCollectionProps,\n FetchOneProps,\n SaveProps,\n WebSocketMessage,\n WebSocketErrorPayload,\n CollectionUpdateMessage,\n SingleUpdateMessage,\n TableMetadata,\n BranchInfo,\n RebaseApiError\n} from \"@rebasepro/types\";\nimport { buildCompositeId, COMPOSITE_ID_SEPARATOR, type PrimaryKeyInfo } from \"@rebasepro/common\";\nimport { rebaseReviver } from \"./reviver\";\n\n\n\n/**\n * Extract error message and code from a WebSocket message payload.\n * Handles both `{ error: string }` and `{ error: { message, code } }` shapes.\n */\nfunction extractMessageError(message: WebSocketMessage): { errorMessage: string; errorCode?: string } {\n const payload = message.payload as WebSocketErrorPayload | undefined;\n const errPayload = payload?.error;\n const errorMessage = typeof errPayload === \"object\"\n ? errPayload.message\n : payload?.message || (typeof errPayload === \"string\" ? errPayload : undefined) || message.error || \"Unknown error\";\n const errorCode = typeof errPayload === \"object\"\n ? errPayload.code\n : payload?.code;\n // Callers treat this as a string (`.toLowerCase()` in isAuthError). A frame\n // carrying a non-string here would throw inside the message handler, where\n // the surrounding try/catch would swallow it — and a subscription error that\n // never reaches its listener is a view stuck loading forever.\n const safeMessage = typeof errorMessage === \"string\"\n ? errorMessage\n : (errorMessage == null ? \"Unknown error\" : JSON.stringify(errorMessage));\n return { errorMessage: safeMessage,\nerrorCode };\n}\n\nexport interface RebaseWebSocketConfig {\n websocketUrl: string;\n /** Optional auth token getter for WebSocket authentication */\n getAuthToken?: () => Promise<string | null>;\n /** Optional WebSocket constructor to override globalThis.WebSocket (e.g. for Node environments) */\n WebSocket?: typeof WebSocket;\n /** Callback to handle unauthorized requests or token expiration (refreshes auth session) */\n onUnauthorized?: () => Promise<boolean>;\n}\n\n\n/**\n * Broadcast and presence frames.\n *\n * Fire-and-forget (the server sends no response envelope), and exempt from the\n * client-side auth gate — a public channel is usable without an account.\n */\nconst CHANNEL_MESSAGE_TYPES = new Set([\n \"join_channel\",\n \"leave_channel\",\n \"broadcast\",\n \"presence_track\",\n \"presence_untrack\",\n \"presence_state\",\n // The catch-up request. Like `presence_state`, its answer comes back as a\n // channel-addressed frame rather than a response envelope, so it must not\n // be given a pending request to wait on.\n \"channel_history\"\n]);\n\n/**\n * Low-level realtime WebSocket client.\n *\n * @internal Not a stable app-facing API. `createRebaseClient()` constructs and\n * manages this internally (exposed as `client.ws`, typed by the minimal\n * `RebaseWebSocket` contract in `@rebasepro/types`). It is re-exported from the\n * package root only because the `@rebasepro/client-postgres` driver\n * instantiates it directly; its surface may change without a major bump.\n */\nexport class RebaseWebSocketClient {\n private websocketUrl: string;\n private ws: WebSocket | null = null;\n public getAuthToken?: () => Promise<string | null>;\n private subscriptions = new Map<string, {\n onUpdate: (data: WebSocketMessage) => void,\n onError?: (error: Error) => void\n }>();\n\n private listeners = new Map<string, Set<(...args: unknown[]) => void>>();\n\n /** Channel-name → handlers, for broadcast and presence frames. */\n private channelHandlers = new Map<string, Set<(message: Record<string, unknown>) => void>>();\n\n /** Set by `close()`. Blocks any later operation from silently redialling. */\n private closedByCaller = false;\n\n /**\n * Whether a socket exists at all (open or still opening).\n *\n * Lets callers distinguish \"authenticate the live socket\" from \"there is\n * nothing to authenticate yet\", without that question forcing a dial.\n */\n public get hasSocket(): boolean {\n return this.ws !== null;\n }\n\n /** So the \"no WebSocket in this environment\" warning is said once, not per call. */\n private warnedNoWebSocket = false;\n\n /** Subscribe to broadcast/presence frames for one channel. */\n public onChannelMessage(channel: string, handler: (message: Record<string, unknown>) => void): () => void {\n if (!this.channelHandlers.has(channel)) this.channelHandlers.set(channel, new Set());\n this.channelHandlers.get(channel)!.add(handler);\n return () => {\n const handlers = this.channelHandlers.get(channel);\n if (!handlers) return;\n handlers.delete(handler);\n if (handlers.size === 0) this.channelHandlers.delete(channel);\n };\n }\n\n /** Notified after the socket comes back, so channels can re-join. */\n public onReconnect(handler: () => void): () => void {\n return this.on(\"reconnect\", handler);\n }\n\n public on(event: \"connect\" | \"disconnect\" | \"reconnect\" | \"error\", cb: (...args: unknown[]) => void) {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(cb);\n return () => this.listeners.get(event)!.delete(cb);\n }\n\n private emit(event: string, ...args: unknown[]) {\n if (this.listeners.has(event)) {\n this.listeners.get(event)!.forEach(cb => cb(...args));\n }\n }\n\n // New: Subscription deduplication management with optimizations\n private collectionSubscriptions = new Map<string, {\n backendSubscriptionId: string;\n callbacks: Map<string, {\n onUpdate: (rows: Record<string, unknown>[]) => void;\n onError?: (error: Error) => void;\n }>;\n props: FetchCollectionProps;\n latestData?: Record<string, unknown>[]; // Cache the latest flat rows\n lastUpdated?: number; // Timestamp for cache invalidation\n isInitialDataReceived?: boolean; // Track if we got initial data\n /**\n * A `subscribe_collection` frame is on the wire and its initial payload\n * has not arrived yet. Without this, a subscription whose subscribe\n * failed is indistinguishable from one still loading, and every later\n * listener attaches to it and waits forever.\n */\n subscribeInFlight?: boolean;\n /**\n * Watchdog for the above. `subscribe_collection` expects no response\n * envelope, so it is not covered by `pendingRequests`' timeout — a lost\n * initial payload would otherwise hang the subscription indefinitely.\n */\n subscribeTimeout?: ReturnType<typeof setTimeout>;\n /**\n * The key columns of this collection, as told by the server on a patch.\n * Rows are columns only, and the SDK holds no collection config, so\n * without this there is nothing to derive an address from.\n */\n pks?: PrimaryKeyInfo[];\n }>();\n\n private singleSubscriptions = new Map<string, {\n backendSubscriptionId: string;\n callbacks: Map<string, {\n onUpdate: (row: Record<string, unknown> | null) => void;\n onError?: (error: Error) => void;\n }>;\n props: FetchOneProps;\n latestData?: Record<string, unknown> | null; // Cache the latest flat row\n lastUpdated?: number; // Timestamp for cache invalidation\n isInitialDataReceived?: boolean; // Track if we got initial data\n /** See the collection subscription counterparts. */\n subscribeInFlight?: boolean;\n subscribeTimeout?: ReturnType<typeof setTimeout>;\n }>();\n\n // Maps to quickly find subscription by backend subscription ID\n private backendToCollectionKey = new Map<string, string>();\n private backendToEntityKey = new Map<string, string>();\n\n\n private pendingRequests = new Map<string, {\n resolve: (p: unknown) => void;\n reject: (p: Error) => void;\n message?: Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void }\n }>();\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n private isConnected = false;\n private messageQueue: Record<string, unknown>[] = [];\n private requestTimeoutMs = 30000;\n private subscriptionTimeoutMs = 30000;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n\n private isAuthenticated = false;\n private authPromise: Promise<void> | null = null;\n private WebSocketConstructor: typeof WebSocket | undefined;\n public onUnauthorized?: () => Promise<boolean>;\n private refreshInProgress: Promise<boolean> | null = null;\n\n constructor(config: RebaseWebSocketConfig) {\n this.websocketUrl = config.websocketUrl;\n this.getAuthToken = config.getAuthToken;\n this.onUnauthorized = config.onUnauthorized;\n this.WebSocketConstructor = config.WebSocket || (typeof WebSocket !== \"undefined\" ? WebSocket : undefined);\n\n // Deliberately does NOT dial here. Constructing the client is not a\n // statement that the app wants a socket — `createRebaseClient` builds\n // one whenever realtime is not explicitly disabled, so connecting here\n // opened a socket on every page load of every app that merely *might*\n // subscribe later. Anonymous-first apps paid that on every visit, to\n // authenticate with nothing, which left them choosing between \"socket\n // on every page load\" and \"no channels at all\".\n //\n // The environment warning is also deferred: an app that never\n // subscribes should say nothing at all. See `ensureConnected`.\n }\n\n /**\n * Open the socket if it is not open (or opening) already.\n *\n * Idempotent, synchronous, and safe to call on every operation that needs a\n * live socket — `initWebSocket` already no-ops on an open socket and is\n * re-entrant, since the reconnect path has always called it.\n */\n public ensureConnected(): void {\n // An explicit `close()` is final. Without this, one queued frame could\n // redial a socket the caller just released and keep a Node process\n // alive forever.\n if (this.closedByCaller) return;\n if (!this.WebSocketConstructor) {\n if (!this.warnedNoWebSocket) {\n this.warnedNoWebSocket = true;\n console.warn(\"WebSocket is not defined in this environment. Realtime subscriptions will not work unless you provide a WebSocket implementation in the config.\");\n }\n return;\n }\n if (this.ws || this.reconnectTimeout) return;\n this.initWebSocket();\n }\n\n /**\n * Authenticate the WebSocket connection\n */\n async authenticate(token: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const requestId = `auth_${Date.now()}`;\n\n const timeout = setTimeout(() => {\n this.pendingRequests.delete(requestId);\n this.authPromise = null; // Clear promise so we can retry later\n reject(new Error(\"Authentication timeout\"));\n }, 30000);\n\n this.pendingRequests.set(requestId, {\n resolve: () => {\n clearTimeout(timeout);\n this.isAuthenticated = true;\n resolve();\n },\n reject: (error) => {\n clearTimeout(timeout);\n reject(error);\n }\n });\n\n const message = {\n type: \"AUTHENTICATE\",\n requestId,\n payload: { token }\n };\n\n if (!this.isConnected || !this.ws) {\n this.messageQueue.unshift(message); // Auth should be first\n } else {\n this.ws.send(JSON.stringify(message));\n }\n });\n }\n\n /**\n * Set the auth token getter function\n */\n setAuthTokenGetter(getAuthToken: () => Promise<string | null>): void {\n this.getAuthToken = getAuthToken;\n // Auto-authenticate if we are already connected but didn't have the token getter yet\n if (this.isConnected && !this.isAuthenticated && !this.authPromise) {\n console.debug(\"WebSocket auto-authenticating after token getter set\");\n this.getAuthToken().then(token => {\n if (!this.ws) return; // Prevent memory leaks / actions after disconnect\n if (token) {\n this.authenticate(token).catch(e => {\n if (this.ws) console.debug(\"WebSocket auto-auth skipped:\", e?.message || e);\n });\n }\n }).catch(e => {\n // User not logged in or auth still loading — this is expected,\n // the WebSocket will authenticate on-demand when a request is made.\n if (this.ws) console.debug(\"WebSocket auto-auth skipped:\", e?.message || e);\n });\n }\n }\n\n /**\n * Drop the socket.\n *\n * `permanent` distinguishes the two callers. Signing out drops the socket\n * but the client stays usable — a later subscribe should reconnect\n * anonymously. `client.close()` is the caller saying they are done, and\n * must not be undone by a stray queued frame.\n */\n public disconnect(permanent = false): void {\n if (permanent) this.closedByCaller = true;\n this.isAuthenticated = false;\n this.authPromise = null;\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n if (this.ws) {\n this.ws.onclose = null; // Prevent reconnect on explicit disconnect\n this.ws.onerror = null; // Prevent errors on explicit disconnect\n this.ws.onopen = null;\n this.ws.onmessage = null;\n this.ws.close();\n this.ws = null;\n }\n }\n\n // Initialize WebSocket connection\n private initWebSocket() {\n if (!this.WebSocketConstructor) return;\n if (this.ws?.readyState === this.WebSocketConstructor.OPEN) return;\n\n // Guard against race condition: if a previous socket is still connecting, tear it down\n if (this.ws) {\n this.ws.onclose = null;\n this.ws.close();\n this.ws = null;\n }\n\n try {\n this.ws = new this.WebSocketConstructor(this.websocketUrl);\n\n this.ws!.onopen = async () => {\n console.debug(\"Connected to PostgreSQL backend\");\n const wasReconnect = this.reconnectAttempts > 0;\n this.isConnected = true;\n this.reconnectAttempts = 0;\n\n // Auto-authenticate if token getter is available\n if (this.getAuthToken && !this.isAuthenticated) {\n try {\n const token = await this.getAuthToken();\n if (token) {\n await this.authenticate(token);\n console.debug(\"WebSocket auto-authenticated\");\n }\n } catch (error) {\n // User not logged in or auth still loading — this is expected.\n // Authentication will happen on-demand when the user logs in.\n console.debug(\"WebSocket connected without auth:\", (error as Error)?.message || error);\n }\n }\n\n this.emit(wasReconnect ? \"reconnect\" : \"connect\");\n this.processMessageQueue();\n\n // Re-subscribe all active subscriptions after reconnect.\n // The server-side subscription state was lost when the connection dropped,\n // so we need to re-register every active subscription.\n if (wasReconnect) {\n this.resubscribeAll();\n }\n\n // Subscribes requested while offline have just gone out; they\n // could not be watchdogged at request time.\n this.armPendingSubscribeWatchdogs();\n };\n\n this.ws!.onmessage = (event) => {\n try {\n const message = JSON.parse(event.data, rebaseReviver);\n this.handleWebSocketMessage(message);\n } catch (error) {\n console.error(\"Error parsing WebSocket message:\", error);\n }\n };\n\n this.ws!.onclose = () => {\n console.debug(\"Disconnected from PostgreSQL backend\");\n this.isConnected = false;\n this.isAuthenticated = false;\n this.authPromise = null;\n // The reconnect path re-subscribes everything; a watchdog firing\n // in the meantime would tear down healthy subscriptions.\n this.suspendSubscribeWatchdogs();\n this.emit(\"disconnect\");\n\n // Re-queue pending requests so the UI doesn't hang indefinitely or crash\n for (const [reqId, request] of this.pendingRequests.entries()) {\n if (reqId.startsWith(\"auth_\")) {\n request.reject(new Error(\"Connection closed during authentication\"));\n } else if (request.message) {\n request.message._queuedResolve = request.resolve;\n request.message._queuedReject = request.reject;\n this.messageQueue.push(request.message);\n } else {\n request.reject(new RebaseApiError(\"Connection closed\"));\n }\n this.pendingRequests.delete(reqId);\n }\n\n this.attemptReconnect();\n };\n\n this.ws!.onerror = (error) => {\n console.error(\"WebSocket error:\", error);\n this.isConnected = false;\n this.emit(\"error\", error);\n };\n } catch (error) {\n console.error(\"Failed to initialize WebSocket:\", error);\n this.attemptReconnect();\n }\n }\n\n private processMessageQueue() {\n while (this.messageQueue.length > 0 && this.isConnected) {\n const message = this.messageQueue.shift();\n if (message) this.sendMessage(message);\n }\n }\n\n private attemptReconnect() {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n console.error(\"Max reconnection attempts reached\");\n // Nothing will re-subscribe now, so stop every subscription that\n // never loaded from spinning forever.\n this.failAllPendingSubscriptions(\n new RebaseApiError(\"Connection lost\", { code: \"CONNECTION_LOST\" })\n );\n return;\n }\n\n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n\n console.debug(`Attempting to reconnect in ${delay}ms (attempt ${this.reconnectAttempts})`);\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n }\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null;\n this.initWebSocket();\n }, delay);\n }\n\n private isAuthError(message: WebSocketMessage): boolean {\n if (message.type === \"AUTH_ERROR\") return true;\n const { errorMessage, errorCode } = extractMessageError(message);\n if (errorCode === \"UNAUTHORIZED\" || errorCode === \"JWT_EXPIRED\" || errorCode === \"AUTH_ERROR\") return true;\n const lowerMessage = errorMessage.toLowerCase();\n return lowerMessage.includes(\"unauthorized\") || lowerMessage.includes(\"token expired\") || lowerMessage.includes(\"token is expired\") || lowerMessage.includes(\"invalid token\") || lowerMessage.includes(\"session expired\") || lowerMessage.includes(\"auth error\");\n }\n\n private async handleAuthFailure(): Promise<boolean> {\n if (this.refreshInProgress) {\n return this.refreshInProgress;\n }\n this.refreshInProgress = (async () => {\n this.isAuthenticated = false;\n this.authPromise = null;\n if (this.onUnauthorized) {\n try {\n const refreshed = await this.onUnauthorized();\n if (refreshed && this.getAuthToken) {\n const token = await this.getAuthToken();\n if (token) {\n await this.authenticate(token);\n return true;\n }\n }\n } catch (error) {\n console.error(\"WebSocket auth refresh failed:\", error);\n }\n }\n return false;\n })();\n try {\n return await this.refreshInProgress;\n } finally {\n this.refreshInProgress = null;\n }\n }\n\n /**\n * Shared logic for re-subscribing a collection or row subscription\n * after an auth error is resolved by refreshing credentials.\n */\n private resubscribeAfterAuthRefresh(\n message: WebSocketMessage,\n subscription: {\n backendSubscriptionId: string;\n callbacks: Map<string, { onUpdate: (...args: never[]) => void; onError?: (error: Error) => void }>;\n props: FetchCollectionProps | FetchOneProps;\n },\n subscriptionKey: string,\n idPrefix: \"collection\" | \"row\",\n backendKeyMap: Map<string, string>,\n messageType: \"subscribe_collection\" | \"subscribe_one\"\n ): void {\n this.handleAuthFailure().then(refreshed => {\n if (refreshed) {\n const oldBackendId = subscription.backendSubscriptionId;\n const newBackendId = `${idPrefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n subscription.backendSubscriptionId = newBackendId;\n backendKeyMap.delete(oldBackendId);\n backendKeyMap.set(newBackendId, subscriptionKey);\n\n // Route through the helpers so the retry is watchdogged too.\n if (messageType === \"subscribe_collection\") {\n this.sendCollectionSubscribe(subscriptionKey);\n } else {\n this.sendEntitySubscribe(subscriptionKey);\n }\n return;\n }\n\n // The refresh did not produce usable credentials. Report the original\n // error and drop the registration, so a later mount can try again\n // rather than attaching to a subscription that will never load.\n const { errorMessage, errorCode } = extractMessageError(message);\n const error = new RebaseApiError(errorMessage, { code: errorCode });\n if (messageType === \"subscribe_collection\") {\n this.failCollectionSubscription(subscriptionKey, error);\n } else {\n this.failEntitySubscription(subscriptionKey, error);\n }\n }).catch(err => {\n const error = err instanceof Error ? err : new Error(String(err));\n if (messageType === \"subscribe_collection\") {\n this.failCollectionSubscription(subscriptionKey, error);\n } else {\n this.failEntitySubscription(subscriptionKey, error);\n }\n });\n }\n\n private handleWebSocketMessage(message: WebSocketMessage) {\n const {\n type,\n requestId,\n subscriptionId\n } = message;\n\n // Handle responses to pending requests\n if (requestId && this.pendingRequests.has(requestId)) {\n const pendingReq = this.pendingRequests.get(requestId)!;\n if (type === \"ERROR\" || type === \"AUTH_ERROR\" || message.error) {\n if (this.isAuthError(message)) {\n this.pendingRequests.delete(requestId);\n this.handleAuthFailure().then(refreshed => {\n if (refreshed && pendingReq.message) {\n this.doSendMessage(pendingReq.message, pendingReq.resolve, pendingReq.reject).catch(pendingReq.reject);\n } else {\n const { errorMessage, errorCode } = extractMessageError(message);\n pendingReq.reject(new RebaseApiError(errorMessage, { code: errorCode }));\n }\n }).catch(err => {\n pendingReq.reject(err);\n });\n } else {\n this.pendingRequests.delete(requestId);\n const { errorMessage, errorCode } = extractMessageError(message);\n pendingReq.reject(new RebaseApiError(errorMessage, { code: errorCode }));\n }\n } else {\n this.pendingRequests.delete(requestId);\n pendingReq.resolve(message.payload || message);\n }\n return;\n }\n\n // Channel traffic (broadcast / presence) is addressed by channel name\n // rather than by requestId or subscriptionId, so it is dispatched\n // before the subscription paths — none of which would match it, and\n // the message would otherwise fall through and be dropped silently.\n if (typeof message.channel === \"string\" &&\n (type === \"broadcast\" || type === \"presence_state\" || type === \"presence_diff\" || type === \"channel_history\")) {\n const handlers = this.channelHandlers.get(message.channel);\n if (handlers) {\n for (const handler of [...handlers]) {\n try {\n handler(message as unknown as Record<string, unknown>);\n } catch (error) {\n console.error(\"Error in channel handler:\", error);\n }\n }\n }\n return;\n }\n\n // Handle subscription updates for collection subscriptions\n if (subscriptionId && type === \"collection_update\") {\n const subscriptionKey = this.backendToCollectionKey.get(subscriptionId);\n if (subscriptionKey) {\n const collectionSub = this.collectionSubscriptions.get(subscriptionKey);\n if (collectionSub) {\n const wireEntities = (message.rows || []) as unknown as Record<string, unknown>[];\n const incomingRows = wireEntities;\n\n // The keys arrive with the rows, so they are known before the\n // first merge — a CDC-driven change never sends a patch, and\n // learning them from patches alone would leave every\n // externally-written collection unable to match a thing.\n const updatePks = (message as unknown as { pks?: PrimaryKeyInfo[] }).pks;\n if (updatePks) collectionSub.pks = updatePks;\n\n // Structural merge: preserve cached row references for rows\n // whose values haven't changed. This prevents downstream React components\n // from re-rendering (VirtualTableCell uses deepEqual on rowData —\n // same reference = instant true, avoiding expensive deep comparison).\n const rows = this.mergeRows(collectionSub.latestData, incomingRows, collectionSub.pks);\n\n // Cache the latest data with optimizations\n collectionSub.latestData = rows;\n collectionSub.lastUpdated = Date.now();\n collectionSub.isInitialDataReceived = true;\n // The subscribe landed — stand the watchdog down.\n if (collectionSub.subscribeTimeout) clearTimeout(collectionSub.subscribeTimeout);\n collectionSub.subscribeTimeout = undefined;\n collectionSub.subscribeInFlight = false;\n\n // Notify all callbacks for this subscription\n collectionSub.callbacks.forEach(callback => {\n try {\n callback.onUpdate(rows);\n } catch (error) {\n console.error(\"Error in collection subscription callback:\", error);\n if (callback.onError) {\n callback.onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n });\n return;\n }\n }\n }\n\n // Handle instant row-level patches for collection subscriptions.\n // These arrive before the full refetch and give immediate cross-tab feedback.\n if (subscriptionId && type === \"collection_patch\") {\n const subscriptionKey = this.backendToCollectionKey.get(subscriptionId);\n if (subscriptionKey) {\n const collectionSub = this.collectionSubscriptions.get(subscriptionKey);\n if (collectionSub && collectionSub.isInitialDataReceived && collectionSub.latestData) {\n const patchWireEntity = message.row ?? null;\n const patchMessage = message as unknown as { id: string; pks?: PrimaryKeyInfo[] };\n const patchEntityId = patchMessage.id;\n // The server knows the key columns; remember them, because the\n // refetch reconciliation needs them too and carries no id.\n if (patchMessage.pks) collectionSub.pks = patchMessage.pks;\n const patchRow = patchWireEntity ? (patchWireEntity as unknown as Record<string, unknown>) : null;\n let updated: Record<string, unknown>[];\n\n if (patchRow === null) {\n // Row was deleted — remove it from the cached list\n updated = collectionSub.latestData.filter(\n e => this.rowAddress(e, collectionSub.pks) !== String(patchEntityId)\n );\n } else {\n // Row was created or updated — merge into the cached list.\n // Matched against the patch's own address rather than\n // anything read off the row: `patchRow.id` is undefined\n // for a table not keyed on `id`, so every update looked\n // like a new row and was prepended as a duplicate.\n const idx = collectionSub.latestData.findIndex(\n e => this.rowAddress(e, collectionSub.pks) === String(patchEntityId)\n );\n if (idx >= 0) {\n // Update in place (preserve array position)\n updated = [...collectionSub.latestData];\n updated[idx] = patchRow;\n } else {\n // New row — prepend (most recently created first)\n updated = [patchRow, ...collectionSub.latestData];\n }\n }\n\n collectionSub.latestData = updated;\n collectionSub.lastUpdated = Date.now();\n\n // Fire all callbacks with the patched data\n collectionSub.callbacks.forEach(callback => {\n try {\n callback.onUpdate(updated);\n } catch (error) {\n console.error(\"Error in collection patch callback:\", error);\n if (callback.onError) {\n callback.onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n });\n return;\n }\n }\n }\n\n // Handle subscription updates for row subscriptions\n if (subscriptionId && type === \"single_update\") {\n const subscriptionKey = this.backendToEntityKey.get(subscriptionId);\n if (subscriptionKey) {\n const entitySub = this.singleSubscriptions.get(subscriptionKey);\n if (entitySub) {\n const wireEntity = message.row ?? null;\n const row = wireEntity ? (wireEntity as unknown as Record<string, unknown>) : null;\n // Cache the latest data with optimizations\n entitySub.latestData = row;\n entitySub.lastUpdated = Date.now();\n entitySub.isInitialDataReceived = true;\n if (entitySub.subscribeTimeout) clearTimeout(entitySub.subscribeTimeout);\n entitySub.subscribeTimeout = undefined;\n entitySub.subscribeInFlight = false;\n\n // Notify all callbacks for this subscription\n entitySub.callbacks.forEach(callback => {\n try {\n callback.onUpdate(row);\n } catch (error) {\n console.error(\"Error in row subscription callback:\", error);\n if (callback.onError) {\n callback.onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n });\n return;\n }\n }\n }\n\n // Handle subscription errors\n if (subscriptionId && (type === \"ERROR\" || message.error)) {\n const collectionKey = this.backendToCollectionKey.get(subscriptionId);\n if (collectionKey) {\n const collectionSub = this.collectionSubscriptions.get(collectionKey);\n if (collectionSub) {\n if (this.isAuthError(message)) {\n this.resubscribeAfterAuthRefresh(\n message,\n collectionSub,\n collectionKey,\n \"collection\",\n this.backendToCollectionKey,\n \"subscribe_collection\"\n );\n return;\n }\n\n // The server answered, so nothing is in flight any more. Leave\n // the registration in place (its listeners are still mounted\n // and have been told), but marked idle so the next listener\n // re-subscribes instead of attaching to a dead entry.\n if (collectionSub.subscribeTimeout) clearTimeout(collectionSub.subscribeTimeout);\n collectionSub.subscribeTimeout = undefined;\n collectionSub.subscribeInFlight = false;\n\n const { errorMessage, errorCode } = extractMessageError(message);\n const error = new RebaseApiError(errorMessage, { code: errorCode });\n collectionSub.callbacks.forEach(callback => {\n if (callback.onError) {\n callback.onError(error);\n }\n });\n return;\n }\n }\n\n const entityKey = this.backendToEntityKey.get(subscriptionId);\n if (entityKey) {\n const entitySub = this.singleSubscriptions.get(entityKey);\n if (entitySub) {\n if (this.isAuthError(message)) {\n this.resubscribeAfterAuthRefresh(\n message,\n entitySub,\n entityKey,\n \"row\",\n this.backendToEntityKey,\n \"subscribe_one\"\n );\n return;\n }\n\n if (entitySub.subscribeTimeout) clearTimeout(entitySub.subscribeTimeout);\n entitySub.subscribeTimeout = undefined;\n entitySub.subscribeInFlight = false;\n\n const { errorMessage, errorCode } = extractMessageError(message);\n const error = new RebaseApiError(errorMessage, { code: errorCode });\n entitySub.callbacks.forEach(callback => {\n if (callback.onError) {\n callback.onError(error);\n }\n });\n return;\n }\n }\n }\n\n // Legacy subscription handling (for backward compatibility)\n if (subscriptionId && this.subscriptions.has(subscriptionId)) {\n const callback = this.subscriptions.get(subscriptionId);\n if (!callback) {\n throw new Error(`Subscription callback not found for subscriptionId: ${subscriptionId}`);\n }\n if (message.type === \"ERROR\" || message.error) {\n if (callback.onError) {\n const { errorMessage, errorCode } = extractMessageError(message);\n callback.onError(new RebaseApiError(errorMessage, { code: errorCode }));\n }\n } else {\n callback.onUpdate(message);\n }\n }\n }\n\n private async ensureAuthenticated(retryCount = 3): Promise<void> {\n // If already authenticated or no token getter, skip\n if (this.isAuthenticated || !this.getAuthToken) return;\n\n // If auth is in progress, wait for it\n if (this.authPromise) {\n await this.authPromise;\n return;\n }\n\n // Try to authenticate with retries\n let lastError: unknown = null;\n\n for (let attempt = 0; attempt < retryCount; attempt++) {\n try {\n const token = await this.getAuthToken();\n if (!token) throw new Error(\"user not logged in\");\n this.authPromise = this.authenticate(token);\n await this.authPromise;\n this.authPromise = null;\n console.debug(\"WebSocket authenticated on demand\");\n return; // Success\n } catch (error: unknown) {\n this.authPromise = null;\n lastError = error;\n\n const errMsg = error instanceof Error ? error.message : String(error);\n // \"not logged in\" / \"Session expired\" are definitive - don't retry\n if (errMsg.includes(\"not logged in\") || errMsg.includes(\"Session expired\")) {\n console.warn(\"WebSocket auth failed: user not logged in\");\n throw error;\n }\n\n // \"still loading\" is transient - retry with backoff (auth controller\n // is restoring tokens from localStorage; it will resolve shortly)\n if (errMsg.includes(\"still loading\")) {\n if (attempt < retryCount - 1) {\n const delay = Math.min(500 * (attempt + 1), 2000);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n }\n\n // For other errors, retry with backoff\n if (attempt < retryCount - 1) {\n const delay = Math.min(1000 * (attempt + 1), 3000);\n console.debug(`WebSocket auth attempt ${attempt + 1} failed, retrying in ${delay}ms...`);\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n\n console.warn(\"WebSocket on-demand auth failed after retries:\", lastError);\n throw lastError;\n }\n\n async reauthenticate(): Promise<void> {\n if (!this.getAuthToken) return;\n\n this.isAuthenticated = false;\n try {\n const token = await this.getAuthToken();\n if (!token) throw new Error(\"user not logged in\");\n await this.authenticate(token);\n console.debug(\"WebSocket reauthenticated successfully\");\n } catch (error) {\n console.error(\"WebSocket reauthentication failed:\", error);\n throw error;\n }\n }\n\n /**\n * Public because `RebaseRealtimeChannel` sends channel frames through it.\n * Not part of the stable surface — prefer `client.realtime.channel(name)`.\n */\n public sendMessage(message: Record<string, unknown>): Promise<unknown> {\n // If already has a requestId (re-sending from queue), use the stored promise handlers\n const queuedMsg = message as Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void };\n if (queuedMsg._queuedResolve && queuedMsg._queuedReject) {\n return this.doSendMessage(message, queuedMsg._queuedResolve, queuedMsg._queuedReject);\n }\n\n if (!this.isConnected || !this.ws) {\n // The queue is only ever drained by a socket opening, so something\n // has to open one. Before lazy connect this was guaranteed by the\n // constructor; now the first frame is what asks for it.\n this.ensureConnected();\n // Queue the message and return a promise that will be resolved when actually sent\n return new Promise<unknown>((resolve, reject) => {\n const queueable = message as Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void };\n queueable._queuedResolve = resolve;\n queueable._queuedReject = reject;\n this.messageQueue.push(message);\n });\n }\n\n return new Promise<unknown>((resolve, reject) => {\n this.doSendMessage(message, resolve, reject);\n });\n }\n\n private async doSendMessage(message: Record<string, unknown>, resolve: (value: unknown) => void, reject: (error: Error) => void): Promise<void> {\n // Ensure authenticated before sending non-auth messages.\n //\n // Channel traffic is exempt. `ensureAuthenticated` throws \"user not\n // logged in\" when there is no token, which rejects the frame before it\n // is ever sent — so on an anonymous-first app (the kind this API was\n // added for) *every* channel operation failed client-side, and the\n // server never got to decide. Presence in a public room does not\n // require an account. A signed-in caller still authenticates: the\n // socket does it from `getAuthToken` on open, and the server authorizes\n // these frames either way.\n if (message.type !== \"AUTHENTICATE\"\n && !CHANNEL_MESSAGE_TYPES.has(message.type as string)\n && this.getAuthToken && !this.isAuthenticated) {\n try {\n await this.ensureAuthenticated();\n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : \"Authentication required\";\n reject(new RebaseApiError(errorMessage));\n return;\n }\n }\n\n const requestId = (message.requestId as string) || `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n message.requestId = requestId;\n\n const expectsResponse = !(\n message.type === \"subscribe_collection\"\n || message.type === \"subscribe_one\"\n || message.type === \"unsubscribe\"\n || CHANNEL_MESSAGE_TYPES.has(message.type as string)\n );\n\n if (expectsResponse && !this.pendingRequests.has(requestId)) {\n const timeoutHandle = setTimeout(() => {\n if (this.pendingRequests.has(requestId)) {\n this.pendingRequests.delete(requestId);\n reject(new RebaseApiError(\"Request timed out\"));\n }\n }, this.requestTimeoutMs);\n\n this.pendingRequests.set(requestId, {\n resolve: (value: unknown) => {\n clearTimeout(timeoutHandle);\n resolve(value);\n },\n reject: (error: Error) => {\n clearTimeout(timeoutHandle);\n reject(error);\n },\n message: message as Record<string, unknown> & { _queuedResolve?: (p: unknown) => void; _queuedReject?: (p: Error) => void }\n });\n }\n\n try {\n this.ws!.send(JSON.stringify(message));\n if (!expectsResponse) {\n resolve(undefined);\n }\n } catch (error) {\n if (expectsResponse) {\n this.pendingRequests.delete(requestId);\n }\n reject(new RebaseApiError(\"Failed to send message\", { cause: error }));\n }\n }\n\n // Data source methods\n async fetchCollection<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> {\n const response = await this.sendMessage({\n type: \"FETCH_COLLECTION\",\n payload: props\n }) as { rows?: Record<string, unknown>[] };\n return (response.rows || []);\n }\n\n async fetchOne<M extends Record<string, unknown>>(props: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> {\n const response = await this.sendMessage({\n type: \"FETCH_ONE\",\n payload: props\n }) as { row?: Record<string, unknown> };\n const wireEntity = response.row;\n return wireEntity ?? undefined;\n }\n\n async save<M extends Record<string, unknown>>(props: SaveProps<M>): Promise<Record<string, unknown>> {\n const response = await this.sendMessage({\n type: \"SAVE\",\n payload: props\n }) as { row: Record<string, unknown> };\n return response.row;\n }\n\n async delete<M extends Record<string, unknown>>(props: DeleteProps<M>): Promise<void> {\n await this.sendMessage({\n type: \"DELETE\",\n payload: props\n });\n }\n\n async executeSql(sql: string, options?: { database?: string, role?: string }): Promise<Record<string, unknown>[]> {\n const response = await this.sendMessage({\n type: \"EXECUTE_SQL\",\n payload: { sql,\noptions }\n }) as { result?: Record<string, unknown>[] };\n return response.result || [];\n }\n\n async fetchAvailableDatabases(): Promise<string[]> {\n const response = await this.sendMessage({\n type: \"FETCH_DATABASES\",\n payload: {}\n }) as { databases?: string[] };\n return response.databases || [];\n }\n\n async fetchAvailableRoles(): Promise<string[]> {\n const response = await this.sendMessage({\n type: \"FETCH_ROLES\"\n }) as { roles?: string[] };\n return response.roles || [];\n }\n\n async fetchApplicationRoles(): Promise<string[]> {\n const response = await this.sendMessage({\n type: \"FETCH_APPLICATION_ROLES\"\n }) as { roles?: string[] };\n return response.roles || [];\n }\n\n async fetchCurrentDatabase(): Promise<string | undefined> {\n const response = await this.sendMessage({\n type: \"FETCH_CURRENT_DATABASE\"\n }) as { database?: string };\n return response.database;\n }\n\n async checkUniqueField(path: string, name: string, value: unknown, id?: string, collection?: CollectionConfig): Promise<boolean> {\n const response = await this.sendMessage({\n type: \"CHECK_UNIQUE_FIELD\",\n payload: {\n path,\n name,\n value,\n id,\n collection\n }\n }) as { isUnique: boolean };\n return response.isUnique;\n }\n\n async count<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number> {\n const response = await this.sendMessage({\n type: \"COUNT\",\n payload: props\n }) as { count: number };\n return response.count;\n }\n\n async fetchUnmappedTables(mappedPaths?: string[]): Promise<string[]> {\n const response = await this.sendMessage({\n type: \"FETCH_UNMAPPED_TABLES\",\n payload: { mappedPaths }\n }) as { tables?: string[] };\n return response.tables || [];\n }\n\n async fetchTableMetadata(tableName: string): Promise<TableMetadata> {\n const response = await this.sendMessage({\n type: \"FETCH_TABLE_METADATA\",\n payload: { tableName }\n }) as { metadata?: TableMetadata };\n\n return response.metadata || ({ columns: [],\nforeignKeys: [],\njunctions: [],\npolicies: [] } as TableMetadata);\n }\n\n async createBranch(name: string, options?: { source?: string }): Promise<BranchInfo> {\n const response = await this.sendMessage({\n type: \"CREATE_BRANCH\",\n payload: { name,\noptions }\n }) as { branch: BranchInfo };\n return response.branch;\n }\n\n async deleteBranch(name: string): Promise<void> {\n await this.sendMessage({\n type: \"DELETE_BRANCH\",\n payload: { name }\n });\n }\n\n async listBranches(): Promise<BranchInfo[]> {\n const response = await this.sendMessage({\n type: \"LIST_BRANCHES\",\n payload: {}\n }) as { branches?: BranchInfo[] };\n return response.branches || [];\n }\n\n /**\n * Recursively compare two values for structural equality.\n * Handles primitives, null, undefined, Date, RegExp, arrays, and plain objects.\n */\n private deepEqual(a: unknown, b: unknown): boolean {\n // Same reference or same primitive\n if (a === b) return true;\n\n // Handle null/undefined\n if (a === null || b === null || a === undefined || b === undefined) return false;\n\n // Different types\n if (typeof a !== typeof b) return false;\n\n // Non-object primitives (number, string, boolean, bigint, symbol)\n // that weren't caught by === above (e.g. NaN !== NaN)\n if (typeof a !== \"object\") return false;\n\n // Date comparison\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n if (a instanceof Date || b instanceof Date) return false;\n\n // RegExp comparison\n if (a instanceof RegExp && b instanceof RegExp) {\n return a.source === b.source && a.flags === b.flags;\n }\n if (a instanceof RegExp || b instanceof RegExp) return false;\n\n // Array comparison\n const aIsArray = Array.isArray(a);\n const bIsArray = Array.isArray(b);\n if (aIsArray !== bIsArray) return false;\n\n if (aIsArray && bIsArray) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!this.deepEqual(a[i], b[i])) return false;\n }\n return true;\n }\n\n // Plain object comparison\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n\n if (aKeys.length !== bKeys.length) return false;\n\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(bObj, key)) return false;\n if (!this.deepEqual(aObj[key], bObj[key])) return false;\n }\n\n return true;\n }\n\n private normalizeForComparison(val: unknown): unknown {\n if (!val) return val;\n\n if (Array.isArray(val)) {\n return val.map(item => this.normalizeForComparison(item));\n }\n\n if (typeof val === \"object\") {\n if (val instanceof Date) return val;\n if (val instanceof RegExp) return val;\n\n const obj = val as Record<string, unknown>;\n if (obj.__type === \"relation\") {\n const { data, ...rest } = obj;\n return rest;\n }\n\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n result[k] = this.normalizeForComparison(v);\n }\n return result;\n }\n\n return val;\n }\n\n /**\n * The address of a row, for matching it against another copy of itself.\n *\n * A row is exactly its columns and carries no address, so it is derived\n * from the key columns the server named — including the ordinary case where\n * that key is `id`, which the server reports like any other.\n *\n * Undefined when there are no keys, which means the server could not\n * resolve any: such rows genuinely cannot be recognised, and guessing at a\n * column called `id` would be inventing an identity for a table that has\n * none.\n */\n private rowAddress(row: Record<string, unknown>, pks: PrimaryKeyInfo[] | undefined): string | undefined {\n if (!pks || pks.length === 0) return undefined;\n const address = buildCompositeId(row, pks);\n if (!address || address.split(COMPOSITE_ID_SEPARATOR).every(part => part === \"\")) return undefined;\n return address;\n }\n\n /**\n * Merge incoming rows with cached data, preserving cached references\n * for rows whose values haven't changed. This avoids unnecessary\n * React re-renders when the server refetches all rows but most\n * haven't actually changed.\n */\n private mergeRows(\n cached: Record<string, unknown>[] | undefined,\n incoming: Record<string, unknown>[],\n pks?: PrimaryKeyInfo[]\n ): Record<string, unknown>[] {\n if (!cached || cached.length === 0) return incoming;\n\n // Build a lookup from cached rows by address for O(1) access\n const cachedById = new Map<string, Record<string, unknown>>();\n for (const row of cached) {\n const address = this.rowAddress(row, pks);\n if (address !== undefined) cachedById.set(address, row);\n }\n\n return incoming.map(incomingRow => {\n const address = this.rowAddress(incomingRow, pks);\n const cachedRow = address === undefined ? undefined : cachedById.get(address);\n if (!cachedRow) return incomingRow;\n\n // Compare flat rows directly (no more path/values nesting)\n const normCached = this.normalizeForComparison(cachedRow) as Record<string, unknown>;\n const normIncoming = this.normalizeForComparison(incomingRow) as Record<string, unknown>;\n\n if (this.deepEqual(normCached, normIncoming)) {\n return cachedRow;\n } else {\n // Deep debug: Why did it fail?\n const mismatches: Record<string, { cached: unknown, incoming: unknown }> = {};\n const allKeys = new Set([...Object.keys(normCached), ...Object.keys(normIncoming)]);\n for (const key of allKeys) {\n if (!this.deepEqual(normCached[key], normIncoming[key])) {\n mismatches[key] = { cached: normCached[key],\nincoming: normIncoming[key] };\n }\n }\n console.debug(`[RebaseWS] Row ${address} refetch mismatch:\\n`, JSON.stringify(mismatches, null, 2));\n }\n return incomingRow;\n });\n }\n\n // Subscription methods\n listenCollection<M extends Record<string, unknown>>(\n props: FetchCollectionProps<M>,\n onUpdate: (rows: Record<string, unknown>[]) => void,\n onError?: (error: Error) => void\n ): () => void {\n // A subscription is the app asking for live data, so this is where the\n // socket is wanted. Called before the dedup check below: joining an\n // existing subscription must still work if the socket has since gone.\n this.ensureConnected();\n\n const subscriptionKey = this.createCollectionSubscriptionKey(props);\n const callbackId = `callback_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n // Check if we already have a subscription for these exact parameters\n const existingSubscription = this.collectionSubscriptions.get(subscriptionKey);\n\n if (existingSubscription) {\n // Reuse existing subscription - just add the new callback\n const callbackMap = existingSubscription.callbacks as Map<string, {\n onUpdate: (rows: Record<string, unknown>[]) => void;\n onError?: (error: Error) => void;\n }>;\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n // Immediately fire the callback with cached data if available\n if (existingSubscription.latestData !== undefined && existingSubscription.isInitialDataReceived) {\n try {\n onUpdate(existingSubscription.latestData);\n } catch (error) {\n console.error(\"Error in collection subscription callback:\", error);\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n } else if (!existingSubscription.subscribeInFlight) {\n // Registered but idle: its subscribe never landed (the send failed,\n // or the server answered with an error). Nothing is coming, so\n // re-issue it — otherwise this listener waits forever.\n this.sendCollectionSubscribe(subscriptionKey);\n }\n\n // Return unsubscribe function\n return () => {\n callbackMap.delete(callbackId);\n if (callbackMap.size === 0) {\n // Only tear down if this is still the same registration — a\n // failed subscribe may have replaced it in the meantime.\n if (this.collectionSubscriptions.get(subscriptionKey) !== existingSubscription) return;\n if (existingSubscription.subscribeTimeout) clearTimeout(existingSubscription.subscribeTimeout);\n this.collectionSubscriptions.delete(subscriptionKey);\n this.backendToCollectionKey.delete(existingSubscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: existingSubscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n };\n }\n\n // Create new subscription\n const backendSubscriptionId = `collection_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n const callbackMap = new Map<string, {\n onUpdate: (rows: Record<string, unknown>[]) => void;\n onError?: (error: Error) => void;\n }>();\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n this.collectionSubscriptions.set(subscriptionKey, {\n backendSubscriptionId,\n callbacks: callbackMap,\n props\n });\n\n // Add reverse lookup\n this.backendToCollectionKey.set(backendSubscriptionId, subscriptionKey);\n\n // Send subscription request to backend. A failure here drops the\n // registration and notifies every listener, so the next mount retries.\n this.sendCollectionSubscribe(subscriptionKey);\n\n // Return unsubscribe function\n return () => {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (subscription) {\n const callbacks = subscription.callbacks;\n callbacks.delete(callbackId);\n if (callbacks.size === 0) {\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n this.collectionSubscriptions.delete(subscriptionKey);\n this.backendToCollectionKey.delete(subscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: subscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n }\n };\n }\n\n listenOne<M extends Record<string, unknown>>(\n props: FetchOneProps<M>,\n onUpdate: (row: Record<string, unknown> | null) => void,\n onError?: (error: Error) => void\n ): () => void {\n this.ensureConnected();\n\n const subscriptionKey = this.createSingleSubscriptionKey(props);\n const callbackId = `callback_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n // Check if we already have a subscription for these exact parameters\n const existingSubscription = this.singleSubscriptions.get(subscriptionKey);\n\n if (existingSubscription) {\n // Reuse existing subscription - just add the new callback\n const callbackMap = existingSubscription.callbacks as Map<string, {\n onUpdate: (row: Record<string, unknown> | null) => void;\n onError?: (error: Error) => void;\n }>;\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n // Immediately fire the callback with cached data if available\n if (existingSubscription.latestData !== undefined && existingSubscription.isInitialDataReceived) {\n try {\n onUpdate(existingSubscription.latestData);\n } catch (error) {\n console.error(\"Error in row subscription callback:\", error);\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n } else if (!existingSubscription.subscribeInFlight) {\n // See listenCollection: a registration with nothing in flight is\n // dead, and attaching to it silently would hang this listener.\n this.sendEntitySubscribe(subscriptionKey);\n }\n\n // Return unsubscribe function\n return () => {\n callbackMap.delete(callbackId);\n if (callbackMap.size === 0) {\n if (this.singleSubscriptions.get(subscriptionKey) !== existingSubscription) return;\n if (existingSubscription.subscribeTimeout) clearTimeout(existingSubscription.subscribeTimeout);\n // No more callbacks, unsubscribe from backend\n this.singleSubscriptions.delete(subscriptionKey);\n this.backendToEntityKey.delete(existingSubscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: existingSubscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n };\n }\n\n // Create new subscription\n const backendSubscriptionId = `entity_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n const callbackMap = new Map<string, {\n onUpdate: (row: Record<string, unknown> | null) => void;\n onError?: (error: Error) => void;\n }>();\n callbackMap.set(callbackId, { onUpdate,\nonError });\n\n this.singleSubscriptions.set(subscriptionKey, {\n backendSubscriptionId,\n callbacks: callbackMap,\n props\n });\n\n // Add reverse lookup\n this.backendToEntityKey.set(backendSubscriptionId, subscriptionKey);\n\n // Send subscription request to backend\n this.sendEntitySubscribe(subscriptionKey);\n\n // Return unsubscribe function\n return () => {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (subscription) {\n const callbacks = subscription.callbacks;\n callbacks.delete(callbackId);\n if (callbacks.size === 0) {\n this.singleSubscriptions.delete(subscriptionKey);\n this.backendToEntityKey.delete(subscription.backendSubscriptionId);\n if (this.isConnected && this.ws) {\n this.sendMessage({\n type: \"unsubscribe\",\n payload: { subscriptionId: subscription.backendSubscriptionId }\n }).catch(console.error);\n }\n }\n }\n };\n }\n\n /**\n * Send a `subscribe_collection` for an already-registered subscription and\n * arm its watchdog.\n *\n * Every path that registers a collection subscription goes through here, so\n * that a subscribe which never lands — a rejected send, or a server that\n * never answers — always ends up in `failCollectionSubscription` rather than\n * leaving the entry parked with `isInitialDataReceived === false` forever.\n */\n private sendCollectionSubscribe(subscriptionKey: string): void {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeInFlight = true;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeTimeout = undefined;\n // Only time out a frame that is actually on the wire. While offline the\n // message just sits in the queue, and reconnect backoff can exceed the\n // timeout — `armPendingSubscribeWatchdogs` picks these up on connect.\n if (this.isConnected) this.sendCollectionSubscribeWatchdog(subscriptionKey);\n\n this.sendMessage({\n type: \"subscribe_collection\",\n payload: {\n ...subscription.props,\n subscriptionId: backendSubscriptionId\n }\n }).catch(error => {\n const current = this.collectionSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n this.failCollectionSubscription(\n subscriptionKey,\n error instanceof Error ? error : new Error(String(error))\n );\n });\n }\n\n /** The `listenOne` counterpart of {@link sendCollectionSubscribe}. */\n private sendEntitySubscribe(subscriptionKey: string): void {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeInFlight = true;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeTimeout = undefined;\n if (this.isConnected) this.sendEntitySubscribeWatchdog(subscriptionKey);\n\n this.sendMessage({\n type: \"subscribe_one\",\n payload: {\n ...subscription.props,\n subscriptionId: backendSubscriptionId\n }\n }).catch(error => {\n const current = this.singleSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n this.failEntitySubscription(\n subscriptionKey,\n error instanceof Error ? error : new Error(String(error))\n );\n });\n }\n\n /**\n * Report a subscribe failure to every listener and drop the registration.\n *\n * Dropping it is the point: the callbacks stay live (their components are\n * still mounted and have been told), but the next `listenCollection` for\n * these params finds no entry and issues a fresh subscribe instead of\n * silently attaching to a dead one.\n */\n private failCollectionSubscription(subscriptionKey: string, error: Error): void {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeInFlight = false;\n\n this.collectionSubscriptions.delete(subscriptionKey);\n this.backendToCollectionKey.delete(subscription.backendSubscriptionId);\n\n subscription.callbacks.forEach(callback => {\n if (callback.onError) {\n try {\n callback.onError(error);\n } catch (callbackError) {\n console.error(\"Error in collection subscription error callback:\", callbackError);\n }\n }\n });\n }\n\n /** The `listenOne` counterpart of {@link failCollectionSubscription}. */\n private failEntitySubscription(subscriptionKey: string, error: Error): void {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n\n if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);\n subscription.subscribeInFlight = false;\n\n this.singleSubscriptions.delete(subscriptionKey);\n this.backendToEntityKey.delete(subscription.backendSubscriptionId);\n\n subscription.callbacks.forEach(callback => {\n if (callback.onError) {\n try {\n callback.onError(error);\n } catch (callbackError) {\n console.error(\"Error in row subscription error callback:\", callbackError);\n }\n }\n });\n }\n\n /**\n * Stop the watchdogs without failing anything — used when the socket drops,\n * since the reconnect path re-subscribes everything anyway and a watchdog\n * firing mid-reconnect would tear down healthy subscriptions.\n */\n private suspendSubscribeWatchdogs(): void {\n for (const sub of this.collectionSubscriptions.values()) {\n if (sub.subscribeTimeout) clearTimeout(sub.subscribeTimeout);\n sub.subscribeTimeout = undefined;\n sub.subscribeInFlight = false;\n }\n for (const sub of this.singleSubscriptions.values()) {\n if (sub.subscribeTimeout) clearTimeout(sub.subscribeTimeout);\n sub.subscribeTimeout = undefined;\n sub.subscribeInFlight = false;\n }\n }\n\n /**\n * Arm watchdogs for subscribes that were requested while offline and have\n * just been flushed to the socket. Their timers were deliberately not set at\n * request time, so without this they would have no timeout at all.\n */\n private armPendingSubscribeWatchdogs(): void {\n for (const [key, sub] of this.collectionSubscriptions.entries()) {\n if (sub.subscribeInFlight && !sub.subscribeTimeout) this.sendCollectionSubscribeWatchdog(key);\n }\n for (const [key, sub] of this.singleSubscriptions.entries()) {\n if (sub.subscribeInFlight && !sub.subscribeTimeout) this.sendEntitySubscribeWatchdog(key);\n }\n }\n\n private sendCollectionSubscribeWatchdog(subscriptionKey: string): void {\n const subscription = this.collectionSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeTimeout = setTimeout(() => {\n const current = this.collectionSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n if (!current.subscribeInFlight) return;\n this.failCollectionSubscription(\n subscriptionKey,\n new RebaseApiError(\"Subscription timed out\", { code: \"SUBSCRIPTION_TIMEOUT\" })\n );\n }, this.subscriptionTimeoutMs);\n }\n\n private sendEntitySubscribeWatchdog(subscriptionKey: string): void {\n const subscription = this.singleSubscriptions.get(subscriptionKey);\n if (!subscription) return;\n const backendSubscriptionId = subscription.backendSubscriptionId;\n subscription.subscribeTimeout = setTimeout(() => {\n const current = this.singleSubscriptions.get(subscriptionKey);\n if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;\n if (!current.subscribeInFlight) return;\n this.failEntitySubscription(\n subscriptionKey,\n new RebaseApiError(\"Subscription timed out\", { code: \"SUBSCRIPTION_TIMEOUT\" })\n );\n }, this.subscriptionTimeoutMs);\n }\n\n /**\n * Fail every subscription that never received data. Called when reconnection\n * is given up on, so views surface an error instead of spinning forever.\n */\n private failAllPendingSubscriptions(error: Error): void {\n for (const key of [...this.collectionSubscriptions.keys()]) {\n const sub = this.collectionSubscriptions.get(key);\n if (sub && !sub.isInitialDataReceived) this.failCollectionSubscription(key, error);\n }\n for (const key of [...this.singleSubscriptions.keys()]) {\n const sub = this.singleSubscriptions.get(key);\n if (sub && !sub.isInitialDataReceived) this.failEntitySubscription(key, error);\n }\n }\n\n /**\n * Re-send all active subscriptions to the backend after a reconnect.\n * The server wipes subscription state when a client disconnects, so\n * we need to re-register everything to resume receiving updates.\n */\n private resubscribeAll(): void {\n console.debug(`[WS] Re-subscribing: ${this.collectionSubscriptions.size} collection(s), ${this.singleSubscriptions.size} row(ies)`);\n\n // Re-subscribe collection subscriptions\n for (const [key, sub] of this.collectionSubscriptions.entries()) {\n // Generate a fresh backend ID since the old one is no longer valid on the server\n const oldBackendId = sub.backendSubscriptionId;\n const newBackendId = `collection_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n sub.backendSubscriptionId = newBackendId;\n\n // Update reverse lookup\n this.backendToCollectionKey.delete(oldBackendId);\n this.backendToCollectionKey.set(newBackendId, key);\n\n this.sendCollectionSubscribe(key);\n }\n\n // Re-subscribe row subscriptions\n for (const [key, sub] of this.singleSubscriptions.entries()) {\n const oldBackendId = sub.backendSubscriptionId;\n const newBackendId = `entity_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n sub.backendSubscriptionId = newBackendId;\n\n this.backendToEntityKey.delete(oldBackendId);\n this.backendToEntityKey.set(newBackendId, key);\n\n this.sendEntitySubscribe(key);\n }\n }\n\n private createCollectionSubscriptionKey(props: FetchCollectionProps): string {\n // Create a deterministic key based on subscription parameters\n const key = {\n path: props.path,\n filter: props.filter,\n limit: props.limit,\n startAfter: props.startAfter,\n orderBy: props.orderBy,\n order: props.order,\n searchString: props.searchString,\n collection: props.collection?.name\n };\n // Use replacer function (not array) to sort keys at all levels for deterministic output\n return JSON.stringify(key, (_, value) => {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n return Object.keys(value).sort().reduce((sorted: Record<string, unknown>, k) => {\n sorted[k] = value[k];\n return sorted;\n }, {});\n }\n return value;\n });\n }\n\n private createSingleSubscriptionKey(props: FetchOneProps): string {\n return `${props.path}|${props.id}`;\n }\n}\n","/**\n * Broadcast channels and presence, as an SDK surface.\n *\n * The realtime engine has supported `join_channel`, `broadcast`,\n * `presence_track`, `presence_untrack` and `presence_state` for a while, but\n * the client only recognised those types well enough to send them\n * fire-and-forget: there were no methods to call and no way to receive channel\n * or broadcast events, since `on()` handles only connect / disconnect /\n * reconnect / error. Anything wanting presence therefore opened a *second*\n * socket and reimplemented the AUTHENTICATE → AUTH_SUCCESS handshake, the\n * reconnect backoff, and the presence heartbeat — a couple of hundred lines\n * per app, all of it duplicating this package.\n *\n * Two protocol details this hides, because both are easy to get wrong and\n * neither is discoverable from the message list:\n *\n * - **A joining client is told only about its own join.** The `presence_diff`\n * it receives after `presence_track` contains just itself. The existing\n * roster arrives only in response to an explicit `presence_state` request,\n * so `join()` sends one.\n * - **Presence expires after 30s** (`PRESENCE_TIMEOUT_MS` server-side). A\n * client that tracks once and goes quiet silently vanishes from everyone\n * else's roster while still sitting in the document, so `track()` starts a\n * heartbeat and `leave()` stops it.\n */\n\n/** Presence state keyed by the server's client id. */\nexport type PresenceState = Record<string, Record<string, unknown>>;\n\nexport interface PresenceDiff {\n joins: PresenceState;\n leaves: PresenceState;\n}\n\nexport interface BroadcastEvent {\n event: string;\n payload: unknown;\n /**\n * Per-channel sequence number, present only on retained channels.\n *\n * Monotonically increasing and dense, so a consumer that remembers the last\n * one it applied can tell the server exactly where to resume from.\n */\n seq?: number;\n /**\n * True when this arrived through catch-up rather than live.\n *\n * Handlers do not have to care — replayed messages are delivered to the\n * same `onBroadcast` handlers, in sequence order, so an operation stream\n * needs no second code path. It is exposed for consumers that want to,\n * for example, skip an animation while fast-forwarding.\n */\n replayed?: boolean;\n}\n\n/** One retained message, as returned by {@link RebaseRealtimeChannel.history}. */\nexport interface ChannelHistoryEntry {\n seq: number;\n event: string;\n payload: unknown;\n senderId?: string;\n at?: string;\n}\n\n/** The answer to a catch-up request. */\nexport interface ChannelHistoryResult {\n messages: ChannelHistoryEntry[];\n /**\n * Whether the server retains anything for this channel.\n *\n * False means there is no retention rule configured for it, so the empty\n * list means \"never keeps history\" rather than \"you missed nothing\" — a\n * client that needs to converge has to fall back to a full resync.\n */\n retained: boolean;\n /** Highest sequence the server holds, even if this batch was capped. */\n latestSeq?: number;\n}\n\n/** Options for a channel handle. */\nexport interface ChannelOptions {\n /**\n * Ask the server to replay what this client missed, on join and on every\n * reconnect.\n *\n * Only meaningful for a channel the *server* has a retention rule for —\n * retention is configured on the backend, since a channel is created by\n * whoever names it and a client-chosen history depth would let any visitor\n * commit the backend to unbounded storage. On a channel with no rule the\n * server answers `retained: false` and this is inert.\n */\n history?: boolean;\n}\n\n/** The socket operations a channel needs; satisfied by RebaseWebSocketClient. */\nexport interface ChannelTransport {\n sendMessage(message: Record<string, unknown>): Promise<unknown>;\n onChannelMessage(channel: string, handler: (message: Record<string, unknown>) => void): () => void;\n onReconnect(handler: () => void): () => void;\n}\n\n/**\n * Re-send presence comfortably inside the server's 30s expiry.\n *\n * Two-thirds of the window: one lost heartbeat still leaves time for the next\n * before the entry is reaped, so a single dropped frame is not a disappearance.\n */\nconst PRESENCE_HEARTBEAT_MS = 20_000;\n\n/**\n * How long live messages are held back waiting for a catch-up response.\n *\n * Short, because the cost of waiting is visible — on a collaborative document\n * this is a stall in everyone else's edits appearing. Long enough that a slow\n * replay of a busy channel is not abandoned needlessly.\n */\nconst CATCH_UP_TIMEOUT_MS = 10_000;\n\nexport class RebaseRealtimeChannel {\n private presenceHandlers = new Set<(state: PresenceState, diff?: PresenceDiff) => void>();\n private broadcastHandlers = new Set<(event: BroadcastEvent) => void>();\n private unsubscribers: (() => void)[] = [];\n\n /** Last known roster, kept so handlers always get a full picture. */\n private presences: PresenceState = {};\n /** What this client last tracked, replayed on reconnect and heartbeat. */\n private trackedState: Record<string, unknown> | null = null;\n private heartbeat: ReturnType<typeof setInterval> | null = null;\n private joined = false;\n\n /** Whether this handle asks the server to replay missed messages. */\n private wantsHistory: boolean;\n\n /**\n * Highest sequence number delivered to handlers so far.\n *\n * This is the resume point sent as `sinceSeq`, and the watermark that makes\n * replay idempotent: catch-up ranges overlap with what arrived live, and\n * anything at or below this has already been seen.\n */\n private lastSeq = 0;\n\n /**\n * Live messages that arrived while a catch-up was in flight.\n *\n * Without this they would be delivered ahead of the older messages being\n * fetched, and — worse — would advance {@link lastSeq} past them, so the\n * catch-up response would then be discarded as already-seen and those\n * messages would be lost for good. Held here and flushed, in order, once\n * the replay lands.\n */\n private pendingLive: BroadcastEvent[] = [];\n private catchUpInFlight = false;\n\n /**\n * Deadline for a catch-up response.\n *\n * Buffering live messages is only safe because the wait is bounded. A\n * catch-up frame that never arrives — a server that dropped it, a socket\n * that died between request and reply — would otherwise leave the channel\n * silently holding every subsequent edit forever, which is a worse failure\n * than the one replay was added to fix.\n */\n private catchUpTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Callers of {@link history} awaiting the next `channel_history` frame.\n *\n * These frames are addressed by channel rather than by request id, so they\n * are matched in arrival order. Requests on one channel are serialized by\n * the socket, so FIFO is the right correlation here.\n */\n private historyWaiters: Array<(result: ChannelHistoryResult) => void> = [];\n\n constructor(\n public readonly name: string,\n private transport: ChannelTransport,\n options: ChannelOptions = {}\n ) {\n this.wantsHistory = options.history ?? false;\n }\n\n /**\n * Turn on catch-up for a handle that was created without it.\n *\n * The client hands back the same channel object for a given name, so a\n * later `channel(name, { history: true })` has no new object to configure —\n * it upgrades this one instead. Idempotent, and never downgrades: one\n * caller asking for history must not be switched off by another that did\n * not ask.\n */\n enableHistory(): void {\n if (this.wantsHistory) return;\n this.wantsHistory = true;\n if (this.joined) void this.requestHistory();\n }\n\n /**\n * Join the channel and ask for the current roster.\n *\n * Called automatically by `track`, `broadcast`, `onPresence` and\n * `onBroadcast`; calling it directly is only needed to start receiving\n * before there is anything to send.\n */\n /**\n * Send a channel message.\n *\n * Every channel message is read by the server out of a `payload` envelope\n * (`payload?.channel`, `payload?.state`, `payload?.event`). Sending those\n * fields flat does not error: `payload?.channel` simply reads as\n * `undefined`, so the client is registered into channel `undefined` with\n * empty state, and the echo comes back with no `channel` for\n * `onChannelMessage` to match — presence and broadcast both go quiet with\n * nothing logged. Funnelled through one place so a new message type cannot\n * reintroduce that.\n */\n private send(type: string, fields: Record<string, unknown> = {}): Promise<unknown> {\n return this.transport.sendMessage({ type, payload: { channel: this.name, ...fields } });\n }\n\n async join(): Promise<void> {\n if (this.joined) return;\n this.joined = true;\n\n this.unsubscribers.push(\n this.transport.onChannelMessage(this.name, (message) => this.handle(message))\n );\n\n // A reconnect drops server-side channel membership and presence, so\n // both have to be re-established. Nothing else notices this: the\n // socket comes back, and the client just stops receiving.\n this.unsubscribers.push(\n this.transport.onReconnect(() => {\n void this.rejoin();\n })\n );\n\n await this.send(\"join_channel\");\n // Not optional. Joining does not push the roster — without this the\n // channel believes it is alone until somebody else happens to move.\n await this.send(\"presence_state\");\n if (this.wantsHistory) await this.requestHistory();\n }\n\n private async rejoin(): Promise<void> {\n try {\n await this.send(\"join_channel\");\n await this.send(\"presence_state\");\n if (this.trackedState) {\n await this.send(\"presence_track\", { state: this.trackedState });\n }\n // The reason this class tracks a sequence number at all: whatever\n // was broadcast while the socket was down was delivered to everyone\n // else and never to us. Asking from `lastSeq` is the difference\n // between resuming and resyncing the whole document.\n if (this.wantsHistory) await this.requestHistory();\n } catch {\n // The socket is down again; the next reconnect will retry.\n }\n }\n\n /**\n * Ask the server for everything after {@link lastSeq}.\n *\n * Live messages are buffered from here until the answer arrives — see\n * {@link pendingLive}.\n */\n private async requestHistory(limit?: number): Promise<void> {\n this.catchUpInFlight = true;\n\n if (this.catchUpTimeout) clearTimeout(this.catchUpTimeout);\n this.catchUpTimeout = setTimeout(() => this.abandonCatchUp(), CATCH_UP_TIMEOUT_MS);\n (this.catchUpTimeout as unknown as { unref?: () => void }).unref?.();\n\n try {\n await this.send(\"channel_history\", {\n sinceSeq: this.lastSeq,\n ...(limit !== undefined ? { limit } : {})\n });\n } catch {\n // The frame never went out, so nothing will answer it.\n this.abandonCatchUp();\n }\n }\n\n /**\n * Give up waiting for a catch-up and release what was held back.\n *\n * The buffered messages are still the freshest thing this client has, so\n * they are delivered rather than dropped. Callers of {@link history} are\n * answered with `retained: false` — accurate in the sense that matters:\n * this client has no history to work from and has to resync.\n */\n private abandonCatchUp(): void {\n if (this.catchUpTimeout) {\n clearTimeout(this.catchUpTimeout);\n this.catchUpTimeout = null;\n }\n if (!this.catchUpInFlight) return;\n this.catchUpInFlight = false;\n for (const resolve of this.historyWaiters.splice(0)) {\n resolve({ messages: [], retained: false });\n }\n this.flushPendingLive();\n }\n\n /**\n * Publish this client's presence state, and keep publishing it.\n *\n * Calling `track` again replaces the state (and restarts the heartbeat),\n * which is how you update e.g. a cursor position.\n */\n async track(state: Record<string, unknown>): Promise<void> {\n await this.join();\n this.trackedState = state;\n\n await this.send(\"presence_track\", { state });\n\n if (!this.heartbeat) {\n this.heartbeat = setInterval(() => {\n if (!this.trackedState) return;\n void this.send(\"presence_track\", { state: this.trackedState })\n .catch(() => { /* a dropped beat is recoverable; the next one carries the same state */ });\n }, PRESENCE_HEARTBEAT_MS);\n // Do not hold a Node process open just to say \"still here\".\n (this.heartbeat as unknown as { unref?: () => void }).unref?.();\n }\n }\n\n /** Stop publishing presence, without leaving the channel. */\n async untrack(): Promise<void> {\n this.stopHeartbeat();\n this.trackedState = null;\n if (this.joined) {\n await this.send(\"presence_untrack\");\n }\n }\n\n /**\n * Observe the roster. The handler fires immediately with what is already\n * known, then on every change.\n */\n onPresence(handler: (state: PresenceState, diff?: PresenceDiff) => void): () => void {\n this.presenceHandlers.add(handler);\n void this.join();\n if (Object.keys(this.presences).length > 0) handler({ ...this.presences });\n return () => this.presenceHandlers.delete(handler);\n }\n\n /** Send a broadcast. The sender does not receive its own message. */\n async broadcast(event: string, payload: unknown): Promise<void> {\n await this.join();\n await this.send(\"broadcast\", { event, payload });\n }\n\n /** Observe broadcasts. Pass an event name to filter. */\n onBroadcast(handler: (event: BroadcastEvent) => void): () => void;\n onBroadcast(event: string, handler: (payload: unknown) => void): () => void;\n onBroadcast(\n eventOrHandler: string | ((event: BroadcastEvent) => void),\n maybeHandler?: (payload: unknown) => void\n ): () => void {\n const wrapped: (event: BroadcastEvent) => void = typeof eventOrHandler === \"string\"\n ? (e) => { if (e.event === eventOrHandler) maybeHandler!(e.payload); }\n : eventOrHandler;\n\n this.broadcastHandlers.add(wrapped);\n void this.join();\n return () => this.broadcastHandlers.delete(wrapped);\n }\n\n /**\n * The last sequence number this channel has delivered.\n *\n * Zero on a channel that retains nothing. Persist it if you want catch-up\n * to survive a page reload as well as a reconnect, and pass it back via\n * {@link history}.\n */\n get sequence(): number {\n return this.lastSeq;\n }\n\n /**\n * Fetch retained messages explicitly, instead of waiting for join or\n * reconnect to do it.\n *\n * Defaults to resuming from {@link sequence}. Messages are delivered to\n * `onBroadcast` handlers as usual — the returned value is for callers that\n * want to inspect the batch, or to learn from `retained` that the channel\n * keeps no history at all.\n */\n async history(options: { sinceSeq?: number; limit?: number } = {}): Promise<ChannelHistoryResult> {\n await this.join();\n if (options.sinceSeq !== undefined) this.lastSeq = options.sinceSeq;\n\n const result = new Promise<ChannelHistoryResult>((resolve) => {\n this.historyWaiters.push(resolve);\n });\n await this.requestHistory(options.limit);\n return result;\n }\n\n /** Leave the channel and release every listener and timer. */\n async leave(): Promise<void> {\n this.stopHeartbeat();\n this.trackedState = null;\n this.presences = {};\n this.presenceHandlers.clear();\n this.broadcastHandlers.clear();\n // A rejoin is a fresh start: replaying from a watermark left over from\n // the previous membership would silently skip everything before it.\n this.lastSeq = 0;\n this.pendingLive = [];\n this.catchUpInFlight = false;\n if (this.catchUpTimeout) {\n clearTimeout(this.catchUpTimeout);\n this.catchUpTimeout = null;\n }\n for (const resolve of this.historyWaiters.splice(0)) {\n resolve({ messages: [], retained: false });\n }\n\n for (const off of this.unsubscribers) off();\n this.unsubscribers = [];\n\n if (this.joined) {\n this.joined = false;\n await this.send(\"leave_channel\");\n }\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeat) {\n clearInterval(this.heartbeat);\n this.heartbeat = null;\n }\n }\n\n /** Fold an incoming frame into the roster and fan it out. */\n private handle(message: Record<string, unknown>): void {\n switch (message.type) {\n case \"presence_state\": {\n this.presences = (message.presences as PresenceState) ?? {};\n this.emitPresence();\n break;\n }\n case \"presence_diff\": {\n const joins = (message.joins as PresenceState) ?? {};\n const leaves = (message.leaves as PresenceState) ?? {};\n // A diff carries only what moved, so the roster is maintained\n // here rather than handed to callers to reassemble.\n for (const [id, state] of Object.entries(joins)) this.presences[id] = state;\n for (const id of Object.keys(leaves)) delete this.presences[id];\n this.emitPresence({ joins, leaves });\n break;\n }\n case \"broadcast\": {\n const seq = typeof message.seq === \"number\" ? message.seq : undefined;\n const event: BroadcastEvent = {\n event: message.event as string,\n payload: message.payload,\n ...(seq !== undefined ? { seq } : {})\n };\n\n // Unsequenced channels keep the original behaviour exactly:\n // straight through, no buffering, no watermark.\n if (seq === undefined) {\n this.deliver(event);\n break;\n }\n\n if (this.catchUpInFlight) {\n this.pendingLive.push(event);\n break;\n }\n if (seq <= this.lastSeq) break; // already delivered\n this.lastSeq = seq;\n this.deliver(event);\n break;\n }\n case \"channel_history\": {\n this.catchUpInFlight = false;\n if (this.catchUpTimeout) {\n clearTimeout(this.catchUpTimeout);\n this.catchUpTimeout = null;\n }\n\n const entries = (message.messages as ChannelHistoryEntry[] | undefined) ?? [];\n const retained = message.retained === true;\n const latestSeq = typeof message.latestSeq === \"number\" ? message.latestSeq : undefined;\n\n for (const resolve of this.historyWaiters.splice(0)) {\n resolve({ messages: entries, retained, latestSeq });\n }\n\n // Server-ordered ascending; the watermark check makes the\n // overlap with anything already seen a no-op rather than a\n // double-apply.\n for (const entry of entries) {\n if (entry.seq <= this.lastSeq) continue;\n this.lastSeq = entry.seq;\n this.deliver({\n event: entry.event,\n payload: entry.payload,\n seq: entry.seq,\n replayed: true\n });\n }\n\n this.flushPendingLive();\n break;\n }\n }\n }\n\n /** Deliver everything held back during a catch-up, in sequence order. */\n private flushPendingLive(): void {\n if (this.pendingLive.length === 0) return;\n const buffered = this.pendingLive.sort((a, b) => (a.seq ?? 0) - (b.seq ?? 0));\n this.pendingLive = [];\n for (const event of buffered) {\n const seq = event.seq;\n if (seq !== undefined) {\n if (seq <= this.lastSeq) continue;\n this.lastSeq = seq;\n }\n this.deliver(event);\n }\n }\n\n private deliver(event: BroadcastEvent): void {\n for (const handler of [...this.broadcastHandlers]) handler(event);\n }\n\n private emitPresence(diff?: PresenceDiff): void {\n const snapshot = { ...this.presences };\n for (const handler of this.presenceHandlers) handler(snapshot, diff);\n }\n}\n","import { createTransport, RebaseClientConfig } from \"./transport\";\nimport { RebaseClientError } from \"./errors\";\nimport { createAuth, CreateAuthOptions } from \"./auth\";\nimport { createAdmin, CreateAdminOptions } from \"./admin\";\nimport { createCron, CreateCronOptions } from \"./cron\";\nimport { createBackups } from \"./backups\";\nimport { createApiKeys, CreateApiKeysOptions } from \"./api-keys\";\nimport { CollectionClient, createCollectionClient } from \"./collection\";\nimport { createFunctionsClient } from \"./functions\";\nimport { createStorage } from \"./storage\";\nimport { ClientStorageSourceRegistry } from \"./storage-registry\";\nimport { RebaseWebSocketClient } from \"./websocket\";\nimport { RebaseRealtimeChannel, type ChannelOptions } from \"./realtime-channel\";\nimport {\n DEFAULT_STORAGE_SOURCE_KEY,\n InsertOf,\n RebaseClient,\n RebaseSdkData,\n RowOf,\n StorageSource,\n StorageSourceDefinition,\n StorageSourceRegistry,\n UpdateOf\n} from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\n\n// ─── Public API surface ──────────────────────────────────────────────────────\n//\n// This barrel is the public API of `@rebasepro/client`. It is an explicit,\n// curated list — NOT `export *` — so that adding an export to a module below\n// does not silently republish it to app developers. Internal factories\n// (`createTransport`, `createAuth`, `createCollectionClient`, …), the raw\n// `Transport`, the storage-source registry impl, the JSON reviver, and the\n// concrete `SDKQueryBuilder` class are intentionally NOT re-exported: they are\n// implementation details of `createRebaseClient()` and have no external\n// consumers. App developers reach them through the client instance, never by\n// importing the factory. To add something to the public surface, add it here\n// deliberately.\n\n// Errors — the single error type thrown by SDK HTTP calls, plus the\n// data-proxy's unknown-collection error.\nexport { RebaseApiError } from \"./transport\";\nexport { RebaseClientError } from \"./errors\";\n\n// Query + collection types (annotate SDK results; construct via the fluent API).\nexport type { RebaseClientConfig, FindParams, FindResponse } from \"./transport\";\nexport type { CollectionClient } from \"./collection\";\nexport type { FindResult, SDKCollectionClient, SDKQueryBuilderInterface, PaginationMeta } from \"@rebasepro/types\";\n\n// Logical-condition helpers for `.where(or(...), and(...))`.\nexport { QueryBuilder, or, and, cond } from \"@rebasepro/common\";\n\n// Auth: session/token types, config, and the pluggable storage strategies.\nexport { createCookieStorage, createMemoryStorage } from \"./auth\";\nexport type { AuthConfig, AuthStorage, CookieStorageOptions, CreateAuthOptions } from \"./auth\";\nexport type { RebaseSession, AuthTokens, AuthChangeEvent, DeviceSession } from \"@rebasepro/types\";\n/** @deprecated Import `User` / `AuthTokens` from `@rebasepro/types` instead. */\nexport type { RebaseUser, RebaseTokens } from \"./auth\";\n\n// Control-plane client option/DTO types (the client instance exposes the impls).\nexport type { CreateAdminOptions } from \"./admin\";\nexport type { AdminUser } from \"./admin\";\nexport type { CreateCronOptions } from \"./cron\";\nexport { createBackups } from \"./backups\";\nexport type { CreateBackupsOptions } from \"./backups\";\nexport type {\n ApiKeyMasked,\n ApiKeyPermission,\n ApiKeyWithSecret,\n CreateApiKeyRequest,\n CreateApiKeysOptions,\n UpdateApiKeyRequest\n} from \"./api-keys\";\nexport type { FunctionInvokeOptions, FunctionsClient } from \"./functions\";\n\n// Realtime: the WebSocket client class is internal to `createRebaseClient()`,\n// but re-exported (see @internal on the class) because the `client-postgres`\n// driver constructs it directly. Not a stable app-facing API.\nexport { RebaseWebSocketClient } from \"./websocket\";\nexport { RebaseRealtimeChannel } from \"./realtime-channel\";\nexport type {\n PresenceState,\n PresenceDiff,\n BroadcastEvent,\n ChannelTransport,\n ChannelOptions,\n ChannelHistoryEntry,\n ChannelHistoryResult\n} from \"./realtime-channel\";\n\nexport interface CreateRebaseClientOptions extends RebaseClientConfig {\n auth?: CreateAuthOptions;\n admin?: CreateAdminOptions;\n cron?: CreateCronOptions;\n apiKeys?: CreateApiKeysOptions;\n /**\n * Declared storage sources for multi-backend support. Server-transport\n * entries are auto-wired into `client.storageRegistry`; `direct` sources\n * are registered app-side (e.g. via a Firebase Storage hook). The default\n * source (`storage`) is always registered under\n * {@link DEFAULT_STORAGE_SOURCE_KEY}.\n */\n storageSources?: StorageSourceDefinition[];\n /**\n * Maps camelCase property names / safe identifiers to the actual\n * collection slugs on the server (e.g. `{ companyMembers: \"company-members\" }`).\n * If provided, the data layer proxy will resolve property accessors to their\n * correct slugs via this map before falling back to automatic snake_casing.\n */\n collections?: Record<string, string>;\n}\n\n// ─── Typed Data Proxy ────────────────────────────────────────────────────────\n// Adds typed collection accessors when `DB` is provided via the SDK generator.\n\ntype KebabToCamelCase<S extends string> =\n S extends `${infer T}-${infer U}`\n ? `${T}${Capitalize<KebabToCamelCase<U>>}`\n : S;\n\n// Resolve a generated `Database` entry from a (kebab-case) slug literal,\n// or `unknown` when the slug isn't in the schema — the extractors below\n// then fall back to the open row / partial shapes.\ntype DBEntry<DB, S extends string> =\n KebabToCamelCase<S> extends keyof DB ? DB[KebabToCamelCase<S>] : unknown;\n\ntype TypedDataLayer<DB> = {\n collection<S extends string>(slug: S): CollectionClient<\n RowOf<DBEntry<DB, S>>,\n InsertOf<DBEntry<DB, S>>,\n UpdateOf<DBEntry<DB, S>>\n >;\n} & {\n [K in keyof DB]: CollectionClient<RowOf<DB[K]>, InsertOf<DB[K]>, UpdateOf<DB[K]>>;\n} & RebaseSdkData;\n\n/**\n * The return type of `createRebaseClient<DB>()`.\n *\n * This is `RebaseClient` (from `@rebasepro/types`) with all optional\n * capabilities populated and the `data` layer narrowed to provide\n * typed collection accessors when a `DB` schema generic is supplied.\n */\nexport type CreateRebaseClientResult<DB = Record<string, unknown>> = Omit<RebaseClient<DB>, \"data\" | \"email\"> & {\n setToken: (token: string | null) => void;\n setAuthTokenGetter: (getter: () => Promise<string | null>) => void;\n setOnUnauthorized: (handler: () => Promise<boolean>) => void;\n resolveToken: () => Promise<string | null>;\n auth: ReturnType<typeof createAuth>;\n admin: ReturnType<typeof createAdmin>;\n cron: ReturnType<typeof createCron>;\n backups: ReturnType<typeof createBackups>;\n apiKeys: ReturnType<typeof createApiKeys>;\n functions: ReturnType<typeof createFunctionsClient>;\n ws?: RebaseWebSocketClient;\n /**\n * Broadcast and presence channels.\n *\n * Was missing from this type while present on the returned object, which\n * made `client.realtime.channel(...)` a type error and forced every adopter\n * to cast around the feature before they could reach it.\n */\n realtime: {\n /**\n * Join a broadcast/presence channel. Repeated calls with the same name\n * return the same channel object. Throws only when the client was\n * created with `realtime: false`.\n *\n * Pass `{ history: true }` to have the channel replay what it missed on\n * join and on every reconnect, for channels the server retains.\n */\n channel: (name: string, options?: ChannelOptions) => RebaseRealtimeChannel;\n };\n /**\n * Release the realtime socket and its reconnect timer.\n *\n * An open socket keeps the Node event loop alive, so a script that does not\n * call this will not exit on its own. Safe when realtime was never started\n * (`realtime: false`), and safe to call twice.\n */\n close: () => void;\n storage: StorageSource;\n storageRegistry: StorageSourceRegistry;\n createStorageSource: (storageId: string) => StorageSource;\n fetchStorageSources: () => Promise<StorageSourceDefinition[]>;\n call: <T = unknown>(endpoint: string, payload?: unknown) => Promise<T>;\n collection: <M extends Record<string, unknown> = Record<string, unknown>>(slug: string) => CollectionClient<M>;\n data: TypedDataLayer<DB>;\n};\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\n/**\n * Derive a WebSocket URL from an HTTP base URL.\n * `http://` → `ws://`, `https://` → `wss://`.\n */\nfunction deriveWebSocketUrl(baseUrl?: string): string {\n if (typeof window !== \"undefined\") {\n let absoluteUrl = \"\";\n if (!baseUrl) {\n absoluteUrl = window.location.origin;\n } else if (/^https?:\\/\\//i.test(baseUrl) || /^wss?:\\/\\//i.test(baseUrl)) {\n absoluteUrl = baseUrl;\n } else {\n try {\n absoluteUrl = new URL(baseUrl, window.location.href).origin;\n } catch {\n absoluteUrl = window.location.origin;\n }\n }\n const protocol = absoluteUrl.startsWith(\"https:\") || absoluteUrl.startsWith(\"wss:\") ? \"wss:\" : \"ws:\";\n return absoluteUrl\n .replace(/^https?:\\/\\//i, `${protocol}//`)\n .replace(/^wss?:\\/\\//i, `${protocol}//`)\n .replace(/\\/$/, \"\");\n }\n\n if (!baseUrl) return \"\";\n if (!/^https?:\\/\\//i.test(baseUrl) && !/^wss?:\\/\\//i.test(baseUrl)) {\n return \"\";\n }\n return baseUrl\n .replace(/^https?:\\/\\//i, (match) => match.toLowerCase() === \"https://\" ? \"wss://\" : \"ws://\")\n .replace(/\\/$/, \"\");\n}\n\nexport function createRebaseClient<DB = Record<string, unknown>>(options: CreateRebaseClientOptions): CreateRebaseClientResult<DB> {\n const transport = createTransport(options);\n const auth = createAuth(transport, options.auth);\n const admin = createAdmin(transport, options.admin);\n const cron = createCron(transport, options.cron);\n const backups = createBackups(transport);\n const apiKeys = createApiKeys(transport, options.apiKeys);\n const storage = createStorage(transport);\n const functions = createFunctionsClient(transport);\n\n // Build a server-backed StorageSource for a given storage-source key.\n const createStorageSource = (storageId: string): StorageSource =>\n storageId === DEFAULT_STORAGE_SOURCE_KEY ? storage : createStorage(transport, storageId);\n\n // Storage registry: always holds the default source, plus any declared\n // server-transport sources. `direct` sources are registered app-side.\n const storageRegistry = new ClientStorageSourceRegistry();\n storageRegistry.register(DEFAULT_STORAGE_SOURCE_KEY, storage);\n for (const def of options.storageSources ?? []) {\n if (def.transport === \"server\" && def.key !== DEFAULT_STORAGE_SOURCE_KEY) {\n storageRegistry.register(def.key, createStorageSource(def.key));\n }\n }\n\n // Discover storage sources from the backend, making the server the single\n // source of truth. Server-transport sources are auto-wired into the\n // registry; `direct` sources are returned for the app to register. The\n // promise is cached on success and reset on failure so it can be retried\n // (e.g. once the user authenticates).\n let storageSourcesPromise: Promise<StorageSourceDefinition[]> | undefined;\n const fetchStorageSources = (): Promise<StorageSourceDefinition[]> => {\n if (storageSourcesPromise) return storageSourcesPromise;\n storageSourcesPromise = transport\n .request<{ data: StorageSourceDefinition[] }>(\"/storage/sources\")\n .then((res) => {\n const defs = res.data ?? [];\n for (const def of defs) {\n if (def.transport === \"server\"\n && def.key !== DEFAULT_STORAGE_SOURCE_KEY\n && !storageRegistry.has(def.key)) {\n storageRegistry.register(def.key, createStorageSource(def.key));\n }\n }\n return defs;\n })\n .catch((e) => {\n storageSourcesPromise = undefined; // allow retry\n throw e;\n });\n return storageSourcesPromise;\n };\n\n // Opting out has to happen before the URL is derived: `deriveWebSocketUrl`\n // always produces one, so a truthy check alone can never leave the socket\n // closed.\n const realtimeEnabled = options.realtime !== false;\n const resolvedWsUrl = realtimeEnabled\n ? (options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl))\n : undefined;\n\n let ws: RebaseWebSocketClient | undefined;\n /** One channel object per name — see `realtime.channel`. */\n const realtimeChannels = new Map<string, RebaseRealtimeChannel>();\n if (resolvedWsUrl) {\n const wsOnUnauthorized = options.onUnauthorized || (async () => {\n try {\n await auth.refreshSession();\n return true;\n } catch (e) {\n return false;\n }\n });\n\n ws = new RebaseWebSocketClient({\n websocketUrl: resolvedWsUrl,\n getAuthToken: async () => {\n let session = auth.getSession();\n if (session && session.expiresAt <= Date.now() + 10000) {\n try {\n session = await auth.refreshSession();\n } catch (e) { /* ignore */ }\n }\n return session?.accessToken || options.token || \"\";\n },\n onUnauthorized: wsOnUnauthorized\n });\n\n auth.onAuthStateChange((event, session) => {\n if (!ws) return;\n if (event === \"SIGNED_OUT\") {\n // Not permanent: the client stays usable, and a later subscribe\n // should reconnect anonymously.\n ws.disconnect();\n } else if (event === \"SIGNED_IN\" || event === \"TOKEN_REFRESHED\") {\n // Only re-authenticate a socket that already exists. Signing in\n // is not a request for realtime, and dialling here would undo\n // lazy connect for every app with a login. A socket opened\n // later authenticates itself from `getAuthToken` on open.\n if (session?.accessToken && ws.hasSocket) {\n ws.authenticate(session.accessToken).catch(console.warn);\n }\n }\n });\n }\n\n // Register transport callback for 401s after auth is instantiated.\n // IMPORTANT: We must use transport.setOnUnauthorized() here — NOT set\n // options.onUnauthorized — because the transport was already created above\n // and captured the (undefined) value from the config closure.\n if (!options.onUnauthorized) {\n transport.setOnUnauthorized(async () => {\n try {\n await auth.refreshSession();\n return true;\n } catch (e) {\n return false;\n }\n });\n }\n\n /**\n * Suggest the closest known collection key for a mistyped accessor.\n * Uses edit-distance-1 and prefix matching — no external dependency.\n */\n function suggestCollection(prop: string, knownKeys: string[]): string | undefined {\n // Prefix match (e.g. \"prod\" → \"products\")\n const prefixMatch = knownKeys.find(k => k.startsWith(prop) || prop.startsWith(k));\n if (prefixMatch) return prefixMatch;\n\n // Edit-distance-1: deletions, insertions, substitutions, transpositions\n for (const key of knownKeys) {\n if (Math.abs(key.length - prop.length) > 1) continue;\n let diffs = 0;\n const longer = key.length >= prop.length ? key : prop;\n const shorter = key.length >= prop.length ? prop : key;\n if (longer.length === shorter.length) {\n // Same length: allow 1 substitution or 1 transposition\n for (let i = 0; i < longer.length; i++) {\n if (longer[i] !== shorter[i]) {\n // Check for transposition\n if (\n i + 1 < longer.length &&\n longer[i] === shorter[i + 1] &&\n longer[i + 1] === shorter[i]\n ) {\n diffs++;\n i++; // skip next char (already accounted for)\n if (diffs > 1) break;\n continue;\n }\n diffs++;\n }\n if (diffs > 1) break;\n }\n } else {\n // Length differs by 1: allow 1 insertion/deletion\n let li = 0;\n let si = 0;\n while (li < longer.length) {\n if (si < shorter.length && longer[li] === shorter[si]) {\n si++;\n } else {\n diffs++;\n }\n li++;\n if (diffs > 1) break;\n }\n }\n if (diffs <= 1) return key;\n }\n\n return undefined;\n }\n\n const collectionClients = new Map<string, CollectionClient<Record<string, unknown>>>();\n let untypedWarned = false;\n\n function collection(slug: string): CollectionClient<Record<string, unknown>> {\n if (!collectionClients.has(slug)) {\n collectionClients.set(slug, createCollectionClient(transport, slug, ws));\n }\n return collectionClients.get(slug)!;\n }\n\n const dataTarget = { collection } as Record<string, unknown>;\n\n const dataProxy = new Proxy(dataTarget, {\n get(_target, prop: string | symbol) {\n if (prop === \"collection\") {\n return collection;\n }\n if (typeof prop === \"symbol\") return undefined;\n if (typeof prop === \"string\" && prop !== \"then\" && prop !== \"toJSON\" && prop !== \"$$typeof\") {\n if (options.collections) {\n if (prop in options.collections) {\n return collection(options.collections[prop]);\n }\n // Strict mode: the developer supplied a typed dictionary,\n // so we know the full set of valid accessors.\n const knownKeys = Object.keys(options.collections);\n const suggestion = suggestCollection(prop, knownKeys);\n const knownList = knownKeys.join(\", \");\n let msg = `Unknown collection accessor \"${prop}\". Known collections: ${knownList}.`;\n if (suggestion) msg += ` Did you mean \"${suggestion}\"?`;\n msg += ` Use data.collection(\"<slug>\") for dynamic slugs.`;\n throw new RebaseClientError(msg);\n }\n // Untyped fallback: convert camelCase property names to snake_case slugs.\n // e.g. `companyMembers` → `company_members`\n if (!untypedWarned) {\n untypedWarned = true;\n console.warn(\n `[Rebase] Untyped data access detected (client.data.${prop}). ` +\n `Collection names are resolved via snake_case conversion, which may cause silent 404s at request time. ` +\n `Pass a \\`collections\\` dictionary to createRebaseClient() or use the generated SDK for type-safe access.`\n );\n }\n const slug = toSnakeCase(prop);\n return collection(slug);\n }\n return undefined;\n }\n });\n\n const target = {\n auth,\n admin,\n cron,\n backups,\n apiKeys,\n functions,\n storage,\n storageRegistry,\n createStorageSource,\n fetchStorageSources,\n ws,\n realtime: {\n /**\n * Join a broadcast/presence channel.\n *\n * Repeated calls with the same name return the same channel, so\n * separate components can attach handlers without each opening its\n * own membership — and `leave()` from one would otherwise silently\n * cut off the others.\n */\n channel: (name: string, options?: ChannelOptions): RebaseRealtimeChannel => {\n // Only `realtime: false` gets here — a hard opt-out, so this\n // stays an error. Being merely *unconnected* does not: the\n // socket opens on the first channel operation, which is the\n // whole point of asking for a channel before you use one.\n if (!ws) {\n throw new RebaseClientError(\n \"Realtime is disabled on this client (realtime: false), so channels are unavailable.\"\n );\n }\n let existing = realtimeChannels.get(name);\n if (!existing) {\n existing = new RebaseRealtimeChannel(name, ws, options);\n realtimeChannels.set(name, existing);\n } else if (options?.history) {\n // Same object by name, so options on a later call have no\n // new channel to apply to. Asking for history upgrades the\n // one that exists rather than being quietly ignored — but\n // never the reverse, so a caller that omits the option\n // cannot switch it off under one that asked for it.\n existing.enableHistory();\n }\n return existing;\n }\n },\n /**\n * Release the realtime socket and its reconnect timer.\n *\n * Until this returns, the open socket keeps the Node event loop alive\n * and the process will not exit on its own. Safe to call when realtime\n * was never started, and safe to call twice.\n */\n close: () => {\n // Channels hold presence heartbeat timers, which would otherwise\n // keep firing (and keep a Node process alive) after the socket\n // they publish over is gone.\n for (const channel of realtimeChannels.values()) void channel.leave();\n realtimeChannels.clear();\n // Permanent: nothing queued afterwards may redial and keep the\n // event loop alive, which is the reason this method exists.\n ws?.disconnect(true);\n },\n setToken: transport.setToken,\n setAuthTokenGetter: transport.setAuthTokenGetter,\n setOnUnauthorized: transport.setOnUnauthorized,\n resolveToken: transport.resolveToken,\n baseUrl: transport.baseUrl,\n collection,\n call: async <T = unknown>(endpoint: string, payload?: unknown): Promise<T> => {\n const prefix = endpoint.startsWith(\"/\") ? \"\" : \"/\";\n const res = await transport.request<{ data: T }>(`${prefix}${endpoint}`, {\n method: \"POST\",\n body: payload ? JSON.stringify(payload) : undefined\n });\n return res.data ?? (res as T);\n },\n data: dataProxy,\n } as unknown as CreateRebaseClientResult<DB>;\n\n return target;\n}\n\n"],"mappings":"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"}