Skip to content
Source
Sign inSign up

observe.ts

63 lines2.5 KB

1import Constants from "expo-constants";
2import { Observe } from "expo-observe";
3​
4// Importing expo-observe installs its global JS error handler; reports leave only through the relay.
5const relayUrl: unknown = Constants.expoConfig?.extra?.relay?.url;
6const appVariant: unknown = Constants.expoConfig?.extra?.appVariant;
7​
8export const crashReportingAvailable = typeof relayUrl === "string" && relayUrl.trim() !== "";
9​
10interface PromiseRejectionTracker {
11 readonly enablePromiseRejectionTracker?: (options: {
12 readonly allRejections: boolean;
13 readonly onUnhandled: (id: number, rejection: unknown) => void;
14 }) => void;
16​
17// React Native tracks unhandled rejections only in development, for LogBox; Observe has no hook.
18if (!__DEV__) {
19 const hermes: PromiseRejectionTracker | undefined = Reflect.get(globalThis, "HermesInternal");
20 hermes?.enablePromiseRejectionTracker?.({
21 allRejections: true,
22 onUnhandled: (_id, rejection) => Observe.reportError(rejection),
23 });
25​
26let latestConfiguration = 0;
27​
28// While sending is off, a dispatch pass drops what it finds, so one runs before turning it back on.
29// Best effort: Observe skips the pass while it is backing off from a failed send.
30export async function setCrashReportsEnabled(enabled: boolean) {
31 const configuration = ++latestConfiguration;
32 const dispatchingEnabled = crashReportingAvailable && enabled;
33 if (dispatchingEnabled) {
34 await Observe.dispatchEvents();
35 if (configuration !== latestConfiguration) return;
36 }
37 Observe.configure({
38 dispatchingEnabled,
39 ...(typeof appVariant === "string" ? { environment: appVariant } : {}),
40 });
42​
43if (!crashReportingAvailable) {
44 void setCrashReportsEnabled(false);
45} else {
46 // Observe keeps its last configuration across launches; configuring it off while the setting
47 // loads would drop the last session's native crash. Imported lazily so the persistence graph
48 // never runs ahead of the imports `index.ts` orders first.
49 const changedSinceLoad = () => latestConfiguration !== 0;
50 void import("../../persistence/imperative")
51 .then(({ loadPreferences }) => loadPreferences())
52 .then(
53 (preferences) =>
54 changedSinceLoad()
55 ? undefined
56 : setCrashReportsEnabled(preferences.crashReportsEnabled !== false),
57 // Observe keeps the last choice it was given, which stands in for the unreadable one.
58 (error: unknown) => console.warn("[observe] could not read the crash report setting", error),
59 )
60 .catch((error: unknown) => {
61 console.warn("[observe] could not apply the crash report setting", error);
62 });