@marktiderman/genesis-native 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +354 -10
- package/dist/block-C5-noMhB.d.ts +223 -0
- package/dist/blocks-a1YQ1Elf.d.ts +1540 -0
- package/dist/chunk-65P7RU4V.js +49 -0
- package/dist/chunk-65P7RU4V.js.map +1 -0
- package/dist/chunk-6BT4PTGH.js +37 -0
- package/dist/chunk-6BT4PTGH.js.map +1 -0
- package/dist/chunk-75YP72G6.js +374 -0
- package/dist/chunk-75YP72G6.js.map +1 -0
- package/dist/chunk-NGYNYJPL.js +90 -0
- package/dist/chunk-NGYNYJPL.js.map +1 -0
- package/dist/chunk-VKTIHNAV.js +95 -0
- package/dist/chunk-VKTIHNAV.js.map +1 -0
- package/dist/{chunk-MMTPWUWI.js → chunk-VTJDIKFC.js} +9 -6
- package/dist/chunk-VTJDIKFC.js.map +1 -0
- package/dist/chunk-XE7LC7K6.js +29 -0
- package/dist/chunk-XE7LC7K6.js.map +1 -0
- package/dist/dev-warnings.d.ts +34 -0
- package/dist/dev-warnings.js +15 -0
- package/dist/dev-warnings.js.map +1 -0
- package/dist/devtools.d.ts +144 -0
- package/dist/devtools.js +390 -0
- package/dist/devtools.js.map +1 -0
- package/dist/index.d.ts +12 -368
- package/dist/index.js +88 -191
- package/dist/index.js.map +1 -1
- package/dist/observability.d.ts +170 -0
- package/dist/observability.js +123 -0
- package/dist/observability.js.map +1 -0
- package/dist/persist.d.ts +1 -1
- package/dist/persist.js +1 -1
- package/dist/push.d.ts +169 -0
- package/dist/push.js +996 -0
- package/dist/push.js.map +1 -0
- package/dist/{query-DhH3lLFa.d.ts → query-DUmVAfsF.d.ts} +11 -6
- package/dist/updates.d.ts +8 -1
- package/dist/updates.js +44 -69
- package/dist/updates.js.map +1 -1
- package/package.json +222 -5
- package/src/app.tsx +491 -0
- package/src/auth.tsx +176 -0
- package/src/blocks.tsx +144 -0
- package/src/boot.tsx +188 -0
- package/src/dev-warnings.ts +43 -0
- package/src/devtools/block.tsx +488 -0
- package/src/devtools/gestures.ts +107 -0
- package/src/devtools/index.ts +22 -0
- package/src/devtools/info.ts +45 -0
- package/src/devtools/slots.ts +21 -0
- package/src/errors.tsx +195 -0
- package/src/held-link.ts +90 -0
- package/src/hydration-gate.ts +88 -0
- package/src/index.ts +83 -0
- package/src/links.ts +140 -0
- package/src/nativewind.d.ts +41 -0
- package/src/observability/block.tsx +300 -0
- package/src/observability/events.ts +89 -0
- package/src/observability/index.ts +44 -0
- package/src/observability/scrub.ts +166 -0
- package/src/observability/sentry.ts +222 -0
- package/src/observability/sink.ts +147 -0
- package/src/persist.ts +83 -0
- package/src/push/backend.ts +129 -0
- package/src/push/block.tsx +545 -0
- package/src/push/index.ts +102 -0
- package/src/push/modules.ts +111 -0
- package/src/push/permission.ts +191 -0
- package/src/push/preferences.ts +136 -0
- package/src/push/quiet-hours.ts +71 -0
- package/src/push/registration.ts +189 -0
- package/src/push/routing.ts +27 -0
- package/src/push/screens.tsx +46 -0
- package/src/push/settings.tsx +378 -0
- package/src/query.ts +100 -0
- package/src/updates/block.tsx +442 -0
- package/src/updates/channels.ts +131 -0
- package/src/updates/checker.ts +190 -0
- package/src/updates/index.ts +87 -0
- package/src/updates/modules.ts +64 -0
- package/src/updates/policy.ts +314 -0
- package/src/updates/screens.tsx +159 -0
- package/src/updates/signature.ts +80 -0
- package/src/updates/store.ts +33 -0
- package/src/updates/version.ts +39 -0
- package/src/updates/whats-new.ts +122 -0
- package/dist/block-Dh5ny06W.d.ts +0 -535
- package/dist/chunk-MMTPWUWI.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/boot.tsx","../src/errors.tsx","../src/auth.tsx","../src/held-link.ts","../src/app.tsx","../src/hydration-gate.ts","../src/links.ts"],"names":["jsx","createContext","useContext","useSyncExternalStore","View","Text","Fragment","useRef","client","persistence","session","boot","FatalFallback","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Boot: the async work an app must finish before its first screen (wipe a\n * session left by a reinstall, hydrate stores, load fonts, restore the query\n * cache, read the session).\n *\n * Steps run once each, in order. A step that finished is never run again, so\n * \"try again\" after a failure resumes at the step that failed. Each step has a\n * timeout (10 seconds by default), so a hung step ends in the fatal screen with\n * retry instead of trapping the splash. A minimum keeps a fast boot from\n * flashing the splash.\n *\n * `createBoot` is the controller (no React); `BootProvider` + `useBoot()` read\n * it from components.\n */\nimport { createContext, useContext, useSyncExternalStore, type ReactNode } from \"react\";\n\nexport interface BootStepContext {\n /**\n * Aborted when the step times out. Stop work when it fires: a retry waits\n * for a timed-out run to settle before running the step again.\n */\n signal: AbortSignal;\n}\n\nexport interface BootStep {\n /** Unique within the list; names the step in errors. */\n id: string;\n run: (context: BootStepContext) => Promise<unknown> | unknown;\n /** Overrides the boot's `timeoutMs` for this step. */\n timeoutMs?: number;\n}\n\nexport type BootStatus = \"idle\" | \"booting\" | \"ready\" | \"failed\";\n\nexport interface BootState {\n status: BootStatus;\n /** Set when `status` is `\"failed\"`. */\n error: Error | null;\n /** The id of the step that failed. */\n failedStep: string | null;\n /** Ids of the steps that have finished, in order. */\n completed: readonly string[];\n}\n\nexport interface BootOptions {\n /** Shortest time the boot takes, so the splash doesn't flash. Default 0. */\n minimumMs?: number;\n /** Longest time one step may take. Default 10 000. */\n timeoutMs?: number;\n}\n\nexport interface BootController {\n getState(): BootState;\n subscribe(listener: () => void): () => void;\n /** Run the steps not yet finished. Calling it while a run is in flight returns that run. */\n start(): Promise<void>;\n /** After a failure: run again from the step that failed. */\n retry(): Promise<void>;\n}\n\n/** Thrown when a step takes longer than its timeout. */\nexport class BootTimeoutError extends Error {\n readonly step: string;\n constructor(step: string, ms: number, reason = \"did not finish\") {\n super(`Boot step \"${step}\" ${reason} within ${ms} ms.`);\n this.name = \"BootTimeoutError\";\n this.step = step;\n }\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nexport function toError(value: unknown): Error {\n if (value instanceof Error) return value;\n return new Error(typeof value === \"string\" ? value : \"Unknown error\", { cause: value });\n}\n\n/** Resolves \"settled\" when `promise` settles, \"pending\" after `ms`. */\nfunction settledWithin(promise: Promise<unknown>, ms: number): Promise<\"settled\" | \"pending\"> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return Promise.race([\n promise.then(\n () => \"settled\" as const,\n () => \"settled\" as const,\n ),\n new Promise<\"pending\">((resolve) => {\n timer = setTimeout(() => resolve(\"pending\"), ms);\n }),\n ]).finally(() => clearTimeout(timer));\n}\n\n/** The boot controller: runs `steps` once each, in order, with a timeout per step. */\nexport function createBoot(steps: readonly BootStep[], options: BootOptions = {}): BootController {\n const seen = new Set<string>();\n for (const step of steps) {\n if (seen.has(step.id)) throw new Error(`Boot step \"${step.id}\" is listed twice.`);\n seen.add(step.id);\n }\n const { minimumMs = 0, timeoutMs = DEFAULT_TIMEOUT_MS } = options;\n const listeners = new Set<() => void>();\n let state: BootState = { status: \"idle\", error: null, failedStep: null, completed: [] };\n let inFlight: Promise<void> | null = null;\n // A step that timed out keeps running (JavaScript can't stop it; `signal`\n // asks it to). A retry waits for it rather than running it twice at once.\n const abandoned = new Map<string, Promise<\"ok\" | \"failed\">>();\n\n const runStep = async (step: BootStep, ms: number): Promise<void> => {\n const previous = abandoned.get(step.id);\n if (previous) {\n if ((await settledWithin(previous, ms)) === \"pending\") {\n throw new BootTimeoutError(step.id, ms, \"is still running from the last attempt\");\n }\n abandoned.delete(step.id);\n // The abandoned run finished after all: it counts.\n if ((await previous) === \"ok\") return;\n }\n const controller = new AbortController();\n const running = Promise.resolve().then(() => step.run({ signal: controller.signal }));\n if ((await settledWithin(running, ms)) === \"pending\") {\n controller.abort();\n abandoned.set(step.id, running.then(() => \"ok\" as const, () => \"failed\" as const));\n throw new BootTimeoutError(step.id, ms);\n }\n await running;\n };\n\n const set = (next: Partial<BootState>) => {\n state = { ...state, ...next };\n for (const listener of listeners) listener();\n };\n\n const run = async () => {\n const started = Date.now();\n set({ status: \"booting\", error: null, failedStep: null });\n for (const step of steps) {\n if (state.completed.includes(step.id)) continue;\n try {\n await runStep(step, step.timeoutMs ?? timeoutMs);\n } catch (error) {\n set({ status: \"failed\", error: toError(error), failedStep: step.id });\n return;\n }\n set({ completed: [...state.completed, step.id] });\n }\n const wait = minimumMs - (Date.now() - started);\n if (wait > 0) await new Promise((resolve) => setTimeout(resolve, wait));\n set({ status: \"ready\" });\n };\n\n const start = () => {\n if (state.status === \"ready\") return Promise.resolve();\n if (!inFlight) {\n inFlight = run().finally(() => {\n inFlight = null;\n });\n }\n return inFlight;\n };\n\n return {\n getState: () => state,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n start,\n retry: start,\n };\n}\n\nconst BootContext = createContext<BootController | null>(null);\n\n/** Makes a boot readable with `useBoot()`. */\nexport function BootProvider({ boot, children }: { boot: BootController; children: ReactNode }) {\n return <BootContext.Provider value={boot}>{children}</BootContext.Provider>;\n}\n\nexport interface UseBootReturn extends BootState {\n retry: () => void;\n}\n\n/** The boot's status, and `retry` after a failure. Inside `GenesisNativeApp` or a `BootProvider`. */\nexport function useBoot(): UseBootReturn {\n const boot = useContext(BootContext);\n if (!boot) throw new Error(\"useBoot must be used inside <GenesisNativeApp> or <BootProvider>.\");\n const state = useSyncExternalStore(boot.subscribe, boot.getState, boot.getState);\n return { ...state, retry: () => void boot.retry() };\n}\n","/**\n * Errors: a boundary per screen tree, and handlers for errors React never sees\n * (a fatal global error from `ErrorUtils`, an unhandled promise rejection).\n * All of them report through one `onError` (wire Sentry there) and show the\n * fatal screen instead of letting the app die; its \"Try again\" remounts the\n * tree with fresh state.\n */\nimport { Component, type ComponentType, type ErrorInfo, type ReactNode } from \"react\";\nimport { Pressable, Text, View } from \"react-native\";\nimport { NativeButton, NativeEmptyState } from \"@marktiderman/genesis-ui-native/components\";\nimport { toError } from \"./boot\";\n\nexport interface FatalScreenProps {\n error: Error;\n /** Clears the error and remounts the app below the shell (and re-runs a failed boot). */\n retry: () => void;\n}\n\n/** The default fatal screen: what went wrong and \"Try again\". */\nexport function FatalScreen({ error, retry }: FatalScreenProps) {\n return (\n <NativeEmptyState\n variant=\"error\"\n title=\"Something went wrong\"\n body=\"The app hit a problem. Try again, and if it keeps happening, close and reopen the app.\"\n details={error.message}\n primaryAction={\n <NativeButton onPress={retry} testID=\"genesis-fatal-retry\">\n Try again\n </NativeButton>\n }\n testID=\"genesis-fatal\"\n />\n );\n}\n\n/**\n * The last-resort fatal screen: React Native primitives only, no theme, no\n * context, nothing that can itself fail. Shown when the providers could not\n * start, or when the `fatal` slot threw.\n */\nexport function PlainFatalScreen({ error, retry }: FatalScreenProps) {\n return (\n <View testID=\"genesis-fatal-plain\" style={{ flex: 1, justifyContent: \"center\", alignItems: \"center\", padding: 24, gap: 12 }}>\n <Text accessibilityRole=\"header\" style={{ fontSize: 17, fontWeight: \"600\" }}>\n Something went wrong\n </Text>\n <Text style={{ textAlign: \"center\" }}>{error.message}</Text>\n <Pressable accessibilityRole=\"button\" onPress={retry} testID=\"genesis-fatal-plain-retry\" style={{ padding: 12 }}>\n <Text style={{ fontSize: 17 }}>Try again</Text>\n </Pressable>\n </View>\n );\n}\n\nexport interface ErrorReport {\n /** True when the app could not go on (a render error, a failed boot, a fatal global error). */\n fatal: boolean;\n source: \"boundary\" | \"global\" | \"boot\" | \"rejection\";\n componentStack?: string;\n}\n\nexport type OnError = (error: Error, report: ErrorReport) => void;\n\nexport interface GenesisErrorBoundaryProps {\n children?: ReactNode;\n /** What to render instead of the tree that threw. */\n fallback: ComponentType<FatalScreenProps>;\n onError?: OnError;\n /** Change it to clear a caught error (the tree remounts). */\n resetKey?: unknown;\n /** Called by the fallback's retry, after the error is cleared. */\n onRetry?: () => void;\n}\n\ninterface BoundaryState {\n error: Error | null;\n}\n\n/** An error boundary whose fallback gets `{ error, retry }`. */\nexport class GenesisErrorBoundary extends Component<GenesisErrorBoundaryProps, BoundaryState> {\n override state: BoundaryState = { error: null };\n\n static getDerivedStateFromError(error: unknown): BoundaryState {\n return { error: toError(error) };\n }\n\n override componentDidCatch(error: unknown, info: ErrorInfo) {\n this.props.onError?.(toError(error), { fatal: true, source: \"boundary\", componentStack: info.componentStack ?? undefined });\n }\n\n override componentDidUpdate(previous: GenesisErrorBoundaryProps) {\n if (this.state.error && previous.resetKey !== this.props.resetKey) this.setState({ error: null });\n }\n\n retry = () => {\n this.setState({ error: null });\n this.props.onRetry?.();\n };\n\n override render() {\n const { error } = this.state;\n if (!error) return this.props.children ?? null;\n const Fallback = this.props.fallback;\n return <Fallback error={error} retry={this.retry} />;\n }\n}\n\n/** React Native's `ErrorUtils` (a global in every RN app), or a stand-in. */\nexport interface ErrorUtilsLike {\n getGlobalHandler(): ((error: unknown, isFatal?: boolean) => void) | undefined;\n setGlobalHandler(handler: (error: unknown, isFatal?: boolean) => void): void;\n}\n\nexport interface GlobalErrorHandlerOptions {\n errorUtils: ErrorUtilsLike;\n onError?: OnError;\n /** A fatal error: show the fatal screen. The previous handler (which would end the app) is not called. */\n onFatal: (error: Error) => void;\n /**\n * True while a fatal screen is already up. Another fatal error then goes to\n * the previous handler, which ends the app (it restarts clean) rather than\n * leaving it stuck behind a screen that may itself be broken.\n */\n alreadyFatal?: () => boolean;\n}\n\n/**\n * Route global errors to `onError`. A fatal one goes to `onFatal` instead of\n * React Native's default handler, which would close the app; a non-fatal one\n * still reaches the previous handler (LogBox in development). Returns a\n * function that puts the previous handler back.\n */\nexport function installGlobalErrorHandler({ errorUtils, onError, onFatal, alreadyFatal }: GlobalErrorHandlerOptions): () => void {\n const previous = errorUtils.getGlobalHandler();\n errorUtils.setGlobalHandler((raw, isFatal) => {\n const error = toError(raw);\n try {\n onError?.(error, { fatal: Boolean(isFatal), source: \"global\" });\n } catch {\n // A failing reporter must not take the handler down with it.\n }\n if (isFatal && !alreadyFatal?.()) onFatal(error);\n else previous?.(raw, isFatal);\n });\n return () => {\n // With no previous handler, leave one that only logs, never ours (it would call an unmounted app).\n errorUtils.setGlobalHandler(previous ?? ((error) => console.error(error)));\n };\n}\n\n/** `globalThis.ErrorUtils` in a React Native runtime, undefined elsewhere. */\nexport function defaultErrorUtils(): ErrorUtilsLike | undefined {\n const candidate = (globalThis as { ErrorUtils?: ErrorUtilsLike }).ErrorUtils;\n return candidate && typeof candidate.setGlobalHandler === \"function\" ? candidate : undefined;\n}\n\n/** Hermes's `HermesInternal.enablePromiseRejectionTracker`, or a stand-in. */\nexport type EnableRejectionTracker = (options: {\n allRejections: boolean;\n onUnhandled: (id: number, rejection: unknown) => void;\n onHandled: (id: number) => void;\n}) => void;\n\n/**\n * Hermes's rejection tracker, when the app runs on Hermes. React Native sends\n * unhandled rejections to `ExceptionsManager` (LogBox in development), never\n * to `ErrorUtils`' global handler, so without this they never reach `onError`.\n */\nexport function defaultRejectionTracker(): EnableRejectionTracker | undefined {\n const hermes = (globalThis as { HermesInternal?: { enablePromiseRejectionTracker?: EnableRejectionTracker } }).HermesInternal;\n const enable = hermes?.enablePromiseRejectionTracker;\n return typeof enable === \"function\" ? enable.bind(hermes) : undefined;\n}\n\n/**\n * Report unhandled promise rejections to `onError` (non-fatal). This replaces\n * React Native's own tracker, so each rejection is also written with\n * `console.warn`, which LogBox shows in development as before.\n */\nexport function installRejectionTracker({ enable, onError }: { enable: EnableRejectionTracker; onError: OnError }): void {\n enable({\n allRejections: true,\n onUnhandled: (id, rejection) => {\n const error = toError(rejection);\n console.warn(`Uncaught (in promise, id: ${id}): ${error.message}`);\n try {\n onError(error, { fatal: false, source: \"rejection\" });\n } catch {\n // A failing reporter must not throw inside the promise machinery.\n }\n },\n onHandled: () => {},\n });\n}\n","/**\n * Auth gate: the Supabase session as app state.\n *\n * `createSessionStore(supabase)` reads the session once (`load`, a boot step,\n * so the splash stays up until it is known) and follows `onAuthStateChange`.\n * `useSession()` reads it; `AuthGate` renders `signedIn` or `signedOut`.\n *\n * Offline, `getSession()` can wait about 30 seconds on a token refresh that\n * can't succeed and then fail with a retryable error, although the session is\n * still on the phone. So `load` waits at most `waitMs` (5 s) and, on a timeout\n * or a network error, uses the stored session: the user stays signed in and\n * sees their cached data, and Supabase's own events correct it once online.\n *\n * With expo-router, gate in a layout instead and let the router render:\n *\n * const { status } = useSession();\n * if (status === \"signedOut\") return <Redirect href=\"/sign-in\" />;\n * return <Stack />;\n */\nimport { createContext, useContext, useSyncExternalStore, type ReactNode } from \"react\";\n\n/** The parts of a Supabase client the gate uses; a `SupabaseClient` fits. */\nexport interface AuthClientLike<S = unknown> {\n auth: {\n getSession(): Promise<{ data: { session: S | null }; error?: unknown }>;\n onAuthStateChange(callback: (event: string, session: S | null) => void): {\n data: { subscription: { unsubscribe(): void } };\n };\n };\n}\n\nexport type SessionStatus = \"loading\" | \"signedIn\" | \"signedOut\";\n\nexport interface SessionState<S = unknown> {\n status: SessionStatus;\n session: S | null;\n /** The signed-in user's id, or null. */\n userId: string | null;\n /** True when the session came from the phone because Supabase couldn't be reached. */\n offline: boolean;\n}\n\nexport interface SessionStore<S = unknown> {\n getState(): SessionState<S>;\n subscribe(listener: () => void): () => void;\n /** Read the current session (the boot step). Throws only on a non-network error. */\n load(): Promise<void>;\n /** Follow sign-in and sign-out; returns the unsubscribe. */\n start(): () => void;\n}\n\nexport interface SessionStoreOptions<S = unknown> {\n /**\n * The signed-in user changed after the session was first known: signed\n * out, signed in, or switched account. `previous` and `next` are user ids\n * (null when nobody). Clear caches here.\n */\n onUserChange?: (previous: string | null, next: string | null) => void;\n /** Longest wait for `getSession()` before using the stored session. Default 5000 ms. */\n waitMs?: number;\n /**\n * Read the session saved on the phone without refreshing it. Default: from\n * the Supabase client's own storage (`auth.storage` under `auth.storageKey`).\n */\n readStoredSession?: () => Promise<S | null>;\n /** The user id in a session. Default `session.user.id`. */\n userIdOf?: (session: S) => string | null;\n}\n\nconst DEFAULT_WAIT_MS = 5000;\n\nfunction defaultUserId(session: unknown): string | null {\n const id = (session as { user?: { id?: unknown } } | null)?.user?.id;\n return typeof id === \"string\" ? id : null;\n}\n\n/** A network failure (supabase-js `AuthRetryableFetchError`, status 0), as opposed to a real refusal. */\nfunction isNetworkError(error: unknown): boolean {\n const e = error as { name?: unknown; status?: unknown } | null;\n return e?.name === \"AuthRetryableFetchError\" || e?.status === 0;\n}\n\n/** The session supabase-js keeps under `auth.storageKey`, read without a refresh. */\nfunction storedSessionReader<S>(client: AuthClientLike<S>): () => Promise<S | null> {\n return async () => {\n const auth = client.auth as { storage?: { getItem(key: string): unknown }; storageKey?: unknown };\n if (!auth.storage || typeof auth.storageKey !== \"string\") return null;\n const raw = await auth.storage.getItem(auth.storageKey);\n if (typeof raw !== \"string\") return (raw as S | null) ?? null;\n try {\n return JSON.parse(raw) as S;\n } catch {\n return null;\n }\n };\n}\n\n/** The Supabase session as a store: `load` reads it once, `start` follows auth events. */\nexport function createSessionStore<S = unknown>(client: AuthClientLike<S>, options: SessionStoreOptions<S> = {}): SessionStore<S> {\n const { onUserChange, waitMs = DEFAULT_WAIT_MS, userIdOf = defaultUserId } = options;\n const readStored = options.readStoredSession ?? storedSessionReader(client);\n const listeners = new Set<() => void>();\n let state: SessionState<S> = { status: \"loading\", session: null, userId: null, offline: false };\n // Bumped by every auth event, so a slow `getSession()` can't overwrite a newer one.\n let version = 0;\n\n const set = (session: S | null, offline = false) => {\n const userId = session ? userIdOf(session) : null;\n const previous = state;\n if (previous.status !== \"loading\" && previous.session === session && previous.offline === offline) return;\n state = { status: session ? \"signedIn\" : \"signedOut\", session, userId, offline };\n for (const listener of listeners) listener();\n if (previous.status !== \"loading\" && previous.userId !== userId) onUserChange?.(previous.userId, userId);\n };\n\n return {\n getState: () => state,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n async load() {\n const startedAt = version;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timedOut = new Promise<\"timeout\">((resolve) => {\n timer = setTimeout(() => resolve(\"timeout\"), waitMs);\n });\n const result = await Promise.race([client.auth.getSession(), timedOut]).finally(() => clearTimeout(timer));\n if (version !== startedAt) return; // an auth event already told us\n if (result !== \"timeout\" && !result.error) return set(result.data.session);\n if (result !== \"timeout\" && !isNetworkError(result.error)) {\n const error = result.error;\n throw error instanceof Error ? error : new Error(\"Could not read the session.\", { cause: error });\n }\n // Offline (or Supabase is slow): carry on with what the phone has.\n const stored = await readStored().catch(() => null);\n if (version !== startedAt) return;\n set(stored, stored !== null);\n },\n start() {\n const { data } = client.auth.onAuthStateChange((_event, session) => {\n version++;\n set(session);\n });\n return () => data.subscription.unsubscribe();\n },\n };\n}\n\nconst SessionContext = createContext<SessionStore | null>(null);\n\n/** Makes a session store readable with `useSession()`. */\nexport function SessionProvider({ store, children }: { store: SessionStore; children: ReactNode }) {\n return <SessionContext.Provider value={store}>{children}</SessionContext.Provider>;\n}\n\n/** The session and whether it is known yet. Inside `GenesisNativeApp` or a `SessionProvider`. */\nexport function useSession<S = unknown>(): SessionState<S> {\n const store = useContext(SessionContext);\n if (!store) throw new Error(\"useSession must be used inside <GenesisNativeApp> or <SessionProvider>.\");\n return useSyncExternalStore(store.subscribe, store.getState, store.getState) as SessionState<S>;\n}\n\nexport interface AuthGateProps {\n signedIn: ReactNode;\n signedOut: ReactNode;\n /** While the session is still being read. Default nothing (the splash is up). */\n loading?: ReactNode;\n}\n\n/** Render one tree for a signed-in user and another for everyone else. */\nexport function AuthGate({ signedIn, signedOut, loading = null }: AuthGateProps) {\n const { status } = useSession();\n if (status === \"loading\") return <>{loading}</>;\n return <>{status === \"signedIn\" ? signedIn : signedOut}</>;\n}\n","/**\n * Hold a deep link until sign-in completes.\n *\n * expo-router opens every incoming link itself. For a signed-in user that is\n * all that should happen. For a signed-out user, the auth layout redirects to\n * sign-in and the link is lost; holding it lets the app go there once the user\n * has signed in. The hold lives outside React, because expo-router's\n * `+native-intent` runs before any component:\n *\n * // lib/links.ts\n * export const linkHold = createLinkHold();\n * // app/+native-intent.ts\n * export function redirectSystemPath({ path }) {\n * const to = normalizeLink(path, links);\n * if (to && to !== \"/\") linkHold.hold(to);\n * return to;\n * }\n *\n * `useHeldLink` follows a held link only if the user was seen signed out\n * while it was held. A link that arrives while signed in, or at a cold start\n * that turns out signed in, is dropped, since the router already opened it.\n * `GenesisNativeApp` runs it for you (`links.onRelease`).\n */\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\n\nexport interface LinkHold {\n /** Hold `path`, replacing any held one. */\n hold(path: string): void;\n peek(): string | null;\n /** Return the held path and forget it. */\n take(): string | null;\n clear(): void;\n subscribe(listener: () => void): () => void;\n}\n\n/** A place to hold one deep link until sign-in completes; lives outside React. */\nexport function createLinkHold(): LinkHold {\n let held: string | null = null;\n const listeners = new Set<() => void>();\n const set = (next: string | null) => {\n if (held === next) return;\n held = next;\n for (const listener of listeners) listener();\n };\n return {\n hold: (path) => set(path),\n peek: () => held,\n take() {\n const path = held;\n set(null);\n return path;\n },\n clear: () => set(null),\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\n/** `\"pending\"` while booting or reading the session. */\nexport type HeldLinkAuth = \"pending\" | \"signedOut\" | \"signedIn\";\n\nexport interface UseHeldLinkOptions {\n auth: HeldLinkAuth;\n /** Go there, e.g. `(path) => router.replace(path)`. Called once per link held across a sign-in. */\n onRelease: (path: string) => void;\n}\n\n/** Follow the held link after a sign-in, drop it otherwise; returns the link still held. */\nexport function useHeldLink(hold: LinkHold, { auth, onRelease }: UseHeldLinkOptions): string | null {\n const held = useSyncExternalStore(hold.subscribe, hold.peek, hold.peek);\n const release = useRef(onRelease);\n release.current = onRelease;\n // Was the user signed out while this link was held?\n const waitedForSignIn = useRef(false);\n useEffect(() => {\n if (held === null) {\n waitedForSignIn.current = false;\n return;\n }\n if (auth === \"signedOut\") waitedForSignIn.current = true;\n if (auth !== \"signedIn\") return;\n const path = hold.take();\n const follow = waitedForSignIn.current;\n waitedForSignIn.current = false;\n if (path !== null && follow) release.current(path);\n }, [auth, held, hold]);\n return held;\n}\n","/**\n * `<GenesisNativeApp>`: everything above an Expo app's screens, so the root\n * `_layout.tsx` is a few lines.\n *\n * last-resort boundary (React Native primitives only)\n * └ theme (GenesisThemeProvider, owning the platform color scheme)\n * └ keyboard-aware scrolling (when `keyboardScroll` is given)\n * └ data (GenesisProvider over the Supabase client, the QueryClient)\n * └ session + boot (splash held until both are known)\n * └ updates (with `updates`: force upgrade, maintenance, banner, what's new)\n * └ errorBoundary → your screens (or `signedOut`)\n *\n * Global errors, render errors and a failed boot show the `fatal` slot with\n * \"Try again\". Every part is a slot (`slots` / `slotProps`, `null` drops it)\n * and is also exported on its own.\n */\nimport { useEffect, useRef, useState, useSyncExternalStore, type ComponentType, type ReactNode } from \"react\";\nimport { Text, View } from \"react-native\";\nimport type { QueryClient, QueryClientConfig } from \"@tanstack/react-query\";\nimport { GenesisThemeProvider } from \"@marktiderman/genesis-design-system/theme\";\nimport type { CanonicalBrand } from \"@marktiderman/genesis-design-system\";\nimport { GenesisProvider, createSupabaseProvider, type DataProvider, type SupabaseClientInput } from \"@marktiderman/genesis-core/provider\";\nimport { renderSlot, type SlotPropsFor, type Slots } from \"@marktiderman/genesis-core/slots\";\nimport { KeyboardScrollProvider, type KeyboardScrollProps } from \"@marktiderman/genesis-ui-native/layouts\";\nimport { BootProvider, createBoot, type BootOptions, type BootStatus, type BootStep } from \"./boot\";\nimport {\n FatalScreen,\n GenesisErrorBoundary,\n PlainFatalScreen,\n defaultErrorUtils,\n defaultRejectionTracker,\n installGlobalErrorHandler,\n installRejectionTracker,\n type EnableRejectionTracker,\n type ErrorUtilsLike,\n type FatalScreenProps,\n type GenesisErrorBoundaryProps,\n type OnError,\n} from \"./errors\";\nimport { SessionProvider, createSessionStore, type AuthClientLike } from \"./auth\";\nimport { useHeldLink, type HeldLinkAuth, type LinkHold } from \"./held-link\";\nimport { connectQueryLifecycle, createNativeQueryClient, type QueryLifecycleOptions, type QueryPersistence } from \"./query\";\n// Types only: the block's code is in the `/updates` entry and arrives with the `updates` prop.\nimport type { UpdatesBlock, UpdatesSlots } from \"./updates/block\";\n\n/** `expo-splash-screen`, or a stand-in. Call `preventAutoHideAsync()` at module scope yourself too. */\nexport interface SplashModule {\n preventAutoHideAsync?: () => Promise<unknown>;\n hideAsync: () => Promise<unknown>;\n}\n\nexport interface BootScreenProps {\n status: BootStatus;\n}\n\nexport interface SignedOutProps {\n /** Your screens. The default renders them, for an expo-router layout that redirects. */\n children: ReactNode;\n}\n\n// A type, not an interface, so it fits the slots contract's Record constraint.\n// The updates block's slots (`forceUpgrade`, `maintenance`, `updateBanner`,\n// `whatsNew`) render only when the `updates` prop is given.\nexport type NativeAppSlots = UpdatesSlots & {\n /** Shown while booting: under the splash at launch, on its own after \"Try again\". Default `BootScreen`. */\n boot: BootScreenProps;\n /** A failed boot, a fatal global error or a render error. Default `FatalScreen`. */\n fatal: FatalScreenProps;\n /** The boundary around your screens. Default `GenesisErrorBoundary`. */\n errorBoundary: GenesisErrorBoundaryProps;\n /** What a signed-out user sees. Default your screens (gate them with `useSession`). */\n signedOut: SignedOutProps;\n};\n\nexport interface NativeQueryClientOptions {\n /** Your own client. Default `createNativeQueryClient(config)`. */\n client?: QueryClient;\n config?: QueryClientConfig;\n}\n\nexport interface GenesisNativeAppProps {\n brand: CanonicalBrand;\n /** A Supabase client (from `createGenesisSupabase` in `@marktiderman/genesis-supabase`). */\n supabase: AuthClientLike & SupabaseClientInput;\n /** The data provider. Default `createSupabaseProvider(supabase)`. */\n provider?: DataProvider;\n queryClient?: NativeQueryClientOptions;\n /**\n * Save queries to the phone: `persistQueries({ storage, keys, buster })`\n * from `@marktiderman/genesis-native/persist`. The saved cache belongs to\n * one user: it is restored only for that user and cleared when the user\n * changes (sign-out, a session that ended while the app was closed, an\n * account switch).\n */\n persist?: (client: QueryClient) => QueryPersistence;\n /** `expo-splash-screen`: hidden once boot has finished and the session is known. */\n splash?: SplashModule;\n /** `KeyboardAwareScrollView` from react-native-keyboard-controller, for form screens. */\n keyboardScroll?: ComponentType<KeyboardScrollProps>;\n /** Follow a link held while signed out, once the user signs in. */\n links?: { hold: LinkHold; onRelease: (path: string) => void };\n /** Run before first render, in order (wipe-on-reinstall, hydrate stores, fonts). Read once. */\n steps?: readonly BootStep[];\n bootOptions?: BootOptions;\n /** Longest wait for Supabase's `getSession()` before using the stored session (offline). Default 5000 ms. */\n sessionWaitMs?: number;\n /** Default `globalThis.ErrorUtils`. */\n errorUtils?: ErrorUtilsLike;\n /** Report unhandled promise rejections to `onError`. Default Hermes's tracker; `null` turns it off. */\n rejectionTracker?: EnableRejectionTracker | null;\n /** `AppState` and NetInfo, so queries refetch on focus and know the network. */\n lifecycle?: QueryLifecycleOptions;\n /** Every caught error, for reporting (Sentry). */\n onError?: OnError;\n /** After a signed-in user signs out, once the query cache is cleared. */\n onSignedOut?: () => void;\n /**\n * The updates block: `createUpdates(…)` from `@marktiderman/genesis-native/updates`\n * (force upgrade, maintenance, the update banner, what's new). Its policy\n * loads behind the splash for at most `policyTimeoutMs` and never fails the\n * boot. Read once; leave it out to turn the block off.\n */\n updates?: UpdatesBlock;\n slots?: Slots<NativeAppSlots>;\n slotProps?: SlotPropsFor<NativeAppSlots>;\n children?: ReactNode;\n}\n\n/** The default boot slot: a plain loading view (the splash covers it at launch). */\nexport function BootScreen(_props: BootScreenProps) {\n return (\n <View testID=\"genesis-boot\" accessibilityRole=\"progressbar\" style={{ flex: 1, justifyContent: \"center\", alignItems: \"center\" }}>\n <Text>Loading…</Text>\n </View>\n );\n}\n\nconst PassThrough: ComponentType<SignedOutProps> = ({ children }) => <>{children}</>;\n\n// The web provider's types don't list the native-only prop; Metro resolves the native provider.\nconst ThemeProvider = GenesisThemeProvider as ComponentType<{\n brand: CanonicalBrand;\n syncNativeAppearance?: boolean;\n children: ReactNode;\n}>;\n\n/**\n * The root of an Expo app: theme, keyboard scrolling, data, boot behind the splash, errors, session and held links.\n *\n * @stability Beta\n */\nexport function GenesisNativeApp(props: GenesisNativeAppProps) {\n // Above every provider: if one of them (or the shell's own set-up) throws,\n // this shows a screen made of nothing that can fail, and retry starts over.\n const [rootKey, setRootKey] = useState(0);\n const onErrorRef = useRef(props.onError);\n onErrorRef.current = props.onError;\n return (\n <GenesisErrorBoundary\n key={rootKey}\n fallback={PlainFatalScreen}\n onError={(e, r) => onErrorRef.current?.(e, r)}\n onRetry={() => setRootKey((key) => key + 1)}\n >\n <ThemedShell {...props} />\n </GenesisErrorBoundary>\n );\n}\n\nfunction ThemedShell(props: GenesisNativeAppProps) {\n const { brand, keyboardScroll } = props;\n const body = <Shell {...props} />;\n return (\n <ThemeProvider brand={brand} syncNativeAppearance>\n {keyboardScroll ? <KeyboardScrollProvider component={keyboardScroll}>{body}</KeyboardScrollProvider> : body}\n </ThemeProvider>\n );\n}\n\nconst SESSION_STEP_MARGIN_MS = 15_000;\n\nfunction Shell(props: GenesisNativeAppProps) {\n const { supabase, provider, queryClient: queryOptions, persist, splash, links, steps = [], bootOptions, sessionWaitMs = 5000 } = props;\n const { errorUtils, rejectionTracker, lifecycle, slots, slotProps, children } = props;\n const latest = useRef(props);\n latest.current = props;\n const onError: OnError = (error, report) => latest.current.onError?.(error, report);\n // How many fatal screens are up (the global handler lets a second fatal error end the app).\n const fatalShown = useRef(0);\n\n // Created once: the shell's parts live as long as the app.\n const [parts] = useState(() => {\n const client = queryOptions?.client ?? createNativeQueryClient(queryOptions?.config);\n const persistence = persist ? persist(client) : null;\n const session = createSessionStore(supabase, {\n waitMs: sessionWaitMs,\n // Another user (or nobody) now: nothing of the last user's may show or stay on disk.\n onUserChange: (previous, next) => {\n client.clear();\n void persistence?.clear();\n if (previous !== null && next === null) latest.current.onSignedOut?.();\n },\n });\n const boot = createBoot(\n [\n ...steps,\n // Settles within its own timeout and never throws: a policy that can't load never blocks the app.\n ...(props.updates ? [props.updates.bootStep] : []),\n { id: \"genesis:session\", run: () => session.load(), timeoutMs: sessionWaitMs + SESSION_STEP_MARGIN_MS },\n // After the session, so only the cache saved for this user is restored.\n ...(persistence ? [{ id: \"genesis:query-cache\", run: () => persistence.restore(session.getState().userId ?? \"\") }] : []),\n ],\n bootOptions,\n );\n // One component type for the life of the app, so a re-render never remounts a visible fatal screen.\n function FatalFallback(fallbackProps: FatalScreenProps) {\n useEffect(() => {\n fatalShown.current++;\n return () => {\n fatalShown.current--;\n };\n }, []);\n const { slots: s, slotProps: sp } = latest.current;\n return (\n // A `fatal` slot that throws falls back to the plain screen.\n <GenesisErrorBoundary fallback={PlainFatalScreen} onError={onError} onRetry={fallbackProps.retry}>\n {renderSlot(FatalScreen, s?.fatal, fallbackProps, sp?.fatal)}\n </GenesisErrorBoundary>\n );\n }\n return { client, persistence, session, boot, FatalFallback, updates: props.updates, provider: provider ?? createSupabaseProvider(supabase) };\n });\n const { boot, session, persistence, client, FatalFallback } = parts;\n const bootState = useSyncExternalStore(boot.subscribe, boot.getState, boot.getState);\n const sessionState = useSyncExternalStore(session.subscribe, session.getState, session.getState);\n const [fatal, setFatal] = useState<Error | null>(null);\n const [resetKey, setResetKey] = useState(0);\n\n useEffect(() => session.start(), [session]);\n useEffect(() => {\n void boot.start();\n }, [boot]);\n useEffect(() => {\n if (bootState.status === \"failed\" && bootState.error) onError(bootState.error, { fatal: true, source: \"boot\" });\n }, [bootState.status, bootState.error]);\n useEffect(() => {\n if (bootState.status === \"ready\" && persistence) return persistence.subscribe(sessionState.userId ?? \"\");\n }, [bootState.status, persistence, sessionState.userId]);\n useEffect(() => {\n const utils = errorUtils ?? defaultErrorUtils();\n if (!utils) return;\n return installGlobalErrorHandler({ errorUtils: utils, onError, onFatal: setFatal, alreadyFatal: () => fatalShown.current > 0 });\n }, [errorUtils]);\n useEffect(() => {\n const enable = rejectionTracker === null ? undefined : (rejectionTracker ?? defaultRejectionTracker());\n if (enable) installRejectionTracker({ enable, onError });\n }, [rejectionTracker]);\n useEffect(() => (lifecycle ? connectQueryLifecycle(lifecycle) : undefined), [lifecycle]);\n\n // Splash: up until boot has finished (the session step included), or failed.\n const settled = bootState.status === \"ready\" || bootState.status === \"failed\" || fatal !== null;\n const splashHidden = useRef(false);\n useEffect(() => {\n if (!settled || !splash || splashHidden.current) return;\n splashHidden.current = true;\n splash.hideAsync().catch(() => {});\n }, [settled, splash]);\n\n const auth: HeldLinkAuth = bootState.status !== \"ready\" || sessionState.status === \"loading\" ? \"pending\" : sessionState.status;\n useHeldLink(links?.hold ?? NO_HOLD, { auth: links ? auth : \"pending\", onRelease: (path) => links?.onRelease(path) });\n\n const retry = () => {\n setFatal(null);\n setResetKey((key) => key + 1);\n if (boot.getState().status === \"failed\") void boot.retry();\n };\n\n let content: ReactNode;\n if (fatal) {\n content = <FatalFallback error={fatal} retry={retry} />;\n } else if (bootState.status === \"failed\" && bootState.error) {\n content = <FatalFallback error={bootState.error} retry={retry} />;\n } else if (bootState.status !== \"ready\") {\n content = renderSlot(BootScreen, slots?.boot, { status: bootState.status }, slotProps?.boot);\n } else {\n const screens =\n sessionState.status === \"signedOut\" ? renderSlot(PassThrough, slots?.signedOut, { children }, slotProps?.signedOut) : children;\n const guarded = renderSlot(\n GenesisErrorBoundary,\n slots?.errorBoundary,\n { fallback: FatalFallback, onError, resetKey, onRetry: retry, children: screens },\n slotProps?.errorBoundary,\n );\n const Updates = parts.updates?.Root;\n content = Updates ? (\n <Updates slots={slots} slotProps={slotProps}>\n {guarded}\n </Updates>\n ) : (\n guarded\n );\n }\n\n return (\n <GenesisProvider provider={parts.provider} queryClient={client}>\n <SessionProvider store={session}>\n <BootProvider boot={boot}>\n <GenesisErrorBoundary key={resetKey} fallback={FatalFallback} onError={onError} onRetry={retry}>\n {content}\n </GenesisErrorBoundary>\n </BootProvider>\n </SessionProvider>\n </GenesisProvider>\n );\n}\n\nconst NO_HOLD: LinkHold = {\n hold: () => {},\n peek: () => null,\n take: () => null,\n clear: () => {},\n subscribe: () => () => {},\n};\n","/**\n * A hydration gate holds writes until a persisted store has loaded from disk.\n *\n * The bug it prevents: a persisted store (zustand `persist`, say) is created\n * with defaults, something sets a value before the saved state has been read,\n * and that write lands on disk first, replacing what the user had. With the\n * gate, a write made before hydration never reaches disk (`storage()`), or\n * waits for it (`run()`).\n *\n * const gate = createHydrationGate();\n * persist(store, {\n * storage: createJSONStorage(() => gate.storage(AsyncStorage)),\n * // Open only after a good read: after a failed one, writes would replace what's on disk.\n * onRehydrateStorage: () => (_state, error) => {\n * if (!error) gate.markHydrated();\n * },\n * });\n */\nimport type { AsyncStorageLike } from \"./query\";\n\nexport interface HydrationGate {\n readonly hydrated: boolean;\n /** Call once the store has read its saved state. Idempotent. */\n markHydrated(): void;\n /** Resolves once hydrated. */\n whenHydrated(): Promise<void>;\n /** Run a write now if hydrated, otherwise once hydrated. */\n run<T>(write: () => T | Promise<T>): Promise<T>;\n /**\n * The storage, with writes made before hydration dropped (reads pass\n * through, since hydration is a read). After hydration the store writes\n * its merged state on its next change, so nothing is lost but the stale\n * write. (A zustand migration's own write during hydration is dropped too;\n * the old version stays on disk and is migrated again until then.)\n */\n storage<S extends AsyncStorageLike>(storage: S): S;\n}\n\nexport interface HydrationGateOptions {\n /** Told about each write `storage()` dropped (to log it in development). */\n onDroppedWrite?: (key: string) => void;\n}\n\n/** A gate that holds writes until a persisted store has hydrated. */\nexport function createHydrationGate({ onDroppedWrite }: HydrationGateOptions = {}): HydrationGate {\n let hydrated = false;\n let open!: () => void;\n const opened = new Promise<void>((resolve) => {\n open = resolve;\n });\n\n const gate: HydrationGate = {\n get hydrated() {\n return hydrated;\n },\n markHydrated() {\n if (hydrated) return;\n hydrated = true;\n open();\n },\n whenHydrated: () => opened,\n async run(write) {\n if (!hydrated) await opened;\n return write();\n },\n storage(storage) {\n const setItem = async (key: string, value: string) => {\n if (!hydrated) return onDroppedWrite?.(key);\n return storage.setItem(key, value);\n };\n const removeItem = async (key: string) => {\n if (!hydrated) return onDroppedWrite?.(key);\n return storage.removeItem(key);\n };\n // A proxy, not a spread: a storage class's prototype methods (and its\n // private fields, through `this`) keep working.\n return new Proxy(storage, {\n get(target, property) {\n if (property === \"setItem\") return setItem;\n if (property === \"removeItem\") return removeItem;\n const value = Reflect.get(target, property, target) as unknown;\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n },\n };\n return gate;\n}\n","/**\n * Deep links: turn an incoming universal link or app link into an app path.\n *\n * Meant for expo-router's `app/+native-intent.ts`:\n *\n * export function redirectSystemPath({ path }: { path: string }) {\n * return normalizeLink(path, links);\n * }\n *\n * A link to a path the map doesn't know goes to `\"/\"` (and `onUnknown`), so a\n * stale or mistyped link opens the app instead of a \"not found\" screen. It\n * never throws: anything it can't read is unknown.\n */\n\n/** A target path (`\"/clients/:id\"`, params filled in) or a function of the params. */\nexport type LinkTarget = string | ((params: Record<string, string>) => string);\n\nexport interface LinkOptions {\n /** App schemes, without `://` (`[\"myapp\"]`). `myapp://clients/1` is the path `/clients/1`. */\n schemes?: readonly string[];\n /** Hosts of universal / app links (`[\"example.com\"]`). Other hosts are unknown. */\n hosts?: readonly string[];\n /**\n * Incoming path pattern → app path. A segment `:name` captures one\n * segment, a final `*` captures the rest (as `params[\"*\"]`). The first\n * match wins; `\"/\"` is always known.\n */\n map: Readonly<Record<string, LinkTarget>>;\n /** Patterns to ignore (return `null`, so expo-router doesn't navigate), e.g. an auth callback. */\n ignore?: readonly string[];\n /** Told about each link that went to `\"/\"` because nothing matched. */\n onUnknown?: (url: string) => void;\n}\n\nconst URL_PATTERN = /^([a-z][a-z0-9+.-]*):\\/\\/([^/?#]*)([^?#]*)(\\?[^#]*)?(#.*)?$/i;\n\ninterface Parsed {\n path: string;\n query: string;\n}\n\nfunction parse(url: string, schemes: readonly string[], hosts: readonly string[]): Parsed | null {\n const trimmed = url.trim();\n const match = URL_PATTERN.exec(trimmed);\n if (!match) {\n // Already a path (expo-router passes paths as well as URLs).\n if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) return null;\n const noHash = trimmed.split(\"#\")[0] ?? \"\";\n const at = noHash.indexOf(\"?\");\n return at < 0 ? { path: noHash, query: \"\" } : { path: noHash.slice(0, at), query: noHash.slice(at) };\n }\n const [, scheme = \"\", host = \"\", path = \"\", query = \"\"] = match;\n const lowerScheme = scheme.toLowerCase();\n if (lowerScheme === \"http\" || lowerScheme === \"https\") {\n const bareHost = host.toLowerCase().replace(/:\\d+$/, \"\");\n if (!hosts.some((h) => h.toLowerCase() === bareHost)) return null;\n return { path, query };\n }\n if (!schemes.some((s) => s.toLowerCase() === lowerScheme)) return null;\n // In `myapp://clients/1`, \"clients\" sits where a host would.\n return { path: `/${host}${path}`, query };\n}\n\nfunction clean(path: string): string {\n const joined = `/${path}`.replace(/\\/{2,}/g, \"/\");\n return joined.length > 1 ? joined.replace(/\\/$/, \"\") : joined;\n}\n\nfunction matchPattern(pattern: string, path: string): Record<string, string> | null {\n const want = clean(pattern).split(\"/\").slice(1);\n const have = path.split(\"/\").slice(1);\n const params: Record<string, string> = {};\n for (let i = 0; i < want.length; i++) {\n const segment = want[i]!;\n if (segment === \"*\" && i === want.length - 1) {\n params[\"*\"] = have.slice(i).join(\"/\");\n return params;\n }\n const value = have[i];\n if (value === undefined) return null;\n if (segment.startsWith(\":\")) params[segment.slice(1)] = value;\n else if (segment !== value) return null;\n }\n return want.length === have.length ? params : null;\n}\n\nfunction fill(target: LinkTarget, params: Record<string, string>): string {\n if (typeof target === \"function\") return target(params);\n return target.replace(/:([A-Za-z_][A-Za-z0-9_]*)|\\*$/g, (token, name: string | undefined) =>\n name === undefined ? (params[\"*\"] ?? \"\") : (params[name] ?? token),\n );\n}\n\nfunction isDotSegment(segment: string): boolean {\n let decoded = segment;\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n // Malformed escapes stay as they are.\n }\n return decoded === \".\" || decoded === \"..\";\n}\n\nfunction withQuery(path: string, query: string): string {\n if (!query || query === \"?\") return path;\n return path.includes(\"?\") ? `${path}&${query.slice(1)}` : `${path}${query}`;\n}\n\n/** The app path for `url`, `\"/\"` when it is unknown, or `null` when it is ignored. */\nexport function normalizeLink(url: string, options: LinkOptions): string | null {\n const { schemes = [], hosts = [], map, ignore = [], onUnknown } = options;\n const unknown = () => {\n onUnknown?.(url);\n return \"/\";\n };\n let parsed: Parsed | null;\n try {\n parsed = parse(url, schemes, hosts);\n } catch {\n parsed = null;\n }\n if (!parsed) return unknown();\n const path = clean(parsed.path);\n // \".\" and \"..\" would let a link climb out of the path it matched (a `*` capture included).\n if (path.split(\"/\").some(isDotSegment)) {\n return unknown();\n }\n if (ignore.some((pattern) => matchPattern(pattern, path))) return null;\n if (path === \"/\") return withQuery(\"/\", parsed.query);\n for (const [pattern, target] of Object.entries(map)) {\n const params = matchPattern(pattern, path);\n if (!params) continue;\n try {\n return withQuery(fill(target, params), parsed.query);\n } catch {\n return unknown();\n }\n }\n return unknown();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/boot.tsx","../src/errors.tsx","../src/held-link.ts","../src/app.tsx","../src/hydration-gate.ts"],"names":["jsx","useSyncExternalStore","View","Text","useRef","useEffect","client","persistence","session","boot","FatalFallback"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Boot: the async work an app must finish before its first screen (wipe a\n * session left by a reinstall, hydrate stores, load fonts, restore the query\n * cache, read the session).\n *\n * Steps run once each, in order. A step that finished is never run again, so\n * \"try again\" after a failure resumes at the step that failed. Each step has a\n * timeout (10 seconds by default), so a hung step ends in the fatal screen with\n * retry instead of trapping the splash. A minimum keeps a fast boot from\n * flashing the splash.\n *\n * `createBoot` is the controller (no React); `BootProvider` + `useBoot()` read\n * it from components.\n */\nimport { createContext, useContext, useSyncExternalStore, type ReactNode } from \"react\";\n\nexport interface BootStepContext {\n /**\n * Aborted when the step times out. Stop work when it fires: a retry waits\n * for a timed-out run to settle before running the step again.\n */\n signal: AbortSignal;\n}\n\nexport interface BootStep {\n /** Unique within the list; names the step in errors. */\n id: string;\n run: (context: BootStepContext) => Promise<unknown> | unknown;\n /** Overrides the boot's `timeoutMs` for this step. */\n timeoutMs?: number;\n}\n\nexport type BootStatus = \"idle\" | \"booting\" | \"ready\" | \"failed\";\n\nexport interface BootState {\n status: BootStatus;\n /** Set when `status` is `\"failed\"`. */\n error: Error | null;\n /** The id of the step that failed. */\n failedStep: string | null;\n /** Ids of the steps that have finished, in order. */\n completed: readonly string[];\n}\n\nexport interface BootOptions {\n /** Shortest time the boot takes, so the splash doesn't flash. Default 0. */\n minimumMs?: number;\n /** Longest time one step may take. Default 10 000. */\n timeoutMs?: number;\n}\n\nexport interface BootController {\n getState(): BootState;\n subscribe(listener: () => void): () => void;\n /** Run the steps not yet finished. Calling it while a run is in flight returns that run. */\n start(): Promise<void>;\n /** After a failure: run again from the step that failed. */\n retry(): Promise<void>;\n}\n\n/** Thrown when a step takes longer than its timeout. */\nexport class BootTimeoutError extends Error {\n readonly step: string;\n constructor(step: string, ms: number, reason = \"did not finish\") {\n super(`Boot step \"${step}\" ${reason} within ${ms} ms.`);\n this.name = \"BootTimeoutError\";\n this.step = step;\n }\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nexport function toError(value: unknown): Error {\n if (value instanceof Error) return value;\n return new Error(typeof value === \"string\" ? value : \"Unknown error\", { cause: value });\n}\n\n/** Resolves \"settled\" when `promise` settles, \"pending\" after `ms`. */\nfunction settledWithin(promise: Promise<unknown>, ms: number): Promise<\"settled\" | \"pending\"> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return Promise.race([\n promise.then(\n () => \"settled\" as const,\n () => \"settled\" as const,\n ),\n new Promise<\"pending\">((resolve) => {\n timer = setTimeout(() => resolve(\"pending\"), ms);\n }),\n ]).finally(() => clearTimeout(timer));\n}\n\n/** The boot controller: runs `steps` once each, in order, with a timeout per step. */\nexport function createBoot(steps: readonly BootStep[], options: BootOptions = {}): BootController {\n const seen = new Set<string>();\n for (const step of steps) {\n if (seen.has(step.id)) throw new Error(`Boot step \"${step.id}\" is listed twice.`);\n seen.add(step.id);\n }\n const { minimumMs = 0, timeoutMs = DEFAULT_TIMEOUT_MS } = options;\n const listeners = new Set<() => void>();\n let state: BootState = { status: \"idle\", error: null, failedStep: null, completed: [] };\n let inFlight: Promise<void> | null = null;\n // A step that timed out keeps running (JavaScript can't stop it; `signal`\n // asks it to). A retry waits for it rather than running it twice at once.\n const abandoned = new Map<string, Promise<\"ok\" | \"failed\">>();\n\n const runStep = async (step: BootStep, ms: number): Promise<void> => {\n const previous = abandoned.get(step.id);\n if (previous) {\n if ((await settledWithin(previous, ms)) === \"pending\") {\n throw new BootTimeoutError(step.id, ms, \"is still running from the last attempt\");\n }\n abandoned.delete(step.id);\n // The abandoned run finished after all: it counts.\n if ((await previous) === \"ok\") return;\n }\n const controller = new AbortController();\n const running = Promise.resolve().then(() => step.run({ signal: controller.signal }));\n if ((await settledWithin(running, ms)) === \"pending\") {\n controller.abort();\n abandoned.set(step.id, running.then(() => \"ok\" as const, () => \"failed\" as const));\n throw new BootTimeoutError(step.id, ms);\n }\n await running;\n };\n\n const set = (next: Partial<BootState>) => {\n state = { ...state, ...next };\n for (const listener of listeners) listener();\n };\n\n const run = async () => {\n const started = Date.now();\n set({ status: \"booting\", error: null, failedStep: null });\n for (const step of steps) {\n if (state.completed.includes(step.id)) continue;\n try {\n await runStep(step, step.timeoutMs ?? timeoutMs);\n } catch (error) {\n set({ status: \"failed\", error: toError(error), failedStep: step.id });\n return;\n }\n set({ completed: [...state.completed, step.id] });\n }\n const wait = minimumMs - (Date.now() - started);\n if (wait > 0) await new Promise((resolve) => setTimeout(resolve, wait));\n set({ status: \"ready\" });\n };\n\n const start = () => {\n if (state.status === \"ready\") return Promise.resolve();\n if (!inFlight) {\n inFlight = run().finally(() => {\n inFlight = null;\n });\n }\n return inFlight;\n };\n\n return {\n getState: () => state,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n start,\n retry: start,\n };\n}\n\nconst BootContext = createContext<BootController | null>(null);\n\n/** Makes a boot readable with `useBoot()`. */\nexport function BootProvider({ boot, children }: { boot: BootController; children: ReactNode }) {\n return <BootContext.Provider value={boot}>{children}</BootContext.Provider>;\n}\n\nexport interface UseBootReturn extends BootState {\n retry: () => void;\n}\n\n/** The boot's status, and `retry` after a failure. Inside `GenesisNativeApp` or a `BootProvider`. */\nexport function useBoot(): UseBootReturn {\n const boot = useContext(BootContext);\n if (!boot) throw new Error(\"useBoot must be used inside <GenesisNativeApp> or <BootProvider>.\");\n const state = useSyncExternalStore(boot.subscribe, boot.getState, boot.getState);\n return { ...state, retry: () => void boot.retry() };\n}\n","/**\n * Errors: a boundary per screen tree, and handlers for errors React never sees\n * (a fatal global error from `ErrorUtils`, an unhandled promise rejection).\n * All of them report through one `onError` (wire Sentry there) and show the\n * fatal screen instead of letting the app die; its \"Try again\" remounts the\n * tree with fresh state.\n */\nimport { Component, type ComponentType, type ErrorInfo, type ReactNode } from \"react\";\nimport { Pressable, Text, View } from \"react-native\";\nimport { NativeButton, NativeEmptyState } from \"@marktiderman/genesis-ui-native/components\";\nimport { toError } from \"./boot\";\n\nexport interface FatalScreenProps {\n error: Error;\n /** Clears the error and remounts the app below the shell (and re-runs a failed boot). */\n retry: () => void;\n}\n\n/** The default fatal screen: what went wrong and \"Try again\". */\nexport function FatalScreen({ error, retry }: FatalScreenProps) {\n return (\n <NativeEmptyState\n variant=\"error\"\n title=\"Something went wrong\"\n body=\"The app hit a problem. Try again, and if it keeps happening, close and reopen the app.\"\n details={error.message}\n primaryAction={\n <NativeButton onPress={retry} testID=\"genesis-fatal-retry\">\n Try again\n </NativeButton>\n }\n testID=\"genesis-fatal\"\n />\n );\n}\n\n/**\n * The last-resort fatal screen: React Native primitives only, no theme, no\n * context, nothing that can itself fail. Shown when the providers could not\n * start, or when the `fatal` slot threw.\n */\nexport function PlainFatalScreen({ error, retry }: FatalScreenProps) {\n return (\n <View testID=\"genesis-fatal-plain\" style={{ flex: 1, justifyContent: \"center\", alignItems: \"center\", padding: 24, gap: 12 }}>\n <Text accessibilityRole=\"header\" style={{ fontSize: 17, fontWeight: \"600\" }}>\n Something went wrong\n </Text>\n <Text style={{ textAlign: \"center\" }}>{error.message}</Text>\n <Pressable accessibilityRole=\"button\" onPress={retry} testID=\"genesis-fatal-plain-retry\" style={{ padding: 12 }}>\n <Text style={{ fontSize: 17 }}>Try again</Text>\n </Pressable>\n </View>\n );\n}\n\nexport interface ErrorReport {\n /** True when the app could not go on (a render error, a failed boot, a fatal global error). */\n fatal: boolean;\n source: \"boundary\" | \"global\" | \"boot\" | \"rejection\";\n componentStack?: string;\n}\n\nexport type OnError = (error: Error, report: ErrorReport) => void;\n\nexport interface GenesisErrorBoundaryProps {\n children?: ReactNode;\n /** What to render instead of the tree that threw. */\n fallback: ComponentType<FatalScreenProps>;\n onError?: OnError;\n /** Change it to clear a caught error (the tree remounts). */\n resetKey?: unknown;\n /** Called by the fallback's retry, after the error is cleared. */\n onRetry?: () => void;\n}\n\ninterface BoundaryState {\n error: Error | null;\n}\n\n/** An error boundary whose fallback gets `{ error, retry }`. */\nexport class GenesisErrorBoundary extends Component<GenesisErrorBoundaryProps, BoundaryState> {\n override state: BoundaryState = { error: null };\n\n static getDerivedStateFromError(error: unknown): BoundaryState {\n return { error: toError(error) };\n }\n\n override componentDidCatch(error: unknown, info: ErrorInfo) {\n this.props.onError?.(toError(error), { fatal: true, source: \"boundary\", componentStack: info.componentStack ?? undefined });\n }\n\n override componentDidUpdate(previous: GenesisErrorBoundaryProps) {\n if (this.state.error && previous.resetKey !== this.props.resetKey) this.setState({ error: null });\n }\n\n retry = () => {\n this.setState({ error: null });\n this.props.onRetry?.();\n };\n\n override render() {\n const { error } = this.state;\n if (!error) return this.props.children ?? null;\n const Fallback = this.props.fallback;\n return <Fallback error={error} retry={this.retry} />;\n }\n}\n\n/** React Native's `ErrorUtils` (a global in every RN app), or a stand-in. */\nexport interface ErrorUtilsLike {\n getGlobalHandler(): ((error: unknown, isFatal?: boolean) => void) | undefined;\n setGlobalHandler(handler: (error: unknown, isFatal?: boolean) => void): void;\n}\n\nexport interface GlobalErrorHandlerOptions {\n errorUtils: ErrorUtilsLike;\n onError?: OnError;\n /** A fatal error: show the fatal screen. The previous handler (which would end the app) is not called. */\n onFatal: (error: Error) => void;\n /**\n * True while a fatal screen is already up. Another fatal error then goes to\n * the previous handler, which ends the app (it restarts clean) rather than\n * leaving it stuck behind a screen that may itself be broken.\n */\n alreadyFatal?: () => boolean;\n}\n\n/**\n * Route global errors to `onError`. A fatal one goes to `onFatal` instead of\n * React Native's default handler, which would close the app; a non-fatal one\n * still reaches the previous handler (LogBox in development). Returns a\n * function that puts the previous handler back.\n */\nexport function installGlobalErrorHandler({ errorUtils, onError, onFatal, alreadyFatal }: GlobalErrorHandlerOptions): () => void {\n const previous = errorUtils.getGlobalHandler();\n errorUtils.setGlobalHandler((raw, isFatal) => {\n const error = toError(raw);\n try {\n onError?.(error, { fatal: Boolean(isFatal), source: \"global\" });\n } catch {\n // A failing reporter must not take the handler down with it.\n }\n if (isFatal && !alreadyFatal?.()) onFatal(error);\n else previous?.(raw, isFatal);\n });\n return () => {\n // With no previous handler, leave one that only logs, never ours (it would call an unmounted app).\n errorUtils.setGlobalHandler(previous ?? ((error) => console.error(error)));\n };\n}\n\n/** `globalThis.ErrorUtils` in a React Native runtime, undefined elsewhere. */\nexport function defaultErrorUtils(): ErrorUtilsLike | undefined {\n const candidate = (globalThis as { ErrorUtils?: ErrorUtilsLike }).ErrorUtils;\n return candidate && typeof candidate.setGlobalHandler === \"function\" ? candidate : undefined;\n}\n\n/** Hermes's `HermesInternal.enablePromiseRejectionTracker`, or a stand-in. */\nexport type EnableRejectionTracker = (options: {\n allRejections: boolean;\n onUnhandled: (id: number, rejection: unknown) => void;\n onHandled: (id: number) => void;\n}) => void;\n\n/**\n * Hermes's rejection tracker, when the app runs on Hermes. React Native sends\n * unhandled rejections to `ExceptionsManager` (LogBox in development), never\n * to `ErrorUtils`' global handler, so without this they never reach `onError`.\n */\nexport function defaultRejectionTracker(): EnableRejectionTracker | undefined {\n const hermes = (globalThis as { HermesInternal?: { enablePromiseRejectionTracker?: EnableRejectionTracker } }).HermesInternal;\n const enable = hermes?.enablePromiseRejectionTracker;\n return typeof enable === \"function\" ? enable.bind(hermes) : undefined;\n}\n\n/**\n * Report unhandled promise rejections to `onError` (non-fatal). This replaces\n * React Native's own tracker, so each rejection is also written with\n * `console.warn`, which LogBox shows in development as before.\n */\nexport function installRejectionTracker({ enable, onError }: { enable: EnableRejectionTracker; onError: OnError }): void {\n enable({\n allRejections: true,\n onUnhandled: (id, rejection) => {\n const error = toError(rejection);\n console.warn(`Uncaught (in promise, id: ${id}): ${error.message}`);\n try {\n onError(error, { fatal: false, source: \"rejection\" });\n } catch {\n // A failing reporter must not throw inside the promise machinery.\n }\n },\n onHandled: () => {},\n });\n}\n","/**\n * Hold a deep link until sign-in completes.\n *\n * expo-router opens every incoming link itself. For a signed-in user that is\n * all that should happen. For a signed-out user, the auth layout redirects to\n * sign-in and the link is lost; holding it lets the app go there once the user\n * has signed in. The hold lives outside React, because expo-router's\n * `+native-intent` runs before any component:\n *\n * // lib/links.ts\n * export const linkHold = createLinkHold();\n * // app/+native-intent.ts\n * export function redirectSystemPath({ path }) {\n * const to = normalizeLink(path, links);\n * if (to && to !== \"/\") linkHold.hold(to);\n * return to;\n * }\n *\n * `useHeldLink` follows a held link only if the user was seen signed out\n * while it was held. A link that arrives while signed in, or at a cold start\n * that turns out signed in, is dropped, since the router already opened it.\n * `GenesisNativeApp` runs it for you (`links.onRelease`).\n */\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\n\nexport interface LinkHold {\n /** Hold `path`, replacing any held one. */\n hold(path: string): void;\n peek(): string | null;\n /** Return the held path and forget it. */\n take(): string | null;\n clear(): void;\n subscribe(listener: () => void): () => void;\n}\n\n/** A place to hold one deep link until sign-in completes; lives outside React. */\nexport function createLinkHold(): LinkHold {\n let held: string | null = null;\n const listeners = new Set<() => void>();\n const set = (next: string | null) => {\n if (held === next) return;\n held = next;\n for (const listener of listeners) listener();\n };\n return {\n hold: (path) => set(path),\n peek: () => held,\n take() {\n const path = held;\n set(null);\n return path;\n },\n clear: () => set(null),\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\n/** `\"pending\"` while booting or reading the session. */\nexport type HeldLinkAuth = \"pending\" | \"signedOut\" | \"signedIn\";\n\nexport interface UseHeldLinkOptions {\n auth: HeldLinkAuth;\n /** Go there, e.g. `(path) => router.replace(path)`. Called once per link held across a sign-in. */\n onRelease: (path: string) => void;\n}\n\n/** Follow the held link after a sign-in, drop it otherwise; returns the link still held. */\nexport function useHeldLink(hold: LinkHold, { auth, onRelease }: UseHeldLinkOptions): string | null {\n const held = useSyncExternalStore(hold.subscribe, hold.peek, hold.peek);\n const release = useRef(onRelease);\n release.current = onRelease;\n // Was the user signed out while this link was held?\n const waitedForSignIn = useRef(false);\n useEffect(() => {\n if (held === null) {\n waitedForSignIn.current = false;\n return;\n }\n if (auth === \"signedOut\") waitedForSignIn.current = true;\n if (auth !== \"signedIn\") return;\n const path = hold.take();\n const follow = waitedForSignIn.current;\n waitedForSignIn.current = false;\n if (path !== null && follow) release.current(path);\n }, [auth, held, hold]);\n return held;\n}\n","/**\n * `<GenesisNativeApp>`: everything above an Expo app's screens, so the root\n * `_layout.tsx` is a few lines.\n *\n * last-resort boundary (React Native primitives only)\n * └ theme (GenesisThemeProvider, owning the platform color scheme)\n * └ keyboard (`keyboardProvider`, once, then `keyboardScroll` for form screens)\n * └ toasts (`NativeToastProvider`, so `useToast()` works on every screen; `toast={null}` drops it)\n * └ data (GenesisProvider over the Supabase client, the QueryClient)\n * └ session + boot (splash held until both are known)\n * └ blocks' roots (with `blocks`, e.g. updates: force upgrade, maintenance, banner, what's new)\n * └ errorBoundary → `bottomSheet`'s provider, if given → your screens (or `signedOut`)\n *\n * Every error the shell catches goes to each block's `onError` (the\n * observability block reports it) and then to the app's own `onError`.\n *\n * `blocks` (`defineBlock` declarations a native shell can run) are resolved\n * once: requirements checked, boot steps run behind the splash, roots\n * mounted, slot fills put under your `slots`, Settings rows handed to\n * `useBlockSettings`.\n * Global errors, render errors and a failed boot show the `fatal` slot with\n * \"Try again\". Every part is a slot (`slots` / `slotProps`, `null` drops it)\n * and is also exported on its own.\n */\nimport { useEffect, useRef, useState, useSyncExternalStore, type ComponentType, type ReactNode } from \"react\";\nimport { Text, View } from \"react-native\";\nimport type { QueryClient, QueryClientConfig } from \"@tanstack/react-query\";\nimport { GenesisThemeProvider } from \"@marktiderman/genesis-design-system/theme\";\nimport type { CanonicalBrand } from \"@marktiderman/genesis-design-system\";\nimport { GenesisProvider, createSupabaseProvider, type DataProvider, type SupabaseClientInput } from \"@marktiderman/genesis-core/provider\";\nimport { renderSlot, type SlotPropsFor, type Slots } from \"@marktiderman/genesis-core/slots\";\nimport { KeyboardScrollProvider, type KeyboardScrollProps, type KeyboardToolbarProps } from \"@marktiderman/genesis-ui-native/layouts\";\nimport {\n GenesisModulesProvider,\n NativeSheetProvider,\n NativeToastProvider,\n type GenesisModules,\n type NativeSheetLibrary,\n type NativeToastProviderProps,\n} from \"@marktiderman/genesis-ui-native/components\";\nimport { BootProvider, createBoot, type BootOptions, type BootStatus, type BootStep } from \"./boot\";\nimport {\n FatalScreen,\n GenesisErrorBoundary,\n PlainFatalScreen,\n defaultErrorUtils,\n defaultRejectionTracker,\n installGlobalErrorHandler,\n installRejectionTracker,\n type EnableRejectionTracker,\n type ErrorUtilsLike,\n type FatalScreenProps,\n type GenesisErrorBoundaryProps,\n type OnError,\n} from \"./errors\";\nimport { SessionProvider, createSessionStore, type AuthClientLike } from \"./auth\";\nimport { useHeldLink, type HeldLinkAuth, type LinkHold } from \"./held-link\";\nimport { connectQueryLifecycle, createNativeQueryClient, type QueryLifecycleOptions, type QueryPersistence } from \"./query\";\nimport { resolveBlocks } from \"@marktiderman/genesis-features/blocks\";\nimport { BlocksProvider, reportToBlocks, type NativeBlock } from \"./blocks\";\nimport type { DevtoolsSlots } from \"./devtools/slots\";\n// Types only: the block's code is in the `/updates` entry and arrives with the `updates` prop.\nimport type { UpdatesBlock, UpdatesSlots } from \"./updates/block\";\n// Types only, likewise: the push block (`/push`) arrives in `blocks`.\nimport type { PushSlots } from \"./push/block\";\n\n/** `expo-splash-screen`, or a stand-in. Call `preventAutoHideAsync()` at module scope yourself too. */\nexport interface SplashModule {\n preventAutoHideAsync?: () => Promise<unknown>;\n hideAsync: () => Promise<unknown>;\n}\n\nexport interface BootScreenProps {\n status: BootStatus;\n}\n\nexport interface SignedOutProps {\n /** Your screens. The default renders them, for an expo-router layout that redirects. */\n children: ReactNode;\n}\n\n// A type, not an interface, so it fits the slots contract's Record constraint.\n// The updates block's slots (`forceUpgrade`, `maintenance`, `updateBanner`,\n// `whatsNew`) render only when the `updates` prop is given.\nexport type NativeAppSlots = UpdatesSlots &\n PushSlots &\n DevtoolsSlots & {\n /** Shown while booting: under the splash at launch, on its own after \"Try again\". Default `BootScreen`. */\n boot: BootScreenProps;\n /** A failed boot, a fatal global error or a render error. Default `FatalScreen`. */\n fatal: FatalScreenProps;\n /** The boundary around your screens. Default `GenesisErrorBoundary`. */\n errorBoundary: GenesisErrorBoundaryProps;\n /** What a signed-out user sees. Default your screens (gate them with `useSession`). */\n signedOut: SignedOutProps;\n};\n\nexport interface NativeQueryClientOptions {\n /** Your own client. Default `createNativeQueryClient(config)`. */\n client?: QueryClient;\n config?: QueryClientConfig;\n}\n\nexport interface GenesisNativeAppProps {\n brand: CanonicalBrand;\n /** A Supabase client (from `createGenesisSupabase` in `@marktiderman/genesis-supabase`). */\n supabase: AuthClientLike & SupabaseClientInput;\n /** The data provider. Default `createSupabaseProvider(supabase)`. */\n provider?: DataProvider;\n queryClient?: NativeQueryClientOptions;\n /**\n * Save queries to the phone: `persistQueries({ storage, keys, buster })`\n * from `@marktiderman/genesis-native/persist`. The saved cache belongs to\n * one user: it is restored only for that user and cleared when the user\n * changes (sign-out, a session that ended while the app was closed, an\n * account switch).\n */\n persist?: (client: QueryClient) => QueryPersistence;\n /** `expo-splash-screen`: hidden once boot has finished and the session is known. */\n splash?: SplashModule;\n /**\n * `KeyboardProvider` from react-native-keyboard-controller, mounted once\n * around the app. Its keyboard views (`keyboardScroll` included) do nothing\n * without it: give both or neither. Read once: it wraps the whole app, so\n * a different component later would remount everything below it. To pass\n * it props, define the wrapper at module scope, not inline.\n */\n keyboardProvider?: ComponentType<{ children: ReactNode }>;\n /** `KeyboardAwareScrollView` from react-native-keyboard-controller, for form screens. Needs `keyboardProvider`. */\n keyboardScroll?: ComponentType<KeyboardScrollProps>;\n /**\n * `KeyboardToolbar` from react-native-keyboard-controller: previous / next /\n * done above the keyboard on Genesis's form layouts. Needs `keyboardScroll`\n * (and so `keyboardProvider`); without them it is ignored.\n */\n keyboardToolbar?: ComponentType<KeyboardToolbarProps>;\n /**\n * The optional native modules the app installed, for Genesis components to\n * use (`GenesisModulesProvider` from `@marktiderman/genesis-ui-native`):\n * FlashList, expo-image, Reanimated, expo-glass-effect, expo-symbols, a\n * lucide icon set, the @expo/ui date picker. Each one left out falls back\n * to plain React Native. Read once.\n */\n modules?: GenesisModules;\n /**\n * `@gorhom/bottom-sheet` v5, to opt every `NativeSheet` into it (snap\n * points, drag between heights): `import * as BottomSheet from \"@gorhom/bottom-sheet\"`,\n * then `bottomSheet={BottomSheet}`. The app mounts `NativeSheetProvider`\n * (and so the library's `BottomSheetModalProvider`) for you; the app's root\n * must still be inside gesture-handler's `GestureHandlerRootView`, with\n * Reanimated set up. Leave it out and sheets are React Native's own modal\n * (an iOS page sheet), which needs neither. Read once.\n */\n bottomSheet?: NativeSheetLibrary;\n /**\n * Toasts (`useToast()` from `@marktiderman/genesis-ui-native`): `NativeToastProvider` is\n * mounted around the screens, at the top of the screen by default (a bottom toast would sit on\n * a tab bar). Pass its options to place it, or `null` to mount your own. Read once.\n */\n toast?: Pick<NativeToastProviderProps, \"position\" | \"disableAnimation\"> | null;\n /** Follow a link held while signed out, once the user signs in. */\n links?: { hold: LinkHold; onRelease: (path: string) => void };\n /** Run before first render, in order (wipe-on-reinstall, hydrate stores, fonts). Read once. */\n steps?: readonly BootStep[];\n bootOptions?: BootOptions;\n /** Longest wait for Supabase's `getSession()` before using the stored session (offline). Default 5000 ms. */\n sessionWaitMs?: number;\n /** Default `globalThis.ErrorUtils`. */\n errorUtils?: ErrorUtilsLike;\n /** Report unhandled promise rejections to `onError`. Default Hermes's tracker; `null` turns it off. */\n rejectionTracker?: EnableRejectionTracker | null;\n /** `AppState` and NetInfo, so queries refetch on focus and know the network. */\n lifecycle?: QueryLifecycleOptions;\n /**\n * Every caught error, after the blocks' own `onError` (the observability\n * block, `createObservability` from `/observability`, reports to Sentry\n * there). A throwing reporter is ignored.\n */\n onError?: OnError;\n /** After a signed-in user signs out, once the query cache is cleared. */\n onSignedOut?: () => void;\n /**\n * The updates block: `createUpdates(…)` from `@marktiderman/genesis-native/updates`\n * (force upgrade, maintenance, the update banner, what's new). Its policy\n * loads behind the splash for at most `policyTimeoutMs` and never fails the\n * boot. Read once; leave it out to turn the block off.\n */\n updates?: UpdatesBlock;\n /**\n * Blocks to run (`createUpdates(…)` is one). Resolved once at start: a\n * block whose requirement is missing, or two blocks contributing the same\n * slot, nav entry or Settings row, shows the fatal screen and reports a\n * `BlockError` to `onError`. Read once.\n */\n blocks?: readonly NativeBlock[];\n /**\n * Your features (FeatureIds) that blocks may require but that aren't\n * blocks. A block requiring anything that is neither one of `blocks` nor\n * listed here is a `BlockError`. Read once.\n */\n appFeatures?: readonly string[];\n slots?: Slots<NativeAppSlots>;\n slotProps?: SlotPropsFor<NativeAppSlots>;\n children?: ReactNode;\n}\n\n/** The default boot slot: a plain loading view (the splash covers it at launch). */\nexport function BootScreen(_props: BootScreenProps) {\n return (\n <View testID=\"genesis-boot\" accessibilityRole=\"progressbar\" style={{ flex: 1, justifyContent: \"center\", alignItems: \"center\" }}>\n <Text>Loading…</Text>\n </View>\n );\n}\n\nconst PassThrough: ComponentType<SignedOutProps> = ({ children }) => <>{children}</>;\n\n// The web provider's types don't list the native-only prop; Metro resolves the native provider.\nconst ThemeProvider = GenesisThemeProvider as ComponentType<{\n brand: CanonicalBrand;\n syncNativeAppearance?: boolean;\n children: ReactNode;\n}>;\n\n/**\n * The root of an Expo app: theme, keyboard, data, boot behind the splash, errors, session and held links.\n *\n * @stability Beta\n */\nexport function GenesisNativeApp(props: GenesisNativeAppProps) {\n // Above every provider: if one of them (or the shell's own set-up) throws,\n // this shows a screen made of nothing that can fail, and retry starts over.\n const [rootKey, setRootKey] = useState(0);\n const onErrorRef = useRef(props.onError);\n onErrorRef.current = props.onError;\n // The blocks as given, before they are resolved: an error here may come from resolving them.\n const blocksRef = useRef(givenBlocks(props));\n const splashRef = useRef(props.splash);\n splashRef.current = props.splash;\n return (\n <GenesisErrorBoundary\n key={rootKey}\n fallback={PlainFatalScreen}\n onError={(e, r) => {\n reportToBlocks(blocksRef.current, e, r);\n try {\n onErrorRef.current?.(e, r);\n } catch {\n // A failing reporter must not stop the fatal screen.\n }\n // The shell (which hides the splash) never mounted: hide it here, or the screen stays behind it.\n splashRef.current?.hideAsync().catch(() => {});\n }}\n onRetry={() => setRootKey((key) => key + 1)}\n >\n <ThemedShell {...props} />\n </GenesisErrorBoundary>\n );\n}\n\ndeclare const __DEV__: boolean | undefined;\n\nconst MISSING_KEYBOARD_PROVIDER =\n \"GenesisNativeApp: `keyboardScroll` was given without `keyboardProvider`, so form screens won't move above the keyboard. \" +\n 'Pass `keyboardProvider={KeyboardProvider}` from \"react-native-keyboard-controller\" too.';\n\nconst TOOLBAR_WITHOUT_SCROLL =\n \"GenesisNativeApp: `keyboardToolbar` was given without `keyboardScroll`, so it is ignored. \" +\n 'Pass `keyboardScroll={KeyboardAwareScrollView}` and `keyboardProvider={KeyboardProvider}` from \"react-native-keyboard-controller\" too.';\n\nfunction ThemedShell(props: GenesisNativeAppProps) {\n const { brand, keyboardScroll, keyboardToolbar } = props;\n // Frozen: a new component type here (an inline wrapper) would remount the shell and reset the app.\n const [Keyboard] = useState(() => props.keyboardProvider);\n // Frozen too: an inline object would hand every component a new module set each render.\n const [modules] = useState(() => props.modules);\n const [toast] = useState(() => (props.toast === null ? null : { position: \"top\" as const, ...props.toast }));\n const missingProvider = Boolean(keyboardScroll) && !Keyboard;\n const toolbarWithoutScroll = Boolean(keyboardToolbar) && !keyboardScroll;\n useEffect(() => {\n if (typeof __DEV__ === \"undefined\" || !__DEV__) return;\n if (missingProvider) console.error(MISSING_KEYBOARD_PROVIDER);\n if (toolbarWithoutScroll) console.error(TOOLBAR_WITHOUT_SCROLL);\n }, [missingProvider, toolbarWithoutScroll]);\n let body = <Shell {...props} />;\n // Inside the modules: a toast animates with Reanimated and draws Liquid Glass when the app gave them.\n if (toast) body = <NativeToastProvider {...toast}>{body}</NativeToastProvider>;\n if (modules) body = <GenesisModulesProvider modules={modules}>{body}</GenesisModulesProvider>;\n if (keyboardScroll) body = <KeyboardScrollProvider component={keyboardScroll} toolbar={keyboardToolbar}>{body}</KeyboardScrollProvider>;\n if (Keyboard) body = <Keyboard>{body}</Keyboard>;\n return (\n <ThemeProvider brand={brand} syncNativeAppearance>\n {body}\n </ThemeProvider>\n );\n}\n\nconst SESSION_STEP_MARGIN_MS = 15_000;\n\nfunction Shell(props: GenesisNativeAppProps) {\n const { supabase, provider, queryClient: queryOptions, persist, splash, links, steps = [], bootOptions, sessionWaitMs = 5000 } = props;\n const { errorUtils, rejectionTracker, lifecycle, slotProps, children } = props;\n const latest = useRef(props);\n latest.current = props;\n const [blockList] = useState(() => givenBlocks(props));\n // Read once, like the keyboard provider: a different module later would remount the screens.\n const [bottomSheet] = useState(() => props.bottomSheet);\n const onError: OnError = (error, report) => {\n reportToBlocks(blockList, error, report);\n try {\n latest.current.onError?.(error, report);\n } catch {\n // A failing reporter must not take the shell down with it.\n }\n };\n // How many fatal screens are up (the global handler lets a second fatal error end the app).\n const fatalShown = useRef(0);\n\n // Created once: the shell's parts live as long as the app.\n const [parts] = useState(() => {\n const list = blockList;\n const blocks = resolveBlocks(list, props.appFeatures ? [...list.map((b) => b.id), ...props.appFeatures] : undefined, {\n platform: \"native\",\n slots: NATIVE_APP_SLOT_NAMES,\n });\n const client = queryOptions?.client ?? createNativeQueryClient(queryOptions?.config);\n const persistence = persist ? persist(client) : null;\n const session = createSessionStore(supabase, {\n waitMs: sessionWaitMs,\n // Another user (or nobody) now: nothing of the last user's may show or stay on disk.\n onUserChange: (previous, next) => {\n client.clear();\n void persistence?.clear();\n if (previous !== null && next === null) latest.current.onSignedOut?.();\n },\n });\n const boot = createBoot(\n [\n ...steps,\n // Blocks' steps, in dependency order (the updates block's settles within its own timeout and never throws).\n ...blocks.blocks.flatMap((block) => block.bootSteps ?? []),\n { id: \"genesis:session\", run: () => session.load(), timeoutMs: sessionWaitMs + SESSION_STEP_MARGIN_MS },\n // After the session, so only the cache saved for this user is restored.\n ...(persistence ? [{ id: \"genesis:query-cache\", run: () => persistence.restore(session.getState().userId ?? \"\") }] : []),\n ],\n bootOptions,\n );\n // One component type for the life of the app, so a re-render never remounts a visible fatal screen.\n function FatalFallback(fallbackProps: FatalScreenProps) {\n useEffect(() => {\n fatalShown.current++;\n return () => {\n fatalShown.current--;\n };\n }, []);\n const { slotProps: sp } = latest.current;\n const s = withBlockSlots(blocks.slots, latest.current.slots);\n return (\n // A `fatal` slot that throws falls back to the plain screen.\n <GenesisErrorBoundary fallback={PlainFatalScreen} onError={onError} onRetry={fallbackProps.retry}>\n {renderSlot(FatalScreen, s?.fatal, fallbackProps, sp?.fatal)}\n </GenesisErrorBoundary>\n );\n }\n return { client, persistence, session, boot, FatalFallback, blocks, provider: provider ?? createSupabaseProvider(supabase) };\n });\n const { boot, session, persistence, client, FatalFallback } = parts;\n const slots = withBlockSlots(parts.blocks.slots, props.slots);\n const bootState = useSyncExternalStore(boot.subscribe, boot.getState, boot.getState);\n const sessionState = useSyncExternalStore(session.subscribe, session.getState, session.getState);\n const [fatal, setFatal] = useState<Error | null>(null);\n const [resetKey, setResetKey] = useState(0);\n\n useEffect(() => session.start(), [session]);\n useEffect(() => {\n void boot.start();\n }, [boot]);\n useEffect(() => {\n if (bootState.status === \"failed\" && bootState.error) onError(bootState.error, { fatal: true, source: \"boot\" });\n }, [bootState.status, bootState.error]);\n useEffect(() => {\n if (bootState.status === \"ready\" && persistence) return persistence.subscribe(sessionState.userId ?? \"\");\n }, [bootState.status, persistence, sessionState.userId]);\n useEffect(() => {\n const utils = errorUtils ?? defaultErrorUtils();\n if (!utils) return;\n return installGlobalErrorHandler({ errorUtils: utils, onError, onFatal: setFatal, alreadyFatal: () => fatalShown.current > 0 });\n }, [errorUtils]);\n useEffect(() => {\n const enable = rejectionTracker === null ? undefined : (rejectionTracker ?? defaultRejectionTracker());\n if (enable) installRejectionTracker({ enable, onError });\n }, [rejectionTracker]);\n useEffect(() => (lifecycle ? connectQueryLifecycle(lifecycle) : undefined), [lifecycle]);\n\n // Splash: up until boot has finished (the session step included), or failed.\n const settled = bootState.status === \"ready\" || bootState.status === \"failed\" || fatal !== null;\n const splashHidden = useRef(false);\n useEffect(() => {\n if (!settled || !splash || splashHidden.current) return;\n splashHidden.current = true;\n splash.hideAsync().catch(() => {});\n }, [settled, splash]);\n\n const auth: HeldLinkAuth = bootState.status !== \"ready\" || sessionState.status === \"loading\" ? \"pending\" : sessionState.status;\n useHeldLink(links?.hold ?? NO_HOLD, { auth: links ? auth : \"pending\", onRelease: (path) => links?.onRelease(path) });\n\n const retry = () => {\n setFatal(null);\n setResetKey((key) => key + 1);\n if (boot.getState().status === \"failed\") void boot.retry();\n };\n\n let content: ReactNode;\n if (fatal) {\n content = <FatalFallback error={fatal} retry={retry} />;\n } else if (bootState.status === \"failed\" && bootState.error) {\n content = <FatalFallback error={bootState.error} retry={retry} />;\n } else if (bootState.status !== \"ready\") {\n content = renderSlot(BootScreen, slots?.boot, { status: bootState.status }, slotProps?.boot);\n } else {\n const screens =\n sessionState.status === \"signedOut\" ? renderSlot(PassThrough, slots?.signedOut, { children }, slotProps?.signedOut) : children;\n const guarded = renderSlot(\n GenesisErrorBoundary,\n slots?.errorBoundary,\n { fallback: FatalFallback, onError, resetKey, onRetry: retry, children: screens },\n slotProps?.errorBoundary,\n );\n // The first block's root is the outermost.\n content = parts.blocks.blocks.reduceRight<ReactNode>((inner, block) => {\n const Root = block.Root;\n return Root ? (\n <Root key={block.id} slots={slots} slotProps={slotProps}>\n {inner}\n </Root>\n ) : (\n inner\n );\n }, guarded);\n }\n\n return (\n <GenesisProvider provider={parts.provider} queryClient={client}>\n <SessionProvider store={session}>\n <BootProvider boot={boot}>\n <BlocksProvider value={parts.blocks}>\n <GenesisErrorBoundary key={resetKey} fallback={FatalFallback} onError={onError} onRetry={retry}>\n {/* Sheet content renders in the library's portal, here: below data, session, boot and blocks. */}\n {bottomSheet ? <NativeSheetProvider bottomSheet={bottomSheet}>{content}</NativeSheetProvider> : content}\n </GenesisErrorBoundary>\n </BlocksProvider>\n </BootProvider>\n </SessionProvider>\n </GenesisProvider>\n );\n}\n\n// Every slot name, checked against NativeAppSlots by the compiler: a block filling any other is a BlockError.\nconst SLOT_NAMES: Record<keyof NativeAppSlots, true> = {\n boot: true,\n fatal: true,\n errorBoundary: true,\n signedOut: true,\n forceUpgrade: true,\n maintenance: true,\n updateBanner: true,\n whatsNew: true,\n devtoolsFeedback: true,\n pushPrompt: true,\n};\nconst NATIVE_APP_SLOT_NAMES: readonly string[] = Object.keys(SLOT_NAMES);\n\n/** Blocks' slot fills under the app's own slots: the app's (a component or `null`) always win. */\nfunction withBlockSlots(fills: Readonly<Record<string, unknown>>, own: Slots<NativeAppSlots> | undefined): Slots<NativeAppSlots> | undefined {\n if (Object.keys(fills).length === 0) return own;\n return { ...(fills as Slots<NativeAppSlots>), ...own };\n}\n\n/** `blocks`, with `updates` added when it was given on its own (given both ways, it runs once). */\nfunction givenBlocks(props: Pick<GenesisNativeAppProps, \"blocks\" | \"updates\">): readonly NativeBlock[] {\n const given = props.blocks ?? [];\n return props.updates && !given.includes(props.updates) ? [...given, props.updates] : given;\n}\n\nconst NO_HOLD: LinkHold = {\n hold: () => {},\n peek: () => null,\n take: () => null,\n clear: () => {},\n subscribe: () => () => {},\n};\n","/**\n * A hydration gate holds writes until a persisted store has loaded from disk.\n *\n * The bug it prevents: a persisted store (zustand `persist`, say) is created\n * with defaults, something sets a value before the saved state has been read,\n * and that write lands on disk first, replacing what the user had. With the\n * gate, a write made before hydration never reaches disk (`storage()`), or\n * waits for it (`run()`).\n *\n * const gate = createHydrationGate();\n * persist(store, {\n * storage: createJSONStorage(() => gate.storage(AsyncStorage)),\n * // Open only after a good read: after a failed one, writes would replace what's on disk.\n * onRehydrateStorage: () => (_state, error) => {\n * if (!error) gate.markHydrated();\n * },\n * });\n */\nimport type { AsyncStorageLike } from \"./query\";\n\nexport interface HydrationGate {\n readonly hydrated: boolean;\n /** Call once the store has read its saved state. Idempotent. */\n markHydrated(): void;\n /** Resolves once hydrated. */\n whenHydrated(): Promise<void>;\n /** Run a write now if hydrated, otherwise once hydrated. */\n run<T>(write: () => T | Promise<T>): Promise<T>;\n /**\n * The storage, with writes made before hydration dropped (reads pass\n * through, since hydration is a read). After hydration the store writes\n * its merged state on its next change, so nothing is lost but the stale\n * write. (A zustand migration's own write during hydration is dropped too;\n * the old version stays on disk and is migrated again until then.)\n */\n storage<S extends AsyncStorageLike>(storage: S): S;\n}\n\nexport interface HydrationGateOptions {\n /** Told about each write `storage()` dropped (to log it in development). */\n onDroppedWrite?: (key: string) => void;\n}\n\n/** A gate that holds writes until a persisted store has hydrated. */\nexport function createHydrationGate({ onDroppedWrite }: HydrationGateOptions = {}): HydrationGate {\n let hydrated = false;\n let open!: () => void;\n const opened = new Promise<void>((resolve) => {\n open = resolve;\n });\n\n const gate: HydrationGate = {\n get hydrated() {\n return hydrated;\n },\n markHydrated() {\n if (hydrated) return;\n hydrated = true;\n open();\n },\n whenHydrated: () => opened,\n async run(write) {\n if (!hydrated) await opened;\n return write();\n },\n storage(storage) {\n const setItem = async (key: string, value: string) => {\n if (!hydrated) return onDroppedWrite?.(key);\n return storage.setItem(key, value);\n };\n const removeItem = async (key: string) => {\n if (!hydrated) return onDroppedWrite?.(key);\n return storage.removeItem(key);\n };\n // A proxy, not a spread: a storage class's prototype methods (and its\n // private fields, through `this`) keep working.\n return new Proxy(storage, {\n get(target, property) {\n if (property === \"setItem\") return setItem;\n if (property === \"removeItem\") return removeItem;\n const value = Reflect.get(target, property, target) as unknown;\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n },\n };\n return gate;\n}\n"]}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { a as ObservabilitySink } from './block-C5-noMhB.js';
|
|
2
|
+
export { B as Breadcrumb, b as BreadcrumbLevel, C as ConsoleSinkOptions, E as ErrorContext, c as EventCheck, d as EventPropSpec, e as EventProps, f as EventSchema, g as EventValues, h as OBSERVABILITY_BLOCK_ID, O as ObservabilityBlock, i as ObservabilityOptions, j as ObservabilityProvider, k as ObserveLike, l as ObserveSinkOptions, R as RecentActivity, m as RecentError, n as RecentStore, T as TimingTags, o as checkEvent, p as consoleSink, q as createObservability, r as defineEvents, s as observeSink, t as scrubBreadcrumb, u as scrubbedError, v as useObservability, w as useRecentActivity } from './block-C5-noMhB.js';
|
|
3
|
+
import { ComponentType } from 'react';
|
|
4
|
+
import { V as VersionSignature } from './blocks-a1YQ1Elf.js';
|
|
5
|
+
import '@marktiderman/genesis-core/slots';
|
|
6
|
+
import '@marktiderman/genesis-features/blocks';
|
|
7
|
+
import '@tanstack/react-query';
|
|
8
|
+
import '@marktiderman/genesis-design-system';
|
|
9
|
+
import '@marktiderman/genesis-core/provider';
|
|
10
|
+
import '@marktiderman/genesis-ui-native/layouts';
|
|
11
|
+
import '@marktiderman/genesis-ui-native/components';
|
|
12
|
+
import './query-DUmVAfsF.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* `sentrySink(Sentry, options)`: Sentry through the observability seam.
|
|
16
|
+
* `@sentry/react-native` is an optional peer, passed in rather than
|
|
17
|
+
* imported (`import * as Sentry from "@sentry/react-native"`), so an app
|
|
18
|
+
* without it never bundles it.
|
|
19
|
+
*
|
|
20
|
+
* Calling it runs `Sentry.init` at once, so call it at module scope (where
|
|
21
|
+
* `createObservability` is built, before the root layout renders): errors
|
|
22
|
+
* thrown while the app's modules load and the shell's first render are then
|
|
23
|
+
* caught. A second call in the same process (Fast Refresh) reuses the client.
|
|
24
|
+
*
|
|
25
|
+
* What it sets up, on Expo SDK 58 with @sentry/react-native 8:
|
|
26
|
+
* - `expoRouterIntegration` (navigation spans, time to initial display);
|
|
27
|
+
* - release `<applicationId>@<version>+<build>` and dist `<build>` from the
|
|
28
|
+
* version signature (Sentry's own format, so release health lines up),
|
|
29
|
+
* with the update id, channel, runtime version and launch as tags;
|
|
30
|
+
* - the PII scrubber on every event, transaction, span, breadcrumb and log
|
|
31
|
+
* (`beforeSend`, `beforeSendTransaction`, `beforeSendSpan`,
|
|
32
|
+
* `beforeBreadcrumb`, `beforeSendLog`), and the user as an id only;
|
|
33
|
+
* - no default PII, screenshots, view hierarchy or accessibility labels, and
|
|
34
|
+
* touch breadcrumbs without the touched element's label (labels hold names);
|
|
35
|
+
* - fatal errors marked unhandled, so release health counts them as crashes.
|
|
36
|
+
*
|
|
37
|
+
* Native crashes (sentry-cocoa, sentry-android) are built on the device's
|
|
38
|
+
* native side and don't pass through these JavaScript hooks.
|
|
39
|
+
*
|
|
40
|
+
* Errors: the shell (`GenesisNativeApp`) reports every error it catches
|
|
41
|
+
* through `captureError`. Sentry's own global handler stays on for errors
|
|
42
|
+
* before the shell mounts; when both see one error object, Sentry's
|
|
43
|
+
* deduplication (`__sentry_captured__`) sends it once.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
type Options = Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* `@sentry/react-native`'s namespace: the calls this sink makes. Method
|
|
49
|
+
* syntax on purpose, so the real namespace (with wider option types) fits.
|
|
50
|
+
*/
|
|
51
|
+
interface SentryLike {
|
|
52
|
+
init(options: Options): unknown;
|
|
53
|
+
getClient(): unknown;
|
|
54
|
+
wrap<P extends Record<string, unknown>>(root: ComponentType<P>): ComponentType<P>;
|
|
55
|
+
captureException(error: unknown, context?: Options): string;
|
|
56
|
+
addBreadcrumb(breadcrumb: Options): void;
|
|
57
|
+
setUser(user: {
|
|
58
|
+
id: string;
|
|
59
|
+
} | null): void;
|
|
60
|
+
setTag(key: string, value: string): void;
|
|
61
|
+
expoRouterIntegration?(options?: {
|
|
62
|
+
enableTimeToInitialDisplay?: boolean;
|
|
63
|
+
}): unknown;
|
|
64
|
+
metrics?: {
|
|
65
|
+
distribution(name: string, value: number, options?: Options): void;
|
|
66
|
+
count(name: string, value?: number, options?: Options): void;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
interface SentrySinkOptions {
|
|
70
|
+
/** `process.env.EXPO_PUBLIC_SENTRY_DSN`. Empty or missing: Sentry is not started and the sink does nothing. */
|
|
71
|
+
dsn: string | undefined | null;
|
|
72
|
+
/** Default `development` in `__DEV__`, else from the signature's channel: `production`, `preview` (`preview` and `pr-*`), `development`, else `production`. */
|
|
73
|
+
environment?: string;
|
|
74
|
+
/** The version signature (`versionSignature(…)` from `/updates`, or the updates block's `signature`): release, dist and update tags. */
|
|
75
|
+
signature?: VersionSignature;
|
|
76
|
+
/** `Application.applicationId` (expo-application): the release's prefix. */
|
|
77
|
+
applicationId?: string | null;
|
|
78
|
+
/** Default 0.2 in production and 1 elsewhere. */
|
|
79
|
+
tracesSampleRate?: number;
|
|
80
|
+
/** Navigation spans and time to initial display through Expo Router. Default true. */
|
|
81
|
+
expoRouter?: boolean | {
|
|
82
|
+
enableTimeToInitialDisplay?: boolean;
|
|
83
|
+
};
|
|
84
|
+
/** More integrations (replay, profiling). Masking is yours to set on them. */
|
|
85
|
+
integrations?: readonly unknown[];
|
|
86
|
+
/**
|
|
87
|
+
* Other `Sentry.init` options. The scrubbing hooks run first and yours
|
|
88
|
+
* after, on the scrubbed value; `sendDefaultPii` and the screenshot,
|
|
89
|
+
* view-hierarchy and accessibility options can be set here on purpose.
|
|
90
|
+
*/
|
|
91
|
+
init?: Options;
|
|
92
|
+
/** False turns the scrubber off (not recommended; it is also the only thing reducing the user to an id). Default true. */
|
|
93
|
+
scrub?: boolean;
|
|
94
|
+
/** Called instead of `console.warn` when the DSN is missing outside development. */
|
|
95
|
+
onMissingDsn?: () => void;
|
|
96
|
+
}
|
|
97
|
+
/** Sentry's release format: `<applicationId>@<version>+<build>`, with `dist` the build; `undefined` parts when unknown. */
|
|
98
|
+
declare function sentryRelease(signature: VersionSignature | undefined, applicationId?: string | null): {
|
|
99
|
+
release?: string;
|
|
100
|
+
dist?: string;
|
|
101
|
+
};
|
|
102
|
+
/** The tags each event carries from the signature. Unknown values are written `unknown`, never left out. */
|
|
103
|
+
declare function signatureTags(signature: VersionSignature | undefined): Record<string, string>;
|
|
104
|
+
/**
|
|
105
|
+
* Start Sentry and return a sink for it. Without a DSN it starts nothing and
|
|
106
|
+
* returns a sink that does nothing (a warning outside development says so).
|
|
107
|
+
*
|
|
108
|
+
* @stability Beta
|
|
109
|
+
*/
|
|
110
|
+
declare function sentrySink(sentry: SentryLike, options: SentrySinkOptions): ObservabilitySink;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The PII scrubber every sink's input goes through by default: text is
|
|
114
|
+
* rewritten by pattern (an email, a phone number, a JWT, a Supabase key, a
|
|
115
|
+
* bearer token, a token in a query string, row values in a database error),
|
|
116
|
+
* values under a key that names a secret or a contact detail are replaced
|
|
117
|
+
* whole, and URLs lose their query and fragment (PostgREST filters carry
|
|
118
|
+
* record ids, auth callbacks carry codes). Strings are cut at 4 KB first, so
|
|
119
|
+
* a huge log line can't stall the JS thread.
|
|
120
|
+
*
|
|
121
|
+
* What it can't know: a person's name in free text. Keep names out of error
|
|
122
|
+
* messages and breadcrumbs; touch breadcrumbs lose their labels in
|
|
123
|
+
* `sentrySink` for this reason.
|
|
124
|
+
*
|
|
125
|
+
* Pattern-based on values, not an allowlist of keys: a key allowlist misses
|
|
126
|
+
* `refresh failed: eyJhbGciOi…`, which is the shape that actually occurs.
|
|
127
|
+
*
|
|
128
|
+
* Fail closed: `scrubEvent` and `scrubRecord` return `null` (drop it) when
|
|
129
|
+
* scrubbing itself throws, never the unscrubbed input.
|
|
130
|
+
*/
|
|
131
|
+
/** What replaces a value under a secret-looking key. */
|
|
132
|
+
declare const FILTERED = "[Filtered]";
|
|
133
|
+
/** True when a value under `key` is a secret (or contact detail) whatever it looks like. */
|
|
134
|
+
declare function isSecretKey(key: string): boolean;
|
|
135
|
+
/** A string with every URL query, email, phone number, JWT, Supabase key, bearer token and query-string token replaced. */
|
|
136
|
+
declare function scrubString(value: string): string;
|
|
137
|
+
/** A URL without its query string and fragment, then scrubbed (an email in a path). */
|
|
138
|
+
declare function scrubUrl(value: string): string;
|
|
139
|
+
/**
|
|
140
|
+
* A deep copy of `value` with every string scrubbed and every value under a
|
|
141
|
+
* secret key replaced. Cycles become `"[Circular]"`; past 8 levels,
|
|
142
|
+
* `"[Truncated]"`. Errors become `{ name, message }`. Header lists
|
|
143
|
+
* (`[["authorization", "…"]]`) are treated like objects.
|
|
144
|
+
*/
|
|
145
|
+
declare function scrubValue(value: unknown, key?: string, depth?: number, seen?: WeakSet<object>): unknown;
|
|
146
|
+
/** The fields of a Sentry-shaped event `scrubEvent` treats specially. Anything else is scrubbed by value. */
|
|
147
|
+
interface ScrubbableEvent {
|
|
148
|
+
user?: {
|
|
149
|
+
id?: unknown;
|
|
150
|
+
[key: string]: unknown;
|
|
151
|
+
} | null;
|
|
152
|
+
request?: {
|
|
153
|
+
url?: unknown;
|
|
154
|
+
method?: unknown;
|
|
155
|
+
headers?: unknown;
|
|
156
|
+
[key: string]: unknown;
|
|
157
|
+
};
|
|
158
|
+
[key: string]: unknown;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The event with the user reduced to its id, the request reduced to its
|
|
162
|
+
* method, URL (cut at `?`) and scrubbed headers, and every other value
|
|
163
|
+
* scrubbed. `null` when scrubbing threw: fail closed, send nothing rather
|
|
164
|
+
* than PII.
|
|
165
|
+
*/
|
|
166
|
+
declare function scrubEvent<E extends ScrubbableEvent>(event: E): E | null;
|
|
167
|
+
/** A breadcrumb, span or any record, scrubbed by value. `null` when scrubbing threw (fail closed). */
|
|
168
|
+
declare function scrubRecord<R extends object>(record: R): R | null;
|
|
169
|
+
|
|
170
|
+
export { FILTERED, ObservabilitySink, type ScrubbableEvent, type SentryLike, type SentrySinkOptions, isSecretKey, scrubEvent, scrubRecord, scrubString, scrubUrl, scrubValue, sentryRelease, sentrySink, signatureTags };
|