@everframe/react-native 0.9.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.
Files changed (38) hide show
  1. package/EverframeRN.podspec +88 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +8 -0
  4. package/README.md +505 -0
  5. package/android/build.gradle.kts +209 -0
  6. package/android/settings.gradle.kts +8 -0
  7. package/android/src/main/AndroidManifest.xml +9 -0
  8. package/android/src/main/java/dev/everframe/rn/EverframeModule.kt +1670 -0
  9. package/android/src/main/java/dev/everframe/rn/EverframePackage.kt +40 -0
  10. package/android/src/main/java/dev/everframe/rn/EverframeSensitiveViewManager.kt +20 -0
  11. package/android/src/main/java/dev/everframe/rn/RnVideoPrivacyAdapter.kt +65 -0
  12. package/dist/NativeEverframe.d.ts +308 -0
  13. package/dist/NativeEverframe.js +1 -0
  14. package/dist/browser-ZQAY6B4M.js +1 -0
  15. package/dist/chunk-LPIKPZNX.js +1 -0
  16. package/dist/chunk-QRPINMCR.js +1 -0
  17. package/dist/chunk-QZRTTQRS.js +1 -0
  18. package/dist/chunk-XFLFA52R.js +1 -0
  19. package/dist/chunk-XUSV3KOD.js +1 -0
  20. package/dist/index.d.ts +1006 -0
  21. package/dist/index.js +51 -0
  22. package/dist/integrations/console.d.ts +8 -0
  23. package/dist/integrations/console.js +1 -0
  24. package/dist/integrations/react-native-video.d.ts +44 -0
  25. package/dist/integrations/react-native-video.js +1 -0
  26. package/dist/integrations/react-navigation.d.ts +21 -0
  27. package/dist/integrations/react-navigation.js +1 -0
  28. package/dist/integrations/theoplayer.d.ts +37 -0
  29. package/dist/integrations/theoplayer.js +1 -0
  30. package/dist/types-D5e4kWaw.d.ts +12 -0
  31. package/ios/Sources/EverframeBridge.swift +1043 -0
  32. package/ios/Sources/EverframeEventEmitter.swift +204 -0
  33. package/ios/Sources/EverframeModule.h +36 -0
  34. package/ios/Sources/EverframeModule.mm +489 -0
  35. package/ios/Sources/RemoteVitalsBridge.swift +99 -0
  36. package/package.json +121 -0
  37. package/src/NativeEverframe.ts +439 -0
  38. package/src/codegen-types.ts +11 -0
@@ -0,0 +1,1006 @@
1
+ import * as React from 'react';
2
+ import { EverframeUserSpec, ConfigOpts } from './NativeEverframe.js';
3
+ export { Rect, Spec } from './NativeEverframe.js';
4
+ import { E as EverframeIntegration } from './types-D5e4kWaw.js';
5
+ import { z } from 'zod';
6
+ import { ViewProps, EventSubscription } from 'react-native';
7
+
8
+ type JsonScalar = string | number | boolean | null;
9
+ type JsonValue = JsonScalar | JsonValue[] | JsonObject;
10
+ type JsonObject = {
11
+ [key: string]: JsonValue;
12
+ };
13
+
14
+ declare const ReportEnvelope: z.ZodObject<{
15
+ protocolVersion: z.ZodLiteral<"1.0">;
16
+ reportId: z.ZodString;
17
+ submittedAt: z.ZodString;
18
+ source: z.ZodOptional<z.ZodEnum<{
19
+ error: "error";
20
+ manual: "manual";
21
+ crash: "crash";
22
+ }>>;
23
+ sessionId: z.ZodOptional<z.ZodString>;
24
+ sdk: z.ZodObject<{
25
+ name: z.ZodEnum<{
26
+ "everframe-react": "everframe-react";
27
+ "everframe-web": "everframe-web";
28
+ "everframe-react-native": "everframe-react-native";
29
+ "everframe-ios": "everframe-ios";
30
+ "everframe-android": "everframe-android";
31
+ }>;
32
+ version: z.ZodString;
33
+ platform: z.ZodEnum<{
34
+ web: "web";
35
+ ios: "ios";
36
+ android: "android";
37
+ tvos: "tvos";
38
+ tizen: "tizen";
39
+ webos: "webos";
40
+ androidtv: "androidtv";
41
+ }>;
42
+ formFactor: z.ZodEnum<{
43
+ phone: "phone";
44
+ tablet: "tablet";
45
+ desktop: "desktop";
46
+ tv: "tv";
47
+ }>;
48
+ }, z.core.$loose>;
49
+ reporter: z.ZodObject<{
50
+ title: z.ZodString;
51
+ description: z.ZodString;
52
+ user: z.ZodOptional<z.ZodObject<{
53
+ id: z.ZodOptional<z.ZodString>;
54
+ email: z.ZodOptional<z.ZodString>;
55
+ displayName: z.ZodOptional<z.ZodString>;
56
+ }, z.core.$loose>>;
57
+ }, z.core.$loose>;
58
+ captures: z.ZodObject<{
59
+ screenshot: z.ZodBoolean;
60
+ uiTree: z.ZodBoolean;
61
+ focus: z.ZodBoolean;
62
+ logs: z.ZodBoolean;
63
+ network: z.ZodBoolean;
64
+ breadcrumbs: z.ZodOptional<z.ZodBoolean>;
65
+ }, z.core.$loose>;
66
+ captureControl: z.ZodObject<{
67
+ included: z.ZodArray<z.ZodString>;
68
+ excluded: z.ZodArray<z.ZodString>;
69
+ degradedReason: z.ZodOptional<z.ZodString>;
70
+ }, z.core.$loose>;
71
+ payload: z.ZodObject<{
72
+ focus: z.ZodOptional<z.ZodObject<{
73
+ path: z.ZodArray<z.ZodNumber>;
74
+ componentPath: z.ZodString;
75
+ source: z.ZodEnum<{
76
+ mouse: "mouse";
77
+ keyboard: "keyboard";
78
+ remote: "remote";
79
+ touch: "touch";
80
+ programmatic: "programmatic";
81
+ }>;
82
+ cursor: z.ZodOptional<z.ZodObject<{
83
+ x: z.ZodNumber;
84
+ y: z.ZodNumber;
85
+ }, z.core.$strip>>;
86
+ }, z.core.$strip>>;
87
+ logs: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
88
+ network: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
89
+ breadcrumbs: z.ZodOptional<z.ZodArray<z.ZodObject<{
90
+ t: z.ZodNumber;
91
+ seq: z.ZodNumber;
92
+ kind: z.ZodEnum<{
93
+ custom: "custom";
94
+ error: "error";
95
+ navigation: "navigation";
96
+ tap: "tap";
97
+ console: "console";
98
+ network: "network";
99
+ lifecycle: "lifecycle";
100
+ }>;
101
+ level: z.ZodOptional<z.ZodEnum<{
102
+ error: "error";
103
+ debug: "debug";
104
+ info: "info";
105
+ warn: "warn";
106
+ }>>;
107
+ message: z.ZodString;
108
+ data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
109
+ truncated: z.ZodOptional<z.ZodBoolean>;
110
+ }, z.core.$loose>>>;
111
+ networkBodies: z.ZodOptional<z.ZodArray<z.ZodObject<{
112
+ ref: z.ZodNumber;
113
+ t: z.ZodNumber;
114
+ reqBody: z.ZodOptional<z.ZodString>;
115
+ resBody: z.ZodOptional<z.ZodString>;
116
+ reqBodyTruncated: z.ZodOptional<z.ZodBoolean>;
117
+ resBodyTruncated: z.ZodOptional<z.ZodBoolean>;
118
+ reqBodyBytes: z.ZodOptional<z.ZodNumber>;
119
+ resBodyBytes: z.ZodOptional<z.ZodNumber>;
120
+ reqHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
121
+ resHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
122
+ reqBodySkipped: z.ZodOptional<z.ZodEnum<{
123
+ error: "error";
124
+ "content-type": "content-type";
125
+ unsupported: "unsupported";
126
+ }>>;
127
+ resBodySkipped: z.ZodOptional<z.ZodEnum<{
128
+ error: "error";
129
+ "content-type": "content-type";
130
+ unsupported: "unsupported";
131
+ }>>;
132
+ }, z.core.$loose>>>;
133
+ vitals: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
134
+ kind: z.ZodLiteral<"sample">;
135
+ t: z.ZodNumber;
136
+ cpu: z.ZodOptional<z.ZodNumber>;
137
+ mem: z.ZodNumber;
138
+ extras: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
139
+ }, z.core.$strip>, z.ZodObject<{
140
+ kind: z.ZodLiteral<"player">;
141
+ t: z.ZodNumber;
142
+ type: z.ZodEnum<{
143
+ error: "error";
144
+ play: "play";
145
+ pause: "pause";
146
+ seek: "seek";
147
+ buffer_start: "buffer_start";
148
+ buffer_end: "buffer_end";
149
+ bitrate_change: "bitrate_change";
150
+ rate_change: "rate_change";
151
+ startup: "startup";
152
+ dropped_frames: "dropped_frames";
153
+ source_change: "source_change";
154
+ player_attach: "player_attach";
155
+ player_detach: "player_detach";
156
+ drm: "drm";
157
+ quality_change: "quality_change";
158
+ stats: "stats";
159
+ }>;
160
+ playerId: z.ZodOptional<z.ZodString>;
161
+ data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
162
+ truncated: z.ZodOptional<z.ZodBoolean>;
163
+ }, z.core.$strip>, z.ZodObject<{
164
+ kind: z.ZodLiteral<"custom">;
165
+ t: z.ZodNumber;
166
+ name: z.ZodString;
167
+ data: z.ZodOptional<z.ZodUnknown>;
168
+ truncated: z.ZodOptional<z.ZodBoolean>;
169
+ playerId: z.ZodOptional<z.ZodString>;
170
+ }, z.core.$strip>], "kind">>>;
171
+ resources: z.ZodOptional<z.ZodArray<z.ZodObject<{
172
+ t: z.ZodNumber;
173
+ cpu: z.ZodOptional<z.ZodNumber>;
174
+ mem: z.ZodNumber;
175
+ extras: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
176
+ }, z.core.$strip>>>;
177
+ annotations: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
178
+ redactions: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
179
+ extra: z.ZodOptional<z.ZodString>;
180
+ crash: z.ZodOptional<z.ZodObject<{
181
+ causeChain: z.ZodOptional<z.ZodObject<{
182
+ causes: z.ZodArray<z.ZodObject<{
183
+ exceptionType: z.ZodString;
184
+ message: z.ZodString;
185
+ frames: z.ZodArray<z.ZodObject<{
186
+ raw: z.ZodString;
187
+ file: z.ZodOptional<z.ZodString>;
188
+ function: z.ZodOptional<z.ZodString>;
189
+ line: z.ZodOptional<z.ZodNumber>;
190
+ col: z.ZodOptional<z.ZodNumber>;
191
+ }, z.core.$strip>>;
192
+ framesTruncated: z.ZodBoolean;
193
+ }, z.core.$strip>>;
194
+ truncated: z.ZodBoolean;
195
+ }, z.core.$strip>>;
196
+ details: z.ZodOptional<z.ZodObject<{
197
+ severity: z.ZodOptional<z.ZodEnum<{
198
+ error: "error";
199
+ info: "info";
200
+ warning: "warning";
201
+ }>>;
202
+ context: z.ZodOptional<z.ZodString>;
203
+ metadata: z.ZodOptional<z.ZodType<JsonObject, unknown, z.core.$ZodTypeInternals<JsonObject, unknown>>>;
204
+ truncated: z.ZodOptional<z.ZodBoolean>;
205
+ }, z.core.$strict>>;
206
+ jsBundle: z.ZodOptional<z.ZodObject<{
207
+ engine: z.ZodLiteral<"hermes">;
208
+ platform: z.ZodEnum<{
209
+ ios: "ios";
210
+ android: "android";
211
+ }>;
212
+ buildId: z.ZodString;
213
+ bundleName: z.ZodString;
214
+ }, z.core.$strip>>;
215
+ jvm: z.ZodOptional<z.ZodObject<{
216
+ mappingId: z.ZodOptional<z.ZodString>;
217
+ causes: z.ZodArray<z.ZodObject<{
218
+ exceptionType: z.ZodString;
219
+ message: z.ZodString;
220
+ frames: z.ZodArray<z.ZodObject<{
221
+ raw: z.ZodString;
222
+ file: z.ZodOptional<z.ZodString>;
223
+ function: z.ZodOptional<z.ZodString>;
224
+ line: z.ZodOptional<z.ZodNumber>;
225
+ col: z.ZodOptional<z.ZodNumber>;
226
+ }, z.core.$loose>>;
227
+ framesTruncated: z.ZodBoolean;
228
+ }, z.core.$strip>>;
229
+ causesTruncated: z.ZodBoolean;
230
+ }, z.core.$strip>>;
231
+ exceptionType: z.ZodString;
232
+ message: z.ZodString;
233
+ frames: z.ZodArray<z.ZodObject<{
234
+ raw: z.ZodString;
235
+ file: z.ZodOptional<z.ZodString>;
236
+ function: z.ZodOptional<z.ZodString>;
237
+ line: z.ZodOptional<z.ZodNumber>;
238
+ col: z.ZodOptional<z.ZodNumber>;
239
+ }, z.core.$loose>>;
240
+ threadName: z.ZodOptional<z.ZodString>;
241
+ mechanism: z.ZodString;
242
+ handled: z.ZodBoolean;
243
+ fatal: z.ZodOptional<z.ZodBoolean>;
244
+ occurredAt: z.ZodString;
245
+ fingerprint: z.ZodString;
246
+ }, z.core.$loose>>;
247
+ }, z.core.$loose>;
248
+ context: z.ZodObject<{
249
+ app: z.ZodObject<{
250
+ name: z.ZodString;
251
+ version: z.ZodString;
252
+ build: z.ZodOptional<z.ZodString>;
253
+ }, z.core.$loose>;
254
+ device: z.ZodObject<{
255
+ os: z.ZodString;
256
+ osVersion: z.ZodString;
257
+ model: z.ZodOptional<z.ZodString>;
258
+ screenSize: z.ZodObject<{
259
+ width: z.ZodNumber;
260
+ height: z.ZodNumber;
261
+ }, z.core.$strip>;
262
+ pixelRatio: z.ZodNumber;
263
+ locale: z.ZodString;
264
+ timezone: z.ZodString;
265
+ userAgent: z.ZodOptional<z.ZodString>;
266
+ }, z.core.$loose>;
267
+ route: z.ZodOptional<z.ZodString>;
268
+ }, z.core.$loose>;
269
+ attachments: z.ZodArray<z.ZodObject<{
270
+ partName: z.ZodString;
271
+ kind: z.ZodEnum<{
272
+ screenshot: "screenshot";
273
+ "annotated-screenshot": "annotated-screenshot";
274
+ video: "video";
275
+ audio: "audio";
276
+ "session-replay": "session-replay";
277
+ other: "other";
278
+ }>;
279
+ contentType: z.ZodString;
280
+ byteLength: z.ZodNumber;
281
+ sha256: z.ZodString;
282
+ width: z.ZodOptional<z.ZodNumber>;
283
+ height: z.ZodOptional<z.ZodNumber>;
284
+ format: z.ZodOptional<z.ZodEnum<{
285
+ rrweb: "rrweb";
286
+ "everframe-vtree-v1": "everframe-vtree-v1";
287
+ "everframe-video-v1": "everframe-video-v1";
288
+ "traceitx-vtree-v1": "traceitx-vtree-v1";
289
+ "traceitx-video-v1": "traceitx-video-v1";
290
+ }>>;
291
+ durationMs: z.ZodOptional<z.ZodNumber>;
292
+ replayStartEpochMs: z.ZodOptional<z.ZodNumber>;
293
+ }, z.core.$strip>>;
294
+ }, z.core.$loose>;
295
+ type ReportEnvelope = z.infer<typeof ReportEnvelope>;
296
+
297
+ interface UINode {
298
+ componentType: string;
299
+ componentName?: string | undefined;
300
+ identifiers: Record<string, string>;
301
+ rect: {
302
+ x: number;
303
+ y: number;
304
+ width: number;
305
+ height: number;
306
+ };
307
+ safeProps: Record<string, string | number | boolean>;
308
+ children: UINode[];
309
+ sensitive?: boolean | undefined;
310
+ nodeKind?: 'compose' | 'view' | 'dom' | undefined;
311
+ }
312
+ declare const UINode: z.ZodType<UINode>;
313
+ declare const UITree: z.ZodObject<{
314
+ root: z.ZodType<UINode, unknown, z.core.$ZodTypeInternals<UINode, unknown>>;
315
+ capturedAt: z.ZodString;
316
+ rendererHint: z.ZodEnum<{
317
+ android: "android";
318
+ dom: "dom";
319
+ "rn-paper": "rn-paper";
320
+ "rn-fabric": "rn-fabric";
321
+ uikit: "uikit";
322
+ }>;
323
+ truncated: z.ZodOptional<z.ZodBoolean>;
324
+ }, z.core.$strip>;
325
+ type UITree = z.infer<typeof UITree>;
326
+ declare const AttachmentRef: z.ZodObject<{
327
+ partName: z.ZodString;
328
+ kind: z.ZodEnum<{
329
+ screenshot: "screenshot";
330
+ "annotated-screenshot": "annotated-screenshot";
331
+ video: "video";
332
+ audio: "audio";
333
+ "session-replay": "session-replay";
334
+ other: "other";
335
+ }>;
336
+ contentType: z.ZodString;
337
+ byteLength: z.ZodNumber;
338
+ sha256: z.ZodString;
339
+ width: z.ZodOptional<z.ZodNumber>;
340
+ height: z.ZodOptional<z.ZodNumber>;
341
+ format: z.ZodOptional<z.ZodEnum<{
342
+ rrweb: "rrweb";
343
+ "everframe-vtree-v1": "everframe-vtree-v1";
344
+ "everframe-video-v1": "everframe-video-v1";
345
+ "traceitx-vtree-v1": "traceitx-vtree-v1";
346
+ "traceitx-video-v1": "traceitx-video-v1";
347
+ }>>;
348
+ durationMs: z.ZodOptional<z.ZodNumber>;
349
+ replayStartEpochMs: z.ZodOptional<z.ZodNumber>;
350
+ }, z.core.$strip>;
351
+ type AttachmentRef = z.infer<typeof AttachmentRef>;
352
+ declare const VitalsPlayerEventType: z.ZodEnum<{
353
+ error: "error";
354
+ play: "play";
355
+ pause: "pause";
356
+ seek: "seek";
357
+ buffer_start: "buffer_start";
358
+ buffer_end: "buffer_end";
359
+ bitrate_change: "bitrate_change";
360
+ rate_change: "rate_change";
361
+ startup: "startup";
362
+ dropped_frames: "dropped_frames";
363
+ source_change: "source_change";
364
+ player_attach: "player_attach";
365
+ player_detach: "player_detach";
366
+ drm: "drm";
367
+ quality_change: "quality_change";
368
+ stats: "stats";
369
+ }>;
370
+ type VitalsPlayerEventType = z.infer<typeof VitalsPlayerEventType>;
371
+
372
+ interface JsBundleConfig {
373
+ buildId: string;
374
+ bundleName: string;
375
+ }
376
+
377
+ /**
378
+ * Resolved by `useEverframe().open()` / top-level `open()`.
379
+ * Mirrors the native NSDictionary / WritableMap shape produced by the iOS
380
+ * (`EverframeBridge.openReporter`) and Android (`EverframeModule.openReporter`)
381
+ * bridges. The `status` field is one of:
382
+ * - 'submitted' — envelope shipped successfully (reportId populated)
383
+ * - 'queued' — envelope persisted for retry (reportId populated)
384
+ * - 'cancelled' — user dismissed the reporter without submitting
385
+ */
386
+ type ReporterResult = {
387
+ status: 'submitted';
388
+ reportId: string;
389
+ } | {
390
+ status: 'queued';
391
+ reportId: string;
392
+ } | {
393
+ status: 'cancelled';
394
+ reason?: string;
395
+ };
396
+ /**
397
+ * Thrown when `open()` is called from a top-level (non-component) site
398
+ * before a `<EverframeProvider>` has mounted. Components reading via
399
+ * `useEverframe()` see a same-class error.
400
+ */
401
+ declare class EverframeNotMountedError extends Error {
402
+ readonly name = "EverframeNotMountedError";
403
+ constructor(message?: string);
404
+ }
405
+
406
+ declare const ErrorSeverity: z.ZodEnum<{
407
+ error: "error";
408
+ info: "info";
409
+ warning: "warning";
410
+ }>;
411
+ type ErrorSeverity = z.infer<typeof ErrorSeverity>;
412
+
413
+ /** Optional per-occurrence details captured with a handled exception. */
414
+ interface CaptureExceptionOptions {
415
+ severity?: ErrorSeverity;
416
+ context?: string;
417
+ metadata?: Record<string, unknown>;
418
+ }
419
+ interface DeviceMetadata {
420
+ os: string;
421
+ osVersion: string;
422
+ model?: string;
423
+ screenSize: {
424
+ width: number;
425
+ height: number;
426
+ };
427
+ pixelRatio: number;
428
+ locale: string;
429
+ timezone: string;
430
+ network?: string;
431
+ /**
432
+ * Raw User-Agent string from `navigator.userAgent`. Surfaced to triagers so
433
+ * they can disambiguate things our OS/version parser doesn't capture
434
+ * (browser engine + version, in-app webviews, bot signatures, accessibility
435
+ * UA overrides). Web SDK only — native SDKs leave this undefined.
436
+ */
437
+ userAgent?: string;
438
+ }
439
+ interface ReportDraft {
440
+ title: string;
441
+ description: string;
442
+ excludedArtifacts: string[];
443
+ annotations: unknown[];
444
+ redactions: unknown[];
445
+ /** Host-supplied free-form metadata (from `setExtra`). Opaque string, ≤2000 chars. */
446
+ extra?: string;
447
+ }
448
+ /**
449
+ * A host-supplied function that produces the next report's `extra` payload
450
+ * on demand. Registered via `setExtra(resolve)`; invoked once per report
451
+ * assembly (see `resolveClientExtra`), never at registration time.
452
+ */
453
+ type ExtraResolver = () => string | Record<string, unknown>;
454
+
455
+ /** Protocol ceiling — `packages/protocol/src/envelope.ts`. */
456
+ declare const EXTRA_MAX_CHARS = 16384;
457
+
458
+ /** Shape exposed via `useEverframe()` and the top-level `open` re-export. */
459
+ interface EverframeContextValue {
460
+ /** Capture a handled exception without opening the reporter. No-op outside the owning mount. */
461
+ captureException(error: unknown, options?: CaptureExceptionOptions): void;
462
+ /**
463
+ * Open the native reporter modal. Resolves with the user-facing outcome
464
+ * (`submitted` / `queued` / `cancelled`). Replaces the pre-0.3 nested
465
+ * `report.open()` — the `.report` namespace held only `.open` so flattening
466
+ * matches sdk-react.
467
+ */
468
+ open(): Promise<ReporterResult>;
469
+ sensitive: {
470
+ register(tag: number, rect: {
471
+ x: number;
472
+ y: number;
473
+ width: number;
474
+ height: number;
475
+ }): void;
476
+ unregister(tag: number): void;
477
+ };
478
+ /**
479
+ * Attach host-supplied free-form metadata to the next report. Each call
480
+ * REPLACES the previous value. Auto-cleared after the next `open()`
481
+ * resolves.
482
+ *
483
+ * Prefer the OBJECT form so the SDK serializes it for you before crossing
484
+ * the bridge. Either form is capped at `EXTRA_MAX_CHARS` (16 KiB): an
485
+ * over-budget object is omitted (a warning is logged), because slicing
486
+ * serialized JSON yields a fragment nothing can parse; an over-budget
487
+ * string is still forwarded to the native side as-is, which applies its
488
+ * own 16 KiB ceiling as a raw character cut, not JSON-aware. Pass an empty
489
+ * string to detach.
490
+ */
491
+ setExtra(value: string): void;
492
+ setExtra(value: Record<string, unknown>): void;
493
+ /**
494
+ * Resolver form (spec 2026-09-17 setExtra-resolver) — matches
495
+ * `@everframe/sdk-core`'s `setExtra(resolve: ExtraResolver)` signature
496
+ * exactly. PREFER THIS over the string/object forms above: triggers the
497
+ * SDK owns (native shake on mobile) open the reporter DIRECTLY, with no
498
+ * chance for the host to refresh a pushed snapshot first — see the fuller
499
+ * rationale on `@everframe/sdk-core`'s `EverframeClient.setExtra`. The
500
+ * resolver is stored, never called at registration time; native ASKS for
501
+ * it (a bounded round trip to JS, mirroring the companion
502
+ * `reportRequested` handshake) right before it drains pending attachments
503
+ * for a report, so it always sees current values with no effect to write
504
+ * or keep in sync. A throwing resolver never breaks the report: it is
505
+ * caught, warned, and `extra` is simply omitted from that report — same
506
+ * budgeting as the object form (`budgetExtra`), applied to the resolver's
507
+ * return value at resolve time instead of at registration time.
508
+ */
509
+ setExtra(resolve: ExtraResolver): void;
510
+ /**
511
+ * Manual escape hatch (Plan 4 / Task 14): drop a host-supplied marker into
512
+ * the native breadcrumb chain — object-form, matching the web SDK
513
+ * signature. RN apps already inherit ALL native auto-capture underneath RN
514
+ * (lifecycle/error/console/network-opt-in/tap/nav); JS-side auto-capture
515
+ * (fetch/react-navigation/touch patches) is an explicit non-goal of this
516
+ * plan. `addBreadcrumb` and `recordScreen` (spec 2026-07-14) are the only
517
+ * JS-initiated crumb paths.
518
+ *
519
+ * NO validation/coercion happens here or on the bridge — the call is
520
+ * forwarded positionally to the native TurboModule spec method, which
521
+ * forwards straight to the platform singleton (`Everframe.shared
522
+ * .addBreadcrumb` on iOS / `Everframe.addBreadcrumb` on Android). That
523
+ * singleton owns ALL coercion (unknown `kind` → `custom`, invalid `level`
524
+ * dropped rather than defaulted, `data` JSON-coerced) and gating (no-op
525
+ * pre-start / while killed).
526
+ */
527
+ addBreadcrumb(input: {
528
+ message: string;
529
+ kind?: string;
530
+ level?: string;
531
+ data?: object;
532
+ }): void;
533
+ /**
534
+ * Navigation screen marker (spec 2026-07-14): record "this screen is now
535
+ * visible". The native side derives the `from → to` transition (global
536
+ * chain shared with native auto-capture), gates, and coerces — nothing
537
+ * happens JS-side. Prefer the `useEverframeScreen` hook / `<EverframeScreen>` component;
538
+ * this raw form suits onStateChange-style whole-app wiring.
539
+ */
540
+ recordScreen(name: string, data?: Record<string, unknown>): void;
541
+ /**
542
+ * Set or clear the active user for self-declared recognition. Call with no
543
+ * argument to clear. Unverified: a label, never a credential.
544
+ */
545
+ setUser(user?: EverframeUserSpec): void;
546
+ }
547
+ /**
548
+ * Top-level imperative `open` re-export. Inside the React tree, prefer
549
+ * `useEverframe().open()`. This re-export exists for non-component call
550
+ * sites (global error handlers, deep-link handlers, native event bridges).
551
+ */
552
+ declare function open(): Promise<ReporterResult>;
553
+ /** Top-level `setExtra` for non-component call sites. No-op if no provider mounted. */
554
+ declare function setExtra(value: string): void;
555
+ declare function setExtra(value: Record<string, unknown>): void;
556
+ declare function setExtra(resolve: ExtraResolver): void;
557
+ /**
558
+ * Top-level `addBreadcrumb` for non-component call sites (global error
559
+ * handlers, deep-link handlers, native event bridges). No-op if no provider
560
+ * mounted — matches `setExtra` above. See
561
+ * `EverframeContextValue.addBreadcrumb` for the full contract.
562
+ */
563
+ declare function addBreadcrumb(input: {
564
+ message: string;
565
+ kind?: string;
566
+ level?: string;
567
+ data?: object;
568
+ }): void;
569
+ /**
570
+ * Top-level `recordScreen` for non-component call sites (e.g. a
571
+ * react-navigation `onStateChange` handler). No-op if no provider mounted —
572
+ * matches `setExtra`/`addBreadcrumb` above.
573
+ */
574
+ declare function recordScreen(name: string, data?: Record<string, unknown>): void;
575
+ /** Top-level `setUser` for non-component call sites. No-op if no provider mounted. */
576
+ declare function setUser(user?: EverframeUserSpec): void;
577
+ /** Capture a handled exception from any call site. No-op without a mounted provider. */
578
+ declare function captureException(error: unknown, options?: CaptureExceptionOptions): void;
579
+
580
+ /**
581
+ * Runtime configuration — the host-facing `EverframeProvider config` shape.
582
+ *
583
+ * Extends the bridge ConfigOpts but OMITS `sdkVersion`: the SDK version is not
584
+ * host-defined, it's owned by the SDK and stamped per release on the native
585
+ * side (`Everframe.SDK_VERSION`). See extractBridgeConfig.
586
+ *
587
+ * External review, finding NN4 — also OMITS `companionBadgeEnabled` /
588
+ * `companionBadgePosition`, the FLAT wire-shaped fields `ConfigOpts` declares
589
+ * for codegen (RN codegen cannot express the nested `{ enabled, position }`
590
+ * object at all — see `companionBadge` below). Without this, `RuntimeConfig`
591
+ * structurally inherited BOTH the flat wire fields AND the nested
592
+ * `companionBadge` declared below, so `{ companionBadgeEnabled: false }`
593
+ * type-checked as a valid host config and silently no-opped: `extractBridge
594
+ * Config` only ever reads the nested `companionBadge` object, never the flat
595
+ * keys, so a host reaching for the (also-valid-looking) flat shape got no
596
+ * error and no effect. Omitting them here makes `companionBadge` the ONLY
597
+ * public surface for this option — passing the flat form is now a
598
+ * compile-time error, matching the runtime's actual (nested-only) behavior.
599
+ * Deliberately NOT applied to `networkBodiesDisabled`, even though the same
600
+ * shape of gap arguably exists there too (`RuntimeConfig` also declares its
601
+ * own nested `networkBodies?: { disabled? }` below, alongside the inherited
602
+ * flat `networkBodiesDisabled?`): out of scope for this fix by explicit
603
+ * review instruction, left as pre-existing behavior rather than folded in
604
+ * here.
605
+ */
606
+ interface RuntimeConfig extends Omit<ConfigOpts, "sdkVersion" | "installIdentifierDisabled" | "companionBadgeEnabled" | "companionBadgePosition" | "shakeToReportEnabled" | "themeBackground" | "themeSurface" | "themeBorder" | "themeText" | "themeTextMuted" | "themeAccent" | "themeAccentForeground" | "themeDestructive" | "vitalsEnabled" | "vitalsSampleRate" | "vitalsCaptureSourceQuery"> {
607
+ /**
608
+ * Per-app SDK key (publishable, not secret). Required on the host-facing
609
+ * config — narrows the bridge `ConfigOpts.apiKey?` to required so a missing
610
+ * key is a compile-time error, matching the React SDK. The bridge type stays
611
+ * optional (extractBridgeConfig builds `{}`); only this host surface requires it.
612
+ */
613
+ apiKey: string;
614
+ appName?: string;
615
+ appVersion?: string;
616
+ appBuild?: string;
617
+ /** Exact loaded Hermes bundle identity, independent of the native app build. */
618
+ jsBundle?: JsBundleConfig;
619
+ /**
620
+ * Opt-in JS-side capture integrations (spec 2026-07-14 RN-iOS parity).
621
+ * Import from '@everframe/react-native/integrations/*'; nothing
622
+ * auto-installs. Setups run after configure-on-mount, teardowns on unmount.
623
+ */
624
+ integrations?: EverframeIntegration[];
625
+ /**
626
+ * Crash/error reporting (spec 2026-07-18). Installs a default-on global
627
+ * ErrorUtils handler on mount — deliberately NOT gated behind
628
+ * `integrations` (deviation from the RN integrations doctrine, recorded in
629
+ * the spec): crash capture is a safety net, not an opt-in enrichment. Set
630
+ * `disabled: true` to veto it entirely.
631
+ */
632
+ crashReporting?: {
633
+ disabled?: boolean;
634
+ };
635
+ /**
636
+ * Network request/response body capture (spec 2026-08-12). CLIENT VETO
637
+ * only: `disabled: true` turns bodies off locally; it can never force them
638
+ * on — the server's per-app `captureBodies` gate is authoritative.
639
+ *
640
+ * NOTE: RN does not currently attach Everframe network capture to its own
641
+ * HTTP clients, so this option is correct but inert until that lands.
642
+ */
643
+ networkBodies?: {
644
+ disabled?: boolean;
645
+ };
646
+ /**
647
+ * Install identifier (MAI meter spec 2026-08-27). ON by default: the SDK
648
+ * sends a value derived from a locally-minted, non-secret per-install seed
649
+ * at most once a day, so distinct installs can be counted toward your
650
+ * plan. Nothing about the person using the app is derived or stored, and
651
+ * the seed never leaves the device.
652
+ *
653
+ * CLIENT VETO only: `disabled: true` stops this app sending one from that
654
+ * point on; it can never force it on. Nested host-facing shape flattened
655
+ * onto `ConfigOpts.installIdentifierDisabled` by `extractBridgeConfig` —
656
+ * same idiom, and the same codegen reason, as `networkBodies` above.
657
+ *
658
+ * NOT retroactive and NOT org-wide: installs already recorded earlier this
659
+ * calendar month stay counted, and the number shown is per ORGANIZATION.
660
+ */
661
+ installIdentifier?: {
662
+ disabled?: boolean;
663
+ };
664
+ /**
665
+ * Built-in attach-PIN surface mode (spec 2026-08-19). Narrows the bridge
666
+ * `ConfigOpts.attachPinUi?: string` to a literal union here — the flat
667
+ * `string` on `ConfigOpts` is a codegen constraint on the WIRE type only
668
+ * (RN codegen can't express a string-literal union in a struct field, see
669
+ * `NativeEverframe.ts`'s D-decision header note); this host-facing surface
670
+ * doesn't cross codegen and gets normal DX. `extractBridgeConfig` passes
671
+ * it through unchanged — the union is a subtype of `string`, so no
672
+ * conversion is needed, same as `captureScreenshot` above.
673
+ */
674
+ attachPinUi?: "builtin" | "custom" | "off";
675
+ /**
676
+ * Companion on-screen name-badge visibility/position (naming spec
677
+ * 2026-08-24, controller ruling / Task 6b) — lets a host that finds the
678
+ * badge intrusive turn it off in one line: `companionBadge: { enabled:
679
+ * false }`. Nested host-facing shape, unlike `attachPinUi` above: RN
680
+ * codegen cannot express a nested object in a struct field at all (not
681
+ * even a flat one with a narrowed literal-union member), so
682
+ * `extractBridgeConfig` flattens both fields onto the wire `ConfigOpts`
683
+ * (`companionBadgeEnabled`/`companionBadgePosition`) — the same
684
+ * flattening idiom `networkBodies.disabled` → `networkBodiesDisabled`
685
+ * above already uses for the same reason.
686
+ */
687
+ companionBadge?: {
688
+ enabled?: boolean;
689
+ position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
690
+ };
691
+ /**
692
+ * Native mobile shake gesture. Enabled by default; the dashboard remains
693
+ * authoritative. React Native/Expo development builds should normally use
694
+ * `{ enabled: !__DEV__ }` to avoid overlapping with the development menu.
695
+ */
696
+ shakeToReport?: {
697
+ enabled?: boolean;
698
+ };
699
+ /**
700
+ * Inline reporter theme (reporter branding spec 2026-08-25, RN slice) —
701
+ * 8 optional `#rrggbb` role strings for the NATIVE report dialogs the RN
702
+ * SDK presents (`open()`); RN itself renders no reporter UI. Nested
703
+ * host-facing shape, flattened onto the 8 flat `ConfigOpts.theme*` wire
704
+ * fields by `extractBridgeConfig` — the same idiom (and codegen reason) as
705
+ * `companionBadge` above.
706
+ *
707
+ * Rendering is entitlement-gated NATIVELY per the branding contract
708
+ * (precedence server → inline → default): the theme applies only when the
709
+ * server says `watermark: false` (paid plan); a free plan ignores it and
710
+ * keeps the watermark — fail closed, never bypassable from RN. Invalid hex
711
+ * values are ignored per-field by each native ThemeResolver; the RN side
712
+ * is pure passthrough by design.
713
+ */
714
+ theme?: {
715
+ background?: string;
716
+ surface?: string;
717
+ border?: string;
718
+ text?: string;
719
+ textMuted?: string;
720
+ accent?: string;
721
+ accentForeground?: string;
722
+ destructive?: string;
723
+ };
724
+ /**
725
+ * Session Vitals local config (spec 2026-09-06). `enabled`: absent =
726
+ * follow the dashboard toggle, `false` = opt out locally, `true` never
727
+ * forces it on. `sampleRate`: [0, 1], min()'d with the server rate.
728
+ * `captureSourceQuery`: keep query strings on `source_change.src`
729
+ * (default false — signed CDN URLs carry tokens). Flattened onto three
730
+ * flat `ConfigOpts.vitals*` wire fields by `extractBridgeConfig`.
731
+ */
732
+ vitals?: {
733
+ enabled?: boolean;
734
+ sampleRate?: number;
735
+ captureSourceQuery?: boolean;
736
+ };
737
+ }
738
+
739
+ interface EverframeProviderProps {
740
+ config: RuntimeConfig;
741
+ children: React.ReactNode;
742
+ }
743
+ declare function EverframeProvider(props: EverframeProviderProps): React.ReactElement;
744
+ /**
745
+ * Read the active runtime from React context. Throws if no provider is
746
+ * mounted above the call site.
747
+ */
748
+ declare function useEverframe(): EverframeContextValue;
749
+
750
+ type Rect = {
751
+ x: number;
752
+ y: number;
753
+ width: number;
754
+ height: number;
755
+ };
756
+ /**
757
+ * Wrap any subtree to mark its bounding box as sensitive. The native screenshot
758
+ * pipeline blurs / blackboxes the rect before the image leaves the device
759
+ * (PRIV-02 / PRIV-03).
760
+ */
761
+ declare function EverframeSensitive(props: ViewProps): React.ReactElement;
762
+ /**
763
+ * Imperatively mark an already-instantiated host (e.g., a third-party
764
+ * <TextInput> wrapper). Pass a ref and a rect; the hook registers on each
765
+ * rect change (RESEARCH §5.3). This effect runs after mounting and cannot protect
766
+ * first paint. Use EverframeSensitive for mount-time Android video privacy.
767
+ */
768
+ declare function useEverframeSensitiveRef<T>(ref: React.RefObject<T | null>, rect: Rect | null): void;
769
+
770
+ /**
771
+ * Emit a navigation marker when this screen appears: on mount, on [name]
772
+ * change, and whenever `opts.focused` flips to true.
773
+ *
774
+ * `focused` defaults to true (mount = appearance — correct when your
775
+ * navigator unmounts hidden screens). Pass it for navigators that keep
776
+ * screens mounted (react-navigation stacks/tabs: `useIsFocused()`). The
777
+ * native `A → A` suppression absorbs StrictMode double-mounts and refocus
778
+ * re-emits. [name] should be a route identifier, never user content (PII).
779
+ */
780
+ declare function useEverframeScreen(name: string, opts?: {
781
+ focused?: boolean;
782
+ }): void;
783
+ interface EverframeScreenProps {
784
+ name: string;
785
+ focused?: boolean;
786
+ }
787
+ /**
788
+ * Declarative form of [useEverframeScreen] for class components / JSX-only
789
+ * placement. Renders nothing.
790
+ */
791
+ declare function EverframeScreen(props: EverframeScreenProps): null;
792
+
793
+ interface PlayerStats {
794
+ bufferAheadMs: number;
795
+ bandwidthEstimate?: number;
796
+ bitrate?: number;
797
+ width?: number;
798
+ height?: number;
799
+ /** CUMULATIVE; native derives the per-tick delta. */
800
+ droppedFrames?: number;
801
+ }
802
+ interface TrackPlayerOptions {
803
+ /** ≤ 32 chars, free string ('react-native-video', 'theoplayer', …). */
804
+ library: string;
805
+ libraryVersion?: string;
806
+ name?: string;
807
+ }
808
+ /**
809
+ * The event types a HOST may emit. `player_attach` / `player_detach` are
810
+ * reserved for the native registry's own lifecycle markers — native drops
811
+ * them if they arrive from JS, so the type excludes them up front.
812
+ */
813
+ type HostPlayerEventType = Exclude<VitalsPlayerEventType, 'player_attach' | 'player_detach'>;
814
+ interface PlayerHandle {
815
+ readonly token: string;
816
+ readonly detached: boolean;
817
+ emit(type: HostPlayerEventType, data?: Record<string, unknown>, t?: number): void;
818
+ updateStats(stats: PlayerStats): void;
819
+ track(name: string, data?: unknown): void;
820
+ detach(): void;
821
+ }
822
+ declare function trackPlayer(opts: TrackPlayerOptions): PlayerHandle;
823
+ declare function trackVitals(name: string, data?: unknown, player?: PlayerHandle): void;
824
+ /**
825
+ * Bind a player registration to a component's lifetime: track on mount,
826
+ * detach on unmount, fresh token when an option changes. The returned
827
+ * handle is STABLE (same identity every render) and forwards to the live
828
+ * inner handle — inert before mount and after unmount — so Fast Refresh and
829
+ * StrictMode's effect double-run cannot leak a registration.
830
+ */
831
+ declare function useTrackPlayer(opts: TrackPlayerOptions): PlayerHandle;
832
+
833
+ /**
834
+ * SDK-facing listener surface. React Native 0.87 intentionally types raw
835
+ * native payloads as `Object[]`; each Everframe event has a narrower bridge
836
+ * contract, so the unchecked native boundary is centralized here instead of
837
+ * repeated at every listener.
838
+ */
839
+ type EverframeNativeEventEmitter = {
840
+ addListener<Args extends readonly unknown[]>(eventType: string, listener: (...args: Args) => unknown): EventSubscription;
841
+ };
842
+ /**
843
+ * Resolve the platform's RN event emitter source. iOS hands listeners to a
844
+ * dedicated `RCTEventEmitter` subclass (`EverframeEventEmitter`); Android
845
+ * uses the default `RCTDeviceEventEmitter` which `NativeEventEmitter`
846
+ * routes to when constructed with no argument.
847
+ */
848
+ declare function getEmitter(): EverframeNativeEventEmitter;
849
+
850
+ /**
851
+ * Companion runtime state — mirrors `CompanionState` in iOS (rawValue) +
852
+ * Android (mapped from the enum via `toRnString`). Keep this union in
853
+ * lock-step with both native sides.
854
+ */
855
+ type CompanionState = 'unpaired' | 'paired' | 'report_in_progress' | 'phone_disconnected';
856
+ /**
857
+ * A pending dashboard-initiated attach-PIN challenge (spec 2026-08-19).
858
+ * Mirrors iOS `CompanionAttachChallenge` / Android `AttachChallengeInfo`.
859
+ * The natives forward this event in every `attachPinUi` mode, including
860
+ * `'builtin'` (which renders the PIN natively AND still fires the event) —
861
+ * it's only NEEDED by hosts configured with `'custom'`, which must read it
862
+ * to build their own surface.
863
+ */
864
+ interface CompanionAttachChallenge {
865
+ code: string;
866
+ requestedByName: string;
867
+ /** Display lifetime — custom UIs should hide the code after this. */
868
+ ttlMs: number;
869
+ }
870
+ /**
871
+ * Open the relay WS connection. The native bridge owns at most one client
872
+ * per process and `start()` is idempotent: calling it again while the
873
+ * companion is already running is a no-op — the socket is NOT recreated.
874
+ * Call `stop()` first, then `start()`, to tear the connection down and open
875
+ * a fresh one.
876
+ *
877
+ * The ingest URL is no longer a JS-side argument — the native SDKs bake it
878
+ * at compile time (Release: https://everframe.dev; Debug: optionally
879
+ * overridden via EVERFRAME_DEV_INGEST_URL on each native build).
880
+ */
881
+ declare function start(): void;
882
+ /**
883
+ * Close the relay WS. The observable state retains its last value — hosts
884
+ * can still read `useCompanion().state` afterwards to render a "paused"
885
+ * indicator. Re-call `start(...)` to reconnect.
886
+ */
887
+ declare function stop(): void;
888
+ /**
889
+ * Subscribe to the "is a session wanted" intent flag (see `_running` above).
890
+ * Returns an unsubscribe function. Use this directly from imperative code;
891
+ * React components should prefer `useCompanion().running`.
892
+ */
893
+ declare function onRunning(handler: (running: boolean) => void): () => void;
894
+ /**
895
+ * Subscribe to companion-state changes. Returns an unsubscribe function.
896
+ * Use this directly from imperative code (e.g. an Activity-lifecycle hook);
897
+ * React components should prefer `useCompanion()`.
898
+ */
899
+ declare function onState(handler: (state: CompanionState) => void): () => void;
900
+ /**
901
+ * Subscribe to pairUrl changes. The URL is set on `pair.created` and retained
902
+ * for the life of the relay socket — it's nulled only when the socket closes
903
+ * (terminal/permanent close). It does NOT flip to null on bond or expiry; drive
904
+ * QR teardown off `state` (e.g. hide once `state === 'paired'`) instead, since
905
+ * `state` is the reliably-delivered signal across the native bridge.
906
+ */
907
+ declare function onPairUrl(handler: (url: string | null) => void): () => void;
908
+ /**
909
+ * Subscribe to the announce display code — the short string the dashboard
910
+ * shows next to this device in the project's Companion list, so a team member
911
+ * can match what they read on the TV screen to a row in the list.
912
+ *
913
+ * `null` when companion discovery was never attempted (no SDK key configured
914
+ * on the native side), when the announce call failed, and after the relay
915
+ * socket closes terminally. A null code costs discovery only — pairing by QR
916
+ * and report submission are unaffected, so never gate the QR on it.
917
+ */
918
+ declare function onCode(handler: (code: string | null) => void): () => void;
919
+ /**
920
+ * Subscribe to the attached dashboard member's display name. Populated only
921
+ * when someone attached to this device FROM the dashboard; an ordinary QR
922
+ * bond carries no such name and leaves this `null`. Render it as e.g.
923
+ * "Paired with <name>" — but drive the paired/unpaired chrome itself off
924
+ * `state`, which is the reliably-delivered signal.
925
+ */
926
+ declare function onAttachedUserName(handler: (name: string | null) => void): () => void;
927
+ /**
928
+ * Subscribe to the server-resolved device display name (naming spec
929
+ * 2026-08-24) — e.g. an org-configured friendly name for this device.
930
+ * `null` before the first successful announce, and when discovery never ran
931
+ * (no SDK key configured on the native side).
932
+ *
933
+ * REPLAY SEMANTIC (external review, finding N5): RN events don't replay to
934
+ * listeners attached after they fired, so a name resolved by an announce
935
+ * that ran before this call would otherwise be invisible to it until the
936
+ * NEXT announce. If `start()` has already cached a resolved name, `handler`
937
+ * is invoked synchronously, immediately, with that cached value — before
938
+ * this function returns, in addition to firing on every later event. Mirrors
939
+ * `onAttachChallenge`'s replay idiom exactly, minus the ttlMs
940
+ * recomputation (a resolved name has no lifetime to recompute).
941
+ */
942
+ declare function onResolvedName(handler: (name: string | null) => void): () => void;
943
+ /**
944
+ * Subscribe to attach-PIN challenges (spec 2026-08-19). Fires with the live
945
+ * challenge when a dashboard member requests attach, and null when it
946
+ * clears (redeemed, expired, burned, superseded, socket closed). The
947
+ * natives fire this event in every `attachPinUi` mode, including
948
+ * `'builtin'` (which renders the PIN natively AND still fires the event) —
949
+ * it's only NEEDED for `'custom'` hosts, which must read it to build their
950
+ * own surface.
951
+ *
952
+ * REPLAY SEMANTIC: RN events don't replay to listeners attached after they
953
+ * fired, so a challenge that arrived before this call would otherwise be
954
+ * invisible to it. If `start()` has already cached a still-live challenge,
955
+ * `handler` is invoked synchronously, immediately, with that cached value —
956
+ * `ttlMs` recomputed as the time REMAINING until its deadline, never the
957
+ * original duration (review finding 4) — before this function returns, in
958
+ * addition to firing on every later event. A cached challenge whose deadline
959
+ * has already passed replays nothing (`attachChallengeReplayValue()` returns
960
+ * null), matching the semantics of a challenge that was never cached at all.
961
+ */
962
+ declare function onAttachChallenge(handler: (challenge: CompanionAttachChallenge | null) => void): () => void;
963
+ /**
964
+ * React hook returning the latest `{ state, pairUrl, code, attachedUserName, attachChallenge }`
965
+ * snapshot. Mounts one NativeEventEmitter subscription per value and tears
966
+ * them all down on unmount.
967
+ *
968
+ * Subscribing is safe to tie to a component; the SESSION is not. Binding
969
+ * `stop()` to unmount means the device stops advertising the moment the
970
+ * screen goes away — including when the user navigates off to the dashboard
971
+ * to attach to it — so prefer starting on mount and ending on an explicit
972
+ * user action. `examples/react-native/src/screens/Companion.tsx` shows that
973
+ * shape, with a module-scoped flag carrying the user's intent across mounts.
974
+ *
975
+ * Note that `stop()` retains the last `state` and `pairUrl` rather than
976
+ * clearing them, so a stopped session must be rendered from your own flag —
977
+ * rendering off `state` alone leaves a dead QR on screen.
978
+ */
979
+ declare function useCompanion(): {
980
+ state: CompanionState;
981
+ pairUrl: string | null;
982
+ code: string | null;
983
+ attachedUserName: string | null;
984
+ resolvedName: string | null;
985
+ attachChallenge: CompanionAttachChallenge | null;
986
+ running: boolean;
987
+ };
988
+
989
+ type companion_CompanionAttachChallenge = CompanionAttachChallenge;
990
+ type companion_CompanionState = CompanionState;
991
+ declare const companion_getEmitter: typeof getEmitter;
992
+ declare const companion_onAttachChallenge: typeof onAttachChallenge;
993
+ declare const companion_onAttachedUserName: typeof onAttachedUserName;
994
+ declare const companion_onCode: typeof onCode;
995
+ declare const companion_onPairUrl: typeof onPairUrl;
996
+ declare const companion_onResolvedName: typeof onResolvedName;
997
+ declare const companion_onRunning: typeof onRunning;
998
+ declare const companion_onState: typeof onState;
999
+ declare const companion_start: typeof start;
1000
+ declare const companion_stop: typeof stop;
1001
+ declare const companion_useCompanion: typeof useCompanion;
1002
+ declare namespace companion {
1003
+ export { type companion_CompanionAttachChallenge as CompanionAttachChallenge, type companion_CompanionState as CompanionState, companion_getEmitter as getEmitter, companion_onAttachChallenge as onAttachChallenge, companion_onAttachedUserName as onAttachedUserName, companion_onCode as onCode, companion_onPairUrl as onPairUrl, companion_onResolvedName as onResolvedName, companion_onRunning as onRunning, companion_onState as onState, companion_start as start, companion_stop as stop, companion_useCompanion as useCompanion };
1004
+ }
1005
+
1006
+ export { AttachmentRef, type CaptureExceptionOptions, type CompanionState, ConfigOpts, type DeviceMetadata, EXTRA_MAX_CHARS, type EverframeContextValue, EverframeIntegration, EverframeNotMountedError, EverframeProvider, type EverframeProviderProps, EverframeScreen, type EverframeScreenProps, EverframeSensitive, EverframeUserSpec, type HostPlayerEventType, type PlayerHandle, type PlayerStats, type ReportDraft, ReportEnvelope, type ReporterResult, type TrackPlayerOptions, UINode, UITree, VitalsPlayerEventType, addBreadcrumb, captureException, companion, open, recordScreen, setExtra, setUser, trackPlayer, trackVitals, useCompanion, useEverframe, useEverframeScreen, useEverframeSensitiveRef, useTrackPlayer };