@basictech/react 0.9.0-beta.1 → 0.11.0-beta.2
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.
- package/LICENSE +21 -0
- package/README.md +1111 -0
- package/dist/index.d.mts +233 -1357
- package/dist/index.d.ts +233 -1357
- package/dist/index.js +1013 -4767
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +994 -4728
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -20
- package/changelog.md +0 -442
- package/readme.md +0 -467
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/context.ts","../src/config.ts","../package.json","../src/utils/network.ts","../src/react/hooks.ts","../src/dev/BasicDevToolbar.tsx","../src/react/BasicProvider.tsx","../src/core/auth/AuthManager.ts","../src/utils/storage.ts","../src/utils/normalizeClientId.ts","../src/utils/resolveDid.ts","../src/core/http/RestClient.ts","../src/core/sync/SyncEngine.ts","../src/core/sync/protocol.ts","../src/core/sync/SyncConnection.ts","../src/core/sync/SyncStore.ts","../src/core/db.ts","../src/core/users.ts","../src/utils/schema.ts","../src/updater/versionUpdater.ts","../src/updater/updateMigrations.ts","../src/core/BasicClient.ts","../src/index.ts"],"sourcesContent":["import { createContext } from 'react'\nimport type { BasicClient } from '../core/BasicClient'\n\nexport const BasicClientContext = createContext<BasicClient | null>(null)\n","export const log = (...args: any[]) => {\n try { \n if (localStorage.getItem('basic_debug') === 'true') {\n console.log('[basic]', ...args)\n }\n } catch (e) {\n // silently fail if localStorage is unavailable (SSR)\n }\n}\n","{\n \"name\": \"@basictech/react\",\n \"version\": \"0.9.0-beta.1\",\n \"description\": \"\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": {\n \"types\": \"./dist/index.d.mts\",\n \"default\": \"./dist/index.mjs\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n }\n }\n },\n \"files\": [\n \"dist\",\n \"readme.md\",\n \"changelog.md\"\n ],\n \"sideEffects\": false,\n \"private\": false,\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"prepublishOnly\": \"npm run build\",\n \"test\": \"vitest run\"\n },\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"semver\": \"^7.7.2\",\n \"dexie\": \"^4.2.1\",\n \"dexie-react-hooks\": \"^4.2.0\",\n \"jwt-decode\": \"^4.0.0\",\n \"@basictech/schema\": \"^0.7.0\"\n },\n \"devDependencies\": {\n \"@repo/typescript-config\": \"*\",\n \"@types/react\": \"^19.0.0\",\n \"@types/ws\": \"^8.5.0\",\n \"fake-indexeddb\": \"^6.0.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.0.0\",\n \"vitest\": \"^3.0.0\",\n \"ws\": \"^8.18.0\"\n },\n \"peerDependencies\": {\n \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n }\n}\n","// Network utilities for Basic React package\nimport semver from 'semver'\nimport { log } from '../config'\nimport { version as pkgVersion } from '../../package.json'\n\nexport function isDevelopment(debug?: boolean): boolean {\n if (debug === true) return true\n if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') return true\n if (typeof window === 'undefined' || !window.location) return false\n const host = window.location.hostname\n return (\n host === 'localhost' ||\n host === '127.0.0.1' ||\n host.includes('localhost') ||\n host.includes('127.0.0.1') ||\n host.includes('.local')\n )\n}\n\nfunction normalizeVersion(v: string | null | undefined): string | null {\n if (v == null) return null\n const t = String(v).trim()\n return t.length ? t : null\n}\n\nfunction versionsMatch(a: string, b: string): boolean {\n const na = a.trim()\n const nb = b.trim()\n if (na === nb) return true\n const va = semver.valid(na)\n const vb = semver.valid(nb)\n if (va && vb) return semver.eq(va, vb)\n return false\n}\n\n/** Use npm `beta` dist-tag when the installed version is a semver prerelease whose first id is `beta`. */\nfunction usesBetaDistTag(version: string): boolean {\n const pre = semver.prerelease(version)\n const id = pre?.[0]\n return typeof id === 'string' && id.toLowerCase() === 'beta'\n}\n\ntype NpmInstallMeta = {\n 'dist-tags'?: { latest?: string; beta?: string }\n}\n\nexport async function checkForNewVersion(): Promise<{ \n hasNewVersion: boolean, \n latestVersion: string | null, \n currentVersion: string | null \n}> {\n try {\n const currentVersion = normalizeVersion(pkgVersion)\n if (!currentVersion) {\n return { hasNewVersion: false, latestVersion: null, currentVersion: null }\n }\n\n const response = await fetch('https://registry.npmjs.org/@basictech/react', {\n headers: { Accept: 'application/vnd.npm.install-v1+json' },\n })\n if (!response.ok) {\n throw new Error('Failed to fetch version from npm');\n }\n\n const data = (await response.json()) as NpmInstallMeta\n const distTags = data['dist-tags'] ?? {}\n const rawRegistry =\n usesBetaDistTag(currentVersion)\n ? distTags.beta ?? distTags.latest\n : distTags.latest\n const latestVersion = normalizeVersion(rawRegistry ?? null)\n if (!latestVersion) {\n throw new Error('Missing dist-tags from npm registry')\n }\n\n const same = versionsMatch(currentVersion, latestVersion)\n\n if (!same && isDevelopment()) {\n log('[basic] version check mismatch:', {\n currentVersion,\n registryVersion: latestVersion,\n channel: usesBetaDistTag(currentVersion) ? 'beta' : 'latest',\n })\n }\n\n if (!same) {\n console.warn('[basic] New version available:', latestVersion, `\\nrun \"npm install @basictech/react@${latestVersion}\" to update`);\n }\n if (usesBetaDistTag(currentVersion)) {\n log('thank you for being on basictech/react beta :)')\n }\n \n return {\n hasNewVersion: !same,\n latestVersion,\n currentVersion\n };\n } catch (error) {\n log('Error checking for new version:', error);\n return {\n hasNewVersion: false,\n latestVersion: null, \n currentVersion: null\n };\n }\n}\n\nexport function cleanOAuthParamsFromUrl(): void {\n if (window.location.search.includes('code') || window.location.search.includes('state')) {\n const url = new URL(window.location.href)\n url.searchParams.delete('code')\n url.searchParams.delete('state')\n window.history.replaceState({}, document.title, url.pathname + url.search)\n log('Cleaned OAuth parameters from URL')\n }\n}\n\nexport function getSyncStatus(statusCode: number): string {\n switch (statusCode) {\n case -1:\n return \"ERROR\";\n case 0:\n return \"OFFLINE\";\n case 1:\n return \"CONNECTING\";\n case 2:\n return \"ONLINE\";\n case 3:\n return \"SYNCING\";\n case 4:\n return \"ERROR_WILL_RETRY\";\n default:\n return \"UNKNOWN\";\n }\n}\n","import { useContext, useEffect, useMemo, useState, useSyncExternalStore } from 'react'\nimport { useLiveQuery } from 'dexie-react-hooks'\nimport { BasicClientContext } from './context'\nimport type { BasicClient, BasicClientSnapshot, ShareMountHandle } from '../core/BasicClient'\nimport type { BasicDb } from '../core/db'\nimport type { BasicUserProfile } from '../core/users'\nimport type { AuthResult, AuthStatus, GetTokenOptions, User } from '../core/auth/AuthManager'\nimport type { SyncStatus } from '../core/sync/SyncEngine'\nimport type { RejectedRow } from '../core/sync/SyncStore'\nimport type { Share } from '../core/sync/protocol'\n\nconst noopSubscribe = () => () => {}\n\n/**\n * Reactive live queries against the local database (sync mode), built on\n * dexie-react-hooks' `useLiveQuery`. Any read through `db.table(...)` (or\n * its `ref` Dexie table) is observable.\n *\n * ```tsx\n * const todos = useQuery(() => db.table('todos').getAll())\n * ```\n *\n * User-aware: the active user's id is appended to `deps` automatically, so\n * queries re-subscribe against the new user's database on `switchUser` /\n * sign-in / sign-out — provided the query reads `db` from the current render\n * (e.g. from `useBasic()`/`useDb()`). For closures created outside render,\n * pass `[db]` in deps explicitly.\n */\nexport function useQuery<T>(\n querier: () => T | Promise<T | undefined> | undefined,\n deps: unknown[] = [],\n): T | undefined {\n const client = useContext(BasicClientContext)\n // Subscribe only to the active-user identity (a stable primitive), so this\n // does not re-render on every client publish — only on user switches.\n const activeUserId = useSyncExternalStore(\n client ? client.subscribe : noopSubscribe,\n () => client?.getSnapshot().activeUser?.id ?? null,\n () => null,\n )\n return useLiveQuery(async () => {\n try {\n return await querier()\n } catch (err) {\n // switch window: an in-flight query can hit a store that was just\n // closed; the deps change re-runs it against the new store\n if (err instanceof Error && err.name === 'DatabaseClosedError') return undefined\n throw err\n }\n }, [...deps, activeUserId])\n}\n\n/** The BasicClient instance from the nearest provider. */\nexport function useBasicClient(): BasicClient {\n const client = useContext(BasicClientContext)\n if (!client) {\n throw new Error('useBasic must be used within a <BasicProvider>')\n }\n return client\n}\n\nfunction useClientSnapshot(client: BasicClient): BasicClientSnapshot {\n return useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n}\n\nexport interface UseAuthResult {\n /** Auth bootstrap finished (a session may or may not exist). */\n isReady: boolean\n isSignedIn: boolean\n /** Active user is a local-only (anonymous) workspace with no account. */\n isAnonymous: boolean\n status: AuthStatus\n errorCode: string | null\n user: User | null\n did: string | null\n /** Space-separated scopes granted in the current access token. */\n scope: string | null\n hasScope: (scope: string) => boolean\n missingScopes: () => string[]\n signIn: (redirectUri?: string) => Promise<void>\n signInWithHandle: (handle: string) => Promise<void>\n signInWithCode: (code: string, state?: string) => Promise<AuthResult>\n signOut: () => Promise<void>\n getToken: (options?: GetTokenOptions) => Promise<string>\n getSignInUrl: (redirectUri?: string) => Promise<string>\n}\n\n/** Auth state + actions. */\nexport function useAuth(): UseAuthResult {\n const client = useBasicClient()\n const snapshot = useClientSnapshot(client)\n\n return useMemo(\n () => ({\n isReady: snapshot.isReady,\n isSignedIn: snapshot.isSignedIn,\n isAnonymous: snapshot.isAnonymous,\n status: snapshot.authStatus,\n errorCode: snapshot.authErrorCode,\n user: snapshot.user,\n did: snapshot.did,\n scope: snapshot.scope,\n hasScope: (s: string) => client.auth.hasScope(s),\n missingScopes: () => client.auth.missingScopes(),\n signIn: (redirectUri?: string) => client.auth.signIn(redirectUri),\n signInWithHandle: (handle: string) => client.auth.signInWithHandle(handle),\n signInWithCode: (code: string, state?: string) => client.auth.signInWithCode(code, state),\n signOut: () => client.signOut(),\n getToken: (options?: GetTokenOptions) => client.auth.getToken(options),\n getSignInUrl: (redirectUri?: string) => client.auth.getSignInUrl(redirectUri),\n }),\n [client, snapshot],\n )\n}\n\n/** The database handle (own channel). Offline-first in sync mode. */\nexport function useDb(): BasicDb {\n const client = useBasicClient()\n return client.db\n}\n\nexport interface UseSyncStatusResult {\n /** Engine status: idle | connecting | online | offline | auth_required | revoked | stopped */\n status: SyncStatus\n /** True when the schema is valid + published and sync can run. */\n enabled: boolean\n /** Locally queued ops not yet confirmed by the server. */\n pendingCount: number\n /** Terminally rejected ops (poison-op rule — never re-pushed). */\n listRejected: () => Promise<RejectedRow[]>\n clearRejected: () => Promise<void>\n}\n\n/** Sync engine state: connection status, pending queue depth, rejected ops. */\nexport function useSyncStatus(): UseSyncStatusResult {\n const client = useBasicClient()\n const snapshot = useClientSnapshot(client)\n\n return useMemo(\n () => ({\n status: snapshot.syncStatus,\n enabled: snapshot.syncEnabled,\n pendingCount: snapshot.pendingCount,\n listRejected: () => client.listRejected(),\n clearRejected: () => client.clearRejected(),\n }),\n [client, snapshot],\n )\n}\n\nexport interface UseSharesResult {\n /** Shares this user granted to others (for this app). */\n granted: Share[]\n /** Shares others granted to this user (mountable). */\n received: Share[]\n isLoading: boolean\n error: Error | null\n refresh: () => Promise<void>\n}\n\n/** List shares granted by / received by the signed-in user for this app. */\nexport function useShares(): UseSharesResult {\n const client = useBasicClient()\n const snapshot = useClientSnapshot(client)\n const [state, setState] = useState<{\n granted: Share[]\n received: Share[]\n isLoading: boolean\n error: Error | null\n }>({ granted: [], received: [], isLoading: false, error: null })\n\n const isSignedIn = snapshot.isSignedIn && snapshot.authStatus === 'authenticated'\n\n const refresh = useMemo(\n () => async () => {\n setState((s) => ({ ...s, isLoading: true, error: null }))\n try {\n const { granted, received } = await client.listShares()\n setState({ granted, received, isLoading: false, error: null })\n } catch (err) {\n setState((s) => ({\n ...s,\n isLoading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n }))\n }\n },\n [client],\n )\n\n const activeUserId = snapshot.activeUser?.id ?? null\n useEffect(() => {\n if (isSignedIn) void refresh()\n else setState({ granted: [], received: [], isLoading: false, error: null })\n }, [isSignedIn, refresh, activeUserId])\n\n return { ...state, refresh }\n}\n\nexport interface UseShareResult {\n /** Table API over the mounted share's keyspace; null until mounted. */\n db: BasicDb | null\n status: 'mounting' | 'mounted' | 'error' | 'revoked'\n error: Error | null\n}\n\n/**\n * Mount a share (data another user granted to you) and get a db handle for\n * it. The mount lives in its own local keyspace with its own cursor and\n * pending queue — never merged with your own data.\n */\nexport function useShare(shareId: string | null | undefined): UseShareResult {\n const client = useBasicClient()\n const snapshot = useClientSnapshot(client)\n const [handle, setHandle] = useState<ShareMountHandle | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [revoked, setRevoked] = useState(false)\n\n const canMount =\n !!shareId && snapshot.isSignedIn && snapshot.authStatus !== 'reauth_required'\n // re-mount when the active user changes — mounts live in per-user keyspaces\n const activeUserId = snapshot.activeUser?.id ?? null\n\n useEffect(() => {\n if (!canMount || !shareId) return\n let cancelled = false\n setError(null)\n setRevoked(false)\n\n client\n .mountShare(shareId)\n .then((h) => {\n if (!cancelled) setHandle(h)\n })\n .catch((err) => {\n if (!cancelled) setError(err instanceof Error ? err : new Error(String(err)))\n })\n\n const offSubError = client.engine?.on('suberror', ({ sub, code }) => {\n if (sub === `share:${shareId}` && (code === 'SHARE_REVOKED' || code === 'CONNECTION_REVOKED')) {\n setRevoked(true)\n setHandle(null)\n }\n })\n\n return () => {\n cancelled = true\n offSubError?.()\n setHandle(null)\n void client.unmountShare(shareId).catch(() => {})\n }\n }, [client, shareId, canMount, activeUserId])\n\n return {\n db: handle?.db ?? null,\n status: revoked ? 'revoked' : error ? 'error' : handle ? 'mounted' : 'mounting',\n error,\n }\n}\n\nexport interface UseUsersResult {\n /** All local user profiles (anonymous and signed-in), shared across tabs. */\n users: BasicUserProfile[]\n /** The profile active in this tab. */\n activeUser: BasicUserProfile | null\n isAnonymous: boolean\n /** Switch this tab to another local user. */\n switchUser: (id: string) => Promise<void>\n /** Create a fresh anonymous user and switch to it. */\n addUser: () => Promise<BasicUserProfile>\n /** Remove a local user (wipes its local data; active user = sign out). */\n removeUser: (id: string) => Promise<void>\n}\n\n/** Multiple local users (anonymous or signed-in) with per-tab switching. */\nexport function useUsers(): UseUsersResult {\n const client = useBasicClient()\n const snapshot = useClientSnapshot(client)\n\n return useMemo(\n () => ({\n users: snapshot.users,\n activeUser: snapshot.activeUser,\n isAnonymous: snapshot.isAnonymous,\n switchUser: (id: string) => client.switchUser(id),\n addUser: () => client.addUser(),\n removeUser: (id: string) => client.removeUser(id),\n }),\n [client, snapshot],\n )\n}\n\nexport interface UseBasicResult extends UseAuthResult {\n db: BasicDb\n sync: UseSyncStatusResult\n /** All local user profiles. */\n users: BasicUserProfile[]\n /** The profile active in this tab. */\n activeUser: BasicUserProfile | null\n /** Local schema vs server status; null if no schema on the provider. */\n devInfo: BasicClientSnapshot['devInfo']\n refreshSchemaStatus: () => Promise<void>\n client: BasicClient\n}\n\n/** Umbrella hook: auth + db + sync status + users. */\nexport function useBasic(): UseBasicResult {\n const client = useBasicClient()\n const snapshot = useClientSnapshot(client)\n const auth = useAuth()\n const sync = useSyncStatus()\n\n return useMemo(\n () => ({\n ...auth,\n db: client.db,\n sync,\n users: snapshot.users,\n activeUser: snapshot.activeUser,\n devInfo: snapshot.devInfo,\n refreshSchemaStatus: () => client.refreshSchemaStatus(),\n client,\n }),\n [client, snapshot, auth, sync],\n )\n}\n","'use client'\n\nimport React, { useCallback, useMemo, useState } from 'react'\nimport { useBasic } from '../react/hooks'\nimport type { BasicSchemaDevInfo } from '../core/BasicClient'\nimport type { SyncStatus } from '../core/sync/SyncEngine'\nimport { version as sdkVersion } from '../../package.json'\nimport { isDevelopment } from '../utils/network'\n\nconst PANEL_PAD_X = 12\n\ntype ChipTone = 'ok' | 'warn' | 'bad' | 'muted'\n\nfunction toneForAuth(isReady: boolean, isSignedIn: boolean): ChipTone {\n if (!isReady) return 'muted'\n if (isSignedIn) return 'ok'\n return 'warn'\n}\n\nfunction toneForSync(mode: string, status: SyncStatus): ChipTone {\n if (mode === 'rest') return 'muted'\n if (status === 'online') return 'ok'\n if (status === 'connecting') return 'warn'\n if (status === 'offline' || status === 'idle' || status === 'stopped' || status === 'local')\n return 'muted'\n return 'bad'\n}\n\nfunction toneForSchema(info: BasicSchemaDevInfo | null): ChipTone {\n if (!info) return 'muted'\n if (info.valid && info.status === 'current') return 'ok'\n if (info.status === 'unpublished') return 'warn'\n if (info.status === 'no_schema') return 'muted'\n return 'bad'\n}\n\nfunction syncStatusLabel(status: SyncStatus): string {\n switch (status) {\n case 'idle':\n return 'Idle'\n case 'local':\n return 'Local only'\n case 'connecting':\n return 'Connecting'\n case 'online':\n return 'Connected'\n case 'offline':\n return 'Offline'\n case 'auth_required':\n return 'Reauth required'\n case 'revoked':\n return 'Connection revoked'\n case 'stopped':\n return 'Stopped'\n default:\n return String(status)\n }\n}\n\nfunction chipColor(tone: ChipTone): string {\n switch (tone) {\n case 'ok':\n return '#22c55e'\n case 'warn':\n return '#eab308'\n case 'bad':\n return '#ef4444'\n default:\n return '#71717a'\n }\n}\n\n/** Full value for display in dev panel (wraps; no truncation). */\nfunction displayDid(did: string | null): string {\n return did || '—'\n}\n\nfunction displayUserLine(user: { sub?: string; email?: string; name?: string; picture?: string }): string {\n const parts: string[] = []\n if (user.sub) parts.push(`sub: ${user.sub}`)\n if (user.email) parts.push(`email: ${user.email}`)\n if (user.name) parts.push(`name: ${user.name}`)\n return parts.length ? parts.join(' · ') : '—'\n}\n\nfunction ClipboardIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n )\n}\n\nexport type BasicDevToolbarProps = {\n /** When false, toolbar does not render. Defaults to true when used standalone. */\n enabled?: boolean\n /** Same as BasicProvider `debug` — when true, toolbar shows even off localhost. */\n debug?: boolean\n}\n\ntype CopyableRowProps = {\n rowKey: string\n label: string\n copyText: string\n copiedKey: string | null\n onCopied: (key: string) => void\n children: React.ReactNode\n}\n\nfunction SectionHeader({ children }: { children: React.ReactNode }) {\n return (\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n color: '#e4e4e7',\n letterSpacing: '0.07em',\n textTransform: 'uppercase',\n marginBottom: 8,\n }}\n >\n {children}\n </div>\n )\n}\n\n/** Full-bleed horizontal rule: only above a section (not under the header). */\nfunction SectionRule() {\n const bleed = PANEL_PAD_X\n return (\n <div\n role=\"separator\"\n style={{\n height: 1,\n background: 'rgba(255, 255, 255, 0.055)',\n marginLeft: -bleed,\n marginRight: -bleed,\n marginTop: 14,\n marginBottom: 10,\n width: `calc(100% + ${bleed * 2}px)`,\n }}\n />\n )\n}\n\nfunction CopyableRow({\n rowKey,\n label,\n copyText,\n copiedKey,\n onCopied,\n children,\n}: CopyableRowProps) {\n const [hover, setHover] = useState(false)\n const canCopy = copyText.length > 0\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation()\n if (!canCopy) return\n void navigator.clipboard.writeText(copyText).then(() => onCopied(rowKey))\n },\n [canCopy, copyText, onCopied, rowKey],\n )\n\n return (\n <div\n role={canCopy ? 'button' : undefined}\n tabIndex={canCopy ? 0 : undefined}\n onClick={canCopy ? handleClick : undefined}\n onKeyDown={\n canCopy\n ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleClick(e as unknown as React.MouseEvent)\n }\n }\n : undefined\n }\n onMouseEnter={() => setHover(true)}\n onMouseLeave={() => setHover(false)}\n style={{\n display: 'flex',\n gap: 8,\n marginBottom: 6,\n alignItems: 'flex-start',\n borderRadius: 6,\n padding: '4px 6px',\n marginLeft: -6,\n marginRight: -6,\n cursor: canCopy ? 'pointer' : 'default',\n background: hover && canCopy ? 'rgba(255,255,255,0.06)' : 'transparent',\n transition: 'background 0.12s ease',\n }}\n >\n <span style={{ color: '#a1a1aa', minWidth: 88, flexShrink: 0, paddingTop: 2 }}>{label}</span>\n <span\n style={{\n flex: 1,\n minWidth: 0,\n wordBreak: 'break-all',\n paddingTop: 2,\n lineHeight: 1.35,\n }}\n >\n {children}\n </span>\n {canCopy && (\n <span\n style={{\n flexShrink: 0,\n color: copiedKey === rowKey ? '#22c55e' : '#71717a',\n opacity: hover || copiedKey === rowKey ? 1 : 0,\n transition: 'opacity 0.12s ease, color 0.12s ease',\n paddingTop: 2,\n display: 'flex',\n alignItems: 'flex-start',\n }}\n title=\"Copy value\"\n >\n {copiedKey === rowKey ? (\n <span style={{ fontSize: 10 }}>✓</span>\n ) : (\n <ClipboardIcon />\n )}\n </span>\n )}\n </div>\n )\n}\n\n/**\n * Floating dev-only toolbar: auth, DB/sync, and schema status. Requires `BasicProvider` with `debug` or localhost / NODE_ENV=development for visibility unless `enabled` is forced.\n */\nexport function BasicDevToolbar({ enabled = true, debug }: BasicDevToolbarProps) {\n const {\n isReady,\n isSignedIn,\n isAnonymous,\n user,\n did,\n scope,\n missingScopes,\n sync,\n users,\n activeUser,\n devInfo,\n refreshSchemaStatus,\n client,\n } = useBasic()\n\n const dbMode = client.mode\n const syncStatus = sync.status\n const indexedDbName =\n dbMode === 'sync' && client.projectId\n ? `basic-sync:${client.projectId}${activeUser?.keyspace ? `:${activeUser.keyspace}` : ''}`\n : null\n const activeUserLabel = activeUser\n ? `${isAnonymous ? 'anonymous' : activeUser.email || activeUser.name || activeUser.did || 'account'} (${activeUser.id.slice(0, 8)}…)${users.length > 1 ? ` · ${users.length} users` : ''}`\n : '—'\n\n const [open, setOpen] = useState(false)\n const [refreshing, setRefreshing] = useState(false)\n const [copied, setCopied] = useState(false)\n const [rowCopied, setRowCopied] = useState<string | null>(null)\n\n const show =\n enabled && typeof window !== 'undefined' && isDevelopment(debug)\n\n const authTone = toneForAuth(isReady, isSignedIn)\n const dbTone = toneForSync(dbMode, syncStatus)\n const schemaTone = toneForSchema(devInfo)\n const syncTone: ChipTone = dbTone\n\n const handleRefreshSchema = useCallback(async () => {\n setRefreshing(true)\n try {\n await refreshSchemaStatus()\n } finally {\n setRefreshing(false)\n }\n }, [refreshSchemaStatus])\n\n const missingList = missingScopes()\n\n const debugPayload = useMemo(() => {\n return {\n sdkVersion,\n isReady,\n isSignedIn,\n did: did ?? null,\n user: user\n ? {\n sub: user.sub,\n email: user.email,\n name: user.name,\n picture: user.picture,\n }\n : null,\n scope,\n missingScopes: missingList,\n dbMode,\n syncStatus,\n pendingOps: sync.pendingCount,\n indexedDbName,\n activeUser: activeUser\n ? { id: activeUser.id, kind: activeUser.kind, did: activeUser.did }\n : null,\n userCount: users.length,\n schema: devInfo,\n }\n }, [isReady, isSignedIn, did, user, scope, dbMode, syncStatus, sync.pendingCount, indexedDbName, activeUser, users.length, devInfo, missingList])\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(JSON.stringify(debugPayload, null, 2))\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n /* ignore */\n }\n }, [debugPayload])\n\n const onRowCopied = useCallback((key: string) => {\n setRowCopied(key)\n setTimeout(() => setRowCopied((k) => (k === key ? null : k)), 1500)\n }, [])\n\n if (!show) return null\n\n const shell: React.CSSProperties = {\n position: 'fixed',\n bottom: 12,\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: 99999,\n fontFamily:\n 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\n fontSize: 11,\n color: '#e4e4e7',\n pointerEvents: 'auto',\n }\n\n const bar: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '8px 12px',\n borderRadius: 999,\n background: 'rgba(24, 24, 27, 0.92)',\n border: '1px solid rgba(63, 63, 70, 0.9)',\n boxShadow: '0 8px 32px rgba(0,0,0,0.35)',\n cursor: 'pointer',\n userSelect: 'none',\n }\n\n /** Fixed box so flex line-height / strut cannot stretch dots when the pill width changes. */\n const dot = (tone: ChipTone) => (\n <span\n style={{\n display: 'block',\n boxSizing: 'border-box',\n width: 6,\n height: 6,\n minWidth: 6,\n minHeight: 6,\n maxWidth: 6,\n maxHeight: 6,\n borderRadius: '50%',\n background: chipColor(tone),\n flexShrink: 0,\n }}\n />\n )\n\n const dotSlot = (title: string, tone: ChipTone) => (\n <span\n title={title}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 6,\n height: 6,\n flexShrink: 0,\n lineHeight: 0,\n }}\n >\n {dot(tone)}\n </span>\n )\n\n const panel: React.CSSProperties = {\n marginBottom: 8,\n maxHeight: '50vh',\n overflow: 'auto',\n padding: PANEL_PAD_X,\n borderRadius: 10,\n background: 'rgba(24, 24, 27, 0.96)',\n border: '1px solid rgba(63, 63, 70, 0.9)',\n boxShadow: '0 8px 32px rgba(0,0,0,0.35)',\n minWidth: 300,\n maxWidth: 'min(560px, calc(100vw - 24px))',\n }\n\n const syncStatusText =\n dbMode === 'rest'\n ? 'REST mode'\n : `${syncStatusLabel(syncStatus)}${sync.pendingCount > 0 ? ` (${sync.pendingCount} pending)` : ''}`\n\n return (\n <div style={shell}>\n {open && (\n <div style={panel}>\n <div style={{ marginBottom: 12 }}>\n <div style={{ fontWeight: 600, fontSize: 12 }}>Basic SDK</div>\n <div style={{ color: '#71717a', fontSize: 10, marginTop: 2 }}>v{sdkVersion}</div>\n </div>\n\n <SectionHeader>Auth</SectionHeader>\n <CopyableRow\n rowKey=\"ready\"\n label=\"Ready\"\n copyText={String(isReady)}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {String(isReady)}\n </CopyableRow>\n <CopyableRow\n rowKey=\"signedIn\"\n label=\"Signed in\"\n copyText={String(isSignedIn)}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {String(isSignedIn)}\n </CopyableRow>\n <CopyableRow\n rowKey=\"did\"\n label=\"DID\"\n copyText={did || ''}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {displayDid(did)}\n </CopyableRow>\n <CopyableRow\n rowKey=\"user\"\n label=\"User\"\n copyText={user ? displayUserLine(user) : ''}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {user ? displayUserLine(user) : '—'}\n </CopyableRow>\n <CopyableRow\n rowKey=\"activeProfile\"\n label=\"Profile\"\n copyText={activeUser?.id ?? ''}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {activeUserLabel}\n </CopyableRow>\n <CopyableRow\n rowKey=\"scopes\"\n label=\"Scopes\"\n copyText={scope || ''}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {scope || '—'}\n </CopyableRow>\n <CopyableRow\n rowKey=\"missingScopes\"\n label=\"Missing scopes\"\n copyText={missingList.length ? missingList.join(', ') : ''}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {missingList.length ? missingList.join(', ') : '—'}\n </CopyableRow>\n\n <SectionRule />\n <SectionHeader>Database</SectionHeader>\n <CopyableRow\n rowKey=\"dbMode\"\n label=\"Mode\"\n copyText={dbMode}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {dbMode}\n </CopyableRow>\n <CopyableRow\n rowKey=\"indexedDb\"\n label=\"IndexedDB\"\n copyText={indexedDbName ?? ''}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {indexedDbName ?? '—'}\n </CopyableRow>\n <CopyableRow\n rowKey=\"syncStatus\"\n label=\"Sync / status\"\n copyText={syncStatusText}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {syncStatusText}\n </CopyableRow>\n\n <SectionRule />\n <SectionHeader>Schema</SectionHeader>\n {devInfo ? (\n <>\n <CopyableRow\n rowKey=\"schemaProject\"\n label=\"Project\"\n copyText={devInfo.projectId ?? ''}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {devInfo.projectId ?? '—'}\n </CopyableRow>\n <CopyableRow\n rowKey=\"schemaLocalVer\"\n label=\"Local version\"\n copyText={\n devInfo.localVersion !== undefined && devInfo.localVersion !== null\n ? String(devInfo.localVersion)\n : ''\n }\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {devInfo.localVersion ?? '—'}\n </CopyableRow>\n <CopyableRow\n rowKey=\"schemaRemote\"\n label=\"Remote check\"\n copyText={devInfo.status}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {devInfo.status}\n </CopyableRow>\n <CopyableRow\n rowKey=\"schemaValid\"\n label=\"Valid\"\n copyText={String(devInfo.valid)}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {String(devInfo.valid)}\n </CopyableRow>\n <CopyableRow\n rowKey=\"schemaChecked\"\n label=\"Checked\"\n copyText={\n devInfo.lastCheckedAt\n ? new Date(devInfo.lastCheckedAt).toISOString()\n : ''\n }\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {devInfo.lastCheckedAt\n ? new Date(devInfo.lastCheckedAt).toLocaleString()\n : '—'}\n </CopyableRow>\n {devInfo.error ? (\n <CopyableRow\n rowKey=\"schemaError\"\n label=\"Error\"\n copyText={devInfo.error}\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n {devInfo.error}\n </CopyableRow>\n ) : null}\n </>\n ) : (\n <CopyableRow\n rowKey=\"schemaStatus\"\n label=\"Status\"\n copyText=\"No schema on provider\"\n copiedKey={rowCopied}\n onCopied={onRowCopied}\n >\n No schema on provider\n </CopyableRow>\n )}\n\n <div style={{ display: 'flex', gap: 8, marginTop: 12, flexWrap: 'wrap' }}>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n void handleRefreshSchema()\n }}\n disabled={refreshing}\n style={{\n padding: '6px 10px',\n borderRadius: 6,\n border: '1px solid #3f3f46',\n background: '#27272a',\n color: '#e4e4e7',\n cursor: refreshing ? 'wait' : 'pointer',\n fontSize: 11,\n fontFamily: 'inherit',\n }}\n >\n {refreshing ? 'Refreshing…' : 'Refresh schema'}\n </button>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n void handleCopy()\n }}\n style={{\n padding: '6px 10px',\n borderRadius: 6,\n border: '1px solid #3f3f46',\n background: '#27272a',\n color: '#e4e4e7',\n cursor: 'pointer',\n fontSize: 11,\n fontFamily: 'inherit',\n }}\n >\n {copied ? 'Copied' : 'Copy debug info'}\n </button>\n </div>\n </div>\n )}\n\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((o) => !o)}\n style={{\n ...bar,\n border: 'none',\n width: '100%',\n cursor: 'pointer',\n }}\n >\n <span style={{ fontWeight: 600, letterSpacing: 0.02 }}>Basic</span>\n <span\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n marginLeft: 8,\n height: 6,\n flexShrink: 0,\n lineHeight: 0,\n }}\n >\n {dotSlot('Auth', authTone)}\n {dotSlot('DB', dbTone)}\n {dotSlot('Sync', syncTone)}\n {dotSlot('Schema', schemaTone)}\n </span>\n <span style={{ color: '#71717a', marginLeft: 4 }}>{open ? '▾' : '▴'}</span>\n </button>\n </div>\n )\n}\n","import React, { Suspense, lazy, useEffect, useRef, useSyncExternalStore } from 'react'\nimport { BasicClientContext } from './context'\nimport { BasicClient, type BasicAuthConfig, type BasicMode } from '../core/BasicClient'\nimport type { BasicStorage } from '../utils/storage'\nimport { isDevelopment, checkForNewVersion } from '../utils/network'\n\nconst BasicDevToolbar = lazy(() =>\n import('../dev/BasicDevToolbar').then((m) => ({ default: m.BasicDevToolbar })),\n)\n\nexport interface BasicProviderProps {\n children: React.ReactNode\n /** The Basic schema object containing project_id and table definitions. */\n schema?: Record<string, unknown>\n /** Project id override; normally taken from `schema.project_id`. */\n project_id?: string\n auth?: BasicAuthConfig\n storage?: BasicStorage\n debug?: boolean\n /**\n * - 'sync' (default): offline-first local replica synced over Sync/2\n * - 'rest': direct REST calls, no local persistence\n */\n mode?: BasicMode\n /**\n * Anonymous/local-first usage (sync mode only, default true): the db works\n * without a session and local data merges into the account on sign-in.\n * Set false to require sign-in before any local data exists.\n */\n anonymous?: boolean\n /** Show the floating dev toolbar (localhost / NODE_ENV=development / debug). */\n devToolbar?: boolean\n /**\n * Render children before auth/db are ready (default false: children render\n * once the client finished bootstrapping, like previous versions).\n */\n renderWhileLoading?: boolean\n}\n\nexport function BasicProvider({\n children,\n schema,\n project_id,\n auth,\n storage,\n debug = false,\n mode = 'sync',\n anonymous = true,\n devToolbar = false,\n renderWhileLoading = false,\n}: BasicProviderProps) {\n const clientRef = useRef<BasicClient | null>(null)\n if (!clientRef.current) {\n clientRef.current = new BasicClient({\n schema: schema as BasicClient['config']['schema'],\n project_id,\n auth,\n storage,\n debug,\n mode,\n anonymous,\n })\n }\n const client = clientRef.current\n\n useEffect(() => {\n void client.start()\n void checkForNewVersion()\n return () => client.stop()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const snapshot = useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n const showDevTools = devToolbar && isDevelopment(debug)\n const ready = snapshot.isReady\n\n return (\n <BasicClientContext.Provider value={client}>\n {showDevTools && (\n <Suspense fallback={null}>\n <BasicDevToolbar debug={debug} />\n </Suspense>\n )}\n {(ready || renderWhileLoading) && children}\n </BasicClientContext.Provider>\n )\n}\n","import { jwtDecode } from 'jwt-decode'\nimport { BasicStorage, STORAGE_KEYS } from '../../utils/storage'\nimport { normalizeClientId } from '../../utils/normalizeClientId'\nimport { resolveHandle } from '../../utils/resolveDid'\nimport { cleanOAuthParamsFromUrl } from '../../utils/network'\nimport { log } from '../../config'\n\nconst DEFINITIVE_TOKEN_ERRORS = new Set([\n 'invalid_grant',\n 'invalid_client',\n 'unauthorized_client',\n])\nconst USER_RECOVERY_RETRY_COOLDOWN_MS = 30_000\nconst SESSION_RECONCILE_THROTTLE_MS = 5_000\n\nclass DefinitiveAuthError extends Error {\n readonly code: string\n\n constructor(code: string) {\n super(`Definitive auth failure: ${code}`)\n this.name = 'DefinitiveAuthError'\n this.code = code\n }\n}\n\n// --- PKCE helpers (RFC 7636) ---\n\nfunction generateCodeVerifier(): string {\n const array = new Uint8Array(32)\n crypto.getRandomValues(array)\n return base64UrlEncode(array)\n}\n\nasync function generateCodeChallenge(\n verifier: string,\n): Promise<{ challenge: string; method: 'S256' | 'plain' }> {\n if (typeof crypto === 'undefined' || !crypto.subtle) {\n log(\n 'crypto.subtle unavailable (non-secure context?) -- falling back to plain PKCE challenge',\n )\n return { challenge: verifier, method: 'plain' }\n }\n const encoder = new TextEncoder()\n const data = encoder.encode(verifier)\n const digest = await crypto.subtle.digest('SHA-256', data)\n return { challenge: base64UrlEncode(new Uint8Array(digest)), method: 'S256' }\n}\n\nfunction base64UrlEncode(buffer: Uint8Array): string {\n let str = ''\n for (let i = 0; i < buffer.length; i++) {\n str += String.fromCharCode(buffer[i]!)\n }\n return btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nexport type Token = {\n access_token: string\n token_type: string\n expires_in: number\n refresh_token: string\n}\n\nexport type User = {\n sub?: string\n name?: string\n email?: string\n picture?: string\n}\n\n/**\n * High-level auth lifecycle state.\n *\n * - `bootstrapping` — SDK is initializing; not yet determined if a session exists.\n * - `authenticated` — User has a valid access token and active session.\n * - `recovering` — A session likely exists (refresh token / cached user) but\n * the SDK hasn't confirmed it yet (e.g. offline, mid-refresh).\n * - `reauth_required` — The session is definitively invalid (revoked, expired\n * refresh token, etc.). The user must sign in again.\n * NOTE: `isSignedIn` remains `true` in this state so the UI\n * can display user info while prompting re-authentication.\n * Use `authStatus === 'reauth_required'` to distinguish\n * this from a healthy signed-in state.\n * - `signed_out` — No session. User is not authenticated.\n *\n * TODO: revisit naming and ergonomics — consider adding a `needsReauth` or\n * `shouldPromptSignIn` convenience getter so consumers don't need to inspect\n * the raw status to decide between \"sign in\" vs \"sign out\" UI.\n */\nexport type AuthStatus =\n | 'bootstrapping'\n | 'authenticated'\n | 'recovering'\n | 'reauth_required'\n | 'signed_out'\n\nexport type AuthResult = {\n success: boolean\n error?: string\n code?: string\n}\n\nexport type GetTokenOptions = {\n forceRefresh?: boolean\n}\n\nexport type PdsEndpoints = {\n pds_url: string\n authorization_endpoint: string\n token_endpoint: string\n userinfo_endpoint: string\n}\n\nexport type AuthManagerConfig = {\n projectId: string | undefined\n scopes: string\n pdsUrl: string\n adminUrl: string\n debug: boolean\n /**\n * Identifies which local user profile this manager belongs to (multi-user).\n * Cross-tab events are scoped to it so a tab active on another profile\n * ignores them. Defaults to '' (single-user / legacy profile).\n */\n instanceKey?: string\n}\n\ntype JwtClaims = {\n sub?: string\n scope?: string\n typ?: string\n exp?: number\n}\n\ntype CurrentSessionInfo = {\n active: boolean\n reauth_required?: boolean\n session_id?: string | null\n client_id?: string\n scope?: string\n account_did?: string\n connection_status?: string\n last_seen_at?: string | null\n error?: string\n}\n\n/**\n * Framework-agnostic auth manager. Holds token state, handles OAuth flow,\n * token refresh (with mutex), and user info fetching.\n *\n * React integration: pass a state-setter as `notify` so the component\n * re-renders whenever auth state changes.\n */\nexport class AuthManager {\n // --- Public state (read by the UI layer) ---\n token: Token | null = null\n user: User | null = null\n isSignedIn: boolean = false\n isAuthReady: boolean = false\n authStatus: AuthStatus = 'bootstrapping'\n authErrorCode: string | null = null\n did: string | null = null\n /** Space-separated scopes granted in the current access token */\n tokenScope: string | null = null\n /** Space-separated scopes originally requested in the auth config */\n requestedScopes: string\n\n readonly config: AuthManagerConfig\n readonly storage: BasicStorage\n\n /** True only during a user-initiated OAuth code exchange (not session restore) */\n private freshSignIn: boolean = false\n\n // --- Private ---\n private notify: () => void\n private refreshPromise: Promise<Token | null> | null = null\n private codeExchangePromise: Promise<Token | null> | null = null\n private pendingRefresh: boolean = false\n private isOnline: boolean =\n typeof navigator !== 'undefined' ? navigator.onLine : true\n private channel: BroadcastChannel | null = null\n private nextUserRecoveryAt: number = 0\n private sessionCheckPromise: Promise<void> | null = null\n private lastSessionCheckAt: number = 0\n\n constructor(\n config: AuthManagerConfig,\n storage: BasicStorage,\n notify: () => void,\n ) {\n this.config = config\n this.storage = storage\n this.notify = notify\n this.requestedScopes = config.scopes\n this.initCrossTabSync()\n }\n\n private get instanceKey(): string {\n return this.config.instanceKey ?? ''\n }\n\n private initCrossTabSync(): void {\n if (typeof BroadcastChannel === 'undefined') return\n\n try {\n this.channel = new BroadcastChannel('basic-auth')\n this.channel.onmessage = (event) => {\n // multi-user: only apply events for the same local profile\n if ((event.data?.userKey ?? '') !== this.instanceKey) return\n if (event.data?.type === 'token_refreshed') {\n log('Received token refresh from another tab')\n void this.handleExternalTokenRefresh(event.data)\n }\n if (event.data?.type === 'signed_in') {\n log('Received sign-in from another tab, restoring session')\n void this.restoreStoredSession('cross-tab sign-in')\n }\n if (event.data?.type === 'signed_out') {\n log('Received sign-out from another tab')\n this.resetAuthState('signed_out')\n this.notify()\n }\n if (event.data?.type === 'session_invalidated') {\n log('Received session invalidation from another tab')\n void this.markReauthRequired(event.data.code || 'invalid_grant', {\n broadcast: false,\n })\n }\n }\n } catch {\n log('BroadcastChannel not available for cross-tab sync')\n }\n }\n\n private broadcastTokenRefresh(): void {\n this.channel?.postMessage({\n type: 'token_refreshed',\n userKey: this.instanceKey,\n accessToken: this.token?.access_token,\n did: this.did,\n tokenScope: this.tokenScope,\n })\n }\n\n private broadcastSignIn(): void {\n this.channel?.postMessage({ type: 'signed_in', userKey: this.instanceKey })\n }\n\n private broadcastSignOut(): void {\n this.channel?.postMessage({ type: 'signed_out', userKey: this.instanceKey })\n }\n\n private broadcastSessionInvalidated(code: string): void {\n this.channel?.postMessage({\n type: 'session_invalidated',\n userKey: this.instanceKey,\n code,\n })\n }\n\n /** Release resources (cross-tab channel). Used when switching users. */\n destroy(): void {\n try {\n this.channel?.close()\n } catch {\n /* ignore */\n }\n this.channel = null\n }\n\n // ------------------------------------------------------------------\n // Public API\n // ------------------------------------------------------------------\n\n /**\n * Bootstrap auth: handle OAuth callback (?code=), restore session\n * from refresh token, or load cached user for offline mode.\n */\n async initialize(): Promise<void> {\n this.updateAuthStatus('bootstrapping')\n await this.storage.set(\n STORAGE_KEYS.DEBUG,\n this.config.debug ? 'true' : 'false',\n )\n\n const storedServerUrl = await this.storage.get(STORAGE_KEYS.SERVER_URL)\n if (storedServerUrl && storedServerUrl !== this.config.pdsUrl) {\n log('PDS URL changed, clearing stored tokens')\n await this.clearStoredAuth()\n }\n await this.storage.set(STORAGE_KEYS.SERVER_URL, this.config.pdsUrl)\n\n try {\n const params = new URLSearchParams(window.location.search)\n\n if (params.has('code')) {\n const code = params.get('code')\n if (!code) {\n this.updateAuthStatus('signed_out')\n this.notify()\n return\n }\n\n const state = await this.storage.get(STORAGE_KEYS.AUTH_STATE)\n const urlState = params.get('state')\n if (!state || state !== urlState) {\n log('error: auth state does not match')\n this.updateAuthStatus('signed_out')\n this.notify()\n await this.storage.remove(STORAGE_KEYS.AUTH_STATE)\n cleanOAuthParamsFromUrl()\n return\n }\n\n await this.storage.remove(STORAGE_KEYS.AUTH_STATE)\n cleanOAuthParamsFromUrl()\n\n this.freshSignIn = true\n this.exchangeToken(code, false).catch((error) => {\n log('Error fetching token:', error)\n this.freshSignIn = false\n void this.restoreCachedUser({\n hasRecoverableSession: !this.isDefinitiveAuthFailure(error),\n })\n })\n } else {\n await this.restoreStoredSession('initialize')\n }\n } catch (e) {\n log('error getting token', e)\n this.updateAuthStatus('signed_out')\n this.notify()\n }\n }\n\n /**\n * Get a valid access token string. Refreshes proactively (5s buffer)\n * or on demand (forceRefresh). Mutex prevents concurrent refreshes.\n */\n async getToken(options?: GetTokenOptions): Promise<string> {\n log('getting token...')\n\n if (!this.token) {\n const refreshToken = await this.getRefreshToken()\n if (refreshToken) {\n log('No token in memory, attempting to refresh from storage')\n\n if (this.refreshPromise) {\n log('Token refresh already in progress, waiting...')\n try {\n const newToken = await this.refreshPromise\n if (newToken?.access_token) {\n return newToken.access_token\n }\n } catch (error) {\n log('In-flight refresh failed:', error)\n throw error\n }\n }\n\n try {\n const newToken = await this.exchangeToken(refreshToken, true)\n if (newToken?.access_token) {\n return newToken.access_token\n }\n } catch (error) {\n log('Failed to refresh token from storage:', error)\n if (this.isNetworkError(error)) {\n throw new Error(\n 'Network offline - authentication will be retried when online',\n )\n }\n if (!this.isDefinitiveAuthFailure(error)) {\n throw error\n }\n throw new Error('Authentication expired. Please sign in again.')\n }\n }\n log('no token found')\n throw new Error('no token found')\n }\n\n const decoded = jwtDecode<JwtClaims>(this.token.access_token)\n const expirationBuffer = 5\n const isExpired =\n decoded.exp && decoded.exp < Date.now() / 1000 + expirationBuffer\n const shouldRefresh = isExpired || options?.forceRefresh === true\n\n if (shouldRefresh) {\n log(\n options?.forceRefresh\n ? 'force refreshing token...'\n : 'token is expired - refreshing ...',\n )\n\n if (this.refreshPromise) {\n log('Token refresh already in progress, waiting...')\n try {\n const newToken = await this.refreshPromise\n if (!newToken?.access_token)\n throw new Error('Token refresh returned empty access token')\n return newToken.access_token\n } catch (error) {\n log('In-flight refresh failed:', error)\n if (this.isNetworkError(error)) {\n log('Network issue - using expired token until network is restored')\n return this.token.access_token\n }\n throw error\n }\n }\n\n const refreshToken = await this.getRefreshToken()\n if (refreshToken) {\n try {\n const newToken = await this.exchangeToken(refreshToken, true)\n if (!newToken?.access_token)\n throw new Error('Token refresh returned empty access token')\n return newToken.access_token\n } catch (error) {\n log('Failed to refresh expired token:', error)\n if (this.isNetworkError(error)) {\n log('Network issue - using expired token until network is restored')\n return this.token.access_token\n }\n if (!this.isDefinitiveAuthFailure(error)) {\n throw error\n }\n throw new Error('Authentication expired. Please sign in again.')\n }\n } else {\n throw new Error('no refresh token available')\n }\n }\n\n if (!this.token.access_token)\n throw new Error('Token exists but access_token is empty')\n return this.token.access_token\n }\n\n async getSignInUrl(\n redirectUri?: string,\n endpoints?: PdsEndpoints,\n ): Promise<string> {\n log('getting sign in link...')\n\n if (!this.config.projectId) {\n throw new Error('Project ID is required to generate sign-in link')\n }\n\n const pdsEndpoints = endpoints || this.defaultPdsEndpoints()\n await this.storage.set(\n STORAGE_KEYS.PDS_ENDPOINTS,\n JSON.stringify(pdsEndpoints),\n )\n\n const randomState = base64UrlEncode(\n crypto.getRandomValues(new Uint8Array(16)),\n )\n await this.storage.set(STORAGE_KEYS.AUTH_STATE, randomState)\n\n const redirectUrl = redirectUri || window.location.href\n if (\n !redirectUrl ||\n (!redirectUrl.startsWith('http://') &&\n !redirectUrl.startsWith('https://'))\n ) {\n throw new Error('Invalid redirect URI provided')\n }\n\n await this.storage.set(STORAGE_KEYS.REDIRECT_URI, redirectUrl)\n log('Stored redirect_uri for token exchange:', redirectUrl)\n\n // PKCE: generate code_verifier and code_challenge (RFC 7636)\n const codeVerifier = generateCodeVerifier()\n const { challenge: codeChallenge, method: challengeMethod } =\n await generateCodeChallenge(codeVerifier)\n await this.storage.set(STORAGE_KEYS.CODE_VERIFIER, codeVerifier)\n\n let baseUrl = pdsEndpoints.authorization_endpoint\n baseUrl += `?client_id=${encodeURIComponent(normalizeClientId(this.config.projectId, this.adminHostname))}`\n baseUrl += `&redirect_uri=${encodeURIComponent(redirectUrl)}`\n baseUrl += `&response_type=code`\n baseUrl += `&scope=${encodeURIComponent(this.config.scopes)}`\n baseUrl += `&state=${randomState}`\n baseUrl += `&code_challenge=${encodeURIComponent(codeChallenge)}`\n baseUrl += `&code_challenge_method=${challengeMethod}`\n\n log('Generated sign-in link successfully with scopes:', this.config.scopes)\n return baseUrl\n }\n\n async signIn(redirectUri?: string): Promise<void> {\n log('signing in...')\n\n if (!this.config.projectId) {\n log('Error: project_id is required for sign-in')\n throw new Error('Project ID is required for authentication')\n }\n\n const signInLink = await this.getSignInUrl(redirectUri)\n log('Generated sign-in link:', signInLink)\n\n try {\n new URL(signInLink)\n } catch {\n log('Error: Invalid sign-in link generated')\n throw new Error('Failed to generate valid sign-in URL')\n }\n\n window.location.href = signInLink\n }\n\n async signInWithHandle(handle: string): Promise<void> {\n log('signing in with handle:', handle)\n\n if (!this.config.projectId) {\n throw new Error('Project ID is required for authentication')\n }\n\n const resolved = await resolveHandle(handle)\n log('Resolved handle to PDS:', resolved.pdsUrl)\n\n const endpoints: PdsEndpoints = {\n pds_url: resolved.pdsUrl,\n authorization_endpoint: resolved.authorization_endpoint,\n token_endpoint: resolved.token_endpoint,\n userinfo_endpoint: resolved.userinfo_endpoint,\n }\n\n const signInLink = await this.getSignInUrl(undefined, endpoints)\n log('Generated federated sign-in link:', signInLink)\n\n try {\n new URL(signInLink)\n } catch {\n throw new Error('Failed to generate valid sign-in URL')\n }\n\n window.location.href = signInLink\n }\n\n async signInWithCode(code: string, state?: string): Promise<AuthResult> {\n try {\n log('signInWithCode called with code:', code)\n\n if (!code || typeof code !== 'string') {\n return { success: false, error: 'Invalid authorization code' }\n }\n\n if (state) {\n const storedState = await this.storage.get(STORAGE_KEYS.AUTH_STATE)\n if (storedState && storedState !== state) {\n log('State parameter mismatch:', {\n provided: state,\n stored: storedState,\n })\n return { success: false, error: 'State parameter mismatch' }\n }\n }\n\n await this.storage.remove(STORAGE_KEYS.AUTH_STATE)\n cleanOAuthParamsFromUrl()\n\n this.freshSignIn = true\n const token = await this.exchangeToken(code, false)\n if (token) {\n log('signInWithCode successful')\n return { success: true }\n } else {\n return { success: false, error: 'Failed to exchange code for token' }\n }\n } catch (error) {\n log('signInWithCode error:', error)\n this.freshSignIn = false\n return {\n success: false,\n error: (error as Error).message || 'Authentication failed',\n }\n }\n }\n\n /**\n * Sign out: revoke the session server-side (`POST /auth/logout`, best\n * effort), then clear auth state and storage. Does NOT handle sync/DB\n * cleanup — the client layer wraps this to add sync teardown.\n */\n async signOut(): Promise<void> {\n log('signing out!')\n\n await this.revokeSessionOnServer()\n\n this.resetAuthState('signed_out')\n\n await this.storage.remove(STORAGE_KEYS.AUTH_STATE)\n await this.storage.remove(STORAGE_KEYS.LAST_CONNECT_REPORT)\n await this.clearStoredAuth()\n\n this.broadcastSignOut()\n this.notify()\n }\n\n /**\n * Best-effort server-side revocation of the current device/session and\n * its refresh chain (Step 2 auth: logout is finally server-side).\n * Never blocks or fails the local sign-out.\n */\n private async revokeSessionOnServer(): Promise<void> {\n try {\n let accessToken: string | null = null\n try {\n accessToken = await this.getToken()\n } catch {\n accessToken = this.token?.access_token ?? null\n }\n if (!accessToken) return\n const endpoints = await this.getActivePdsEndpoints()\n await fetch(`${endpoints.pds_url}/auth/logout`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n log('Server-side logout succeeded')\n } catch (error) {\n log('Server-side logout failed (non-blocking):', error)\n }\n }\n\n async reconcileSession(\n reason: string = 'manual',\n options?: { forceRefresh?: boolean; throttleMs?: number },\n ): Promise<void> {\n if (this.authStatus === 'signed_out' || this.authStatus === 'reauth_required') {\n return\n }\n\n if (!this.isOnline) {\n this.updateAuthStatus('recovering', this.authErrorCode)\n this.notify()\n return\n }\n\n const throttleMs = options?.throttleMs ?? SESSION_RECONCILE_THROTTLE_MS\n const forceRefresh = options?.forceRefresh === true\n const now = Date.now()\n\n if (this.sessionCheckPromise) {\n return this.sessionCheckPromise\n }\n\n if (!forceRefresh && now - this.lastSessionCheckAt < throttleMs) {\n return\n }\n\n this.lastSessionCheckAt = now\n\n let sessionCheck: Promise<void> | null = null\n sessionCheck = (async () => {\n try {\n const accessToken = await this.getToken(\n forceRefresh ? { forceRefresh: true } : undefined,\n )\n const currentSession = await this.fetchCurrentSession(accessToken)\n if (currentSession?.active) {\n this.updateAuthStatus('authenticated')\n this.notify()\n if (!this.user) {\n await this.recoverMissingUserProfile(reason, accessToken)\n }\n }\n } catch (error) {\n log(`Session reconciliation failed on ${reason}:`, error)\n if (this.isDefinitiveAuthFailure(error)) {\n return\n }\n if (this.isNetworkError(error)) {\n this.updateAuthStatus('recovering', this.authErrorCode)\n this.notify()\n }\n } finally {\n if (this.sessionCheckPromise === sessionCheck) {\n this.sessionCheckPromise = null\n }\n }\n })()\n\n this.sessionCheckPromise = sessionCheck\n return sessionCheck\n }\n\n hasScope(scope: string): boolean {\n if (!this.tokenScope) return false\n return this.tokenScope\n .split(/[\\s,]+/)\n .filter(Boolean)\n .includes(scope)\n }\n\n /**\n * Returns scopes that were requested but not granted in the current token.\n * Useful after login or when a 403 is returned.\n */\n missingScopes(): string[] {\n const requested = this.requestedScopes.split(/[\\s,]+/).filter(Boolean)\n if (!this.tokenScope) return requested\n const granted = new Set(this.tokenScope.split(/[\\s,]+/).filter(Boolean))\n return requested.filter((s) => !granted.has(s))\n }\n\n /**\n * Register online/offline and visibility handlers that retry pending\n * refreshes and proactively refresh tokens when the app resumes from\n * background (critical for PWAs and mobile browsers where timers are\n * frozen while backgrounded).\n * Returns a cleanup function for useEffect teardown.\n */\n setupNetworkListeners(): () => void {\n const handleOnline = async () => {\n log('Network came back online')\n this.isOnline = true\n if (this.pendingRefresh) {\n log('Retrying pending token refresh')\n this.pendingRefresh = false\n const refreshToken = await this.getRefreshToken()\n if (refreshToken) {\n this.exchangeToken(refreshToken, true).catch((error) => {\n log('Retry refresh failed:', error)\n })\n }\n }\n if (this.isSignedIn) {\n this.reconcileSession('online event', {\n forceRefresh: true,\n throttleMs: 0,\n }).catch((error) => {\n log('Session reconciliation on online failed:', error)\n })\n } else if (this.user) {\n await this.restoreStoredSession('online restore')\n }\n }\n\n const handleOffline = () => {\n log('Network went offline')\n this.isOnline = false\n }\n\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'visible' && this.isSignedIn) {\n log('App became visible - reconciling auth session')\n this.reconcileSession('visibility resume', {\n forceRefresh: true,\n }).catch((err) => {\n log('Session reconciliation on visibility resume failed:', err)\n })\n }\n }\n\n window.addEventListener('online', handleOnline)\n window.addEventListener('offline', handleOffline)\n\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', handleVisibilityChange)\n }\n\n return () => {\n window.removeEventListener('online', handleOnline)\n window.removeEventListener('offline', handleOffline)\n if (typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n }\n }\n }\n\n // ------------------------------------------------------------------\n // Private\n // ------------------------------------------------------------------\n\n private get adminHostname(): string {\n try {\n return new URL(this.config.adminUrl).hostname\n } catch {\n return 'api.basic.tech'\n }\n }\n\n private defaultPdsEndpoints(): PdsEndpoints {\n return {\n pds_url: this.config.pdsUrl,\n authorization_endpoint: `${this.config.pdsUrl}/auth/authorize`,\n token_endpoint: `${this.config.pdsUrl}/auth/token`,\n userinfo_endpoint: `${this.config.pdsUrl}/auth/userinfo`,\n }\n }\n\n private async getActivePdsEndpoints(): Promise<PdsEndpoints> {\n const stored = await this.storage.get(STORAGE_KEYS.PDS_ENDPOINTS)\n if (stored) {\n try {\n return JSON.parse(stored) as PdsEndpoints\n } catch {\n /* fall through */\n }\n }\n return this.defaultPdsEndpoints()\n }\n\n private async reportConnection(accessToken: string): Promise<void> {\n if (!this.config.projectId || !this.config.adminUrl) return\n const lastReport = await this.storage.get(STORAGE_KEYS.LAST_CONNECT_REPORT)\n if (lastReport) {\n const elapsed = Date.now() - parseInt(lastReport, 10)\n if (elapsed < 24 * 60 * 60 * 1000) return\n }\n try {\n await fetch(\n `${this.config.adminUrl}/project/${this.config.projectId}/user/connect`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token: accessToken }),\n },\n )\n await this.storage.set(\n STORAGE_KEYS.LAST_CONNECT_REPORT,\n Date.now().toString(),\n )\n log('Reported connection to admin server')\n } catch (err) {\n log('Failed to report connection (non-blocking):', err)\n }\n }\n\n /**\n * After a new token is stored, decode JWT claims and fetch user info.\n */\n private async processNewToken(): Promise<void> {\n if (!this.token) {\n this.updateAuthStatus('signed_out')\n this.notify()\n return\n }\n\n try {\n const decoded = jwtDecode<JwtClaims>(this.token.access_token)\n this.applyTokenClaims(decoded)\n this.updateAuthStatus('authenticated')\n this.notify()\n this.broadcastSessionUpdate()\n await this.fetchUser(this.token.access_token)\n } catch (error) {\n log('Error processing token:', error)\n this.updateAuthStatus('recovering')\n this.notify()\n }\n }\n\n private async restoreCachedUser(options?: {\n hasRecoverableSession: boolean\n }): Promise<void> {\n const cached = await this.storage.get(STORAGE_KEYS.USER_INFO)\n if (cached && options?.hasRecoverableSession) {\n try {\n this.user = JSON.parse(cached)\n log('Restored cached user info for recoverable session')\n } catch {\n /* corrupted cache, ignore */\n }\n } else {\n this.user = null\n }\n this.updateAuthStatus(\n options?.hasRecoverableSession ? 'recovering' : 'signed_out',\n )\n this.notify()\n }\n\n private async fetchUser(accessToken: string): Promise<void> {\n log('fetching user')\n try {\n const endpoints = await this.getActivePdsEndpoints()\n const response = await fetch(endpoints.userinfo_endpoint, {\n method: 'GET',\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch user info: ${response.status}`)\n }\n\n const user = await response.json()\n\n if (user.error) {\n log('error fetching user', user.error)\n throw new Error(`User info error: ${user.error}`)\n }\n\n if (this.token?.refresh_token) {\n await this.storage.set(\n STORAGE_KEYS.REFRESH_TOKEN,\n this.token.refresh_token,\n )\n }\n\n await this.storage.set(STORAGE_KEYS.USER_INFO, JSON.stringify(user))\n log('Cached user info in storage')\n\n this.user = user\n if (this.authStatus !== 'reauth_required') {\n this.updateAuthStatus('authenticated')\n }\n this.nextUserRecoveryAt = 0\n this.notify()\n } catch (error) {\n log('Failed to fetch user info:', error)\n await this.handleUserFetchFailure()\n }\n }\n\n /**\n * Exchange an auth code or refresh token for an access token.\n * Handles mutex (one in-flight refresh), token validation, and\n * triggers processNewToken on success.\n */\n private async exchangeToken(\n codeOrRefreshToken: string,\n isRefreshToken: boolean,\n ): Promise<Token | null> {\n if (!codeOrRefreshToken || codeOrRefreshToken.trim() === '') {\n const errorMsg = isRefreshToken\n ? 'Refresh token is empty or undefined'\n : 'Authorization code is empty or undefined'\n log('Error:', errorMsg)\n throw new Error(errorMsg)\n }\n\n if (isRefreshToken && this.refreshPromise) {\n log('Reusing in-flight refresh token request')\n return this.refreshPromise\n }\n\n if (!isRefreshToken && this.codeExchangePromise) {\n log('Reusing in-flight code exchange request')\n return this.codeExchangePromise\n }\n\n const tokenPromise = (async (): Promise<Token | null> => {\n try {\n if (!this.isOnline) {\n log('Network is offline, marking refresh as pending')\n this.pendingRefresh = true\n throw new Error(\n 'Network offline - refresh will be retried when online',\n )\n }\n\n const endpoints = await this.getActivePdsEndpoints()\n let requestBody: any\n\n if (isRefreshToken) {\n requestBody = {\n grant_type: 'refresh_token',\n refresh_token: codeOrRefreshToken,\n }\n if (this.config.projectId) {\n requestBody.client_id = normalizeClientId(\n this.config.projectId,\n this.adminHostname,\n )\n }\n } else {\n requestBody = {\n grant_type: 'authorization_code',\n code: codeOrRefreshToken,\n }\n\n const storedRedirectUri = await this.storage.get(\n STORAGE_KEYS.REDIRECT_URI,\n )\n if (storedRedirectUri) {\n requestBody.redirect_uri = storedRedirectUri\n log('Including redirect_uri in token exchange:', storedRedirectUri)\n } else {\n log('Warning: No redirect_uri found in storage for token exchange')\n }\n\n // PKCE: include code_verifier from the authorization request\n const codeVerifier = await this.storage.get(\n STORAGE_KEYS.CODE_VERIFIER,\n )\n if (codeVerifier) {\n requestBody.code_verifier = codeVerifier\n }\n\n if (this.config.projectId) {\n requestBody.client_id = normalizeClientId(\n this.config.projectId,\n this.adminHostname,\n )\n }\n }\n\n log('Token exchange request body:', {\n ...requestBody,\n ...(isRefreshToken\n ? { refresh_token: '[REDACTED]' }\n : { code: '[REDACTED]' }),\n ...(requestBody.code_verifier ? { code_verifier: '[REDACTED]' } : {}),\n })\n\n const response = await fetch(endpoints.token_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n }).catch((error) => {\n log('Network error fetching token:', error)\n if (!this.isOnline) {\n this.pendingRefresh = true\n throw new Error(\n 'Network offline - refresh will be retried when online',\n )\n }\n throw new Error('Network error during token refresh')\n })\n\n // Rate limited (Step 2 auth adds @fastify/rate-limit on /auth/token).\n // Transient by definition: keep the refresh token, retry later.\n if (response.status === 429) {\n log('Token endpoint rate limited (429) - will retry later')\n this.pendingRefresh = true\n throw new Error(\n 'Token endpoint rate limited - refresh will be retried',\n )\n }\n\n const token = await response.json().catch(() => {\n throw new Error(\n `Token endpoint returned invalid JSON (status ${response.status})`,\n )\n })\n\n if (token.access_token) {\n try {\n const decoded = jwtDecode<{ typ?: string }>(token.access_token)\n if (decoded.typ === 'refresh') {\n log('Error: received refresh token as access token')\n throw new Error(\n 'Invalid token: received refresh token instead of access token',\n )\n }\n } catch (decodeError) {\n if ((decodeError as Error).message.includes('Invalid token')) {\n throw decodeError\n }\n log(\n 'Warning: could not decode access token for type check:',\n decodeError,\n )\n }\n }\n\n if (token.error) {\n log('error fetching token', token.error)\n\n if (\n typeof token.error === 'string' &&\n (token.error.includes('network') || token.error.includes('timeout'))\n ) {\n this.pendingRefresh = true\n throw new Error(\n 'Network issue - refresh will be retried when online',\n )\n }\n\n // Only clear stored auth on definitive OAuth rejection.\n // Transient server errors (500, 503, etc.) should NOT wipe\n // the refresh token — the user can retry later.\n if (this.isDefinitiveTokenErrorCode(token.error)) {\n await this.markReauthRequired(token.error)\n throw new DefinitiveAuthError(token.error)\n }\n throw new Error(`Token refresh failed: ${token.error}`)\n } else {\n if (!token.access_token) {\n throw new Error('Token response missing access token')\n }\n this.token = token\n this.pendingRefresh = false\n\n if (token.refresh_token) {\n await this.storage.set(\n STORAGE_KEYS.REFRESH_TOKEN,\n token.refresh_token,\n )\n log('Updated refresh token in storage')\n }\n\n if (!isRefreshToken) {\n await this.storage.remove(STORAGE_KEYS.REDIRECT_URI)\n await this.storage.remove(STORAGE_KEYS.CODE_VERIFIER)\n log(\n 'Cleaned up redirect_uri and code_verifier from storage after successful exchange',\n )\n }\n\n this.reportConnection(token.access_token).catch(() => {})\n\n await this.processNewToken()\n }\n\n return token\n } catch (error) {\n log('Token refresh error:', error)\n if (this.isDefinitiveAuthFailure(error)) {\n log('Preserving cleared auth state after definitive token rejection')\n } else if (this.isNetworkError(error)) {\n log('Recoverable network auth failure - preserving session state')\n } else {\n log('Recoverable auth failure - preserving session state')\n }\n\n throw error\n }\n })()\n\n if (isRefreshToken) {\n this.refreshPromise = tokenPromise\n tokenPromise.finally(() => {\n if (this.refreshPromise === tokenPromise) {\n this.refreshPromise = null\n log('Cleared refresh promise reference')\n }\n })\n } else {\n this.codeExchangePromise = tokenPromise\n tokenPromise.finally(() => {\n if (this.codeExchangePromise === tokenPromise) {\n this.codeExchangePromise = null\n log('Cleared code exchange promise reference')\n }\n })\n }\n\n return tokenPromise\n }\n\n private resetAuthState(status: AuthStatus = 'signed_out'): void {\n this.user = status === 'reauth_required' ? this.user : null\n this.token = null\n if (status !== 'reauth_required') {\n this.did = null\n }\n this.tokenScope = null\n this.nextUserRecoveryAt = 0\n this.updateAuthStatus(status)\n }\n\n private async clearStoredAuth(): Promise<void> {\n await this.storage.remove(STORAGE_KEYS.REFRESH_TOKEN)\n await this.storage.remove(STORAGE_KEYS.USER_INFO)\n await this.storage.remove(STORAGE_KEYS.REDIRECT_URI)\n await this.storage.remove(STORAGE_KEYS.CODE_VERIFIER)\n await this.storage.remove(STORAGE_KEYS.SERVER_URL)\n await this.storage.remove(STORAGE_KEYS.PDS_ENDPOINTS)\n }\n\n private isNetworkError(error: unknown): boolean {\n if (error instanceof TypeError) return true\n if (error instanceof Error) {\n return (\n error.message.includes('offline') ||\n error.message.includes('Network') ||\n // 429 on the token endpoint: transient, keep the session alive\n error.message.includes('rate limited')\n )\n }\n return false\n }\n\n private async getRefreshToken(): Promise<string | null> {\n const storedRefreshToken = await this.storage.get(\n STORAGE_KEYS.REFRESH_TOKEN,\n )\n if (storedRefreshToken) {\n log('Using refresh token from storage')\n if (this.token && this.token.refresh_token !== storedRefreshToken) {\n this.token = { ...this.token, refresh_token: storedRefreshToken }\n }\n return storedRefreshToken\n }\n\n const memoryRefreshToken = this.token?.refresh_token ?? null\n if (memoryRefreshToken) {\n log('Using refresh token from memory fallback')\n } else {\n log('No refresh token available in storage or memory')\n }\n return memoryRefreshToken\n }\n\n private async syncRefreshTokenFromStorage(): Promise<void> {\n const storedRefreshToken = await this.storage.get(\n STORAGE_KEYS.REFRESH_TOKEN,\n )\n if (\n storedRefreshToken &&\n this.token &&\n this.token.refresh_token !== storedRefreshToken\n ) {\n this.token = { ...this.token, refresh_token: storedRefreshToken }\n log('Synced refresh token from shared storage into memory')\n }\n }\n\n private applyTokenClaims(decoded: JwtClaims): void {\n this.did = decoded.sub || null\n this.tokenScope = decoded.scope || null\n }\n\n private broadcastSessionUpdate(): void {\n if (this.freshSignIn) {\n this.freshSignIn = false\n this.broadcastSignIn()\n } else {\n this.broadcastTokenRefresh()\n }\n }\n\n private async handleUserFetchFailure(): Promise<void> {\n if (this.isCompatibleUser(this.user)) {\n log('Preserving existing user after userinfo failure')\n } else if (this.user) {\n log('Discarding stale in-memory user after userinfo failure')\n this.user = null\n }\n\n if (!this.user) {\n const cached = await this.storage.get(STORAGE_KEYS.USER_INFO)\n if (cached) {\n try {\n const parsed = JSON.parse(cached) as User\n if (this.isCompatibleUser(parsed)) {\n this.user = parsed\n log('Recovered cached user after userinfo failure')\n } else {\n log('Cached user did not match the active session')\n }\n } catch (error) {\n log('Failed to parse cached user after userinfo failure:', error)\n }\n }\n }\n\n if (!this.user) {\n log('No compatible cached user available after userinfo failure')\n this.nextUserRecoveryAt = Date.now() + USER_RECOVERY_RETRY_COOLDOWN_MS\n } else {\n this.nextUserRecoveryAt = 0\n }\n\n if (this.authStatus === 'bootstrapping') {\n this.updateAuthStatus(this.token ? 'authenticated' : 'recovering')\n }\n this.notify()\n }\n\n private isCompatibleUser(user: User | null): boolean {\n if (!user) return false\n if (!this.did) return true\n return user.sub === this.did\n }\n\n private async recoverMissingUserProfile(\n reason: string,\n accessToken?: string,\n ): Promise<void> {\n if (!this.isSignedIn || this.user) return\n const now = Date.now()\n if (this.nextUserRecoveryAt > now) {\n log(\n `Skipping user profile recovery on ${reason} until ${new Date(this.nextUserRecoveryAt).toISOString()}`,\n )\n return\n }\n log(`Attempting user profile recovery on ${reason}`)\n const token = accessToken ?? (await this.getToken())\n if (this.user) return\n await this.fetchUser(token)\n }\n\n private isDefinitiveTokenErrorCode(code: unknown): code is string {\n return typeof code === 'string' && DEFINITIVE_TOKEN_ERRORS.has(code)\n }\n\n private isDefinitiveAuthFailure(error: unknown): boolean {\n return error instanceof DefinitiveAuthError\n }\n\n /**\n * Centralised auth status setter. Derives `isSignedIn` and `isAuthReady`\n * from the status so they stay consistent.\n *\n * `isSignedIn` is intentionally `true` during `reauth_required` so the\n * UI layer can still display user info while prompting re-authentication.\n * Consumers should check `authStatus` (or a future convenience getter)\n * when they need to distinguish \"healthy session\" from \"needs re-auth\".\n */\n private updateAuthStatus(\n status: AuthStatus,\n errorCode: string | null = null,\n ): void {\n this.authStatus = status\n this.authErrorCode = errorCode\n this.isSignedIn =\n status === 'authenticated' ||\n status === 'recovering' ||\n status === 'reauth_required'\n this.isAuthReady = status !== 'bootstrapping'\n }\n\n private async clearStoredSessionTokens(): Promise<void> {\n await this.storage.remove(STORAGE_KEYS.REFRESH_TOKEN)\n await this.storage.remove(STORAGE_KEYS.REDIRECT_URI)\n await this.storage.remove(STORAGE_KEYS.CODE_VERIFIER)\n }\n\n private async restoreStoredSession(reason: string): Promise<void> {\n const refreshToken = await this.getRefreshToken()\n if (!refreshToken) {\n log(`No stored refresh token available during ${reason}`)\n await this.restoreCachedUser({ hasRecoverableSession: false })\n return\n }\n\n log(`Restoring stored session during ${reason}`)\n await this.restoreCachedUser({ hasRecoverableSession: true })\n\n if (!this.isOnline) {\n return\n }\n\n this.exchangeToken(refreshToken, true).catch(async (error) => {\n log(`Stored session refresh failed during ${reason}:`, error)\n if (this.isDefinitiveAuthFailure(error)) {\n return\n }\n await this.restoreCachedUser({ hasRecoverableSession: true })\n })\n }\n\n private async handleExternalTokenRefresh(data: {\n accessToken?: string\n did?: string\n tokenScope?: string\n }): Promise<void> {\n await this.syncRefreshTokenFromStorage()\n const refreshToken = await this.getRefreshToken()\n if (data.accessToken && refreshToken) {\n try {\n const decoded = jwtDecode<JwtClaims>(data.accessToken)\n const expiresIn =\n decoded.exp != null\n ? Math.max(0, decoded.exp - Math.floor(Date.now() / 1000))\n : 0\n this.token = {\n access_token: data.accessToken,\n token_type: 'Bearer',\n expires_in: expiresIn,\n refresh_token: refreshToken,\n }\n this.applyTokenClaims(decoded)\n } catch (error) {\n log('Failed to decode token refreshed by another tab:', error)\n this.token = {\n access_token: data.accessToken,\n token_type: 'Bearer',\n expires_in: 0,\n refresh_token: refreshToken,\n }\n }\n if (this.authStatus !== 'reauth_required') {\n this.updateAuthStatus('authenticated')\n }\n } else if (refreshToken) {\n await this.restoreCachedUser({ hasRecoverableSession: true })\n }\n\n if (data.did) this.did = data.did\n if (data.tokenScope) this.tokenScope = data.tokenScope\n this.notify()\n }\n\n private async fetchCurrentSession(\n accessToken: string,\n ): Promise<CurrentSessionInfo | null> {\n const endpoints = await this.getActivePdsEndpoints()\n const response = await fetch(`${endpoints.pds_url}/auth/session`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n const data = (await response.json().catch(() => ({}))) as CurrentSessionInfo\n\n if (response.status === 401 && data.reauth_required) {\n await this.markReauthRequired(data.error || 'invalid_session')\n throw new DefinitiveAuthError(data.error || 'invalid_session')\n }\n\n if (!response.ok) {\n throw new Error(`Failed to reconcile session: ${response.status}`)\n }\n\n return data\n }\n\n private async markReauthRequired(\n code: string,\n options?: { broadcast?: boolean },\n ): Promise<void> {\n log('Marking auth session as requiring reauthentication:', code)\n await this.clearStoredSessionTokens()\n if (!this.user) {\n const cached = await this.storage.get(STORAGE_KEYS.USER_INFO)\n if (cached) {\n try {\n this.user = JSON.parse(cached)\n } catch {\n /* ignore corrupted cache */\n }\n }\n }\n this.token = null\n this.tokenScope = null\n this.nextUserRecoveryAt = 0\n this.updateAuthStatus('reauth_required', code)\n if (options?.broadcast !== false) {\n this.broadcastSessionInvalidated(code)\n }\n this.notify()\n }\n}\n","// Storage utilities for Basic React package\nexport interface BasicStorage {\n get(key: string): Promise<string | null>\n set(key: string, value: string): Promise<void>\n remove(key: string): Promise<void>\n}\n\nexport class LocalStorageAdapter implements BasicStorage {\n async get(key: string): Promise<string | null> {\n return localStorage.getItem(key)\n }\n \n async set(key: string, value: string): Promise<void> {\n localStorage.setItem(key, value)\n }\n \n async remove(key: string): Promise<void> {\n localStorage.removeItem(key)\n }\n}\n\nexport const STORAGE_KEYS = {\n REFRESH_TOKEN: 'basic_refresh_token',\n USER_INFO: 'basic_user_info',\n AUTH_STATE: 'basic_auth_state',\n REDIRECT_URI: 'basic_redirect_uri',\n SERVER_URL: 'basic_server_url',\n PDS_ENDPOINTS: 'basic_pds_endpoints',\n LAST_CONNECT_REPORT: 'basic_last_connect_report',\n DEBUG: 'basic_debug',\n CODE_VERIFIER: 'basic_code_verifier'\n} as const\n\nexport function getCookie(name: string): string {\n let cookieValue = '';\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i]?.trim();\n if (cookie && cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n}\n\nexport function setCookie(name: string, value: string, options?: { secure?: boolean, sameSite?: string, httpOnly?: boolean }): void {\n const opts = {\n secure: true,\n sameSite: 'Strict',\n httpOnly: false,\n ...options\n };\n \n let cookieString = `${name}=${value}`;\n if (opts.secure) cookieString += '; Secure';\n if (opts.sameSite) cookieString += `; SameSite=${opts.sameSite}`;\n if (opts.httpOnly) cookieString += '; HttpOnly';\n \n document.cookie = cookieString;\n}\n\nexport function clearCookie(name: string): void {\n document.cookie = `${name}=; Secure; SameSite=Strict`;\n}\n","const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\n/**\n * Normalize a project_id / client_id to the canonical did:web format\n * before sending it to the PDS.\n *\n * - did:web:... -> passthrough (already canonical)\n * - bare UUID -> did:web:{adminHostname}:projects:{hex}\n * - \"self\" -> passthrough\n */\nexport function normalizeClientId(projectId: string, adminHostname: string = 'api.basic.tech'): string {\n if (!projectId) return projectId\n if (projectId === 'self') return projectId\n if (projectId.startsWith('did:')) return projectId\n\n if (UUID_RE.test(projectId)) {\n const hex = projectId.replace(/-/g, '').toLowerCase()\n return `did:web:${adminHostname}:projects:${hex}`\n }\n\n return projectId\n}\n","export type ResolvedDid = {\n did: string\n handle?: string\n didDocument: Record<string, unknown>\n pdsUrl: string\n authorization_endpoint: string\n token_endpoint: string\n userinfo_endpoint: string\n}\n\n/**\n * Convert a did:web DID to the HTTPS URL where its DID document lives.\n *\n * did:web:pds.basic.id:did:abc123 -> https://pds.basic.id/did/abc123/did.json\n * did:web:example.com -> https://example.com/.well-known/did.json\n */\nexport function resolveDidWebUrl(did: string): string | null {\n if (!did.startsWith('did:web:')) return null\n\n const rest = did.slice(8) // strip 'did:web:'\n if (!rest) return null\n const parts = rest.split(':')\n\n // Decode the hostname (first part, may contain %3A for port)\n const hostname = parts[0]!.replace(/%3A/gi, ':')\n\n if (parts.length === 1) {\n return `https://${hostname}/.well-known/did.json`\n }\n\n const pathParts = parts.slice(1).map(p => decodeURIComponent(p))\n return `https://${hostname}/${pathParts.join('/')}/did.json`\n}\n\n/**\n * Given a DID document, extract PDS URL and discover OAuth endpoints.\n */\nasync function resolveFromDocument(did: string, didDocument: Record<string, unknown>): Promise<ResolvedDid> {\n const services = didDocument.service as Array<{ id: string; type: string; serviceEndpoint: string }> | undefined\n const pdsService = services?.find(\n (s) => s.id === '#basic_pds' || s.id === `${did}#basic_pds`\n )\n if (!pdsService) {\n throw new Error(`DID document has no #basic_pds service entry`)\n }\n const pdsUrl = pdsService.serviceEndpoint.replace(/\\/+$/, '')\n\n const oauthRes = await fetch(`${pdsUrl}/auth/.well-known/openid-configuration`)\n if (!oauthRes.ok) {\n throw new Error(`Failed to fetch OpenID configuration from ${pdsUrl}: ${oauthRes.status}`)\n }\n const oauth = await oauthRes.json()\n\n return {\n did,\n didDocument,\n pdsUrl,\n authorization_endpoint: oauth.authorization_endpoint,\n token_endpoint: oauth.token_endpoint,\n userinfo_endpoint: oauth.userinfo_endpoint,\n }\n}\n\n/**\n * Fetch a DID document by DID, extract the PDS URL, and discover OAuth endpoints.\n */\nexport async function resolveDid(did: string): Promise<ResolvedDid> {\n const url = resolveDidWebUrl(did)\n if (!url) {\n throw new Error(`Unsupported DID method: ${did}`)\n }\n\n const didRes = await fetch(url)\n if (!didRes.ok) {\n throw new Error(`Failed to fetch DID document at ${url}: ${didRes.status}`)\n }\n const didDocument = await didRes.json()\n\n return resolveFromDocument(did, didDocument)\n}\n\n/**\n * Resolve a handle (e.g. \"alice.basic.id\") to a DID and discover PDS + OAuth endpoints.\n *\n * Fetches https://{handle}/.well-known/did.json per the did:web spec.\n */\nexport async function resolveHandle(handle: string): Promise<ResolvedDid> {\n const res = await fetch(`https://${handle}/.well-known/did.json`)\n if (!res.ok) {\n throw new Error(`Handle resolution failed for ${handle}: ${res.status}`)\n }\n const didDocument = await res.json()\n const did = didDocument.id as string\n if (!did) {\n throw new Error(`Handle response has no 'id' field`)\n }\n\n const resolved = await resolveFromDocument(did, didDocument)\n resolved.handle = handle\n return resolved\n}\n","/**\n * RestClient — the REST v2 surface under `/account/:project_id/db/...`.\n *\n * Used by the sync engine for bootstrap (`snapshot`) and pull sync\n * (`changes`), by the shares API, and by the REST-mode table API (CRUD on\n * materialized state). All writes go through the same server-side sync\n * engine as WebSocket pushes — one write path.\n */\nimport type { ChangesPage, Share, Snapshot } from '../sync/protocol'\n\nexport interface GetTokenOptions {\n forceRefresh?: boolean\n}\n\nexport class RestError extends Error {\n readonly status: number\n readonly code?: string\n readonly response?: unknown\n\n constructor(message: string, status: number, code?: string, response?: unknown) {\n super(message)\n this.name = 'RestError'\n this.status = status\n this.code = code\n this.response = response\n }\n}\n\nexport class NotAuthenticatedError extends Error {\n constructor(message: string = 'Not authenticated') {\n super(message)\n this.name = 'NotAuthenticatedError'\n }\n}\n\nexport interface RestClientOptions {\n /** PDS base URL, e.g. `https://pds.basic.id` */\n baseUrl: string\n /** Project id (UUID or DID) — used in `/account/:project_id/...` paths. */\n projectId: string\n getToken: (options?: GetTokenOptions) => Promise<string>\n log?: (...args: unknown[]) => void\n}\n\n/** A record as returned by REST reads: flattened `{ id, ...fields }`. */\nexport type RestRecord = { id: string } & Record<string, unknown>\n\nexport class RestClient {\n private readonly opts: RestClientOptions\n\n constructor(opts: RestClientOptions) {\n this.opts = { ...opts, baseUrl: opts.baseUrl.replace(/\\/$/, '') }\n }\n\n get projectId(): string {\n return this.opts.projectId\n }\n\n // -------------------------------------------------------------------\n // Sync surface\n // -------------------------------------------------------------------\n\n /** `GET /account/:project_id/db` — tables, enforced schema version, channel head. */\n async getDbInfo(): Promise<{\n tables: string[]\n schema_version: string | number | null\n channel: { id: string; head_seq: number; compacted_to_seq: number }\n }> {\n const res = await this.request<{ data: never }>('GET', `${this.dbPath}`)\n return res.data\n }\n\n /** Bootstrap snapshot (SPEC §5). `share` bootstraps a mount; `table` filters. */\n async getSnapshot(options?: { share?: string; table?: string }): Promise<Snapshot> {\n const query = new URLSearchParams()\n if (options?.share) query.set('share', options.share)\n if (options?.table) query.set('table', options.table)\n const qs = query.toString()\n const res = await this.request<{ data: Snapshot }>(\n 'GET',\n `${this.dbPath}/snapshot${qs ? `?${qs}` : ''}`,\n )\n return res.data\n }\n\n /** Pull ordered ops after a cursor — the non-WebSocket sync path. */\n async getChanges(options: {\n cursor: number\n limit?: number\n share?: string\n table?: string\n }): Promise<ChangesPage> {\n const query = new URLSearchParams({ cursor: String(options.cursor) })\n if (options.limit) query.set('limit', String(options.limit))\n if (options.share) query.set('share', options.share)\n if (options.table) query.set('table', options.table)\n const res = await this.request<{ data: ChangesPage }>(\n 'GET',\n `${this.dbPath}/changes?${query.toString()}`,\n )\n return res.data\n }\n\n // -------------------------------------------------------------------\n // Shares (multiplayer v1)\n // -------------------------------------------------------------------\n\n /**\n * Shares granted by and received by the caller. App tokens see only\n * shares involving their own app (the ones they can mount).\n */\n async listShares(): Promise<{ granted: Share[]; received: Share[] }> {\n const res = await this.request<{ data: { granted: Share[]; received: Share[] } }>(\n 'GET',\n '/account/shares',\n )\n return res.data\n }\n\n // -------------------------------------------------------------------\n // CRUD on materialized state (REST-mode table API)\n // -------------------------------------------------------------------\n\n async list(table: string, query?: Record<string, string>): Promise<RestRecord[]> {\n const qs = query ? `?${new URLSearchParams(query).toString()}` : ''\n const res = await this.request<{ data: RestRecord[] }>(\n 'GET',\n `${this.dbPath}/${encodeURIComponent(table)}${qs}`,\n )\n return res.data ?? []\n }\n\n async getRecord(table: string, id: string): Promise<RestRecord | null> {\n try {\n const res = await this.request<{ data: RestRecord }>(\n 'GET',\n `${this.dbPath}/${encodeURIComponent(table)}/${encodeURIComponent(id)}`,\n )\n return res.data ?? null\n } catch (err) {\n if (err instanceof RestError && err.status === 404) return null\n throw err\n }\n }\n\n /** `POST` — server mints the record id. */\n async createRecord(table: string, value: Record<string, unknown>): Promise<RestRecord> {\n const res = await this.request<{ data: RestRecord }>(\n 'POST',\n `${this.dbPath}/${encodeURIComponent(table)}`,\n { value },\n )\n return res.data\n }\n\n /** `PUT` — full replace. REST semantics: 404 for missing records. */\n async putRecord(\n table: string,\n id: string,\n value: Record<string, unknown>,\n ): Promise<RestRecord | null> {\n try {\n const res = await this.request<{ data: RestRecord }>(\n 'PUT',\n `${this.dbPath}/${encodeURIComponent(table)}/${encodeURIComponent(id)}`,\n { value },\n )\n return res.data ?? null\n } catch (err) {\n if (err instanceof RestError && err.status === 404) return null\n throw err\n }\n }\n\n /** `PATCH` — partial merge. 404 → null. */\n async patchRecord(\n table: string,\n id: string,\n value: Record<string, unknown>,\n ): Promise<RestRecord | null> {\n try {\n const res = await this.request<{ data: RestRecord }>(\n 'PATCH',\n `${this.dbPath}/${encodeURIComponent(table)}/${encodeURIComponent(id)}`,\n { value },\n )\n return res.data ?? null\n } catch (err) {\n if (err instanceof RestError && err.status === 404) return null\n throw err\n }\n }\n\n /** `DELETE`. Returns false when the record did not exist. */\n async deleteRecord(table: string, id: string): Promise<boolean> {\n try {\n await this.request(\n 'DELETE',\n `${this.dbPath}/${encodeURIComponent(table)}/${encodeURIComponent(id)}`,\n )\n return true\n } catch (err) {\n if (err instanceof RestError && err.status === 404) return false\n throw err\n }\n }\n\n // -------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------\n\n private get dbPath(): string {\n return `/account/${encodeURIComponent(this.opts.projectId)}/db`\n }\n\n /** Authenticated request; retries once with a force-refreshed token on 401. */\n private async request<R>(\n method: string,\n path: string,\n body?: unknown,\n isRetry: boolean = false,\n ): Promise<R> {\n let token: string\n try {\n token = await this.opts.getToken(isRetry ? { forceRefresh: true } : undefined)\n } catch (err) {\n throw new NotAuthenticatedError(\n err instanceof Error ? err.message : 'could not get access token',\n )\n }\n\n const url = `${this.opts.baseUrl}${path}`\n this.opts.log?.('[rest]', method, url)\n\n const headers: Record<string, string> = { Authorization: `Bearer ${token}` }\n if (body !== undefined) headers['Content-Type'] = 'application/json'\n\n const response = await fetch(url, {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n })\n\n const responseData = (await response.json().catch(() => ({}))) as Record<string, unknown>\n\n if (!response.ok) {\n if (response.status === 401 && !isRetry) {\n this.opts.log?.('[rest] 401 — refreshing token and retrying once')\n return this.request<R>(method, path, body, true)\n }\n const code = typeof responseData.error === 'string' ? responseData.error : undefined\n const message =\n (typeof responseData.message === 'string' && responseData.message) ||\n code ||\n `request failed: ${response.status}`\n throw new RestError(message, response.status, code, responseData)\n }\n\n return responseData as R\n }\n}\n","/**\n * SyncEngine — the six client responsibilities (SYNC_V2.md §15) per\n * subscription, over one multiplexed connection:\n *\n * 1. Store — local materialized records (SyncStore `_server` + views)\n * 2. Pending — locally created ops not yet confirmed (persisted)\n * 3. Cursor — last seq seen, persisted\n * 4. Ordered apply — incoming ops applied in seq order\n * 5. Dedupe/confirm — own ops confirmed by op_id echo; skips re-applies\n * 6. Rebase — app-visible view = serverState + pending, recomputed on change\n *\n * Plus the §9 error contract: terminal op errors are poison (rejected store,\n * never re-pushed); SNAPSHOT_REQUIRED/RESET_REQUIRED re-bootstraps keeping\n * pending ops; SHARE_REVOKED drops the mount; retryables back off.\n *\n * Subscriptions: `own` (the token's app channel) plus one per mounted share.\n * Each has its own SyncStore keyspace — mounted data is never merged with\n * own-channel data (§12.3).\n */\nimport { validateData } from '@basictech/schema'\nimport { SyncConnection, type ConnectionStatus } from './SyncConnection'\nimport { SyncStore, type PendingRow, type RejectedRow } from './SyncStore'\nimport {\n DEFAULT_LIMITS,\n isRebootstrapError,\n isTerminalOpError,\n mintOpId,\n type ErrorMsg,\n type LoggedOp,\n type OpEnvelope,\n type OpType,\n type OpsMsg,\n type PushedMsg,\n type ServerMsg,\n type Snapshot,\n type SubscribedMsg,\n type SyncLimits,\n type WelcomeMsg,\n} from './protocol'\n\nexport type SyncStatus =\n | 'idle'\n | 'local'\n | 'connecting'\n | 'online'\n | 'offline'\n | 'auth_required'\n | 'revoked'\n | 'stopped'\n\nexport const OWN_SUB = 'own'\n\nexport function shareSubKey(shareId: string): string {\n return `share:${shareId}`\n}\n\ninterface PendingEntry {\n op: OpEnvelope\n sent: boolean\n ackedSeq?: number\n}\n\ntype SubStatus = 'initializing' | 'live' | 'revoked' | 'error'\n\nclass BoundedSet {\n private set = new Set<string>()\n private order: string[] = []\n constructor(private readonly cap: number = 2048) {}\n has(value: string): boolean {\n return this.set.has(value)\n }\n add(value: string): void {\n if (this.set.has(value)) return\n this.set.add(value)\n this.order.push(value)\n if (this.order.length > this.cap) {\n const evicted = this.order.shift()\n if (evicted !== undefined) this.set.delete(evicted)\n }\n }\n clear(): void {\n this.set.clear()\n this.order = []\n }\n}\n\nexport interface SubscriptionState {\n key: string\n shareId: string | null\n store: SyncStore\n cursor: number\n pending: PendingEntry[]\n /** Bound on the current socket (subscribed ack received). */\n active: boolean\n bootstrapped: boolean\n status: SubStatus\n revokedCode?: string\n appliedOpIds: BoundedSet\n /** Serializes ops/pushed/bootstrap handling per subscription. */\n chain: Promise<void>\n schemaVersion: string | number | null\n}\n\nexport interface SyncEngineEvents {\n status: SyncStatus\n /** Records changed in a subscription's view (local write or server ops). */\n change: { sub: string; tables: string[] }\n rejected: { sub: string; rejection: RejectedRow }\n /** Sub-level protocol errors (share revoked, re-bootstrapping, ...). */\n suberror: { sub: string; code: string; message?: string }\n /** Connection-level revocation — the app connection is gone. */\n revoked: { code: string; message?: string }\n}\n\nexport interface EngineSchema {\n project_id?: string\n version?: number\n tables: Record<\n string,\n { fields: Record<string, { type: string; required?: boolean; indexed?: boolean }> }\n >\n}\n\nexport interface SyncEngineOptions {\n projectId: string\n schema: EngineSchema\n /** e.g. `wss://pds.basic.id/sync/` */\n wsUrl: string\n getToken: (options?: { forceRefresh?: boolean }) => Promise<string>\n /** Bootstrap fetch (REST snapshot). Injected so the engine stays transport-thin. */\n fetchSnapshot: (options?: { share?: string }) => Promise<Snapshot>\n /** Prefix for IndexedDB database names. Default `basic-sync`. */\n dbNamePrefix?: string\n /**\n * Keyspace segment appended to database names (multi-user: the local user\n * id). `''`/unset = the legacy single-user keyspace.\n */\n keyspaceId?: string\n /**\n * The account DID the current session belongs to, consulted at bootstrap\n * for the owner guard: a keyspace stamped with a different DID is wiped\n * before bootstrapping (never merge one account's local data into\n * another); an unstamped keyspace (anonymous-era data) keeps its pending\n * ops — that is the anonymous → signed-in migration path.\n */\n getOwnerDid?: () => string | null | Promise<string | null>\n /**\n * App name included in `subscribe` messages. Production derives the channel\n * from the token and ignores this; the sync-playground conformance server\n * requires it. Leave unset against production.\n */\n appName?: string\n WebSocketImpl?: typeof WebSocket\n heartbeatMs?: number\n /** Validate writes locally before queueing (mirrors server). Default true. */\n validateWrites?: boolean\n log?: (...args: unknown[]) => void\n}\n\nconst RETRY_FLUSH_DELAY_MS = 1_200\n\nexport class SyncEngine {\n readonly projectId: string\n readonly schema: EngineSchema\n\n private readonly opts: SyncEngineOptions\n private readonly connection: SyncConnection\n private readonly subs = new Map<string, SubscriptionState>()\n private limits: SyncLimits = { ...DEFAULT_LIMITS }\n private actor: string | null = null\n\n /** Own-sub store is open (local reads/writes work). */\n private storesOpen = false\n /** A live connection is wanted (vs. local-only / paused). */\n private connectIntended = false\n private openingLocal: Promise<void> | null = null\n private revokedInfo: { code: string; message?: string } | null = null\n private connectionStatus: ConnectionStatus = 'idle'\n private _status: SyncStatus = 'idle'\n\n private listeners = new Map<keyof SyncEngineEvents, Set<(data: never) => void>>()\n private timers = new Set<ReturnType<typeof setTimeout>>()\n\n constructor(opts: SyncEngineOptions) {\n this.opts = opts\n this.projectId = opts.projectId\n this.schema = opts.schema\n this.connection = new SyncConnection({\n wsUrl: opts.wsUrl,\n getToken: opts.getToken,\n WebSocketImpl: opts.WebSocketImpl,\n heartbeatMs: opts.heartbeatMs,\n onWelcome: (msg) => this.handleWelcome(msg),\n onMessage: (msg) => this.handleMessage(msg),\n onStatus: (status) => this.handleConnectionStatus(status),\n log: opts.log,\n })\n }\n\n // -------------------------------------------------------------------\n // Events\n // -------------------------------------------------------------------\n\n on<E extends keyof SyncEngineEvents>(\n event: E,\n fn: (data: SyncEngineEvents[E]) => void,\n ): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set())\n const set = this.listeners.get(event)! as Set<(data: SyncEngineEvents[E]) => void>\n set.add(fn)\n return () => set.delete(fn)\n }\n\n private emit<E extends keyof SyncEngineEvents>(event: E, data: SyncEngineEvents[E]): void {\n const set = this.listeners.get(event) as Set<(data: SyncEngineEvents[E]) => void> | undefined\n if (!set) return\n for (const fn of set) {\n try {\n fn(data)\n } catch (err) {\n this.log('listener error:', err)\n }\n }\n }\n\n // -------------------------------------------------------------------\n // Public state\n // -------------------------------------------------------------------\n\n get status(): SyncStatus {\n return this._status\n }\n\n get syncLimits(): SyncLimits {\n return { ...this.limits }\n }\n\n get serverActor(): string | null {\n return this.actor\n }\n\n getSubscription(key: string): SubscriptionState | undefined {\n return this.subs.get(key)\n }\n\n get own(): SubscriptionState | undefined {\n return this.subs.get(OWN_SUB)\n }\n\n get pendingCount(): number {\n let n = 0\n for (const sub of this.subs.values()) n += sub.pending.length\n return n\n }\n\n async listRejected(subKey: string = OWN_SUB): Promise<RejectedRow[]> {\n const sub = this.subs.get(subKey)\n if (!sub) return []\n return sub.store.listRejected()\n }\n\n async clearRejected(subKey: string = OWN_SUB): Promise<void> {\n await this.subs.get(subKey)?.store.clearRejected()\n }\n\n // -------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------\n\n /**\n * Open the own-channel keyspace for local reads/writes — no connection,\n * no token needed. This is the anonymous / offline-cold-start entry point.\n * Idempotent.\n */\n async openLocal(): Promise<void> {\n if (this.subs.has(OWN_SUB)) {\n this.storesOpen = true\n this.recomputeStatus()\n return\n }\n if (!this.openingLocal) {\n this.openingLocal = (async () => {\n const sub = await this.openSub(OWN_SUB, null)\n this.subs.set(OWN_SUB, sub)\n this.storesOpen = true\n })().finally(() => {\n this.openingLocal = null\n })\n }\n await this.openingLocal\n this.recomputeStatus()\n }\n\n /**\n * Open the keyspace (if needed) and start syncing. Idempotent.\n * Note: a `CONNECTION_REVOKED` latch is NOT cleared here — reconnecting a\n * revoked app connection requires a fresh consent flow. Call\n * {@link clearRevoked} (or rebind the engine) after re-authorization.\n */\n async connect(): Promise<void> {\n await this.openLocal()\n if (this.revokedInfo) {\n // CONNECTION_REVOKED is terminal per the protocol — never auto-reconnect\n this.log('connect() ignored: app connection is revoked')\n return\n }\n this.connectIntended = true\n this.connection.start()\n this.recomputeStatus()\n }\n\n /** Clear the revocation latch (after the user re-authorized the app). */\n clearRevoked(): void {\n this.revokedInfo = null\n this.recomputeStatus()\n }\n\n /** @deprecated alias of {@link connect} */\n async start(): Promise<void> {\n return this.connect()\n }\n\n /**\n * Disconnect but keep stores open: local reads/writes keep working and\n * ops queue for the next connect. Used on reauth_required.\n */\n pause(): void {\n this.connectIntended = false\n this.connection.stop()\n for (const t of this.timers) clearTimeout(t)\n this.timers.clear()\n for (const sub of this.subs.values()) {\n sub.active = false\n for (const p of sub.pending) {\n p.sent = false\n p.ackedSeq = undefined\n }\n }\n this.recomputeStatus()\n }\n\n /** Close the socket and stores; local data is kept. */\n stop(): void {\n this.connectIntended = false\n this.storesOpen = false\n this.connection.stop()\n for (const t of this.timers) clearTimeout(t)\n this.timers.clear()\n for (const sub of this.subs.values()) {\n sub.active = false\n sub.store.close()\n }\n this.subs.clear()\n this.recomputeStatus()\n }\n\n /**\n * Stop and delete every local database for this project (sign-out).\n * Best-effort discovery of mount keyspaces from previous sessions.\n */\n async destroyLocal(): Promise<void> {\n const open = [...this.subs.values()]\n this.stop()\n for (const sub of open) {\n try {\n await sub.store.destroy()\n } catch (err) {\n this.log('failed deleting local db:', err)\n }\n }\n // stale mount keyspaces from previous sessions. Match exactly this\n // keyspace's base name and its `:share:` mounts — a bare prefix match\n // would delete OTHER users' keyspaces (multi-user).\n try {\n const idb = (globalThis as { indexedDB?: IDBFactory }).indexedDB\n if (idb && typeof idb.databases === 'function') {\n const base = this.baseDbName\n const dbs = await idb.databases()\n for (const info of dbs) {\n if (info.name && (info.name === base || info.name.startsWith(`${base}:share:`))) {\n await new Promise<void>((resolve) => {\n const req = idb.deleteDatabase(info.name!)\n req.onsuccess = req.onerror = req.onblocked = () => resolve()\n })\n }\n }\n }\n } catch {\n /* best effort */\n }\n }\n\n // -------------------------------------------------------------------\n // Shares (mounts)\n // -------------------------------------------------------------------\n\n /**\n * Mount a share: separate keyspace `(project, share)` with its own cursor\n * and pending queue. Bootstraps + subscribes when the socket is online.\n */\n async mountShare(shareId: string): Promise<SubscriptionState> {\n const key = shareSubKey(shareId)\n const existing = this.subs.get(key)\n if (existing) return existing\n\n const sub = await this.openSub(key, shareId)\n this.subs.set(key, sub)\n if (this.connection.isOnline) {\n this.enqueue(sub, () => this.activateSub(sub))\n }\n return sub\n }\n\n /** Unsubscribe a mount. Local cache is kept unless `purge` is set. */\n async unmountShare(shareId: string, options?: { purge?: boolean }): Promise<void> {\n const key = shareSubKey(shareId)\n const sub = this.subs.get(key)\n if (!sub) return\n if (sub.active) {\n this.connection.send({ type: 'unsubscribe', sub: key })\n }\n this.subs.delete(key)\n if (options?.purge) {\n await sub.store.destroy()\n } else {\n sub.store.close()\n }\n }\n\n // -------------------------------------------------------------------\n // Writes (responsibility 2 + 6: pending queue + optimistic rebase)\n // -------------------------------------------------------------------\n\n /**\n * Queue a local op, apply it optimistically, and push when online.\n * Returns the resulting view record (null when deleted).\n * Throws on local validation failure (fail fast — the server would\n * terminally reject it anyway).\n */\n async apply(\n subKey: string,\n partial: { type: OpType; table: string; record_id: string; data?: Record<string, unknown> },\n ): Promise<Record<string, unknown> | null> {\n const sub = this.subs.get(subKey)\n if (!sub) throw new Error(`unknown subscription '${subKey}' — is the engine started?`)\n if (!sub.store.hasTable(partial.table)) {\n throw new Error(`table \"${partial.table}\" not found in schema`)\n }\n\n if (this.opts.validateWrites !== false && partial.type !== 'delete') {\n // mirror the server: put validates required fields, patch does not\n const result = validateData(\n this.schema as Parameters<typeof validateData>[0],\n partial.table,\n partial.data ?? {},\n partial.type === 'put',\n )\n if (!result.valid) {\n throw new Error(result.message || 'data validation failed')\n }\n }\n\n const op: OpEnvelope = {\n op_id: mintOpId(),\n type: partial.type,\n table: partial.table,\n record_id: partial.record_id,\n ...(partial.type !== 'delete' ? { data: partial.data ?? {} } : {}),\n base_seq: Math.max(sub.cursor, 0),\n }\n\n const bytes = JSON.stringify(op).length\n if (bytes > this.limits.max_op_bytes) {\n throw new Error(\n `op exceeds max_op_bytes (${bytes} > ${this.limits.max_op_bytes}) — PAYLOAD_TOO_LARGE`,\n )\n }\n\n let view: Record<string, unknown> | null = null\n await this.enqueue(sub, async () => {\n view = await sub.store.addPending(op)\n sub.pending.push({ op, sent: false })\n })\n this.emit('change', { sub: sub.key, tables: [op.table] })\n this.flush(sub)\n return view\n }\n\n // -------------------------------------------------------------------\n // Connection handling\n // -------------------------------------------------------------------\n\n private handleConnectionStatus(status: ConnectionStatus): void {\n this.connectionStatus = status\n if (\n status === 'offline' ||\n status === 'connecting' ||\n status === 'auth_failed' ||\n status === 'stopped'\n ) {\n for (const sub of this.subs.values()) {\n sub.active = false\n // re-push everything after reconnect; idempotent by op_id\n for (const p of sub.pending) {\n p.sent = false\n p.ackedSeq = undefined\n }\n }\n }\n this.recomputeStatus()\n }\n\n private handleWelcome(msg: WelcomeMsg): void {\n this.actor = msg.actor\n if (msg.limits) this.limits = { ...this.limits, ...msg.limits }\n for (const sub of this.subs.values()) {\n if (sub.status === 'revoked') continue\n this.enqueue(sub, () => this.activateSub(sub))\n }\n }\n\n private handleMessage(msg: ServerMsg): void {\n switch (msg.type) {\n case 'subscribed':\n this.handleSubscribed(msg)\n return\n case 'ops': {\n const sub = this.subs.get(msg.sub)\n if (sub) this.enqueue(sub, () => this.processOps(sub, msg))\n return\n }\n case 'pushed': {\n const sub = this.subs.get(msg.sub)\n if (sub) this.enqueue(sub, () => this.processPushed(sub, msg))\n return\n }\n case 'error':\n this.handleError(msg)\n return\n case 'pong':\n case 'token_ok':\n case 'unsubscribed':\n case 'welcome':\n return\n default:\n // forward compatibility: ignore unknown message types\n return\n }\n }\n\n private handleSubscribed(msg: SubscribedMsg): void {\n const sub = this.subs.get(msg.sub)\n if (!sub) return\n sub.active = true\n sub.status = 'live'\n sub.schemaVersion = msg.schema_version\n this.log(`subscribed '${sub.key}' channel=${msg.channel} cursor=${msg.cursor} head=${msg.head}`)\n this.flush(sub)\n }\n\n private handleError(msg: ErrorMsg): void {\n const subKey = msg.sub\n this.log(`server error${subKey ? ` (sub ${subKey})` : ''}: ${msg.code} — ${msg.message ?? ''}`)\n\n if (subKey) {\n const sub = this.subs.get(subKey)\n if (!sub) return\n this.emit('suberror', { sub: subKey, code: msg.code, message: msg.message })\n\n if (isRebootstrapError(msg.code)) {\n // §5 recovery: discard state, snapshot again, resubscribe — pending\n // survives and is re-pushed (idempotent by op_id)\n sub.active = false\n sub.bootstrapped = false\n for (const p of sub.pending) {\n p.sent = false\n p.ackedSeq = undefined\n }\n this.enqueue(sub, async () => {\n await this.activateSub(sub)\n })\n return\n }\n if (msg.code === 'SHARE_REVOKED' || msg.code === 'CONNECTION_REVOKED') {\n sub.active = false\n sub.status = 'revoked'\n sub.revokedCode = msg.code\n this.subs.delete(subKey)\n // a revoked mount's cache is purged per the guest-side contract\n void sub.store.destroy().catch(() => {})\n return\n }\n return\n }\n\n // connection-level\n switch (msg.code) {\n case 'CONNECTION_REVOKED':\n this.revokedInfo = { code: msg.code, message: msg.message }\n this.connectIntended = false\n this.connection.stop()\n this.recomputeStatus()\n this.emit('revoked', { code: msg.code, message: msg.message })\n return\n case 'UNSUPPORTED_VERSION':\n this.connectIntended = false\n this.connection.stop()\n this.recomputeStatus()\n return\n case 'TOO_MANY_OPS':\n case 'RATE_LIMITED': {\n for (const sub of this.subs.values()) {\n for (const p of sub.pending) {\n if (p.ackedSeq === undefined) p.sent = false\n }\n }\n this.timer(() => {\n for (const sub of this.subs.values()) this.flush(sub)\n }, RETRY_FLUSH_DELAY_MS)\n return\n }\n case 'UNAUTHORIZED':\n case 'TOKEN_EXPIRED':\n // SyncConnection already handles refresh-and-retry\n return\n case 'SNAPSHOT_REQUIRED':\n case 'RESET_REQUIRED':\n // defensive: shouldn't occur without a sub in multiplexed mode\n for (const sub of this.subs.values()) {\n sub.active = false\n sub.bootstrapped = false\n this.enqueue(sub, () => this.activateSub(sub))\n }\n return\n default:\n return\n }\n }\n\n // -------------------------------------------------------------------\n // Subscription state machine (serialized per sub via `chain`)\n // -------------------------------------------------------------------\n\n private async openSub(key: string, shareId: string | null): Promise<SubscriptionState> {\n const name = shareId ? `${this.baseDbName}:share:${shareId}` : this.baseDbName\n const store = new SyncStore(name, this.schema)\n const [cursor, pendingRows] = await Promise.all([store.getCursor(), store.loadPending()])\n return {\n key,\n shareId,\n store,\n cursor: cursor ?? -1, // -1 = never bootstrapped\n pending: pendingRows.map((row: PendingRow) => ({ op: row.op, sent: false })),\n active: false,\n bootstrapped: cursor !== null,\n status: 'initializing',\n appliedOpIds: new BoundedSet(),\n chain: Promise.resolve(),\n schemaVersion: null,\n }\n }\n\n /** Bootstrap if needed, then bind the stream on the current socket. */\n private async activateSub(sub: SubscriptionState): Promise<void> {\n if (!this.connection.isOnline) return\n // Owner guard, pre-subscribe: a keyspace bootstrapped under a different\n // account must never resume its cursor against the new account's channel\n // — force a fresh bootstrap (which wipes on mismatch).\n if (sub.bootstrapped && !sub.shareId && this.opts.getOwnerDid) {\n try {\n const did = (await this.opts.getOwnerDid()) ?? null\n if (did) {\n const stamped = await sub.store.getOwner()\n if (stamped && stamped !== did) sub.bootstrapped = false\n }\n } catch {\n /* guard re-checked in bootstrapSub */\n }\n }\n if (!sub.bootstrapped || sub.cursor < 0) {\n try {\n await this.bootstrapSub(sub)\n } catch (err) {\n this.log(`bootstrap failed for '${sub.key}':`, err)\n sub.status = 'error'\n // retry on next welcome / explicit flush; snapshot failures are\n // usually transient (offline) or auth (handled by connection)\n return\n }\n }\n this.connection.send({\n type: 'subscribe',\n sub: sub.key,\n cursor: sub.cursor,\n ...(sub.shareId\n ? { share: sub.shareId }\n : this.opts.appName\n ? { app: this.opts.appName }\n : {}),\n } as Parameters<SyncConnection['send']>[0])\n }\n\n /** Cold start = snapshot + tail; never log replay (§5). Pending survives. */\n private async bootstrapSub(sub: SubscriptionState): Promise<void> {\n // Owner guard (own channel only): never merge one account's local data\n // into another. An unstamped keyspace (anonymous-era data) keeps its\n // pending ops — flushing them after this bootstrap IS the anonymous →\n // signed-in migration.\n let ownerDid: string | null = null\n if (!sub.shareId && this.opts.getOwnerDid) {\n try {\n ownerDid = (await this.opts.getOwnerDid()) ?? null\n } catch {\n ownerDid = null\n }\n if (ownerDid) {\n const stamped = await sub.store.getOwner()\n if (stamped && stamped !== ownerDid) {\n this.log(\n `keyspace owned by ${stamped} but session is ${ownerDid} — wiping local data before bootstrap`,\n )\n await sub.store.wipeAll()\n sub.pending = []\n sub.appliedOpIds.clear()\n sub.cursor = -1\n }\n }\n }\n\n const snapshot = await this.opts.fetchSnapshot(\n sub.shareId ? { share: sub.shareId } : undefined,\n )\n await sub.store.replaceFromSnapshot({\n channel: snapshot.channel,\n records: snapshot.records ?? {},\n cursor: snapshot.cursor ?? 0,\n })\n if (!sub.shareId && ownerDid) {\n await sub.store.setOwner(ownerDid)\n }\n sub.cursor = snapshot.cursor ?? 0\n sub.bootstrapped = true\n sub.appliedOpIds.clear() // snapshot state subsumes history\n this.log(`bootstrapped '${sub.key}' cursor=${sub.cursor}`)\n this.emit('change', { sub: sub.key, tables: sub.store.tables })\n }\n\n /**\n * Responsibilities 3+4+5: ordered apply, cursor advance, dedupe/confirm.\n * Runs inside the sub's serial chain.\n */\n private async processOps(sub: SubscriptionState, msg: OpsMsg): Promise<void> {\n const applyOps: LoggedOp[] = []\n const confirmedOpIds: string[] = []\n\n for (const op of msg.ops) {\n if (typeof op.seq !== 'number' || op.seq <= sub.cursor) continue // already seen\n sub.cursor = op.seq\n if (sub.appliedOpIds.has(op.op_id)) continue\n const idx = sub.pending.findIndex((p) => p.op.op_id === op.op_id)\n if (idx >= 0) {\n // own op echoed back — confirmation (may arrive before `pushed`)\n sub.pending.splice(idx, 1)\n confirmedOpIds.push(op.op_id)\n }\n if (!sub.store.hasTable(op.table)) {\n // forward compatibility: unknown tables/op shapes advance the cursor only\n sub.appliedOpIds.add(op.op_id)\n continue\n }\n applyOps.push(op)\n sub.appliedOpIds.add(op.op_id)\n }\n\n // empty `ops` may still advance the cursor (filtered tail) — must adopt it\n if (typeof msg.cursor === 'number' && msg.cursor > sub.cursor) {\n sub.cursor = msg.cursor\n }\n\n if (applyOps.length > 0 || confirmedOpIds.length > 0) {\n await sub.store.commitIncoming({ applyOps, confirmedOpIds, cursor: sub.cursor })\n const tables = [...new Set(applyOps.map((op) => op.table))]\n this.emit('change', { sub: sub.key, tables })\n } else {\n await sub.store.setCursor(sub.cursor)\n }\n }\n\n /**\n * Push verdicts (§6.5, §8, §9). Success acks are recorded but the op stays\n * pending until its echo arrives in seq order — this preserves strict\n * ordered apply even when `pushed` races ahead of intermediate remote ops.\n * Terminal errors apply the poison-op rule; retryables back off.\n */\n private async processPushed(sub: SubscriptionState, msg: PushedMsg): Promise<void> {\n let needsRetry = false\n const changedTables = new Set<string>()\n\n for (const result of msg.results) {\n const idx = sub.pending.findIndex((p) => p.op.op_id === result.op_id)\n\n if ('seq' in result && typeof result.seq === 'number') {\n if (idx >= 0) {\n if (result.seq <= sub.cursor) {\n // The op is already part of confirmed history — either its echo\n // was applied or a re-bootstrap snapshot subsumed it (idempotent\n // re-push returned the original seq). The echo will never arrive,\n // so confirm now: drop from pending and rebase the record.\n const [entry] = sub.pending.splice(idx, 1)\n await sub.store.commitIncoming({\n applyOps: [],\n confirmedOpIds: [entry!.op.op_id],\n cursor: sub.cursor,\n })\n changedTables.add(entry!.op.table)\n } else {\n sub.pending[idx]!.ackedSeq = result.seq\n await sub.store.markAcked(result.op_id, result.seq)\n }\n }\n continue\n }\n\n if ('error' in result) {\n if (isTerminalOpError(result.error, result.terminal)) {\n // poison-op rule: out of pending forever, into rejected, surfaced\n if (idx >= 0) sub.pending.splice(idx, 1)\n const rejection = await sub.store.rejectPending(\n result.op_id,\n result.error,\n result.message,\n )\n if (rejection) {\n changedTables.add(rejection.op.table)\n this.emit('rejected', { sub: sub.key, rejection })\n this.log(\n `op rejected (${result.error}): ${rejection.op.type} ${rejection.op.table}/${rejection.op.record_id}`,\n )\n }\n } else if (idx >= 0) {\n sub.pending[idx]!.sent = false\n needsRetry = true\n }\n }\n }\n\n if (changedTables.size > 0) {\n this.emit('change', { sub: sub.key, tables: [...changedTables] })\n }\n if (needsRetry) {\n this.timer(() => this.flush(sub), RETRY_FLUSH_DELAY_MS)\n }\n }\n\n /** Push unsent pending ops, chunked to `limits.max_ops_per_push`. */\n private flush(sub: SubscriptionState): void {\n if (!this.connection.isOnline || !sub.active) return\n const unsent = sub.pending.filter((p) => !p.sent && p.ackedSeq === undefined)\n if (unsent.length === 0) return\n const chunkSize = Math.max(1, this.limits.max_ops_per_push)\n for (let i = 0; i < unsent.length; i += chunkSize) {\n const chunk = unsent.slice(i, i + chunkSize)\n for (const p of chunk) p.sent = true\n const ok = this.connection.send({\n type: 'push',\n sub: sub.key,\n ops: chunk.map((p) => p.op),\n })\n if (!ok) {\n for (const p of chunk) p.sent = false\n return\n }\n }\n this.log(`pushed ${unsent.length} op(s) on '${sub.key}'`)\n }\n\n // -------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------\n\n private get dbPrefix(): string {\n return this.opts.dbNamePrefix ?? 'basic-sync'\n }\n\n /** Base database name for this keyspace (multi-user: includes the user id). */\n private get baseDbName(): string {\n const base = `${this.dbPrefix}:${this.projectId}`\n return this.opts.keyspaceId ? `${base}:${this.opts.keyspaceId}` : base\n }\n\n private enqueue(sub: SubscriptionState, task: () => Promise<void>): Promise<void> {\n sub.chain = sub.chain.then(task).catch((err) => {\n this.log(`task failed on '${sub.key}':`, err)\n })\n return sub.chain\n }\n\n private timer(fn: () => void, ms: number): void {\n const t = setTimeout(() => {\n this.timers.delete(t)\n fn()\n }, ms)\n this.timers.add(t)\n }\n\n private recomputeStatus(): void {\n let status: SyncStatus\n if (this.revokedInfo) status = 'revoked'\n else if (this.connectionStatus === 'auth_failed') status = 'auth_required'\n else if (!this.storesOpen) status = this.connectionStatus === 'stopped' ? 'stopped' : 'idle'\n else if (!this.connectIntended) status = 'local'\n else if (this.connectionStatus === 'online') status = 'online'\n else if (this.connectionStatus === 'connecting') status = 'connecting'\n else if (this.connectionStatus === 'idle') status = 'connecting'\n else if (this.connectionStatus === 'stopped') status = 'local'\n else status = 'offline'\n\n if (status !== this._status) {\n this._status = status\n this.emit('status', status)\n }\n }\n\n private log(...args: unknown[]): void {\n this.opts.log?.('[sync-engine]', ...args)\n }\n}\n","/**\n * Sync/2 wire protocol types — the client side of basic-server's\n * `docs/SYNC_V2.md` contract (protocol version 1).\n *\n * WebSocket endpoint: `wss://<pds>/sync/`\n * HTTP bootstrap: `GET /account/:project_id/db/snapshot`\n * HTTP pull: `GET /account/:project_id/db/changes`\n */\n\nexport const PROTOCOL_VERSION = 1\n\n// ---------------------------------------------------------------------------\n// Ops\n// ---------------------------------------------------------------------------\n\nexport type OpType = 'put' | 'patch' | 'delete'\n\n/** An op as pushed by the client. `op_id` is the client-minted idempotency key. */\nexport interface OpEnvelope {\n op_id: string\n type: OpType\n table: string\n record_id: string\n data?: Record<string, unknown> | null\n /** What the writer had seen when creating the op. Recorded, never enforced (v1). */\n base_seq?: number | null\n}\n\n/** An op as delivered by the server (`ops` message / `changes` endpoint). */\nexport interface LoggedOp extends OpEnvelope {\n seq: number\n /** Server-stamped writer identity — never sent by the client. */\n actor: string\n server_ts: string | number\n}\n\n// ---------------------------------------------------------------------------\n// Error taxonomy (SYNC_V2.md §9)\n// ---------------------------------------------------------------------------\n\nexport type SyncErrorCode =\n // terminal op-level: the input will never succeed; re-pushing is a bug\n | 'SCHEMA_VALIDATION_FAILED'\n | 'UNKNOWN_TABLE'\n | 'RECORD_NOT_FOUND'\n | 'PERMISSION_DENIED'\n | 'PAYLOAD_TOO_LARGE'\n | 'CHANNEL_FULL'\n // retryable\n | 'TOO_MANY_OPS'\n | 'RATE_LIMITED'\n | 'TRY_AGAIN'\n // recovery (re-bootstrap from snapshot, keep pending ops)\n | 'SNAPSHOT_REQUIRED'\n | 'RESET_REQUIRED'\n // auth / lifecycle\n | 'UNAUTHORIZED'\n | 'TOKEN_EXPIRED'\n | 'SHARE_REVOKED'\n | 'CONNECTION_REVOKED'\n | 'UNSUPPORTED_VERSION'\n | 'BAD_MESSAGE'\n\nconst TERMINAL_OP_ERRORS: ReadonlySet<string> = new Set([\n 'SCHEMA_VALIDATION_FAILED',\n 'UNKNOWN_TABLE',\n 'RECORD_NOT_FOUND',\n 'PERMISSION_DENIED',\n 'PAYLOAD_TOO_LARGE',\n 'CHANNEL_FULL',\n 'BAD_MESSAGE',\n])\n\n/** Terminal = poison-op rule applies: park in rejected store, never re-push. */\nexport function isTerminalOpError(code: string | undefined, terminalFlag?: boolean): boolean {\n if (terminalFlag !== undefined) return terminalFlag\n return code !== undefined && TERMINAL_OP_ERRORS.has(code)\n}\n\n/** Errors that mean \"discard channel state, re-bootstrap from snapshot, resubscribe\". */\nexport function isRebootstrapError(code: string): boolean {\n return code === 'SNAPSHOT_REQUIRED' || code === 'RESET_REQUIRED'\n}\n\n/** Errors that mean the subscription is gone and must not be retried. */\nexport function isRevocationError(code: string): boolean {\n return code === 'SHARE_REVOKED' || code === 'CONNECTION_REVOKED'\n}\n\n/** Errors that mean the token was rejected; reauth then reconnect. */\nexport function isAuthError(code: string): boolean {\n return code === 'UNAUTHORIZED' || code === 'TOKEN_EXPIRED'\n}\n\n// ---------------------------------------------------------------------------\n// Limits (advertised in `welcome.limits`; authoritative)\n// ---------------------------------------------------------------------------\n\nexport interface SyncLimits {\n max_ops_per_push: number\n max_op_bytes: number\n replay_limit: number\n}\n\nexport const DEFAULT_LIMITS: SyncLimits = {\n max_ops_per_push: 500,\n max_op_bytes: 64 * 1024,\n replay_limit: 1000,\n}\n\n// ---------------------------------------------------------------------------\n// Client → server messages\n// ---------------------------------------------------------------------------\n\n/**\n * First message on the socket. Sending only `{version, token}` opens a\n * multiplexed session (auth-only welcome); streams are then bound with\n * explicit `subscribe` messages. (The legacy single-subscription handshake\n * with `cursor`/`share` on the hello is not used by this client.)\n */\nexport interface HelloMsg {\n type: 'hello'\n version: number\n token: string\n}\n\nexport interface SubscribeFilter {\n table: string\n record_ids?: string[]\n}\n\nexport interface SubscribeMsg {\n type: 'subscribe'\n sub: string\n /** Last seq seen. Required — a null/absent cursor gets SNAPSHOT_REQUIRED. */\n cursor: number\n /** Mount a share instead of the token's own channel. */\n share?: string\n /** Narrow an own-channel subscription (partial sync). */\n filter?: SubscribeFilter\n}\n\nexport interface UnsubscribeMsg {\n type: 'unsubscribe'\n sub: string\n}\n\nexport interface PushMsg {\n type: 'push'\n sub: string\n ops: OpEnvelope[]\n}\n\nexport interface PingMsg {\n type: 'ping'\n cursor?: number\n}\n\n/** Refresh auth on a live socket without reconnecting. */\nexport interface TokenMsg {\n type: 'token'\n token: string\n}\n\nexport type ClientMsg =\n | HelloMsg\n | SubscribeMsg\n | UnsubscribeMsg\n | PushMsg\n | PingMsg\n | TokenMsg\n\n// ---------------------------------------------------------------------------\n// Server → client messages\n// ---------------------------------------------------------------------------\n\n/** Multiplexed handshake: auth-only welcome (`channel`/`cursor` absent). */\nexport interface WelcomeMsg {\n type: 'welcome'\n actor: string\n limits: SyncLimits\n channel?: string\n cursor?: number\n head?: number\n schema_version?: string | number | null\n}\n\nexport interface SubscribedMsg {\n type: 'subscribed'\n sub: string\n channel: string\n cursor: number\n head: number\n schema_version: string | number | null\n}\n\nexport interface UnsubscribedMsg {\n type: 'unsubscribed'\n sub: string\n}\n\nexport interface OpsMsg {\n type: 'ops'\n sub: string\n /** May be empty — a filtered tail still advances `cursor`; always adopt it. */\n ops: LoggedOp[]\n cursor: number\n}\n\nexport type PushResult =\n | { op_id: string; seq: number }\n | { op_id: string; error: SyncErrorCode; terminal?: boolean; message?: string }\n\nexport interface PushedMsg {\n type: 'pushed'\n sub: string\n results: PushResult[]\n /** Channel head after commit. Absent when nothing was committed. */\n cursor?: number\n}\n\nexport interface PongMsg {\n type: 'pong'\n head: number\n heads?: Record<string, number>\n}\n\nexport interface TokenOkMsg {\n type: 'token_ok'\n}\n\nexport interface ErrorMsg {\n type: 'error'\n code: SyncErrorCode\n message?: string\n terminal?: boolean\n /** Present when the error concerns one subscription on a multiplexed socket. */\n sub?: string\n}\n\nexport type ServerMsg =\n | WelcomeMsg\n | SubscribedMsg\n | UnsubscribedMsg\n | OpsMsg\n | PushedMsg\n | PongMsg\n | TokenOkMsg\n | ErrorMsg\n\n// ---------------------------------------------------------------------------\n// HTTP shapes\n// ---------------------------------------------------------------------------\n\n/** `GET /account/:project_id/db/snapshot` → `{ data: Snapshot }` */\nexport interface Snapshot {\n channel: string\n /** table → record_id → field values (tombstones excluded, no `id` field). */\n records: Record<string, Record<string, Record<string, unknown>>>\n /** Head seq the snapshot is consistent with. */\n cursor: number\n}\n\n/** `GET /account/:project_id/db/changes` → `{ data: ChangesPage }` */\nexport interface ChangesPage {\n ops: LoggedOp[]\n cursor: number\n more: boolean\n}\n\nexport type SharePermission = 'read' | 'write'\n\nexport interface ShareSelector {\n table: string\n record_ids?: string[] | null\n}\n\n/** A share row as returned by `GET /account/shares`. */\nexport interface Share {\n id: string\n account_id: string\n channel_id: string\n grantee: string\n selector: ShareSelector\n permission: SharePermission\n created_at: string\n expires_at: string | null\n revoked_at: string | null\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Client-minted op id (idempotency key). */\nexport function mintOpId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n // non-secure-context fallback\n return 'op-' + Math.random().toString(36).slice(2) + Date.now().toString(36)\n}\n\n/** JSON-safe deep clone (op payloads are JSON by construction). */\nexport function cloneData<T>(value: T): T {\n return value === undefined ? value : JSON.parse(JSON.stringify(value))\n}\n\n/**\n * Apply one op to a record's field data. Returns the new data, or `undefined`\n * when the record does not exist (deleted / never created).\n *\n * - `put`: create or replace the whole record\n * - `patch`: shallow-merge top-level fields; no effect on a missing record\n * - `delete`: tombstone (idempotent)\n */\nexport function applyOpToData(\n existing: Record<string, unknown> | undefined,\n op: OpEnvelope,\n): Record<string, unknown> | undefined {\n switch (op.type) {\n case 'put':\n return cloneData(op.data ?? {}) as Record<string, unknown>\n case 'patch':\n if (existing === undefined) return undefined\n return { ...existing, ...(cloneData(op.data ?? {}) as Record<string, unknown>) }\n case 'delete':\n return undefined\n }\n}\n","/**\n * SyncConnection — one multiplexed WebSocket to `wss://<pds>/sync/`\n * (SYNC_V2.md §6.9: one socket, many streams).\n *\n * Owns the transport only: hello handshake, heartbeat ping, exponential\n * backoff reconnect, and token refresh on auth rejection. Everything above\n * the socket (subscriptions, cursors, pending queues) belongs to SyncEngine,\n * which receives every parsed server message via `onMessage`.\n */\nimport {\n PROTOCOL_VERSION,\n isAuthError,\n type ClientMsg,\n type ServerMsg,\n type WelcomeMsg,\n} from './protocol'\n\nexport type ConnectionStatus =\n | 'idle'\n | 'connecting'\n | 'online'\n | 'offline'\n | 'auth_failed'\n | 'stopped'\n\nexport interface SyncConnectionOptions {\n /** e.g. `wss://pds.basic.id/sync/` */\n wsUrl: string\n getToken: (options?: { forceRefresh?: boolean }) => Promise<string>\n /** Pass the `ws` constructor in Node; defaults to global WebSocket. */\n WebSocketImpl?: typeof WebSocket\n /** Heartbeat interval (default 30s per spec). */\n heartbeatMs?: number\n onWelcome: (msg: WelcomeMsg) => void\n onMessage: (msg: ServerMsg) => void\n onStatus: (status: ConnectionStatus) => void\n log?: (...args: unknown[]) => void\n}\n\nconst INITIAL_RECONNECT_DELAY_MS = 500\nconst MAX_RECONNECT_DELAY_MS = 30_000\n\nexport class SyncConnection {\n private readonly opts: SyncConnectionOptions\n private readonly WS: typeof WebSocket\n private readonly heartbeatMs: number\n\n private ws: WebSocket | null = null\n private _status: ConnectionStatus = 'idle'\n private stopped = true\n private reconnectDelay = INITIAL_RECONNECT_DELAY_MS\n private timers = new Set<ReturnType<typeof setTimeout>>()\n private heartbeatTimer: ReturnType<typeof setTimeout> | null = null\n /** One forced-refresh reconnect attempt per auth rejection. */\n private authRetryUsed = false\n private removeOnlineListener: (() => void) | null = null\n\n constructor(opts: SyncConnectionOptions) {\n this.opts = opts\n this.WS = opts.WebSocketImpl ?? (globalThis.WebSocket as typeof WebSocket)\n this.heartbeatMs = opts.heartbeatMs ?? 30_000\n }\n\n get status(): ConnectionStatus {\n return this._status\n }\n\n get isOnline(): boolean {\n return this._status === 'online' && this.ws?.readyState === 1\n }\n\n start(): void {\n if (!this.stopped && this.ws) return\n this.stopped = false\n this.authRetryUsed = false\n this.listenForNetwork()\n this.open()\n }\n\n stop(): void {\n this.stopped = true\n this.clearTimers()\n this.removeOnlineListener?.()\n this.removeOnlineListener = null\n if (this.ws) {\n try {\n this.ws.close()\n } catch {\n /* ignore */\n }\n this.ws = null\n }\n this.setStatus('stopped')\n }\n\n /** Send a message; returns false when the socket is not open. */\n send(msg: ClientMsg): boolean {\n if (this.ws?.readyState === 1) {\n this.ws.send(JSON.stringify(msg))\n return true\n }\n return false\n }\n\n /** Refresh auth on the live socket (no reconnect). */\n async sendToken(): Promise<void> {\n if (!this.isOnline) return\n try {\n const token = await this.opts.getToken()\n this.send({ type: 'token', token })\n } catch {\n /* token unavailable; auth errors will surface through the socket */\n }\n }\n\n /**\n * The server rejected our token (`UNAUTHORIZED` / `TOKEN_EXPIRED` + close).\n * Retry once with a force-refreshed token; give up (status `auth_failed`)\n * when the refresh itself fails or a fresh token is rejected again.\n */\n handleAuthRejection(): void {\n if (this.stopped) return\n if (this.authRetryUsed) {\n this.log('fresh token rejected — giving up until reauth')\n this.stopped = true\n this.clearTimers()\n this.setStatus('auth_failed')\n return\n }\n this.authRetryUsed = true\n this.log('token rejected — force refreshing and reconnecting')\n void (async () => {\n try {\n await this.opts.getToken({ forceRefresh: true })\n this.scheduleReconnect(0)\n } catch (err) {\n this.log('token refresh failed after auth rejection:', err)\n this.stopped = true\n this.setStatus('auth_failed')\n }\n })()\n }\n\n // -------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------\n\n private open(): void {\n if (this.stopped) return\n if (this.ws && (this.ws.readyState === 0 || this.ws.readyState === 1)) return\n if (!this.WS) {\n this.log('no WebSocket implementation available')\n this.setStatus('offline')\n return\n }\n this.setStatus('connecting')\n\n const ws = new this.WS(this.opts.wsUrl)\n this.ws = ws\n\n ws.onopen = () => {\n void (async () => {\n try {\n const token = await this.opts.getToken()\n if (this.ws !== ws || ws.readyState !== 1) return\n const hello = { type: 'hello', version: PROTOCOL_VERSION, token } satisfies ClientMsg\n ws.send(JSON.stringify(hello))\n } catch (err) {\n this.log('could not get token for hello:', err)\n try {\n ws.close()\n } catch {\n /* ignore */\n }\n }\n })()\n }\n\n ws.onmessage = (event: MessageEvent) => {\n let msg: ServerMsg\n try {\n const text =\n typeof event.data === 'string' ? event.data : new TextDecoder().decode(event.data)\n msg = JSON.parse(text)\n } catch {\n return\n }\n this.handleMessage(msg)\n }\n\n ws.onclose = () => {\n if (this.ws !== ws) return\n this.ws = null\n this.stopHeartbeat()\n if (this.stopped) return\n this.setStatus('offline')\n this.scheduleReconnect()\n }\n\n ws.onerror = () => {\n /* onclose follows */\n }\n }\n\n private handleMessage(msg: ServerMsg): void {\n if (msg.type === 'welcome') {\n this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS\n this.authRetryUsed = false\n this.setStatus('online')\n this.startHeartbeat()\n this.opts.onWelcome(msg)\n return\n }\n if (msg.type === 'error' && !('sub' in msg && msg.sub) && isAuthError(msg.code)) {\n // connection-level auth rejection; the server closes the socket\n this.handleAuthRejection()\n this.opts.onMessage(msg)\n return\n }\n this.opts.onMessage(msg)\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n const tick = () => {\n if (this.stopped) return\n this.send({ type: 'ping' })\n this.heartbeatTimer = setTimeout(tick, this.heartbeatMs)\n this.timers.add(this.heartbeatTimer)\n }\n this.heartbeatTimer = setTimeout(tick, this.heartbeatMs)\n this.timers.add(this.heartbeatTimer)\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer)\n this.timers.delete(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n }\n\n private scheduleReconnect(delayOverride?: number): void {\n if (this.stopped) return\n const delay = delayOverride ?? this.reconnectDelay\n this.reconnectDelay = Math.min(this.reconnectDelay * 2, MAX_RECONNECT_DELAY_MS)\n this.log(`reconnecting in ${delay}ms`)\n const timer = setTimeout(() => {\n this.timers.delete(timer)\n this.open()\n }, delay)\n this.timers.add(timer)\n }\n\n private listenForNetwork(): void {\n if (this.removeOnlineListener || typeof window === 'undefined') return\n const handleOnline = () => {\n if (this.stopped) return\n this.log('network online — reconnecting immediately')\n this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS\n this.open()\n }\n window.addEventListener('online', handleOnline)\n this.removeOnlineListener = () => window.removeEventListener('online', handleOnline)\n }\n\n private clearTimers(): void {\n for (const t of this.timers) clearTimeout(t)\n this.timers.clear()\n this.heartbeatTimer = null\n }\n\n private setStatus(status: ConnectionStatus): void {\n if (this._status === status) return\n this._status = status\n this.opts.onStatus(status)\n }\n\n private log(...args: unknown[]): void {\n this.opts.log?.('[sync-connection]', ...args)\n }\n}\n","/**\n * SyncStore — persistent local state for one sync keyspace (an own channel or\n * a mounted share), backed by plain Dexie/IndexedDB.\n *\n * Layout (one Dexie database per keyspace):\n * - one **view** store per app table: `{ id, ...fields }` — what the app\n * reads (server state + pending ops rebased). `useQuery`/liveQuery reads\n * these stores directly.\n * - `_server`: confirmed records only, keyed `[table+record_id]`.\n * - `_pending`: queued local ops (survive restarts), insertion-ordered.\n * - `_rejected`: terminally rejected ops (poison-op rule — never re-pushed).\n * - `_meta`: cursor, channel id, limits, schema version.\n *\n * The app-visible view is always `serverState + pending applied in order`\n * (client responsibility #6). Rebasing is done per affected record inside\n * the same transaction as the change that triggered it.\n */\nimport Dexie, { type Table } from 'dexie'\nimport {\n applyOpToData,\n cloneData,\n type LoggedOp,\n type OpEnvelope,\n type SyncErrorCode,\n} from './protocol'\n\nexport interface ServerRow {\n table: string\n record_id: string\n data: Record<string, unknown>\n}\n\nexport interface PendingRow {\n /** Auto-increment — preserves creation order across restarts. */\n idx?: number\n op_id: string\n op: OpEnvelope\n /** Set when the server acked the op (`pushed` seq) but the echo hasn't arrived yet. */\n acked_seq?: number\n}\n\nexport interface RejectedRow {\n idx?: number\n op_id: string\n op: OpEnvelope\n error: SyncErrorCode | string\n message?: string\n rejected_at: number\n}\n\ninterface MetaRow {\n key: string\n value: unknown\n}\n\nconst META_CURSOR = 'cursor'\nconst META_CHANNEL = 'channel'\nconst META_OWNER = 'owner_did'\n\nexport interface SyncStoreSchema {\n version?: number\n tables: Record<string, { fields: Record<string, { indexed?: boolean }> }>\n}\n\nexport class SyncStore {\n readonly db: Dexie\n readonly name: string\n private readonly tableNames: string[]\n\n constructor(name: string, schema: SyncStoreSchema) {\n this.name = name\n this.tableNames = Object.keys(schema.tables)\n this.db = new Dexie(name)\n\n const stores: Record<string, string> = {\n _server: '[table+record_id], table',\n _pending: '++idx, op_id',\n _rejected: '++idx, op_id',\n _meta: 'key',\n }\n for (const [tableName, table] of Object.entries(schema.tables)) {\n const indexed = Object.entries(table.fields)\n .filter(([, f]) => f.indexed)\n .map(([fieldName]) => `,${fieldName}`)\n .join('')\n stores[tableName] = 'id' + indexed\n }\n // Dexie versions must be monotonic; app schema versions are (enforced by\n // @basictech/schema validateUpdateSchema), so reuse them.\n this.db.version(Math.max(schema.version ?? 1, 1)).stores(stores)\n }\n\n /** The Dexie view table for an app table (what liveQuery reads). */\n view(table: string): Table<Record<string, unknown>, string> {\n return this.db.table(table)\n }\n\n hasTable(table: string): boolean {\n return this.tableNames.includes(table)\n }\n\n get tables(): string[] {\n return [...this.tableNames]\n }\n\n private get server(): Table<ServerRow, [string, string]> {\n return this.db.table('_server')\n }\n private get pending(): Table<PendingRow, number> {\n return this.db.table('_pending')\n }\n private get rejected(): Table<RejectedRow, number> {\n return this.db.table('_rejected')\n }\n private get meta(): Table<MetaRow, string> {\n return this.db.table('_meta')\n }\n\n private get allStores(): string[] {\n return ['_server', '_pending', '_rejected', '_meta', ...this.tableNames]\n }\n\n // -------------------------------------------------------------------\n // Meta\n // -------------------------------------------------------------------\n\n async getCursor(): Promise<number | null> {\n const row = await this.meta.get(META_CURSOR)\n return typeof row?.value === 'number' ? row.value : null\n }\n\n async getChannel(): Promise<string | null> {\n const row = await this.meta.get(META_CHANNEL)\n return typeof row?.value === 'string' ? row.value : null\n }\n\n /**\n * The account DID this keyspace's confirmed data belongs to. Absent for\n * anonymous-era data (which may be merged into whichever account signs in).\n */\n async getOwner(): Promise<string | null> {\n const row = await this.meta.get(META_OWNER)\n return typeof row?.value === 'string' ? row.value : null\n }\n\n async setOwner(did: string): Promise<void> {\n await this.meta.put({ key: META_OWNER, value: did })\n }\n\n /**\n * Clear everything (views, server state, pending, rejected, meta) without\n * deleting the database — used when the keyspace changes owners.\n */\n async wipeAll(): Promise<void> {\n await this.db.transaction('rw', this.allStores, async () => {\n await this.server.clear()\n await this.pending.clear()\n await this.rejected.clear()\n await this.meta.clear()\n for (const tableName of this.tableNames) {\n await this.view(tableName).clear()\n }\n })\n }\n\n // -------------------------------------------------------------------\n // Pending / rejected\n // -------------------------------------------------------------------\n\n /** All pending ops in creation order (used to warm the in-memory queue). */\n async loadPending(): Promise<PendingRow[]> {\n return this.pending.orderBy('idx').toArray()\n }\n\n async listRejected(): Promise<RejectedRow[]> {\n return this.rejected.orderBy('idx').toArray()\n }\n\n async clearRejected(): Promise<void> {\n await this.rejected.clear()\n }\n\n /** Record a server ack for a pending op (echo not yet seen). */\n async markAcked(opId: string, seq: number): Promise<void> {\n await this.pending.where('op_id').equals(opId).modify({ acked_seq: seq })\n }\n\n // -------------------------------------------------------------------\n // Writes\n // -------------------------------------------------------------------\n\n /**\n * Enqueue a local op and apply it optimistically to the view.\n * Returns the resulting view record (null when the op deletes it).\n */\n async addPending(op: OpEnvelope): Promise<Record<string, unknown> | null> {\n return this.db.transaction('rw', this.allStores, async () => {\n await this.pending.add({ op_id: op.op_id, op: cloneData(op) })\n return this.recomputeViewRecord(op.table, op.record_id)\n })\n }\n\n /**\n * Commit a batch of incoming server ops (already filtered/deduped by the\n * engine): update `_server`, drop confirmed pending ops, advance the\n * cursor, and rebase every affected view record — in one transaction.\n */\n async commitIncoming(params: {\n applyOps: LoggedOp[]\n confirmedOpIds: string[]\n cursor: number\n }): Promise<void> {\n const { applyOps, confirmedOpIds, cursor } = params\n await this.db.transaction('rw', this.allStores, async () => {\n const affected = new Set<string>()\n for (const op of applyOps) affected.add(`${op.table}\\u0000${op.record_id}`)\n\n for (const op of applyOps) {\n await this.applyToServer(op)\n }\n if (confirmedOpIds.length > 0) {\n // confirmed ops outside applyOps (already subsumed by a snapshot or\n // an earlier echo) still need their records rebased once the pending\n // row is gone — collect them before deleting\n const confirmedRows = await this.pending.where('op_id').anyOf(confirmedOpIds).toArray()\n for (const row of confirmedRows) affected.add(`${row.op.table}\\u0000${row.op.record_id}`)\n await this.pending.where('op_id').anyOf(confirmedOpIds).delete()\n }\n await this.meta.put({ key: META_CURSOR, value: cursor })\n\n for (const key of affected) {\n const [table, recordId] = key.split('\\u0000') as [string, string]\n await this.recomputeViewRecord(table, recordId)\n }\n })\n }\n\n /** Persist a cursor advance with no ops (empty `ops` message / pushed cursor). */\n async setCursor(cursor: number): Promise<void> {\n await this.meta.put({ key: META_CURSOR, value: cursor })\n }\n\n /**\n * Terminal rejection: remove from pending, park in the rejected store,\n * roll the view record back to server state + remaining pending ops.\n */\n async rejectPending(\n opId: string,\n error: SyncErrorCode | string,\n message?: string,\n ): Promise<RejectedRow | null> {\n return this.db.transaction('rw', this.allStores, async () => {\n const row = await this.pending.where('op_id').equals(opId).first()\n if (!row) return null\n await this.pending.where('op_id').equals(opId).delete()\n const rejectedRow: RejectedRow = {\n op_id: opId,\n op: row.op,\n error,\n message,\n rejected_at: Date.now(),\n }\n await this.rejected.add(rejectedRow)\n await this.recomputeViewRecord(row.op.table, row.op.record_id)\n return rejectedRow\n })\n }\n\n // -------------------------------------------------------------------\n // Bootstrap\n // -------------------------------------------------------------------\n\n /**\n * Replace all server state from a snapshot (cold start or\n * SNAPSHOT_REQUIRED/RESET_REQUIRED recovery). Pending ops survive and are\n * re-applied on top of the fresh state.\n */\n async replaceFromSnapshot(params: {\n channel: string\n records: Record<string, Record<string, Record<string, unknown>>>\n cursor: number\n }): Promise<void> {\n const { channel, records, cursor } = params\n await this.db.transaction('rw', this.allStores, async () => {\n await this.server.clear()\n for (const tableName of this.tableNames) {\n await this.view(tableName).clear()\n }\n\n for (const [tableName, tableRecords] of Object.entries(records)) {\n if (!this.hasTable(tableName)) continue\n const serverRows: ServerRow[] = []\n const viewRows: Record<string, unknown>[] = []\n for (const [recordId, data] of Object.entries(tableRecords)) {\n serverRows.push({ table: tableName, record_id: recordId, data: data ?? {} })\n viewRows.push({ id: recordId, ...(data ?? {}) })\n }\n await this.server.bulkPut(serverRows)\n await this.view(tableName).bulkPut(viewRows)\n }\n\n // rebase pending ops on top of the fresh snapshot\n const pendingRows = await this.pending.orderBy('idx').toArray()\n const affected = new Set<string>()\n for (const row of pendingRows) affected.add(`${row.op.table}\\u0000${row.op.record_id}`)\n for (const key of affected) {\n const [table, recordId] = key.split('\\u0000') as [string, string]\n if (this.hasTable(table)) await this.recomputeViewRecord(table, recordId)\n }\n\n await this.meta.put({ key: META_CURSOR, value: cursor })\n await this.meta.put({ key: META_CHANNEL, value: channel })\n })\n }\n\n // -------------------------------------------------------------------\n // Reads\n // -------------------------------------------------------------------\n\n async getViewRecord(table: string, id: string): Promise<Record<string, unknown> | null> {\n const record = await this.view(table).get(id)\n return record ?? null\n }\n\n async getViewRecords(table: string): Promise<Record<string, unknown>[]> {\n return this.view(table).toArray()\n }\n\n // -------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------\n\n close(): void {\n this.db.close()\n }\n\n /** Delete the underlying IndexedDB database (sign-out / revoked mount). */\n async destroy(): Promise<void> {\n this.db.close()\n await Dexie.delete(this.name)\n }\n\n // -------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------\n\n private async applyToServer(op: LoggedOp): Promise<void> {\n if (!this.hasTable(op.table)) return\n const existing = await this.server.get([op.table, op.record_id])\n const next = applyOpToData(existing?.data, op)\n if (next === undefined) {\n await this.server.delete([op.table, op.record_id])\n } else {\n await this.server.put({ table: op.table, record_id: op.record_id, data: next })\n }\n }\n\n /**\n * Rebase one record: view = server data + pending ops for that record in\n * creation order. Must run inside a transaction covering all stores.\n */\n private async recomputeViewRecord(\n table: string,\n recordId: string,\n ): Promise<Record<string, unknown> | null> {\n if (!this.hasTable(table)) return null\n const serverRow = await this.server.get([table, recordId])\n let data: Record<string, unknown> | undefined = serverRow\n ? cloneData(serverRow.data)\n : undefined\n\n const pendingRows = await this.pending.orderBy('idx').toArray()\n for (const row of pendingRows) {\n if (row.op.table === table && row.op.record_id === recordId) {\n data = applyOpToData(data, row.op)\n }\n }\n\n if (data === undefined) {\n await this.view(table).delete(recordId)\n return null\n }\n const viewRecord = { id: recordId, ...data }\n await this.view(table).put(viewRecord)\n return viewRecord\n }\n}\n","/**\n * The table API — the app-facing database surface, shaped around Sync/2 ops.\n *\n * Two implementations of the same interface:\n * - `SyncDb` — offline-first over a SyncEngine subscription (own channel or\n * a mounted share). Writes queue ops and apply optimistically; reads hit\n * the local Dexie view stores (which `useQuery`/liveQuery observe).\n * - `RestDb` — direct REST calls, no local persistence (for server-ish\n * contexts or apps that don't want a local replica).\n */\nimport type { Table } from 'dexie'\nimport { SyncEngine, OWN_SUB } from './sync/SyncEngine'\nimport { mintOpId } from './sync/protocol'\nimport { RestClient, type RestRecord } from './http/RestClient'\n\nexport type BasicRecord = { id: string } & Record<string, unknown>\n\nexport interface BasicTable<T extends BasicRecord = BasicRecord> {\n /** Create a record. Sync mode mints the id locally; REST mode server-side. */\n create(data: Omit<T, 'id'>): Promise<T>\n /** Create or replace the whole record (Sync/2 `put` op). */\n put(id: string, data: Omit<T, 'id'>): Promise<T>\n /** Shallow-merge top-level fields (`patch` op). Returns null when missing. */\n patch(id: string, data: Partial<Omit<T, 'id'>>): Promise<T | null>\n /** Delete (tombstone). Idempotent. */\n delete(id: string): Promise<void>\n get(id: string): Promise<T | null>\n getAll(): Promise<T[]>\n find(predicate: (record: T) => boolean): Promise<T[]>\n /** Sync mode: the Dexie view table (for liveQuery / advanced queries). */\n ref?: Table<T, string>\n}\n\nexport interface BasicDb {\n readonly kind: 'sync' | 'rest'\n table<T extends BasicRecord = BasicRecord>(name: string): BasicTable<T>\n}\n\nfunction mintRecordId(): string {\n return mintOpId()\n}\n\n// ---------------------------------------------------------------------------\n// Sync mode\n// ---------------------------------------------------------------------------\n\nclass SyncTable<T extends BasicRecord> implements BasicTable<T> {\n constructor(\n private readonly engine: SyncEngine,\n private readonly subKey: string,\n private readonly name: string,\n ) {}\n\n private get store() {\n const sub = this.engine.getSubscription(this.subKey)\n if (!sub) {\n throw new Error(\n `subscription '${this.subKey}' is not open — wait for the client to be ready (isReady) before using the db`,\n )\n }\n return sub.store\n }\n\n get ref(): Table<T, string> {\n return this.store.view(this.name) as unknown as Table<T, string>\n }\n\n async create(data: Omit<T, 'id'>): Promise<T> {\n const id = mintRecordId()\n const view = await this.engine.apply(this.subKey, {\n type: 'put',\n table: this.name,\n record_id: id,\n data: data as Record<string, unknown>,\n })\n return (view ?? { id, ...data }) as T\n }\n\n async put(id: string, data: Omit<T, 'id'>): Promise<T> {\n if (!id) throw new Error('put() requires an id')\n const view = await this.engine.apply(this.subKey, {\n type: 'put',\n table: this.name,\n record_id: id,\n data: data as Record<string, unknown>,\n })\n return (view ?? { id, ...data }) as T\n }\n\n async patch(id: string, data: Partial<Omit<T, 'id'>>): Promise<T | null> {\n if (!id) throw new Error('patch() requires an id')\n // a patch on a missing record is a terminal server rejection — fail fast\n const existing = await this.store.getViewRecord(this.name, id)\n if (!existing) return null\n const view = await this.engine.apply(this.subKey, {\n type: 'patch',\n table: this.name,\n record_id: id,\n data: data as Record<string, unknown>,\n })\n return view as T | null\n }\n\n async delete(id: string): Promise<void> {\n if (!id) throw new Error('delete() requires an id')\n await this.engine.apply(this.subKey, {\n type: 'delete',\n table: this.name,\n record_id: id,\n })\n }\n\n async get(id: string): Promise<T | null> {\n return (await this.store.getViewRecord(this.name, id)) as T | null\n }\n\n async getAll(): Promise<T[]> {\n return (await this.store.getViewRecords(this.name)) as T[]\n }\n\n async find(predicate: (record: T) => boolean): Promise<T[]> {\n const all = await this.getAll()\n return all.filter(predicate)\n }\n}\n\nexport class SyncDb implements BasicDb {\n readonly kind = 'sync' as const\n private readonly tables = new Map<string, SyncTable<BasicRecord>>()\n\n constructor(\n private readonly engine: SyncEngine,\n private readonly subKey: string = OWN_SUB,\n ) {}\n\n table<T extends BasicRecord = BasicRecord>(name: string): BasicTable<T> {\n if (!this.engine.schema.tables[name]) {\n throw new Error(`table \"${name}\" not found in schema`)\n }\n if (!this.tables.has(name)) {\n this.tables.set(name, new SyncTable(this.engine, this.subKey, name))\n }\n return this.tables.get(name) as unknown as BasicTable<T>\n }\n}\n\n// ---------------------------------------------------------------------------\n// REST mode\n// ---------------------------------------------------------------------------\n\nclass RestTable<T extends BasicRecord> implements BasicTable<T> {\n constructor(\n private readonly rest: RestClient,\n private readonly name: string,\n ) {}\n\n async create(data: Omit<T, 'id'>): Promise<T> {\n const record = await this.rest.createRecord(this.name, data as Record<string, unknown>)\n return record as T\n }\n\n async put(id: string, data: Omit<T, 'id'>): Promise<T> {\n if (!id) throw new Error('put() requires an id')\n const record = await this.rest.putRecord(this.name, id, data as Record<string, unknown>)\n if (!record) throw new Error(`record ${this.name}/${id} not found (REST put is replace-only)`)\n return record as T\n }\n\n async patch(id: string, data: Partial<Omit<T, 'id'>>): Promise<T | null> {\n if (!id) throw new Error('patch() requires an id')\n const record = await this.rest.patchRecord(this.name, id, data as Record<string, unknown>)\n return record as T | null\n }\n\n async delete(id: string): Promise<void> {\n if (!id) throw new Error('delete() requires an id')\n await this.rest.deleteRecord(this.name, id)\n }\n\n async get(id: string): Promise<T | null> {\n const record: RestRecord | null = await this.rest.getRecord(this.name, id)\n return record as T | null\n }\n\n async getAll(): Promise<T[]> {\n return (await this.rest.list(this.name)) as T[]\n }\n\n async find(predicate: (record: T) => boolean): Promise<T[]> {\n const all = await this.getAll()\n return all.filter(predicate)\n }\n}\n\nexport class RestDb implements BasicDb {\n readonly kind = 'rest' as const\n private readonly tables = new Map<string, RestTable<BasicRecord>>()\n\n constructor(\n private readonly rest: RestClient,\n private readonly schema?: { tables?: Record<string, unknown> },\n ) {}\n\n table<T extends BasicRecord = BasicRecord>(name: string): BasicTable<T> {\n if (this.schema?.tables && !this.schema.tables[name]) {\n throw new Error(`table \"${name}\" not found in schema`)\n }\n if (!this.tables.has(name)) {\n this.tables.set(name, new RestTable(this.rest, name))\n }\n return this.tables.get(name) as unknown as BasicTable<T>\n }\n}\n","/**\n * User registry — multiple local users per project (anonymous or signed-in),\n * one active at a time, switchable.\n *\n * - Profiles live in localStorage under `basic_users:{projectId}` and are\n * shared across tabs.\n * - The *active* user id is per-tab (sessionStorage) so different tabs can be\n * on different users; it survives the OAuth redirect, so a sign-in resumes\n * on the profile that initiated it. Falls back to the most recently active\n * profile.\n * - Each profile owns an isolated sync keyspace and a namespaced slice of\n * auth storage (refresh token, cached userinfo, PKCE state, ...) via\n * `PrefixedStorage`.\n * - A pre-multi-user session (0.9.0-beta.0: bare `basic_refresh_token` +\n * `basic-sync:{projectId}` keyspace) is adopted as the first profile with\n * empty prefix/keyspace — no key or IndexedDB renames.\n */\nimport type { BasicStorage } from '../utils/storage'\nimport { STORAGE_KEYS } from '../utils/storage'\nimport { mintOpId } from './sync/protocol'\nimport { log } from '../config'\n\nexport type BasicUserKind = 'anon' | 'account'\n\nexport interface BasicUserProfile {\n /** Local profile id (uuid). Stable across sign-in upgrades. */\n id: string\n kind: BasicUserKind\n /** Account identity, set once signed in. */\n did?: string | null\n handle?: string | null\n email?: string | null\n name?: string | null\n picture?: string | null\n /**\n * Keyspace segment for sync data. `''` = the legacy pre-multi-user\n * keyspace (`basic-sync:{projectId}`); otherwise db names append it.\n */\n keyspace: string\n /**\n * Prefix for this profile's auth storage keys. `''` = legacy unprefixed\n * keys; otherwise `u:{id}:`.\n */\n storagePrefix: string\n createdAt: number\n lastActiveAt: number\n}\n\n/** Namespaces every key of an underlying BasicStorage adapter. */\nexport class PrefixedStorage implements BasicStorage {\n constructor(\n private readonly inner: BasicStorage,\n readonly prefix: string,\n ) {}\n\n get(key: string): Promise<string | null> {\n return this.inner.get(this.prefix + key)\n }\n set(key: string, value: string): Promise<void> {\n return this.inner.set(this.prefix + key, value)\n }\n remove(key: string): Promise<void> {\n return this.inner.remove(this.prefix + key)\n }\n}\n\nfunction registryKey(projectId: string): string {\n return `basic_users:${projectId}`\n}\n\nfunction activeUserSessionKey(projectId: string): string {\n return `basic_active_user:${projectId}`\n}\n\nexport class UserRegistry {\n constructor(\n private readonly storage: BasicStorage,\n private readonly projectId: string,\n ) {}\n\n // -------------------------------------------------------------------\n // Registry CRUD\n // -------------------------------------------------------------------\n\n async list(): Promise<BasicUserProfile[]> {\n const raw = await this.storage.get(registryKey(this.projectId))\n if (!raw) return []\n try {\n const parsed = JSON.parse(raw) as BasicUserProfile[]\n return Array.isArray(parsed) ? parsed : []\n } catch {\n return []\n }\n }\n\n private async save(users: BasicUserProfile[]): Promise<void> {\n await this.storage.set(registryKey(this.projectId), JSON.stringify(users))\n }\n\n async get(id: string): Promise<BasicUserProfile | null> {\n const users = await this.list()\n return users.find((u) => u.id === id) ?? null\n }\n\n async createAnon(): Promise<BasicUserProfile> {\n const id = mintOpId()\n const now = Date.now()\n const profile: BasicUserProfile = {\n id,\n kind: 'anon',\n keyspace: id,\n storagePrefix: `u:${id}:`,\n createdAt: now,\n lastActiveAt: now,\n }\n const users = await this.list()\n users.push(profile)\n await this.save(users)\n log(`created anonymous user ${id}`)\n return profile\n }\n\n async update(\n id: string,\n patch: Partial<Omit<BasicUserProfile, 'id' | 'keyspace' | 'storagePrefix'>>,\n ): Promise<BasicUserProfile | null> {\n const users = await this.list()\n const idx = users.findIndex((u) => u.id === id)\n if (idx < 0) return null\n users[idx] = { ...users[idx]!, ...patch }\n await this.save(users)\n return users[idx]!\n }\n\n async remove(id: string): Promise<void> {\n const users = await this.list()\n await this.save(users.filter((u) => u.id !== id))\n if (this.getActiveIdRaw() === id) this.clearActiveId()\n }\n\n /** The profile (if any) already bound to an account DID. */\n async findByDid(did: string): Promise<BasicUserProfile | null> {\n const users = await this.list()\n return users.find((u) => u.did === did) ?? null\n }\n\n // -------------------------------------------------------------------\n // Active user (per-tab)\n // -------------------------------------------------------------------\n\n private getActiveIdRaw(): string | null {\n try {\n return sessionStorage.getItem(activeUserSessionKey(this.projectId))\n } catch {\n return null\n }\n }\n\n setActiveId(id: string): void {\n try {\n sessionStorage.setItem(activeUserSessionKey(this.projectId), id)\n } catch {\n /* SSR / storage unavailable */\n }\n }\n\n private clearActiveId(): void {\n try {\n sessionStorage.removeItem(activeUserSessionKey(this.projectId))\n } catch {\n /* ignore */\n }\n }\n\n /**\n * Resolve the active profile for this tab: sessionStorage choice if it\n * still exists, else the most recently active profile, else null.\n */\n async resolveActive(): Promise<BasicUserProfile | null> {\n const users = await this.list()\n const activeId = this.getActiveIdRaw()\n if (activeId) {\n const match = users.find((u) => u.id === activeId)\n if (match) return match\n }\n if (users.length === 0) return null\n const recent = [...users].sort((a, b) => b.lastActiveAt - a.lastActiveAt)[0]!\n this.setActiveId(recent.id)\n return recent\n }\n\n async touch(id: string): Promise<void> {\n await this.update(id, { lastActiveAt: Date.now() })\n }\n\n // -------------------------------------------------------------------\n // Legacy adoption\n // -------------------------------------------------------------------\n\n /**\n * Adopt a pre-multi-user session as the first profile. Idempotent: runs\n * only when the registry is empty and a bare refresh token exists. The\n * adopted profile keeps the unprefixed storage keys and the legacy\n * keyspace name, so nothing needs to move.\n */\n async adoptLegacySession(): Promise<BasicUserProfile | null> {\n const users = await this.list()\n if (users.length > 0) return null\n const legacyRefresh = await this.storage.get(STORAGE_KEYS.REFRESH_TOKEN)\n if (!legacyRefresh) return null\n\n let cachedUser: { sub?: string; email?: string; name?: string; picture?: string } | null = null\n try {\n const raw = await this.storage.get(STORAGE_KEYS.USER_INFO)\n if (raw) cachedUser = JSON.parse(raw)\n } catch {\n /* ignore corrupted cache */\n }\n\n const now = Date.now()\n const profile: BasicUserProfile = {\n id: mintOpId(),\n kind: 'account',\n did: cachedUser?.sub ?? null,\n email: cachedUser?.email ?? null,\n name: cachedUser?.name ?? null,\n picture: cachedUser?.picture ?? null,\n keyspace: '', // legacy `basic-sync:{projectId}` database\n storagePrefix: '', // legacy unprefixed auth keys\n createdAt: now,\n lastActiveAt: now,\n }\n await this.save([profile])\n log('adopted legacy single-user session as profile', profile.id)\n return profile\n }\n}\n","// Schema utilities for Basic React package\nimport { validateSchema, compareSchemas } from '@basictech/schema'\nimport { log } from '../config'\n\nexport async function getSchemaStatus(schema: any): Promise<{\n valid: boolean,\n status: string,\n latest: any\n}> {\n const projectId = schema.project_id\n const valid = validateSchema(schema)\n\n if (!valid.valid) {\n console.warn('BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled')\n return { \n valid: false, \n status: 'invalid',\n latest: null\n }\n }\n\n const latestSchema = await fetch(`https://api.basic.tech/project/${projectId}/schema`)\n .then(res => res.json())\n .then(data => data.data[0].schema)\n .catch(err => {\n return { \n valid: false, \n status: 'error',\n latest: null\n }\n })\n\n if (!latestSchema.version) {\n return { \n valid: false, \n status: 'error',\n latest: null\n }\n }\n\n if (latestSchema.version > schema.version) {\n // error_code: schema_behind\n console.warn('BasicDB Error: your local schema version is behind the latest. Found version:', schema.version, 'but expected', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'behind', \n latest: latestSchema\n }\n } else if (latestSchema.version < schema.version) {\n // error_code: schema_ahead\n console.warn('BasicDB Error: your local schema version is ahead of the latest. Found version:', schema.version, 'but expected', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'ahead', \n latest: latestSchema\n }\n } else if (latestSchema.version === schema.version) {\n const changes = compareSchemas(schema, latestSchema)\n if (changes.valid) {\n return { \n valid: true,\n status: 'current',\n latest: latestSchema\n }\n } else {\n // error_code: schema_conflict\n console.warn('BasicDB Error: your local schema is conflicting with the latest. Your version:', schema.version, 'does not match origin version', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'conflict',\n latest: latestSchema\n }\n }\n } else { \n return { \n valid: false, \n status: 'error',\n latest: null\n }\n }\n}\n\nexport async function validateAndCheckSchema(schema: any): Promise<{\n isValid: boolean,\n schemaStatus: { valid: boolean, status?: string, latest?: any },\n errors?: any[]\n}> {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n log('Basic Schema is invalid!', valid.errors)\n console.group('Schema Errors')\n let errorMessage = ''\n valid.errors.forEach((error, index) => {\n log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`)\n errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}\\n`\n })\n console.groupEnd()\n \n return {\n isValid: false,\n schemaStatus: { valid: false },\n errors: valid.errors\n }\n }\n\n let schemaStatus: { valid: boolean, status?: string, latest?: any } = { valid: false }\n if (schema.version !== 0) {\n schemaStatus = await getSchemaStatus(schema)\n log('schemaStatus', schemaStatus)\n } else {\n schemaStatus = { valid: false, status: 'unpublished' }\n log(\"schema not published - at version 0\")\n }\n\n return {\n isValid: true,\n schemaStatus\n }\n}\n","import { BasicStorage } from '../utils/storage'\nimport { log } from '../config'\n\nexport interface VersionInfo {\n version: string\n lastUpdated: number\n}\n\nexport interface Migration {\n fromVersion: string\n toVersion: string\n migrate: (storage: BasicStorage) => Promise<void>\n}\n\nexport class VersionUpdater {\n private storage: BasicStorage\n private currentVersion: string\n private migrations: Migration[]\n private versionKey = 'basic_app_version'\n\n constructor(storage: BasicStorage, currentVersion: string, migrations: Migration[] = []) {\n this.storage = storage\n this.currentVersion = currentVersion\n this.migrations = migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion))\n }\n\n /**\n * Check current stored version and run migrations if needed\n * Only compares major.minor versions, ignoring beta/prerelease parts\n * Example: \"0.7.0-beta.1\" and \"0.7.0\" are treated as the same version\n */\n async checkAndUpdate(): Promise<{ updated: boolean; fromVersion?: string; toVersion: string }> {\n const storedVersion = await this.getStoredVersion()\n \n if (!storedVersion) {\n // First time setup\n await this.setStoredVersion(this.currentVersion)\n return { updated: false, toVersion: this.currentVersion }\n }\n\n if (storedVersion === this.currentVersion) {\n return { updated: false, toVersion: this.currentVersion }\n }\n\n // Need to run migrations\n const migrationsToRun = this.getMigrationsToRun(storedVersion, this.currentVersion)\n \n if (migrationsToRun.length === 0) {\n // No migrations needed, just update version\n await this.setStoredVersion(this.currentVersion)\n return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion }\n }\n\n // Run migrations\n for (const migration of migrationsToRun) {\n try {\n log(`Running migration from ${migration.fromVersion} to ${migration.toVersion}`)\n await migration.migrate(this.storage)\n } catch (error) {\n console.error(`Migration failed from ${migration.fromVersion} to ${migration.toVersion}:`, error)\n throw new Error(`Migration failed: ${error}`)\n }\n }\n\n // Update to current version\n await this.setStoredVersion(this.currentVersion)\n return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion }\n }\n\n private async getStoredVersion(): Promise<string | null> {\n try {\n const versionData = await this.storage.get(this.versionKey)\n if (!versionData) return null\n \n const versionInfo: VersionInfo = JSON.parse(versionData)\n return versionInfo.version\n } catch (error) {\n console.warn('Failed to get stored version:', error)\n return null\n }\n }\n\n private async setStoredVersion(version: string): Promise<void> {\n const versionInfo: VersionInfo = {\n version,\n lastUpdated: Date.now()\n }\n await this.storage.set(this.versionKey, JSON.stringify(versionInfo))\n }\n\n private getMigrationsToRun(fromVersion: string, toVersion: string): Migration[] {\n return this.migrations.filter(migration => {\n const storedLessThanMigrationTo = this.compareVersions(fromVersion, migration.toVersion) < 0\n const currentGreaterThanOrEqualMigrationTo = this.compareVersions(toVersion, migration.toVersion) >= 0\n const shouldRun = storedLessThanMigrationTo && currentGreaterThanOrEqualMigrationTo\n log(`Migration ${migration.fromVersion} → ${migration.toVersion}: shouldRun=${shouldRun}`)\n return shouldRun\n })\n }\n\n /**\n * Simple semantic version comparison (major.minor only, ignoring beta/prerelease)\n * Returns: -1 if a < b, 0 if a === b, 1 if a > b\n */\n private compareVersions(a: string, b: string): number {\n // Extract major.minor from version strings, ignoring beta/prerelease parts\n const aMajorMinor = this.extractMajorMinor(a)\n const bMajorMinor = this.extractMajorMinor(b)\n \n // Compare major version first\n if (aMajorMinor.major !== bMajorMinor.major) {\n return aMajorMinor.major - bMajorMinor.major\n }\n \n // Then compare minor version\n return aMajorMinor.minor - bMajorMinor.minor\n }\n\n /**\n * Extract major.minor from version string, ignoring beta/prerelease\n * Examples: \"0.7.0-beta.1\" -> {major: 0, minor: 7}\n * \"1.2.3\" -> {major: 1, minor: 2}\n */\n private extractMajorMinor(version: string): { major: number, minor: number } {\n // Remove beta/prerelease parts and split by dots\n const cleanVersion = version.split('-')[0]?.split('+')[0] || version\n const parts = cleanVersion.split('.').map(Number)\n \n return {\n major: parts[0] || 0,\n minor: parts[1] || 0\n }\n }\n\n /**\n * Add a migration to the updater\n */\n addMigration(migration: Migration): void {\n this.migrations.push(migration)\n this.migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion))\n }\n}\n\n/**\n * Create a simple version updater instance\n */\nexport function createVersionUpdater(\n storage: BasicStorage, \n currentVersion: string, \n migrations: Migration[] = []\n): VersionUpdater {\n return new VersionUpdater(storage, currentVersion, migrations)\n}\n","import { BasicStorage } from '../utils/storage'\nimport { Migration } from './versionUpdater'\nimport { log } from '../config'\n\nexport const addMigrationTimestamp: Migration = {\n fromVersion: '0.6.0',\n toVersion: '0.7.0',\n async migrate(storage: BasicStorage) {\n log('Running migration 0.6.0 → 0.7.0')\n storage.set('test_migration', 'true')\n }\n}\n\n/**\n * 0.9.0 replaced the dexie-syncable sync client with the Sync/2 engine.\n * The legacy `basicdb` IndexedDB database is unused; delete it. Data loss is\n * safe: the server is the source of truth and 0.9 bootstraps fresh replicas\n * into `basic-sync:<project_id>` databases.\n */\nexport const dropLegacySyncDb: Migration = {\n fromVersion: '0.8.0',\n toVersion: '0.9.0',\n async migrate() {\n log('Running migration 0.8.0 → 0.9.0: deleting legacy basicdb')\n try {\n const idb = (globalThis as { indexedDB?: IDBFactory }).indexedDB\n if (!idb) return\n await new Promise<void>((resolve) => {\n const req = idb.deleteDatabase('basicdb')\n req.onsuccess = req.onerror = req.onblocked = () => resolve()\n })\n } catch {\n /* best effort */\n }\n }\n}\n\n/**\n * Get all available migrations\n */\nexport function getMigrations(): Migration[] {\n return [\n addMigrationTimestamp,\n dropLegacySyncDb\n ]\n}\n","/**\n * BasicClient — the framework-agnostic SDK core. Owns, per active user:\n * - AuthManager (OAuth/PKCE, tokens, cross-tab session; storage namespaced\n * per local user profile)\n * - SyncEngine (Sync/2 client on the profile's own keyspace)\n * - RestClient (REST v2: snapshot/changes bootstrap, shares, CRUD)\n *\n * plus the multi-user registry: several local users (anonymous or signed-in)\n * exist side by side, one active at a time per tab, switchable.\n *\n * Local-first rules:\n * - The local keyspace opens with no token and no network (anonymous mode is\n * on by default; offline cold start works).\n * - Anonymous writes are pending ops; sign-in upgrades the profile in place\n * and the normal bootstrap+flush merges them into the account.\n * - `reauth_required` pauses the connection but keeps local reads/writes.\n * - Sign-out wipes the profile's local data and falls through to the next\n * (or a fresh anonymous) user. No page reloads.\n */\nimport { AuthManager } from './auth/AuthManager'\nimport type { AuthStatus, GetTokenOptions, User } from './auth/AuthManager'\nimport { RestClient } from './http/RestClient'\nimport { SyncEngine, OWN_SUB, shareSubKey, type SyncStatus } from './sync/SyncEngine'\nimport type { RejectedRow } from './sync/SyncStore'\nimport type { Share } from './sync/protocol'\nimport { SyncDb, RestDb, type BasicDb } from './db'\nimport { UserRegistry, PrefixedStorage, type BasicUserProfile } from './users'\nimport { BasicStorage, LocalStorageAdapter, STORAGE_KEYS } from '../utils/storage'\nimport { validateAndCheckSchema } from '../utils/schema'\nimport { createVersionUpdater } from '../updater/versionUpdater'\nimport { getMigrations } from '../updater/updateMigrations'\nimport { log as debugLog } from '../config'\nimport { version as sdkVersion } from '../../package.json'\n\nexport type BasicMode = 'sync' | 'rest'\n\nexport interface BasicAuthConfig {\n scopes?: string | string[]\n /** PDS URL for auth, data, and sync (default https://pds.basic.id) */\n pds_url?: string\n /** Admin server URL for connect reporting + schema status (default https://api.basic.tech) */\n admin_url?: string\n /** Sync WebSocket URL. Default: pds_url with ws(s) scheme + `/sync/`. */\n sync_url?: string\n}\n\nexport interface BasicClientConfig {\n /** The Basic schema document (`{ project_id, version, tables }`). */\n schema?: Record<string, unknown> & {\n project_id?: string\n version?: number\n tables?: Record<string, unknown>\n }\n /** Project id override; normally taken from `schema.project_id`. */\n project_id?: string\n auth?: BasicAuthConfig\n storage?: BasicStorage\n debug?: boolean\n /** 'sync' (offline-first local replica, default) or 'rest' (direct API). */\n mode?: BasicMode\n /**\n * Anonymous/local-first usage (sync mode only, default true): the local db\n * works without a session; data merges into the account on sign-in.\n */\n anonymous?: boolean\n /** Node/testing: pass the `ws` constructor. */\n WebSocketImpl?: typeof WebSocket\n}\n\n/** Local schema vs server status (dev toolbar and debugging). */\nexport interface BasicSchemaDevInfo {\n projectId: string | null\n localVersion: number | undefined\n status: string\n valid: boolean\n lastCheckedAt: number\n error?: string\n}\n\nexport interface BasicClientSnapshot {\n /** Auth bootstrap finished and (in sync mode) the local db is decided. */\n isReady: boolean\n isSignedIn: boolean\n authStatus: AuthStatus\n authErrorCode: string | null\n user: User | null\n did: string | null\n /** Space-separated scopes granted in the current access token. */\n scope: string | null\n syncStatus: SyncStatus\n pendingCount: number\n /** True when the schema allows sync (valid + published + matching server). */\n syncEnabled: boolean\n devInfo: BasicSchemaDevInfo | null\n mode: BasicMode\n /** All local user profiles (anonymous and signed-in). */\n users: BasicUserProfile[]\n /** The profile active in this tab. */\n activeUser: BasicUserProfile | null\n /** Active profile has no account yet (local-only workspace). */\n isAnonymous: boolean\n}\n\nexport interface ShareMountHandle {\n shareId: string\n db: BasicDb\n}\n\nconst DEFAULTS = {\n scopes: 'profile,email,app:admin',\n pds_url: 'https://pds.basic.id',\n admin_url: 'https://api.basic.tech',\n} as const\n\nfunction deriveSyncUrl(pdsUrl: string): string {\n return pdsUrl.replace(/^http/, 'ws').replace(/\\/$/, '') + '/sync/'\n}\n\n/** In-memory profile used when multi-user is unavailable (rest mode / no project). */\nfunction ephemeralLegacyProfile(): BasicUserProfile {\n const now = Date.now()\n return {\n id: 'default',\n kind: 'anon',\n keyspace: '',\n storagePrefix: '',\n createdAt: now,\n lastActiveAt: now,\n }\n}\n\ninterface ProfileBinding {\n profile: BasicUserProfile\n auth: AuthManager\n engine: SyncEngine | null\n syncDb: SyncDb | null\n /** Binding-lifetime wiring (engine event handlers). Runs on binding teardown. */\n cleanup: Array<() => void>\n /** Start-lifetime listeners (network events). Runs on stop() and teardown. */\n sessionCleanup: Array<() => void>\n}\n\nexport class BasicClient {\n readonly rest: RestClient\n readonly mode: BasicMode\n readonly config: BasicClientConfig\n readonly projectId: string | undefined\n readonly users: UserRegistry | null\n\n private readonly rawStorage: BasicStorage\n private readonly restDb: RestDb\n private readonly debug: boolean\n private readonly anonymousEnabled: boolean\n private readonly authConfig: { scopes: string; pds_url: string; admin_url: string }\n private readonly syncUrl: string\n\n private binding: ProfileBinding\n private usersCache: BasicUserProfile[] = []\n\n private devInfo: BasicSchemaDevInfo | null = null\n private syncEnabled = false\n private schemaChecked = false\n private started = false\n private signOutInProgress = false\n /** Serializes profile transitions (switch, dispose, sign-out fallthrough). */\n private profileOps: Promise<void> = Promise.resolve()\n private mounts = new Map<string, ShareMountHandle>()\n\n private listeners = new Set<() => void>()\n private snapshot: BasicClientSnapshot\n\n constructor(config: BasicClientConfig) {\n this.config = config\n this.debug = config.debug ?? false\n this.mode = config.mode ?? 'sync'\n this.projectId = (config.schema?.project_id as string | undefined) || config.project_id\n this.anonymousEnabled = this.mode === 'sync' && (config.anonymous ?? true)\n\n this.authConfig = {\n scopes: Array.isArray(config.auth?.scopes)\n ? config.auth!.scopes.join(' ')\n : config.auth?.scopes || DEFAULTS.scopes,\n pds_url: config.auth?.pds_url || DEFAULTS.pds_url,\n admin_url: config.auth?.admin_url || DEFAULTS.admin_url,\n }\n this.syncUrl = config.auth?.sync_url || deriveSyncUrl(this.authConfig.pds_url)\n this.rawStorage = config.storage || new LocalStorageAdapter()\n\n this.users =\n this.mode === 'sync' && this.projectId\n ? new UserRegistry(this.rawStorage, this.projectId)\n : null\n\n this.rest = new RestClient({\n baseUrl: this.authConfig.pds_url,\n projectId: this.projectId ?? '',\n getToken: (opts?: GetTokenOptions) => this.auth.getToken(opts),\n log: this.debug ? debugLog : undefined,\n })\n this.restDb = new RestDb(this.rest, this.config.schema as { tables?: Record<string, unknown> })\n\n // Bind the legacy profile synchronously so auth/engine exist before\n // start(); start() rebinds if the resolved profile differs. For existing\n // single-user installs this initial binding IS the right one.\n this.binding = this.createBinding(ephemeralLegacyProfile())\n this.snapshot = this.buildSnapshot()\n }\n\n // -------------------------------------------------------------------\n // Public surface\n // -------------------------------------------------------------------\n\n get auth(): AuthManager {\n return this.binding.auth\n }\n\n get engine(): SyncEngine | null {\n return this.binding.engine\n }\n\n /** The database handle for the active user. Identity changes on switch. */\n get db(): BasicDb {\n if (this.mode === 'sync' && this.binding.syncDb) return this.binding.syncDb\n return this.restDb\n }\n\n get activeUser(): BasicUserProfile | null {\n return this.users ? this.binding.profile : null\n }\n\n /** Bootstrap: version migrations, profile resolution, schema check, auth init. */\n async start(): Promise<void> {\n if (this.started) return\n this.started = true\n\n try {\n const updater = createVersionUpdater(this.rawStorage, sdkVersion, getMigrations())\n const result = await updater.checkAndUpdate()\n if (result.updated) debugLog(`SDK storage migrated ${result.fromVersion} → ${result.toVersion}`)\n } catch (err) {\n debugLog('version updater failed:', err)\n }\n\n // schema gate runs concurrently with profile/auth bootstrap\n void this.checkSchema().then(() => this.syncLifecycle())\n\n await this.queueProfileOp(async () => {\n let profile: BasicUserProfile | null = null\n if (this.users) {\n await this.users.adoptLegacySession()\n profile = await this.users.resolveActive()\n if (!profile && this.anonymousEnabled) {\n profile = await this.users.createAnon()\n }\n if (profile) this.users.setActiveId(profile.id)\n }\n await this.activateProfile(profile ?? ephemeralLegacyProfile(), { initial: true })\n await this.refreshUsers()\n })\n }\n\n /**\n * Sign out the active user: server-side revoke, wipe the profile's local\n * data, drop the profile, and fall through to the next (or a fresh\n * anonymous) user.\n */\n async signOut(): Promise<void> {\n await this.queueProfileOp(async () => {\n const { profile, auth, engine } = this.binding\n this.signOutInProgress = true\n try {\n await auth.signOut()\n } finally {\n this.signOutInProgress = false\n }\n this.mounts.clear()\n try {\n await engine?.destroyLocal()\n } catch (err) {\n debugLog('local data teardown failed:', err)\n }\n if (this.users && profile.id !== 'default') {\n await this.users.remove(profile.id)\n }\n await this.activateNextProfileLocked()\n await this.refreshUsers()\n })\n }\n\n // ---------------- multi-user ----------------\n\n /** Switch this tab to another local user. */\n async switchUser(id: string): Promise<void> {\n await this.queueProfileOp(async () => {\n if (!this.users) throw new Error('multiple users require sync mode with a project id')\n if (this.binding.profile.id === id) return\n const target = await this.users.get(id)\n if (!target) throw new Error(`unknown user '${id}'`)\n this.users.setActiveId(id)\n await this.users.touch(id)\n await this.activateProfile(target)\n await this.refreshUsers()\n })\n }\n\n /** Create a fresh anonymous user and switch to it. */\n async addUser(): Promise<BasicUserProfile> {\n let created: BasicUserProfile | null = null\n await this.queueProfileOp(async () => {\n if (!this.users) throw new Error('multiple users require sync mode with a project id')\n created = await this.users.createAnon()\n this.users.setActiveId(created.id)\n await this.activateProfile(created)\n await this.refreshUsers()\n })\n return created!\n }\n\n /**\n * Remove a local user: best-effort server-side revoke, wipe its keyspace\n * and auth storage, drop the profile. Removing the active user signs out.\n */\n async removeUser(id: string): Promise<void> {\n if (this.binding.profile.id === id) {\n return this.signOut()\n }\n await this.queueProfileOp(async () => {\n if (!this.users) return\n const profile = await this.users.get(id)\n if (!profile) return\n await this.disposeProfileData(profile)\n await this.users.remove(id)\n await this.refreshUsers()\n })\n }\n\n /** Stop connections and listeners; local data is kept. */\n stop(): void {\n this.started = false\n this.binding.engine?.stop()\n // only session listeners — engine event wiring survives so a restart of\n // the same binding (e.g. React StrictMode remount) stays reactive\n for (const fn of this.binding.sessionCleanup) {\n try {\n fn()\n } catch {\n /* ignore */\n }\n }\n this.binding.sessionCleanup = []\n }\n\n /** Re-run the remote schema status check (dev toolbar). */\n async refreshSchemaStatus(): Promise<void> {\n this.schemaChecked = false\n await this.checkSchema()\n this.syncLifecycle()\n }\n\n async listRejected(): Promise<RejectedRow[]> {\n return this.engine?.listRejected() ?? []\n }\n\n async clearRejected(): Promise<void> {\n await this.engine?.clearRejected()\n this.publish()\n }\n\n // ---------------- shares ----------------\n\n /** Shares granted by / received by this user for this app. */\n async listShares(): Promise<{ granted: Share[]; received: Share[] }> {\n return this.rest.listShares()\n }\n\n /** Mount a share: separate local keyspace + subscription. */\n async mountShare(shareId: string): Promise<ShareMountHandle> {\n const engine = this.engine\n if (!engine) throw new Error('shares require sync mode')\n const existing = this.mounts.get(shareId)\n if (existing) return existing\n await engine.mountShare(shareId)\n const handle: ShareMountHandle = {\n shareId,\n db: new SyncDb(engine, shareSubKey(shareId)),\n }\n this.mounts.set(shareId, handle)\n this.publish()\n return handle\n }\n\n async unmountShare(shareId: string, options?: { purge?: boolean }): Promise<void> {\n if (!this.engine) return\n await this.engine.unmountShare(shareId, options)\n this.mounts.delete(shareId)\n this.publish()\n }\n\n getMountedShare(shareId: string): ShareMountHandle | undefined {\n return this.mounts.get(shareId)\n }\n\n // ---------------- React subscription surface ----------------\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n getSnapshot = (): BasicClientSnapshot => {\n return this.snapshot\n }\n\n // -------------------------------------------------------------------\n // Profile binding & transitions\n // -------------------------------------------------------------------\n\n private createBinding(profile: BasicUserProfile): ProfileBinding {\n const storage = profile.storagePrefix\n ? new PrefixedStorage(this.rawStorage, profile.storagePrefix)\n : this.rawStorage\n\n const binding: Partial<ProfileBinding> = { profile, cleanup: [], sessionCleanup: [] }\n\n const auth = new AuthManager(\n {\n projectId: this.projectId,\n scopes: this.authConfig.scopes,\n pdsUrl: this.authConfig.pds_url,\n adminUrl: this.authConfig.admin_url,\n debug: this.debug,\n instanceKey: profile.storagePrefix,\n },\n storage,\n () => {\n // stale notifications from a previous binding are ignored\n if (this.binding === binding) this.handleAuthChange()\n },\n )\n binding.auth = auth\n\n if (this.mode === 'sync' && this.projectId && this.config.schema?.tables) {\n const engine = new SyncEngine({\n projectId: this.projectId,\n schema: this.config.schema as SyncEngine['schema'],\n wsUrl: this.syncUrl,\n getToken: (opts) => auth.getToken(opts),\n fetchSnapshot: (opts) => this.rest.getSnapshot(opts),\n WebSocketImpl: this.config.WebSocketImpl,\n keyspaceId: profile.keyspace,\n getOwnerDid: () => auth.did,\n log: debugLog,\n })\n binding.engine = engine\n binding.syncDb = new SyncDb(engine, OWN_SUB)\n binding.cleanup!.push(\n engine.on('status', () => this.publish()),\n engine.on('change', () => this.publish()),\n engine.on('rejected', ({ rejection }) => {\n debugLog('op rejected:', rejection.error, rejection.op)\n this.publish()\n }),\n engine.on('revoked', ({ code, message }) => {\n // the app connection was revoked (user disconnected the app on\n // basic.id). Probe the session so auth state reflects reality.\n debugLog('connection revoked:', code, message)\n void auth\n .reconcileSession('connection revoked', { forceRefresh: true, throttleMs: 0 })\n .catch(() => {})\n this.publish()\n }),\n )\n } else {\n binding.engine = null\n binding.syncDb = null\n }\n\n return binding as ProfileBinding\n }\n\n /**\n * Bind and boot a profile. Publishes the new binding first so React\n * subscriptions re-attach to the new db, then tears the old binding down\n * on the next tick (avoids in-flight live queries hitting a closed store).\n */\n private async activateProfile(\n profile: BasicUserProfile,\n options?: { initial?: boolean },\n ): Promise<void> {\n let old: ProfileBinding | null = null\n\n if (options?.initial && this.bindingMatches(profile)) {\n // constructor's legacy binding is already correct — just adopt the profile\n this.binding.profile = profile\n } else {\n old = this.binding\n this.binding = this.createBinding(profile)\n if (options?.initial) {\n // the pre-start placeholder was never initialized — release it now\n for (const fn of [...old.cleanup, ...old.sessionCleanup]) fn()\n old.engine?.stop()\n old.auth.destroy()\n old = null\n }\n }\n\n await this.binding.auth.initialize()\n this.binding.sessionCleanup.push(this.binding.auth.setupNetworkListeners())\n this.mounts.clear()\n this.syncLifecycle()\n this.publish()\n\n if (old) {\n setTimeout(() => {\n try {\n for (const fn of [...old.cleanup, ...old.sessionCleanup]) fn()\n old.engine?.stop()\n old.auth.destroy()\n } catch {\n /* ignore */\n }\n }, 50)\n }\n }\n\n private bindingMatches(profile: BasicUserProfile): boolean {\n return (\n this.binding.profile.storagePrefix === profile.storagePrefix &&\n this.binding.profile.keyspace === profile.keyspace\n )\n }\n\n /** After sign-out/disposal: resume on the next profile or a fresh anon one. */\n private async activateNextProfileLocked(): Promise<void> {\n let next: BasicUserProfile | null = null\n if (this.users) {\n next = await this.users.resolveActive()\n if (!next && this.anonymousEnabled) {\n next = await this.users.createAnon()\n }\n if (next) this.users.setActiveId(next.id)\n }\n await this.activateProfile(next ?? ephemeralLegacyProfile())\n }\n\n /** Wipe a (non-active) profile's local footprint: keyspace dbs + auth keys. */\n private async disposeProfileData(profile: BasicUserProfile): Promise<void> {\n const storage = profile.storagePrefix\n ? new PrefixedStorage(this.rawStorage, profile.storagePrefix)\n : this.rawStorage\n\n // best-effort server-side revoke of that profile's refresh chain (RFC 7009)\n try {\n const refreshToken = await storage.get(STORAGE_KEYS.REFRESH_TOKEN)\n if (refreshToken) {\n await fetch(`${this.authConfig.pds_url}/auth/revoke`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token: refreshToken, token_type_hint: 'refresh_token' }),\n })\n }\n } catch {\n /* best effort */\n }\n\n for (const key of Object.values(STORAGE_KEYS)) {\n try {\n await storage.remove(key)\n } catch {\n /* ignore */\n }\n }\n\n await this.deleteKeyspaceDatabases(profile.keyspace)\n }\n\n private async deleteKeyspaceDatabases(keyspace: string): Promise<void> {\n if (!this.projectId) return\n const base = keyspace\n ? `basic-sync:${this.projectId}:${keyspace}`\n : `basic-sync:${this.projectId}`\n try {\n const idb = (globalThis as { indexedDB?: IDBFactory }).indexedDB\n if (!idb) return\n const names: string[] = [base]\n if (typeof idb.databases === 'function') {\n const dbs = await idb.databases()\n for (const info of dbs) {\n if (info.name && info.name.startsWith(`${base}:share:`)) names.push(info.name)\n }\n }\n for (const name of names) {\n await new Promise<void>((resolve) => {\n const req = idb.deleteDatabase(name)\n req.onsuccess = req.onerror = req.onblocked = () => resolve()\n })\n }\n } catch {\n /* best effort */\n }\n }\n\n // -------------------------------------------------------------------\n // Orchestration\n // -------------------------------------------------------------------\n\n /** Previous auth status, for transition detection (revoked-latch clearing). */\n private lastAuthStatus: AuthStatus | null = null\n\n private handleAuthChange(): void {\n const status = this.auth.authStatus\n\n // A fresh transition into `authenticated` (sign-in / re-auth) is the only\n // signal that a revoked app connection may have been re-consented —\n // release the engine's revocation latch so it can try again.\n if (\n status === 'authenticated' &&\n this.lastAuthStatus !== 'authenticated' &&\n this.engine?.status === 'revoked'\n ) {\n this.engine.clearRevoked()\n }\n this.lastAuthStatus = status\n\n if (status === 'signed_out' && !this.signOutInProgress && this.started) {\n // external sign-out (another tab, or a dead session at bootstrap) for\n // an account profile: mirror the wipe + fall through to the next user\n const profile = this.binding.profile\n if (this.users && profile.kind === 'account') {\n void this.queueProfileOp(async () => {\n if (this.binding.profile.id !== profile.id) return\n if (this.binding.auth.authStatus !== 'signed_out') return\n this.mounts.clear()\n try {\n await this.binding.engine?.destroyLocal()\n } catch {\n /* ignore */\n }\n await this.users!.remove(profile.id)\n await this.activateNextProfileLocked()\n await this.refreshUsers()\n })\n return\n }\n }\n this.syncLifecycle()\n void this.maybeUpgradeProfile()\n this.publish()\n }\n\n /**\n * Drive the engine from auth + schema state:\n * - local keyspace opens with no token (anonymous mode / offline cold start)\n * - connect when a session exists (recovering counts — the connection\n * retries token acquisition itself)\n * - reauth_required pauses the connection, keeps local data usable\n */\n private syncLifecycle(): void {\n const { engine, auth, profile } = this.binding\n if (!engine || !this.started) return\n\n const status = auth.authStatus\n if (status === 'reauth_required') {\n engine.pause()\n return\n }\n\n // classic mode (anonymous disabled), signed out: no local workspace —\n // sign-out paths already tore the engine down\n const localAllowed = this.anonymousEnabled || auth.isSignedIn || profile.kind === 'account'\n if (!localAllowed) return\n\n const schemaLocallyUsable = this.devInfo === null || this.devInfo.status !== 'invalid'\n if (!schemaLocallyUsable) return\n\n void engine\n .openLocal()\n .then(() => {\n if (this.binding.engine !== engine) return\n if (this.syncEnabled && auth.isSignedIn && auth.authStatus !== 'reauth_required') {\n return engine.connect()\n }\n })\n .catch((err) => debugLog('sync lifecycle failed:', err))\n }\n\n /**\n * After sign-in: bind the account identity to the active profile\n * (anonymous → account upgrade) and dedupe against an existing profile\n * for the same DID.\n */\n private async maybeUpgradeProfile(): Promise<void> {\n const { profile, auth } = this.binding\n if (!this.users || auth.authStatus !== 'authenticated' || !auth.did) return\n // the ephemeral fallback profile (anonymous mode disabled) is not in the\n // registry — classic single-user behavior, nothing to upgrade\n if (profile.id === 'default') return\n const did = auth.did\n const user = auth.user\n\n const needsUpdate =\n profile.did !== did ||\n profile.kind !== 'account' ||\n profile.email !== (user?.email ?? profile.email) ||\n profile.name !== (user?.name ?? profile.name)\n if (!needsUpdate) return\n\n await this.queueProfileOp(async () => {\n if (this.binding.profile.id !== profile.id) return\n if (!this.users) return\n\n // dedupe: another local profile already bound to this account — the\n // current profile wins (it may carry anonymous pending ops); the other\n // one's local cache is server-backed and safe to drop.\n const existing = await this.users.findByDid(did)\n if (existing && existing.id !== profile.id) {\n debugLog(`deduping user profiles for ${did}: dropping ${existing.id}`)\n await this.disposeProfileData(existing)\n await this.users.remove(existing.id)\n }\n\n const updated = await this.users.update(profile.id, {\n kind: 'account',\n did,\n email: user?.email ?? profile.email ?? null,\n name: user?.name ?? profile.name ?? null,\n picture: user?.picture ?? profile.picture ?? null,\n lastActiveAt: Date.now(),\n })\n if (updated) {\n this.binding.profile = updated\n }\n await this.refreshUsers()\n })\n }\n\n private async refreshUsers(): Promise<void> {\n if (this.users) {\n this.usersCache = await this.users.list()\n }\n this.publish()\n }\n\n private queueProfileOp(task: () => Promise<void>): Promise<void> {\n this.profileOps = this.profileOps.then(task).catch((err) => {\n debugLog('profile operation failed:', err)\n })\n return this.profileOps\n }\n\n private async checkSchema(): Promise<void> {\n if (this.schemaChecked) return\n const schema = this.config.schema\n if (!schema) {\n this.devInfo = this.projectId\n ? {\n projectId: this.projectId,\n localVersion: undefined,\n status: 'no_schema',\n valid: false,\n lastCheckedAt: Date.now(),\n }\n : null\n this.syncEnabled = false\n this.publish()\n return\n }\n\n try {\n const result = await validateAndCheckSchema(schema)\n if (!result.isValid) {\n const errText =\n result.errors\n ?.map((e: { message?: string }) => e.message || '')\n .join('; ') || 'invalid'\n this.devInfo = {\n projectId: (schema.project_id as string) ?? null,\n localVersion: schema.version as number | undefined,\n status: 'invalid',\n valid: false,\n lastCheckedAt: Date.now(),\n error: errText,\n }\n this.syncEnabled = false\n } else {\n const status = result.schemaStatus.status ?? 'unknown'\n this.devInfo = {\n projectId: (schema.project_id as string) ?? null,\n localVersion: schema.version as number | undefined,\n status,\n valid: result.schemaStatus.valid,\n lastCheckedAt: Date.now(),\n }\n // Offline-first: only a *definitive* server verdict (behind / ahead /\n // conflict / unpublished) disables sync. A failed registry check\n // (offline, registry down) must not brick the app — the server\n // validates every op anyway.\n const locallyPublishable =\n typeof schema.version === 'number' && (schema.version as number) > 0\n const remoteCheckInconclusive = status === 'error' || status === 'unknown'\n this.syncEnabled =\n result.schemaStatus.valid || (remoteCheckInconclusive && locallyPublishable)\n if (!result.schemaStatus.valid) {\n if (status === 'unpublished') {\n debugLog('Schema not published (version 0) — sync is disabled, local-only mode.')\n } else if (remoteCheckInconclusive && locallyPublishable) {\n debugLog('Schema registry check failed — proceeding with the local schema (offline-first).')\n }\n }\n }\n } catch (err) {\n debugLog('schema check failed:', err)\n // network failure checking the registry must not brick offline usage:\n // a locally valid, published schema still allows sync\n this.syncEnabled = !!schema.version && (schema.version as number) > 0\n this.devInfo = {\n projectId: (schema.project_id as string) ?? null,\n localVersion: schema.version as number | undefined,\n status: 'unknown',\n valid: this.syncEnabled,\n lastCheckedAt: Date.now(),\n }\n }\n this.schemaChecked = true\n this.publish()\n }\n\n private buildSnapshot(): BasicClientSnapshot {\n const { auth, engine, profile } = this.binding\n return {\n isReady: auth.isAuthReady,\n isSignedIn: auth.isSignedIn,\n authStatus: auth.authStatus,\n authErrorCode: auth.authErrorCode,\n user: auth.user,\n did: auth.did,\n scope: auth.tokenScope,\n syncStatus: engine?.status ?? 'idle',\n pendingCount: engine?.pendingCount ?? 0,\n syncEnabled: this.syncEnabled,\n devInfo: this.devInfo,\n mode: this.mode,\n users: this.usersCache,\n activeUser: this.users ? profile : null,\n isAnonymous: this.users ? profile.kind === 'anon' && !auth.isSignedIn : false,\n }\n }\n\n private publish(): void {\n this.snapshot = this.buildSnapshot()\n for (const listener of this.listeners) {\n try {\n listener()\n } catch {\n /* ignore */\n }\n }\n }\n}\n\nexport function createBasicClient(config: BasicClientConfig): BasicClient {\n return new BasicClient(config)\n}\n","// @basictech/react — Basic SDK for React, built on the Sync/2 protocol.\n\n// ---------------------------------------------------------------------------\n// React layer\n// ---------------------------------------------------------------------------\nexport { BasicProvider } from './react/BasicProvider'\nexport type { BasicProviderProps } from './react/BasicProvider'\nexport {\n useBasic,\n useAuth,\n useDb,\n useQuery,\n useSyncStatus,\n useShares,\n useShare,\n useUsers,\n useBasicClient,\n} from './react/hooks'\nexport type {\n UseBasicResult,\n UseAuthResult,\n UseSyncStatusResult,\n UseSharesResult,\n UseShareResult,\n UseUsersResult,\n} from './react/hooks'\n\n// ---------------------------------------------------------------------------\n// Client core (framework-agnostic)\n// ---------------------------------------------------------------------------\nexport { BasicClient, createBasicClient } from './core/BasicClient'\nexport type {\n BasicClientConfig,\n BasicClientSnapshot,\n BasicAuthConfig,\n BasicMode,\n BasicSchemaDevInfo,\n ShareMountHandle,\n} from './core/BasicClient'\n\n// Database (table API)\nexport { SyncDb, RestDb } from './core/db'\nexport type { BasicDb, BasicTable, BasicRecord } from './core/db'\n\n// Multi-user\nexport { UserRegistry, PrefixedStorage } from './core/users'\nexport type { BasicUserProfile, BasicUserKind } from './core/users'\n\n// Auth\nexport { AuthManager } from './core/auth/AuthManager'\nexport type {\n Token,\n User,\n AuthResult,\n AuthStatus,\n GetTokenOptions,\n PdsEndpoints,\n} from './core/auth/AuthManager'\n\n// REST\nexport { RestClient, RestError, NotAuthenticatedError } from './core/http/RestClient'\nexport type { RestClientOptions, RestRecord } from './core/http/RestClient'\n\n// ---------------------------------------------------------------------------\n// Sync/2 protocol + engine (for advanced use and other runtimes)\n// ---------------------------------------------------------------------------\nexport { SyncEngine, SyncConnection, SyncStore, OWN_SUB, shareSubKey } from './core/sync'\nexport type {\n SyncStatus,\n SyncEngineOptions,\n SyncEngineEvents,\n SubscriptionState,\n ConnectionStatus,\n SyncStoreSchema,\n PendingRow,\n RejectedRow,\n} from './core/sync'\nexport {\n PROTOCOL_VERSION,\n DEFAULT_LIMITS,\n isTerminalOpError,\n isRebootstrapError,\n isRevocationError,\n isAuthError,\n mintOpId,\n applyOpToData,\n} from './core/sync/protocol'\nexport type {\n OpType,\n OpEnvelope,\n LoggedOp,\n SyncErrorCode,\n SyncLimits,\n Snapshot,\n ChangesPage,\n Share,\n ShareSelector,\n SharePermission,\n PushResult,\n} from './core/sync/protocol'\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\nexport { STORAGE_KEYS, LocalStorageAdapter } from './utils/storage'\nexport type { BasicStorage } from './utils/storage'\nexport { resolveDid, resolveHandle, resolveDidWebUrl } from './utils/resolveDid'\nexport type { ResolvedDid } from './utils/resolveDid'\n\n// Dev tools\nexport { BasicDevToolbar } from './dev/BasicDevToolbar'\nexport type { BasicDevToolbarProps } from './dev/BasicDevToolbar'\n"],"mappings":"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","names":["version","useMemo","useState","useEffect","useSyncExternalStore","version","jsx","jsxs","BasicDevToolbar","useEffect","useSyncExternalStore"]}
|
|
1
|
+
{"version":3,"sources":["../src/create-client.ts","../src/adapters/broadcast-channel.ts","../src/adapters/navigation.ts","../src/adapters/persistence.ts","../src/adapters/storage.ts","../src/adapters/token-store.ts","../src/adapters/upload.ts","../src/provider.tsx","../src/context.ts","../src/hooks/accounts.ts","../src/hooks/client.ts","../src/hooks/auth.ts","../src/hooks/db.ts","../src/hooks/repos.ts","../src/hooks/status.ts","../src/hooks/basic.ts","../src/hooks/files.ts","../src/hooks/mounts.ts","../src/hooks/query.ts","../src/create-basic.tsx"],"sourcesContent":["import {\n MemoryKeyValueStorage,\n MemoryReplicaStoreFactory,\n createBasicClient as createCoreClient,\n type BasicClient,\n type BasicConfig,\n type BasicSchema,\n} from '@basictech/core'\nimport { createBrowserAuthChannelFactory } from './adapters/broadcast-channel'\nimport { browserCurrentUrl, browserNavigate, browserReplaceUrl } from './adapters/navigation'\nimport { PersistenceStore } from './adapters/persistence'\nimport { browserStorage } from './adapters/storage'\nimport { BrowserTokenStore } from './adapters/token-store'\nimport { browserUploadTransport } from './adapters/upload'\n\nexport type BrowserBasicConfig<S extends BasicSchema = BasicSchema> = BasicConfig<S>\n\nfunction browserReconcileTrigger(listener: () => void): () => void {\n if (typeof window === 'undefined' || typeof document === 'undefined') return () => {}\n const onVisible = () => {\n if (document.visibilityState === 'visible') listener()\n }\n window.addEventListener('focus', listener)\n window.addEventListener('online', listener)\n document.addEventListener('visibilitychange', onVisible)\n return () => {\n window.removeEventListener('focus', listener)\n window.removeEventListener('online', listener)\n document.removeEventListener('visibilitychange', onVisible)\n }\n}\n\n/** Create a core client with the complete browser adapter set installed. */\nexport function createBasicClient<S extends BasicSchema>(\n config: BrowserBasicConfig<S>,\n): BasicClient<S> {\n const local = browserStorage('localStorage') ?? new MemoryKeyValueStorage()\n const session = browserStorage('sessionStorage') ?? new MemoryKeyValueStorage()\n const defaultTokenStore = config.tokenStore ? null : new BrowserTokenStore(local)\n const canBroadcast = typeof BroadcastChannel !== 'undefined'\n const canPersistReplica = typeof indexedDB !== 'undefined'\n\n return createCoreClient({\n ...config,\n kv: config.kv ?? local,\n tokenStore: config.tokenStore ?? defaultTokenStore!,\n sessionStorage: config.sessionStorage ?? session,\n replicaStore: config.replicaStore ?? (\n canPersistReplica ? new PersistenceStore(config.clientId) : new MemoryReplicaStoreFactory()\n ),\n navigate: config.navigate ?? browserNavigate,\n currentUrl: config.currentUrl ?? browserCurrentUrl,\n replaceUrl: config.replaceUrl ?? browserReplaceUrl,\n reconcileTrigger: config.reconcileTrigger ?? browserReconcileTrigger,\n createMessageChannel: config.createMessageChannel ?? (\n canBroadcast && defaultTokenStore\n ? createBrowserAuthChannelFactory(config.clientId, defaultTokenStore)\n : undefined\n ),\n uploadTransport: config.uploadTransport ?? (\n typeof XMLHttpRequest === 'undefined' ? undefined : browserUploadTransport\n ),\n })\n}\n","import type { AuthMessageChannel } from '@basictech/core'\nimport type { BrowserTokenStore } from './token-store'\n\nexport interface BrowserMessageChannel {\n postMessage(message: unknown): void\n close(): void\n onmessage: ((event: { data: unknown }) => void) | null\n}\n\ninterface AccessTokenMessage {\n type?: string\n expiresAt?: number\n __basicAccessToken?: string\n __basicRefreshToken?: string\n}\n\n/** Core message-channel adapter backed by the browser BroadcastChannel API. */\nexport function createBrowserMessageChannel(name: string): BrowserMessageChannel {\n const channel = new BroadcastChannel(name)\n const adapter: BrowserMessageChannel = {\n postMessage: (message) => channel.postMessage(message),\n close: () => channel.close(),\n onmessage: null,\n }\n channel.onmessage = (event) => adapter.onmessage?.({ data: event.data })\n return adapter\n}\n\n/**\n * Access tokens may cross tabs transiently but are never written to browser\n * storage. The receiving adapter adopts the token before core handles the\n * ordinary token-rotation notification.\n */\nexport function createBrowserAuthChannelFactory(\n clientId: string,\n tokenStore: BrowserTokenStore,\n): (name: string) => AuthMessageChannel {\n const prefix = `basic_auth:${clientId}:`\n return (name) => {\n const channel = createBrowserMessageChannel(name)\n const profileId = name.startsWith(prefix) ? name.slice(prefix.length) : ''\n const tokenKey = `u:${profileId}:basic_tokens`\n const adapter: AuthMessageChannel = {\n postMessage: (message) => {\n const outgoing = message as AccessTokenMessage\n const access = outgoing?.type === 'tokens' ? tokenStore.accessToken(tokenKey) : null\n channel.postMessage(access ? {\n ...outgoing,\n expiresAt: access.expiresAt,\n __basicAccessToken: access.value,\n __basicRefreshToken: access.refreshToken,\n } satisfies AccessTokenMessage : message)\n },\n close: () => channel.close(),\n onmessage: null,\n }\n channel.onmessage = (event) => {\n void (async () => {\n const incoming = event.data as AccessTokenMessage\n if (incoming?.type === 'tokens' && incoming.__basicAccessToken && incoming.__basicRefreshToken) {\n await tokenStore.adoptAccessToken(\n tokenKey,\n incoming.__basicAccessToken,\n incoming.expiresAt ?? 0,\n incoming.__basicRefreshToken,\n )\n }\n adapter.onmessage?.({ data: event.data })\n })()\n }\n return adapter\n }\n}\n","import { BasicError } from '@basictech/core'\n\nexport function browserNavigate(url: string): void {\n if (typeof location === 'undefined') throw new BasicError('NAVIGATE_ADAPTER_REQUIRED')\n location.assign(url)\n}\n\nexport function browserCurrentUrl(): string {\n return typeof location === 'undefined' ? '' : location.href\n}\n\nexport function browserReplaceUrl(url: string): void {\n if (typeof history !== 'undefined') history.replaceState({}, '', url)\n}\n","import Dexie, { type Table } from 'dexie'\nimport {\n BasicError,\n partitionKey,\n type PersistedReplicaState,\n type PersistenceLeaderHooks,\n type ReplicaStore,\n type ReplicaStoreFactory,\n type StoragePartition,\n type SyncOp,\n} from '@basictech/core'\n\nexport type { PersistedReplicaState, StoragePartition } from '@basictech/core'\n\ninterface PartitionRow {\n key: string\n profileId: string\n state: PersistedReplicaState\n updatedAt: number\n}\n\nexport interface ReplicaMessageChannel {\n postMessage(message: unknown): void\n close(): void\n onmessage: ((event: { data: unknown }) => void) | null\n}\n\ninterface AvailableLock {\n name: string\n}\n\nexport interface BrowserLockManager {\n request<T>(\n name: string,\n options: { mode?: 'exclusive'; ifAvailable?: true },\n callback: (lock: AvailableLock | null) => T | Promise<T>,\n ): Promise<T>\n}\n\nexport interface PersistenceStoreOptions {\n locks?: BrowserLockManager | null\n createChannel?: ((name: string) => ReplicaMessageChannel) | null\n}\n\ntype CoordinatorMessage =\n | { type: 'mutation'; requestId: string; operation: SyncOp }\n | { type: 'mutation-result'; requestId: string; opId?: string; code?: string; message?: string }\n | { type: 'state'; state: PersistedReplicaState }\n\nfunction browserLocks(): BrowserLockManager | null {\n if (typeof navigator === 'undefined' || !navigator.locks) return null\n return navigator.locks as unknown as BrowserLockManager\n}\n\nfunction browserChannel(name: string): ReplicaMessageChannel {\n const channel = new BroadcastChannel(name)\n const adapter: ReplicaMessageChannel = {\n postMessage: (message) => channel.postMessage(message),\n close: () => channel.close(),\n onmessage: null,\n }\n channel.onmessage = (event) => adapter.onmessage?.({ data: event.data })\n return adapter\n}\n\n/**\n * Per-partition single-writer coordinator. With Web Locks, followers forward\n * mutations and consume committed-state broadcasts. Browsers lacking Locks\n * use the documented degraded last-committed-writer-wins mode: every tab may\n * write, the version guard rejects stale commits, and broadcasts refresh\n * surviving views. Concurrent offline intent can be lost in that fallback.\n */\nclass PartitionCoordinator implements PersistenceLeaderHooks {\n private readonly mutationListeners = new Set<(operation: SyncOp) => Promise<string>>()\n private readonly stateListeners = new Set<(state: PersistedReplicaState) => void>()\n private readonly leadershipListeners = new Set<(isLeader: boolean) => void | Promise<void>>()\n private readonly pending = new Map<string, {\n operation: SyncOp\n resolve: (opId: string) => void\n reject: (error: Error) => void\n deadline: number\n timer?: ReturnType<typeof setTimeout>\n }>()\n private readonly election: Promise<boolean>\n private leadershipReady: Promise<void> = Promise.resolve()\n private releaseLock: (() => void) | null = null\n private leader = true\n private closed = false\n\n constructor(\n name: string,\n locks: BrowserLockManager | null,\n private readonly channel: ReplicaMessageChannel | null,\n ) {\n this.channel && (this.channel.onmessage = (event) => this.receive(event.data))\n if (!locks || !channel) {\n this.election = Promise.resolve(true)\n return\n }\n this.leader = false\n this.election = new Promise<boolean>((resolve) => {\n void locks.request(`basic-replica:${name}`, { ifAvailable: true }, async (lock) => {\n this.setLeader(Boolean(lock))\n resolve(this.leader)\n if (!lock) {\n this.waitForLeadership(locks, name)\n return\n }\n await new Promise<void>((release) => {\n this.releaseLock = release\n })\n }).catch(() => {\n this.setLeader(true)\n resolve(true)\n })\n })\n }\n\n async isLeader(): Promise<boolean> {\n await this.election\n await this.leadershipReady\n return this.leader\n }\n\n subscribeLeadership(listener: (isLeader: boolean) => void | Promise<void>): () => void {\n this.leadershipListeners.add(listener)\n return () => this.leadershipListeners.delete(listener)\n }\n\n async forwardMutation(operation: SyncOp): Promise<string> {\n if (await this.isLeader()) return this.dispatchMutation(operation)\n if (this.closed) throw new BasicError('PARTITION_COORDINATOR_CLOSED')\n if (!this.channel) throw new BasicError('PARTITION_LEADER_UNAVAILABLE')\n const requestId = crypto.randomUUID()\n return new Promise<string>((resolve, reject) => {\n const flight = { operation, resolve, reject, deadline: Date.now() + 10_000 }\n this.pending.set(requestId, flight)\n this.sendPending(requestId, flight)\n })\n }\n\n subscribeMutations(listener: (operation: SyncOp) => Promise<string>): () => void {\n this.mutationListeners.add(listener)\n return () => this.mutationListeners.delete(listener)\n }\n\n publishState(state: PersistedReplicaState): void {\n this.channel?.postMessage({ type: 'state', state } satisfies CoordinatorMessage)\n }\n\n subscribeState(listener: (state: PersistedReplicaState) => void): () => void {\n this.stateListeners.add(listener)\n return () => this.stateListeners.delete(listener)\n }\n\n close(): void {\n this.closed = true\n this.setLeader(false)\n this.releaseLock?.()\n this.releaseLock = null\n this.channel?.close()\n for (const flight of this.pending.values()) {\n if (flight.timer) clearTimeout(flight.timer)\n flight.reject(new BasicError('PARTITION_COORDINATOR_CLOSED'))\n }\n this.pending.clear()\n }\n\n private waitForLeadership(locks: BrowserLockManager, name: string): void {\n void locks.request(`basic-replica:${name}`, { mode: 'exclusive' }, async (lock) => {\n if (!lock || this.closed) return\n this.setLeader(true)\n await new Promise<void>((release) => {\n this.releaseLock = release\n })\n this.setLeader(false)\n }).catch(() => {\n if (!this.closed) this.setLeader(true)\n })\n }\n\n private setLeader(isLeader: boolean): void {\n if (this.leader === isLeader) return\n this.leader = isLeader\n this.leadershipReady = Promise.all(\n [...this.leadershipListeners].map((listener) => listener(isLeader)),\n ).then(() => {})\n if (isLeader) void this.leadershipReady.then(() => this.drainPending()).catch(() => {})\n }\n\n private receive(value: unknown): void {\n if (this.closed || !value || typeof value !== 'object') return\n const message = value as CoordinatorMessage\n if (message.type === 'state') {\n for (const listener of this.stateListeners) listener(structuredClone(message.state))\n } else if (message.type === 'mutation' && this.leader) {\n void this.leadershipReady.then(() => this.dispatchMutation(message.operation)).then(\n (opId) => this.channel?.postMessage({\n type: 'mutation-result', requestId: message.requestId, opId,\n } satisfies CoordinatorMessage),\n (error: unknown) => this.channel?.postMessage({\n type: 'mutation-result',\n requestId: message.requestId,\n code: error instanceof BasicError ? error.code : 'FORWARDED_MUTATION_FAILED',\n message: error instanceof Error ? error.message : String(error),\n } satisfies CoordinatorMessage),\n )\n } else if (message.type === 'mutation-result') {\n const flight = this.pending.get(message.requestId)\n if (!flight) return\n if (!message.opId && (message.code === 'STALE_STATE_VERSION' ||\n message.code === 'PARTITION_LEADER_UNAVAILABLE')) {\n this.sendPending(message.requestId, flight)\n return\n }\n this.pending.delete(message.requestId)\n if (flight.timer) clearTimeout(flight.timer)\n if (message.opId) flight.resolve(message.opId)\n else flight.reject(new BasicError(message.code ?? 'FORWARDED_MUTATION_FAILED', message.message))\n }\n }\n\n private async dispatchMutation(operation: SyncOp): Promise<string> {\n const listener = this.mutationListeners.values().next().value\n if (!listener) throw new BasicError('PARTITION_LEADER_UNAVAILABLE')\n return listener(operation)\n }\n\n private drainPending(): void {\n for (const [requestId, flight] of this.pending) {\n void this.dispatchMutation(flight.operation).then(\n (opId) => {\n if (this.pending.get(requestId) !== flight) return\n this.pending.delete(requestId)\n if (flight.timer) clearTimeout(flight.timer)\n flight.resolve(opId)\n },\n (error: unknown) => {\n if (this.pending.get(requestId) !== flight) return\n this.pending.delete(requestId)\n if (flight.timer) clearTimeout(flight.timer)\n flight.reject(error instanceof Error ? error : new BasicError('FORWARDED_MUTATION_FAILED'))\n },\n )\n }\n }\n\n private sendPending(\n requestId: string,\n flight: {\n operation: SyncOp\n resolve: (opId: string) => void\n reject: (error: Error) => void\n deadline: number\n timer?: ReturnType<typeof setTimeout>\n },\n ): void {\n if (this.pending.get(requestId) !== flight) return\n if (flight.timer) clearTimeout(flight.timer)\n const remaining = flight.deadline - Date.now()\n if (remaining <= 0) {\n this.pending.delete(requestId)\n flight.reject(new BasicError('PARTITION_LEADER_TIMEOUT'))\n return\n }\n try {\n this.channel?.postMessage({\n type: 'mutation', requestId, operation: flight.operation,\n } satisfies CoordinatorMessage)\n } catch {\n this.pending.delete(requestId)\n flight.reject(new BasicError('PARTITION_LEADER_UNAVAILABLE'))\n return\n }\n flight.timer = setTimeout(() => this.sendPending(requestId, flight), Math.min(100, remaining))\n }\n}\n\nclass DexieReplicaStore implements ReplicaStore {\n constructor(\n private readonly table: Table<PartitionRow, string>,\n readonly partition: StoragePartition,\n readonly key: string,\n readonly leader: PartitionCoordinator,\n ) {}\n\n async load(): Promise<PersistedReplicaState | null> {\n return (await this.table.get(this.key))?.state ?? null\n }\n\n async save(state: PersistedReplicaState): Promise<void> {\n if (!Number.isSafeInteger(state.version) || state.version < 1) {\n throw new BasicError('INVALID_STATE_VERSION')\n }\n await this.table.db.transaction('rw', this.table, async () => {\n const current = await this.table.get(this.key)\n if ((current?.state.version ?? 0) >= state.version) throw new BasicError('STALE_STATE_VERSION')\n await this.table.put({\n key: this.key,\n profileId: this.partition.profileId,\n state: structuredClone(state),\n updatedAt: Date.now(),\n })\n })\n this.leader.publishState(structuredClone(state))\n }\n\n async delete(): Promise<void> {\n await this.table.delete(this.key)\n }\n}\n\n/** Dexie adapter for core's six-field, version-guarded replica store. */\nexport class PersistenceStore implements ReplicaStoreFactory {\n private readonly db: Dexie\n private readonly stores = new Map<string, DexieReplicaStore>()\n private readonly locks: BrowserLockManager | null\n private readonly createChannel: ((name: string) => ReplicaMessageChannel) | null\n private opened = false\n\n constructor(appKey: string, options: PersistenceStoreOptions = {}) {\n this.db = new Dexie(`basic:${appKey}`)\n this.db.version(1).stores({ partitions: 'key' })\n this.db.version(2).stores({ partitions: 'key,profileId' }).upgrade((transaction) =>\n transaction.table('partitions').clear())\n this.locks = options.locks === undefined ? browserLocks() : options.locks\n this.createChannel = options.createChannel === undefined\n ? (typeof BroadcastChannel === 'undefined' ? null : browserChannel)\n : options.createChannel\n }\n\n private get partitions(): Table<PartitionRow, string> {\n return this.db.table<PartitionRow, string>('partitions')\n }\n\n async open(): Promise<void> {\n if (this.opened) return\n await cleanupLegacyState()\n await this.db.open()\n this.opened = true\n }\n\n forPartition(partition: StoragePartition): ReplicaStore {\n const key = partitionKey(partition)\n let store = this.stores.get(key)\n if (!store) {\n const channelName = `basic-replica:${this.db.name}:${key}`\n const channel = this.createChannel?.(channelName) ?? null\n const leader = new PartitionCoordinator(channelName, this.locks, channel)\n store = new DexieReplicaStore(this.partitions, { ...partition }, key, leader)\n this.stores.set(key, store)\n }\n return store\n }\n\n async deleteProfile(profileId: string): Promise<void> {\n await this.partitions.where('profileId').equals(profileId).delete()\n for (const [key, store] of this.stores) {\n if (store.partition.profileId !== profileId) continue\n store.leader.close()\n this.stores.delete(key)\n }\n }\n\n close(): void {\n for (const store of this.stores.values()) store.leader.close()\n this.stores.clear()\n if (this.opened) this.db.close()\n this.opened = false\n }\n}\n\n/** Best-effort cleanup of pre-repo-era IndexedDB databases. */\nexport async function cleanupLegacyState(): Promise<void> {\n try {\n const idb = (globalThis as { indexedDB?: IDBFactory }).indexedDB\n if (!idb || typeof idb.databases !== 'function') return\n for (const info of await idb.databases()) {\n if (!info.name?.startsWith('basic-sync:')) continue\n await new Promise<void>((resolve) => {\n const request = idb.deleteDatabase(info.name!)\n request.onsuccess = request.onerror = request.onblocked = () => resolve()\n })\n }\n } catch {\n // Legacy cleanup is deliberately best effort.\n }\n}\n","import type { KeyValueStorage } from '@basictech/core'\n\n/** Synchronous browser Storage adapted to core's key-value contract. */\nexport class BrowserKeyValueStorage implements KeyValueStorage {\n constructor(private readonly storage: Storage) {}\n\n get(key: string): string | null {\n return this.storage.getItem(key)\n }\n\n set(key: string, value: string): void {\n this.storage.setItem(key, value)\n }\n\n remove(key: string): void {\n this.storage.removeItem(key)\n }\n}\n\nexport function browserStorage(\n name: 'localStorage' | 'sessionStorage',\n): BrowserKeyValueStorage | null {\n try {\n const storage = globalThis[name]\n return storage ? new BrowserKeyValueStorage(storage) : null\n } catch {\n return null\n }\n}\n","import type { KeyValueStorage, TokenSet, TokenStore } from '@basictech/core'\n\nconst ACCESS_TOKEN_ADOPTION_TIMEOUT_MS = 100\n\ninterface MemoryAccessToken {\n value: string\n expiresAt: number\n refreshToken: string\n}\n\ninterface AccessWaiter {\n refreshToken: string\n resolve(access: MemoryAccessToken | null): void\n}\n\ntype PersistedTokenSet = Omit<TokenSet, 'access_token' | 'expires_at'>\n\nfunction parseTokens(value: string | null): Partial<TokenSet> | null {\n if (!value) return null\n try {\n const parsed = JSON.parse(value) as Partial<TokenSet>\n return parsed && typeof parsed === 'object' ? parsed : null\n } catch {\n return null\n }\n}\n\n/**\n * Browser token policy: refresh tokens survive reloads in the supplied\n * persistent store; access tokens exist only in this JavaScript realm.\n */\nexport class BrowserTokenStore implements TokenStore {\n private readonly accessTokens = new Map<string, MemoryAccessToken>()\n private readonly accessWaiters = new Map<string, AccessWaiter[]>()\n\n constructor(private readonly persistent: KeyValueStorage) {}\n\n async get(key: string): Promise<string | null> {\n const persisted = parseTokens(await this.persistent.get(key))\n if (!persisted?.refresh_token || typeof persisted.token_type !== 'string') return null\n const refreshToken = persisted.refresh_token\n let access = this.accessTokens.get(key)\n if (access && access.refreshToken !== refreshToken) {\n access = await this.waitForAccessToken(key, refreshToken) ?? undefined\n }\n return JSON.stringify({\n ...persisted,\n access_token: access?.refreshToken === refreshToken ? access.value : '',\n expires_at: access?.refreshToken === refreshToken ? access.expiresAt : 0,\n token_type: persisted.token_type,\n refresh_token: refreshToken,\n } satisfies TokenSet)\n }\n\n async set(key: string, value: string): Promise<void> {\n const tokens = parseTokens(value)\n if (!tokens?.refresh_token || typeof tokens.access_token !== 'string' ||\n typeof tokens.token_type !== 'string') {\n throw new TypeError('invalid token set')\n }\n this.accessTokens.set(key, {\n value: tokens.access_token,\n expiresAt: tokens.expires_at ?? 0,\n refreshToken: tokens.refresh_token,\n })\n const { access_token: _accessToken, expires_at: _expiresAt, ...persisted } = tokens\n await this.persistent.set(key, JSON.stringify(persisted satisfies Partial<PersistedTokenSet>))\n this.resolveAccessWaiters(key)\n }\n\n async remove(key: string): Promise<void> {\n this.accessTokens.delete(key)\n for (const waiter of this.accessWaiters.get(key) ?? []) waiter.resolve(null)\n this.accessWaiters.delete(key)\n await this.persistent.remove(key)\n }\n\n accessToken(key: string): MemoryAccessToken | null {\n return this.accessTokens.get(key) ?? null\n }\n\n async adoptAccessToken(\n key: string,\n value: string,\n expiresAt: number,\n refreshToken: string,\n ): Promise<void> {\n if (!value) return\n const persisted = parseTokens(await this.persistent.get(key))\n if (persisted?.refresh_token !== refreshToken) return\n this.accessTokens.set(key, { value, expiresAt, refreshToken })\n this.resolveAccessWaiters(key)\n }\n\n private resolveAccessWaiters(key: string): void {\n const access = this.accessTokens.get(key)\n if (!access) return\n const waiting = this.accessWaiters.get(key) ?? []\n const remaining = waiting.filter((waiter) => {\n if (waiter.refreshToken !== access.refreshToken) return true\n waiter.resolve(access)\n return false\n })\n if (remaining.length) this.accessWaiters.set(key, remaining)\n else this.accessWaiters.delete(key)\n }\n\n private waitForAccessToken(key: string, refreshToken: string): Promise<MemoryAccessToken | null> {\n return new Promise((resolve) => {\n let timer: ReturnType<typeof setTimeout>\n const waiter: AccessWaiter = {\n refreshToken,\n resolve: (access) => {\n clearTimeout(timer)\n resolve(access)\n },\n }\n const waiters = this.accessWaiters.get(key) ?? []\n waiters.push(waiter)\n this.accessWaiters.set(key, waiters)\n timer = setTimeout(() => {\n const remaining = (this.accessWaiters.get(key) ?? [])\n .filter((candidate) => candidate !== waiter)\n if (remaining.length) this.accessWaiters.set(key, remaining)\n else this.accessWaiters.delete(key)\n resolve(null)\n }, ACCESS_TOKEN_ADOPTION_TIMEOUT_MS)\n })\n }\n}\n","import {\n BasicError,\n type UploadTransportAdapter,\n type UploadTransportRequest,\n} from '@basictech/core'\n\nfunction responseHeaders(xhr: XMLHttpRequest): Headers {\n const headers = new Headers()\n for (const line of xhr.getAllResponseHeaders().trim().split(/[\\r\\n]+/)) {\n if (!line) continue\n const separator = line.indexOf(':')\n if (separator > 0) headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim())\n }\n return headers\n}\n\n/** Browser multipart transport with upload progress, adapted from the Drive UI. */\nexport const browserUploadTransport: UploadTransportAdapter = {\n upload(request: UploadTransportRequest): Promise<Response> {\n if (typeof XMLHttpRequest === 'undefined') {\n return Promise.reject(new BasicError('XHR_UNAVAILABLE'))\n }\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n let settled = false\n const finish = (callback: () => void) => {\n if (settled) return\n settled = true\n if (request.signal) request.signal.removeEventListener('abort', abort)\n callback()\n }\n const abort = () => xhr.abort()\n\n xhr.open('POST', request.url)\n if (request.accessToken) xhr.setRequestHeader('authorization', `Bearer ${request.accessToken}`)\n xhr.setRequestHeader('idempotency-key', request.idempotencyKey)\n if (request.onProgress) {\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) request.onProgress?.(event.loaded, event.total)\n }\n }\n if (request.signal) {\n if (request.signal.aborted) {\n reject(request.signal.reason ?? new DOMException('Aborted', 'AbortError'))\n return\n }\n request.signal.addEventListener('abort', abort, { once: true })\n }\n xhr.onload = () => finish(() => resolve(new Response(xhr.responseText || null, {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: responseHeaders(xhr),\n })))\n xhr.onerror = () => finish(() => reject(new BasicError('NETWORK_ERROR', 'the upload could not reach the server')))\n xhr.onabort = () => finish(() => reject(request.signal?.reason ?? new DOMException('Aborted', 'AbortError')))\n xhr.ontimeout = () => finish(() => reject(new BasicError('NETWORK_ERROR', 'the upload timed out')))\n\n const form = new FormData()\n form.append('path', request.path)\n if (request.name !== undefined) form.append('name', request.name)\n if (request.mtime !== undefined) form.append('mtime', String(request.mtime))\n form.append('file', request.file, request.filename)\n xhr.send(form)\n })\n },\n}\n","import { useEffect, useRef, useState, useSyncExternalStore, type ReactNode } from 'react'\nimport type { BasicClient, BasicSchema } from '@basictech/core'\nimport { BasicClientContext } from './context'\nimport { createBasicClient, type BrowserBasicConfig } from './create-client'\n\ninterface ProviderChildrenProps {\n children: ReactNode\n renderWhileLoading?: boolean\n}\n\nexport type BasicProviderProps<S extends BasicSchema = BasicSchema> = ProviderChildrenProps & (\n | { client: BasicClient<S> }\n | (BrowserBasicConfig<S> & { client?: never })\n)\n\ninterface ClientLifecycle {\n references: number\n start: Promise<void> | null\n stopTimer: ReturnType<typeof setTimeout> | null\n}\n\nconst clientLifecycles = new WeakMap<BasicClient<BasicSchema>, ClientLifecycle>()\n\nfunction retainClient(client: BasicClient<BasicSchema>): {\n started: Promise<void>\n release: () => void\n} {\n let lifecycle = clientLifecycles.get(client)\n if (!lifecycle) {\n lifecycle = { references: 0, start: null, stopTimer: null }\n clientLifecycles.set(client, lifecycle)\n }\n lifecycle.references += 1\n if (lifecycle.stopTimer) {\n clearTimeout(lifecycle.stopTimer)\n lifecycle.stopTimer = null\n }\n lifecycle.start ??= Promise.resolve(client.start()).catch((error: unknown) => {\n lifecycle!.start = null\n throw error\n })\n\n let released = false\n return {\n started: lifecycle.start,\n release: () => {\n if (released) return\n released = true\n lifecycle!.references = Math.max(0, lifecycle!.references - 1)\n if (lifecycle!.references > 0 || lifecycle!.stopTimer) return\n lifecycle!.stopTimer = setTimeout(() => {\n lifecycle!.stopTimer = null\n if (lifecycle!.references > 0) return\n const started = lifecycle!.start ?? Promise.resolve()\n void started.catch(() => {}).then(() => {\n if (lifecycle!.references > 0) return\n client.stop()\n lifecycle!.start = null\n })\n }, 0)\n },\n }\n}\n\n/** Generic provider for schema-less or explicitly generic applications. */\nexport function BasicProvider<S extends BasicSchema = BasicSchema>(props: BasicProviderProps<S>) {\n const clientRef = useRef<BasicClient<S> | null>(null)\n if (!clientRef.current) {\n if ('client' in props && props.client) {\n clientRef.current = props.client\n } else {\n const { children: _children, renderWhileLoading: _renderWhileLoading, ...config } = props\n clientRef.current = createBasicClient(config as BrowserBasicConfig<S>)\n }\n }\n const client = clientRef.current\n const [startError, setStartError] = useState<unknown>(null)\n\n useEffect(() => {\n let active = true\n const retained = retainClient(client as BasicClient<BasicSchema>)\n void retained.started.catch((error: unknown) => {\n if (active) setStartError(error)\n })\n return () => {\n active = false\n retained.release()\n }\n }, [client])\n\n const snapshot = useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n if (startError) throw startError\n\n return (\n <BasicClientContext.Provider value={client as BasicClient<BasicSchema>}>\n {(snapshot.isReady || props.renderWhileLoading) && props.children}\n </BasicClientContext.Provider>\n )\n}\n","import { createContext } from 'react'\nimport type { BasicClient, BasicSchema } from '@basictech/core'\n\nexport const BasicClientContext = createContext<BasicClient<BasicSchema> | null>(null)\n","import { useCallback, useMemo } from 'react'\nimport type { BasicClient, BasicProfile, BasicSchema } from '@basictech/core'\nimport { useClientSnapshot, useRequiredClient } from './client'\n\nexport interface UseAccountsResult {\n accounts: BasicProfile[]\n active: BasicProfile | null\n switchAccount(id: string): Promise<void>\n addAccount(): Promise<BasicProfile>\n removeAccount(id: string): Promise<void>\n}\n\nexport function useAccountsFor<S extends BasicSchema>(client: BasicClient<S>): UseAccountsResult {\n const snapshot = useClientSnapshot(client)\n const switchAccount = useCallback((id: string) => client.switchAccount(id), [client])\n const addAccount = useCallback(() => client.addAccount(), [client])\n const removeAccount = useCallback((id: string) => client.removeAccount(id), [client])\n\n return useMemo(() => ({\n accounts: snapshot.profiles,\n active: snapshot.activeProfile,\n switchAccount,\n addAccount,\n removeAccount,\n }), [snapshot.profiles, snapshot.activeProfile, switchAccount, addAccount, removeAccount])\n}\n\nexport function useAccounts(): UseAccountsResult {\n return useAccountsFor(useRequiredClient())\n}\n","import { useContext, useEffect, useRef, useState, useSyncExternalStore } from 'react'\nimport {\n BasicError,\n type BasicClient,\n type BasicClientSnapshot,\n type BasicSchema,\n} from '@basictech/core'\nimport { BasicClientContext } from '../context'\n\nexport interface AsyncResult<T> {\n data: T\n isLoading: boolean\n error: BasicError | null\n refresh(): void\n}\n\nexport function useRequiredClient<S extends BasicSchema = BasicSchema>(): BasicClient<S> {\n const client = useContext(BasicClientContext)\n if (!client) throw new Error('Basic hooks must be used within a <BasicProvider>')\n return client as unknown as BasicClient<S>\n}\n\nexport function useClientSnapshot<S extends BasicSchema>(\n client: BasicClient<S>,\n): BasicClientSnapshot {\n return useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n}\n\nexport function toBasicError(error: unknown, fallback = 'UNKNOWN_ERROR'): BasicError {\n if (error instanceof BasicError) return error\n return new BasicError(fallback, error instanceof Error ? error.message : String(error))\n}\n\nexport function useAsyncResult<T>(\n load: () => Promise<T>,\n initialData: T,\n enabled: boolean,\n settled: boolean,\n dependencies: readonly unknown[],\n): AsyncResult<T> {\n const loadRef = useRef(load)\n loadRef.current = load\n const [refreshVersion, setRefreshVersion] = useState(0)\n const [state, setState] = useState<Omit<AsyncResult<T>, 'refresh'>>({\n data: initialData,\n isLoading: !settled || enabled,\n error: null,\n })\n\n useEffect(() => {\n let active = true\n if (!enabled) {\n setState({ data: initialData, isLoading: !settled, error: null })\n return () => {\n active = false\n }\n }\n setState((current) => ({ ...current, isLoading: true, error: null }))\n void loadRef.current().then(\n (data) => {\n if (active) setState({ data, isLoading: false, error: null })\n },\n (error: unknown) => {\n if (active) setState((current) => ({\n ...current,\n isLoading: false,\n error: toBasicError(error),\n }))\n },\n )\n return () => {\n active = false\n }\n // The caller supplies semantic dependencies; load identity is held in a ref.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, settled, refreshVersion, ...dependencies])\n\n return {\n ...state,\n refresh: () => setRefreshVersion((version) => version + 1),\n }\n}\n","import { useCallback, useMemo } from 'react'\nimport {\n BasicError,\n type AuthStatus,\n type AuthUser,\n type BasicClient,\n type BasicSchema,\n} from '@basictech/core'\nimport { useClientSnapshot, useRequiredClient } from './client'\n\nexport interface UseAuthResult {\n isReady: boolean\n isSignedIn: boolean\n isAnonymous: boolean\n status: AuthStatus\n error: BasicError | null\n user: AuthUser | null\n did: string | null\n handle: string | null\n signIn(input?: string): Promise<void>\n signOut(): Promise<void>\n getToken(): Promise<string>\n}\n\nexport function useAuthFor<S extends BasicSchema>(client: BasicClient<S>): UseAuthResult {\n const snapshot = useClientSnapshot(client)\n const signIn = useCallback((input?: string) => client.signIn(input), [client])\n const signOut = useCallback(() => client.signOut(), [client])\n const getToken = useCallback(() => client.getToken(), [client])\n\n return useMemo(() => ({\n isReady: snapshot.isReady,\n isSignedIn: snapshot.isSignedIn,\n isAnonymous: snapshot.isAnonymous,\n status: snapshot.authStatus,\n error: snapshot.authErrorCode ? new BasicError(snapshot.authErrorCode) : null,\n user: snapshot.user,\n did: snapshot.did,\n handle: snapshot.handle,\n signIn,\n signOut,\n getToken,\n }), [snapshot, signIn, signOut, getToken])\n}\n\nexport function useAuth(): UseAuthResult {\n return useAuthFor(useRequiredClient())\n}\n","import type {\n BasicClient,\n BasicDb,\n BasicSchema,\n Collection,\n InferValue,\n JsonObject,\n MountViewerFiles,\n OwnerFiles,\n SourceRef,\n TableNames,\n} from '@basictech/core'\nimport { useRequiredClient } from './client'\n\nexport function useDbFor<S extends BasicSchema>(\n client: BasicClient<S>,\n source: { mountId: string },\n): BasicDb<S, MountViewerFiles>\nexport function useDbFor<S extends BasicSchema>(\n client: BasicClient<S>,\n source?: 'default' | { repoId: string },\n): BasicDb<S, OwnerFiles>\nexport function useDbFor<S extends BasicSchema>(\n client: BasicClient<S>,\n source: SourceRef,\n): BasicDb<S, OwnerFiles | MountViewerFiles>\nexport function useDbFor<S extends BasicSchema>(\n client: BasicClient<S>,\n source: SourceRef = 'default',\n): BasicDb<S, OwnerFiles | MountViewerFiles> {\n return client.db(source)\n}\n\nexport function useDb<S extends BasicSchema = BasicSchema>(\n source: { mountId: string },\n): BasicDb<S, MountViewerFiles>\nexport function useDb<S extends BasicSchema = BasicSchema>(\n source?: 'default' | { repoId: string },\n): BasicDb<S, OwnerFiles>\nexport function useDb<S extends BasicSchema = BasicSchema>(\n source: SourceRef,\n): BasicDb<S, OwnerFiles | MountViewerFiles>\nexport function useDb<S extends BasicSchema = BasicSchema>(\n source: SourceRef = 'default',\n): BasicDb<S, OwnerFiles | MountViewerFiles> {\n return useRequiredClient<S>().db(source)\n}\n\nexport function useCollectionFor<\n S extends BasicSchema,\n T extends TableNames<S>,\n>(\n client: BasicClient<S>,\n name: T,\n options: { source?: SourceRef } = {},\n): Collection<InferValue<S, T> & JsonObject> {\n return client.db(options.source ?? 'default').collection(name)\n}\n\nexport function useCollection<V extends JsonObject = JsonObject>(\n name: string,\n options: { source?: SourceRef } = {},\n): Collection<V> {\n return useRequiredClient().db(options.source ?? 'default').collection<V>(name)\n}\n","import { useCallback, useMemo } from 'react'\nimport type { BasicClient, BasicSchema, JsonObject, Repo } from '@basictech/core'\nimport { useClientSnapshot, useRequiredClient } from './client'\n\nexport interface UseReposResult {\n repos: Repo[]\n defaultRepoId: string | null\n refresh(): Promise<Repo[]>\n create(input: {\n name: string\n schema_type?: Repo['schema_type']\n schema?: JsonObject\n }): Promise<Repo>\n archive(repoId: string): Promise<void>\n}\n\nexport function useReposFor<S extends BasicSchema>(client: BasicClient<S>): UseReposResult {\n const snapshot = useClientSnapshot(client)\n const refresh = useCallback(() => client.refreshRepos(), [client])\n const create = useCallback((input: {\n name: string\n schema_type?: Repo['schema_type']\n schema?: JsonObject\n }) => client.createRepo(input), [client])\n const archive = useCallback((repoId: string) => client.archiveRepo(repoId), [client])\n\n return useMemo(() => ({\n repos: snapshot.repos,\n defaultRepoId: snapshot.defaultRepoId,\n refresh,\n create,\n archive,\n }), [snapshot.repos, snapshot.defaultRepoId, refresh, create, archive])\n}\n\nexport function useRepos(): UseReposResult {\n return useReposFor(useRequiredClient())\n}\n","import { useCallback, useMemo } from 'react'\nimport type {\n BasicClient,\n BasicConflict,\n BasicRejection,\n BasicSchema,\n BasicSyncStatus,\n SchemaStatus,\n SourceRef,\n} from '@basictech/core'\nimport { useClientSnapshot, useRequiredClient } from './client'\n\nexport interface UseSyncStatusResult {\n status: BasicSyncStatus\n pendingCount: number\n rejected: BasicRejection[]\n conflicts: BasicConflict[]\n resolveConflict(opId: string, choice: 'keep-mine' | 'keep-theirs'): Promise<boolean>\n discardRejected(opId: string): Promise<boolean>\n}\n\nexport function useSyncStatusFor<S extends BasicSchema>(\n client: BasicClient<S>,\n source?: SourceRef,\n): UseSyncStatusResult {\n const snapshot = useClientSnapshot(client)\n const sourceKey = JSON.stringify(source)\n const resolveConflict = useCallback(\n (opId: string, choice: 'keep-mine' | 'keep-theirs') =>\n client.resolveConflict(opId, choice, source ?? 'default'),\n // sourceKey captures semantic source identity.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, sourceKey],\n )\n const discardRejected = useCallback(\n (opId: string) => client.discardRejected(opId, source ?? 'default'),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, sourceKey],\n )\n\n return useMemo(() => ({\n status: source === undefined ? snapshot.syncStatus : client.status(source),\n pendingCount: client.pending(source).length,\n rejected: client.rejected(source),\n conflicts: client.conflicts(source),\n resolveConflict,\n discardRejected,\n // sourceKey captures semantic source identity.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [client, snapshot, sourceKey, resolveConflict, discardRejected])\n}\n\nexport function useSyncStatus(source?: SourceRef): UseSyncStatusResult {\n return useSyncStatusFor(useRequiredClient(), source)\n}\n\nexport function useSchemaStatusFor<S extends BasicSchema>(\n client: BasicClient<S>,\n source: SourceRef = 'default',\n): SchemaStatus {\n useClientSnapshot(client)\n return client.schemaStatus(source)\n}\n\nexport function useSchemaStatus(source: SourceRef = 'default'): SchemaStatus {\n return useSchemaStatusFor(useRequiredClient(), source)\n}\n","import type {\n BasicClient,\n BasicDb,\n BasicSchema,\n Repo,\n} from '@basictech/core'\nimport { useAccountsFor, type UseAccountsResult } from './accounts'\nimport { useAuthFor, type UseAuthResult } from './auth'\nimport { useRequiredClient } from './client'\nimport { useDbFor } from './db'\nimport { useReposFor } from './repos'\nimport { useSyncStatusFor, type UseSyncStatusResult } from './status'\n\nexport interface UseBasicResult<S extends BasicSchema = BasicSchema> extends UseAuthResult {\n client: BasicClient<S>\n db: BasicDb<S>\n accounts: UseAccountsResult\n sync: UseSyncStatusResult\n repos: Repo[]\n}\n\nexport function useBasicFor<S extends BasicSchema>(client: BasicClient<S>): UseBasicResult<S> {\n const auth = useAuthFor(client)\n const accounts = useAccountsFor(client)\n const sync = useSyncStatusFor(client)\n const repos = useReposFor(client)\n return {\n ...auth,\n client,\n db: useDbFor(client),\n accounts,\n sync,\n repos: repos.repos,\n }\n}\n\nexport function useBasic<S extends BasicSchema = BasicSchema>(): UseBasicResult<S> {\n return useBasicFor(useRequiredClient<S>())\n}\n","import { useMemo, useSyncExternalStore } from 'react'\nimport type {\n BasicClient,\n BasicError,\n BasicSchema,\n FileListQuery,\n FileRecord,\n MountFileInfo,\n SourceRef,\n StorageInfo,\n} from '@basictech/core'\nimport { useAsyncResult, useClientSnapshot, useRequiredClient } from './client'\n\nconst zero = () => 0\n\nexport interface UseFilesResult {\n data: Array<FileRecord | MountFileInfo>\n isLoading: boolean\n error: BasicError | null\n refresh(): void\n}\n\nexport function useFilesFor<S extends BasicSchema>(\n client: BasicClient<S>,\n query: FileListQuery = {},\n options: { source?: SourceRef } = {},\n): UseFilesResult {\n const source = options.source ?? 'default'\n const sourceKey = JSON.stringify(source)\n const queryKey = JSON.stringify(query)\n const snapshot = useClientSnapshot(client)\n const subscription = useMemo(\n () => client.queryStore.collection(source, '_files'),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, sourceKey],\n )\n const version = useSyncExternalStore(subscription.subscribe, subscription.getSnapshot, zero)\n return useAsyncResult(\n async () => {\n const files = client.db(source).files\n if (source !== 'default' && 'mountId' in source) {\n const page = await files.list({\n ...(query.prefix !== undefined ? { prefix: query.prefix } : {}),\n ...(query.limit !== undefined ? { limit: query.limit } : {}),\n ...(query.cursor !== undefined ? { cursor: query.cursor } : {}),\n })\n return page.data\n }\n return (await files.list(query)).data\n },\n [],\n snapshot.isReady,\n snapshot.isReady,\n [sourceKey, queryKey, version, snapshot.activeProfile?.id],\n )\n}\n\nexport function useFiles(\n query: FileListQuery = {},\n options: { source?: SourceRef } = {},\n): UseFilesResult {\n return useFilesFor(useRequiredClient(), query, options)\n}\n\nexport interface UseStorageInfoResult {\n data: StorageInfo | null\n isLoading: boolean\n error: BasicError | null\n refresh(): void\n}\n\nexport function useStorageInfoFor<S extends BasicSchema>(\n client: BasicClient<S>,\n): UseStorageInfoResult {\n const snapshot = useClientSnapshot(client)\n return useAsyncResult(\n () => client.storageInfo(client.resolveRepoId()),\n null,\n snapshot.isReady && snapshot.isSignedIn,\n snapshot.isReady,\n [snapshot.activeProfile?.id],\n )\n}\n\nexport function useStorageInfo(): UseStorageInfoResult {\n return useStorageInfoFor(useRequiredClient())\n}\n","import { useCallback } from 'react'\nimport type {\n BasicClient,\n BasicError,\n BasicSchema,\n CreateOutgoingShareInput,\n MountHandle,\n MountInfo,\n MountsQuery,\n OutgoingShareInfo,\n} from '@basictech/core'\nimport { useAsyncResult, useClientSnapshot, useRequiredClient } from './client'\n\nexport interface UseMountsResult<S extends BasicSchema = BasicSchema> {\n data: MountInfo[]\n mounts: MountInfo[]\n isLoading: boolean\n error: BasicError | null\n refresh(): void\n open(mountId: string): Promise<MountHandle<S>>\n manageUrl(): string\n}\n\nexport function useMountsFor<S extends BasicSchema>(\n client: BasicClient<S>,\n query: MountsQuery = {},\n): UseMountsResult<S> {\n const snapshot = useClientSnapshot(client)\n const queryKey = JSON.stringify(query)\n const result = useAsyncResult(\n () => client.shares.mounts(query),\n [],\n snapshot.isReady && snapshot.isSignedIn,\n snapshot.isReady,\n [queryKey, snapshot.activeProfile?.id],\n )\n const open = useCallback(\n (mountId: string) => client.shares.mount(mountId),\n [client],\n )\n const manageUrl = useCallback(() => client.shares.manageUrl(), [client])\n const { data: mounts, ...state } = result\n return { data: mounts, mounts, ...state, open, manageUrl }\n}\n\nexport function useMounts(query: MountsQuery = {}): UseMountsResult {\n return useMountsFor(useRequiredClient(), query)\n}\n\nexport interface UseOutgoingSharesResult {\n data: OutgoingShareInfo[]\n outgoingShares: OutgoingShareInfo[]\n isLoading: boolean\n error: BasicError | null\n refresh(): void\n create(input: CreateOutgoingShareInput): Promise<OutgoingShareInfo>\n get(id: string): Promise<OutgoingShareInfo>\n cancel(id: string): Promise<OutgoingShareInfo>\n revoke(id: string): Promise<OutgoingShareInfo>\n getContactHandle(did: string): Promise<string | null>\n manageUrl(): string\n}\n\nexport function useOutgoingSharesFor<S extends BasicSchema>(\n client: BasicClient<S>,\n): UseOutgoingSharesResult {\n const snapshot = useClientSnapshot(client)\n const result = useAsyncResult(\n () => client.shares.listOutgoing(),\n [],\n snapshot.isReady && snapshot.isSignedIn,\n snapshot.isReady,\n [snapshot.activeProfile?.id],\n )\n const create = useCallback((input: CreateOutgoingShareInput) =>\n client.shares.createOutgoing(input), [client])\n const get = useCallback((id: string) => client.shares.getOutgoing(id), [client])\n const cancel = useCallback((id: string) => client.shares.cancel(id), [client])\n const revoke = useCallback((id: string) => client.shares.revoke(id), [client])\n const getContactHandle = useCallback((did: string) => client.shares.getContactHandle(did), [client])\n const manageUrl = useCallback(() => client.shares.manageUrl(), [client])\n const { data: outgoingShares, ...state } = result\n return {\n data: outgoingShares,\n outgoingShares,\n ...state,\n create,\n get,\n cancel,\n revoke,\n getContactHandle,\n manageUrl,\n }\n}\n\nexport function useOutgoingShares(): UseOutgoingSharesResult {\n return useOutgoingSharesFor(useRequiredClient())\n}\n","import { useEffect, useMemo, useState, useSyncExternalStore } from 'react'\nimport {\n type BasicClient,\n type BasicRecord,\n type BasicSchema,\n type InferValue,\n type JsonObject,\n type Query,\n type SourceRef,\n type TableNames,\n} from '@basictech/core'\nimport { toBasicError, useClientSnapshot, useRequiredClient } from './client'\nimport type { BasicError } from '@basictech/core'\n\nconst subscribeNever = () => () => {}\nconst zero = () => 0\n\nexport interface UseQueryResult<V extends JsonObject> {\n data: BasicRecord<V>[]\n isLoading: boolean\n error: BasicError | null\n}\n\nexport function useQueryValueFor<\n S extends BasicSchema,\n V extends JsonObject,\n>(\n client: BasicClient<S>,\n collection: string,\n query: Query<V> = {},\n options: { source?: SourceRef } = {},\n): UseQueryResult<V> {\n const source = options.source ?? 'default'\n const sourceKey = JSON.stringify(source)\n const queryKey = JSON.stringify(query)\n const snapshot = useClientSnapshot(client)\n const subscription = useMemo(\n () => client.queryStore.collection(source, collection),\n // sourceKey captures semantic source identity rather than object identity.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, sourceKey, collection],\n )\n const version = useSyncExternalStore(\n subscription?.subscribe ?? subscribeNever,\n subscription?.getSnapshot ?? zero,\n zero,\n )\n const [result, setResult] = useState<UseQueryResult<V>>({\n data: [],\n isLoading: true,\n error: null,\n })\n\n useEffect(() => {\n let active = true\n if (!snapshot.isReady) {\n setResult((current) => ({ ...current, isLoading: true, error: null }))\n return () => {\n active = false\n }\n }\n setResult((current) => ({ ...current, isLoading: true, error: null }))\n const collectionApi = client.db(source).collection<V>(collection)\n const list = collectionApi.list as unknown as (\n value: Query<V>,\n ) => Promise<{ data: BasicRecord<V>[] }>\n void list.call(collectionApi, query).then(\n (page) => {\n if (active) setResult({ data: page.data, isLoading: false, error: null })\n },\n (error: unknown) => {\n if (active) setResult((current) => ({\n ...current,\n isLoading: false,\n error: toBasicError(error, 'QUERY_FAILED'),\n }))\n },\n )\n return () => {\n active = false\n }\n // source and query are represented by their stable semantic keys.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, collection, sourceKey, queryKey, version, snapshot.isReady])\n\n return result\n}\n\nexport function useQueryFor<\n S extends BasicSchema,\n T extends TableNames<S>,\n>(\n client: BasicClient<S>,\n collection: T,\n query: Query<InferValue<S, T> & JsonObject> = {},\n options: { source?: SourceRef } = {},\n): UseQueryResult<InferValue<S, T> & JsonObject> {\n return useQueryValueFor(client, collection, query, options)\n}\n\nexport function useQuery<V extends JsonObject = JsonObject>(\n collection: string,\n query: Query<V> = {},\n options: { source?: SourceRef } = {},\n): UseQueryResult<V> {\n return useQueryValueFor(useRequiredClient(), collection, query, options)\n}\n","import type { ReactElement, ReactNode } from 'react'\nimport type {\n BasicClient,\n BasicDb,\n BasicSchema,\n Collection,\n FileListQuery,\n InferValue,\n JsonObject,\n MountViewerFiles,\n MountsQuery,\n OwnerFiles,\n Query,\n SourceRef,\n TableNames,\n} from '@basictech/core'\nimport { createBasicClient, type BrowserBasicConfig } from './create-client'\nimport { BasicProvider } from './provider'\nimport { useAccountsFor, type UseAccountsResult } from './hooks/accounts'\nimport { useAuthFor, type UseAuthResult } from './hooks/auth'\nimport { useBasicFor, type UseBasicResult } from './hooks/basic'\nimport { useCollectionFor } from './hooks/db'\nimport {\n useFilesFor,\n useStorageInfoFor,\n type UseFilesResult,\n type UseStorageInfoResult,\n} from './hooks/files'\nimport {\n useMountsFor,\n useOutgoingSharesFor,\n type UseMountsResult,\n type UseOutgoingSharesResult,\n} from './hooks/mounts'\nimport { useQueryFor, type UseQueryResult } from './hooks/query'\nimport { useReposFor, type UseReposResult } from './hooks/repos'\nimport { useSchemaStatusFor, useSyncStatusFor, type UseSyncStatusResult } from './hooks/status'\nimport type { SchemaStatus } from '@basictech/core'\n\nexport type CreateBasicConfig<S extends BasicSchema> = BrowserBasicConfig<S> & { schema: S }\n\nexport interface BoundBasicProviderProps {\n children: ReactNode\n renderWhileLoading?: boolean\n}\n\nexport interface CreatedBasic<S extends BasicSchema> {\n client: BasicClient<S>\n Provider(props: BoundBasicProviderProps): ReactElement\n useBasic(): UseBasicResult<S>\n useAuth(): UseAuthResult\n useAccounts(): UseAccountsResult\n useDb(source: { mountId: string }): BasicDb<S, MountViewerFiles>\n useDb(source?: 'default' | { repoId: string }): BasicDb<S, OwnerFiles>\n useDb(source: SourceRef): BasicDb<S, OwnerFiles | MountViewerFiles>\n useCollection<T extends TableNames<S>>(\n name: T,\n options?: { source?: SourceRef },\n ): Collection<InferValue<S, T> & JsonObject>\n useQuery<T extends TableNames<S>>(\n collection: T,\n query?: Query<InferValue<S, T> & JsonObject>,\n options?: { source?: SourceRef },\n ): UseQueryResult<InferValue<S, T> & JsonObject>\n useSyncStatus(source?: SourceRef): UseSyncStatusResult\n useSchemaStatus(source?: SourceRef): SchemaStatus\n useRepos(): UseReposResult\n useFiles(query?: FileListQuery, options?: { source?: SourceRef }): UseFilesResult\n useStorageInfo(): UseStorageInfoResult\n useMounts(query?: MountsQuery): UseMountsResult<S>\n useOutgoingShares(): UseOutgoingSharesResult\n}\n\n/** Create one browser client and a complete hook surface bound to its schema. */\nexport function createBasic<const S extends BasicSchema>(config: CreateBasicConfig<S>): CreatedBasic<S> {\n const client = createBasicClient(config)\n\n function Provider({ children, renderWhileLoading }: BoundBasicProviderProps) {\n return (\n <BasicProvider client={client} renderWhileLoading={renderWhileLoading}>\n {children}\n </BasicProvider>\n )\n }\n\n function useBoundDb(source: { mountId: string }): BasicDb<S, MountViewerFiles>\n function useBoundDb(source?: 'default' | { repoId: string }): BasicDb<S, OwnerFiles>\n function useBoundDb(source: SourceRef): BasicDb<S, OwnerFiles | MountViewerFiles>\n function useBoundDb(\n source: SourceRef = 'default',\n ): BasicDb<S, OwnerFiles | MountViewerFiles> {\n return client.db(source)\n }\n\n return {\n client,\n Provider,\n useBasic: () => useBasicFor(client),\n useAuth: () => useAuthFor(client),\n useAccounts: () => useAccountsFor(client),\n useDb: useBoundDb,\n useCollection: (name, options = {}) => useCollectionFor(client, name, options),\n useQuery: (collection, query = {}, options = {}) =>\n useQueryFor(client, collection, query, options),\n useSyncStatus: (source) => useSyncStatusFor(client, source),\n useSchemaStatus: (source = 'default') => useSchemaStatusFor(client, source),\n useRepos: () => useReposFor(client),\n useFiles: (query = {}, options = {}) => useFilesFor(client, query, options),\n useStorageInfo: () => useStorageInfoFor(client),\n useMounts: (query = {}) => useMountsFor(client, query),\n useOutgoingShares: () => useOutgoingSharesFor(client),\n }\n}\n"],"mappings":"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","names":["BasicError","BasicError","useEffect","useRef","useState","useSyncExternalStore","BasicError","useSyncExternalStore","BasicError","useRef","useState","useEffect","useCallback","useMemo","BasicError","useCallback","useMemo","BasicError","useCallback","useMemo","useCallback","useMemo","useCallback","useMemo","useCallback","useMemo","useMemo","useSyncExternalStore","useMemo","useSyncExternalStore","useCallback","useCallback","useEffect","useMemo","useState","useSyncExternalStore","zero","useMemo","useSyncExternalStore","useState","useEffect","jsx"]}
|