@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
package/package.json ADDED
@@ -0,0 +1,121 @@
1
+ {
2
+ "name": "@everframe/react-native",
3
+ "version": "0.9.0",
4
+ "description": "React Native SDK for Everframe — AI-ready in-app bug reporting, bridging the native iOS and Android reporter to your RN app. Supports phone, Apple TV, and Android TV.",
5
+ "author": {
6
+ "name": "Scriptx, UAB",
7
+ "email": "support@everframe.dev",
8
+ "url": "https://everframe.dev"
9
+ },
10
+ "keywords": [
11
+ "bug-report",
12
+ "bug-reporting",
13
+ "feedback",
14
+ "screenshot",
15
+ "annotation",
16
+ "session-replay",
17
+ "breadcrumbs",
18
+ "crash-reporting",
19
+ "error-reporting",
20
+ "react-native",
21
+ "ios",
22
+ "android",
23
+ "tvos",
24
+ "android-tv",
25
+ "turbomodule",
26
+ "everframe"
27
+ ],
28
+ "homepage": "https://everframe.dev",
29
+ "bugs": {
30
+ "url": "https://github.com/scriptx-com/everframe/issues"
31
+ },
32
+ "type": "module",
33
+ "license": "MIT",
34
+ "sideEffects": false,
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/scriptx-com/everframe.git",
38
+ "directory": "packages/sdk-react-native"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "main": "./dist/index.js",
44
+ "module": "./dist/index.js",
45
+ "react-native": "./dist/index.js",
46
+ "types": "./dist/index.d.ts",
47
+ "exports": {
48
+ ".": {
49
+ "types": "./dist/index.d.ts",
50
+ "default": "./dist/index.js"
51
+ },
52
+ "./integrations/console": {
53
+ "types": "./dist/integrations/console.d.ts",
54
+ "default": "./dist/integrations/console.js"
55
+ },
56
+ "./integrations/react-navigation": {
57
+ "types": "./dist/integrations/react-navigation.d.ts",
58
+ "default": "./dist/integrations/react-navigation.js"
59
+ },
60
+ "./integrations/react-native-video": {
61
+ "types": "./dist/integrations/react-native-video.d.ts",
62
+ "default": "./dist/integrations/react-native-video.js"
63
+ },
64
+ "./integrations/theoplayer": {
65
+ "types": "./dist/integrations/theoplayer.d.ts",
66
+ "default": "./dist/integrations/theoplayer.js"
67
+ }
68
+ },
69
+ "files": [
70
+ "dist",
71
+ "src/NativeEverframe.ts",
72
+ "src/codegen-types.ts",
73
+ "ios/Sources",
74
+ "ios/*.h",
75
+ "android/build.gradle.kts",
76
+ "android/settings.gradle.kts",
77
+ "android/src/main",
78
+ "*.podspec",
79
+ "LICENSE",
80
+ "NOTICE"
81
+ ],
82
+ "peerDependencies": {
83
+ "react": "^18 || ^19",
84
+ "react-native": ">=0.84"
85
+ },
86
+ "dependencies": {
87
+ "bippy": "^0.5.39",
88
+ "zod": "^4.3.0"
89
+ },
90
+ "devDependencies": {
91
+ "@arethetypeswrong/cli": "^0.18.0",
92
+ "@testing-library/react": "^16.3.2",
93
+ "@types/react": "^19.0.0",
94
+ "@types/react-dom": "^19.0.0",
95
+ "jsdom": "^29.1.1",
96
+ "react-dom": "^19.0.0",
97
+ "publint": "^0.3.0",
98
+ "tsup": "^8.0.0",
99
+ "vitest": "^4.0.0",
100
+ "@everframe/sdk-core": "0.4.0",
101
+ "@everframe/protocol": "0.5.0"
102
+ },
103
+ "codegenConfig": {
104
+ "name": "EverframeSpec",
105
+ "type": "modules",
106
+ "jsSrcsDir": "src",
107
+ "android": {
108
+ "javaPackageName": "dev.everframe.rn"
109
+ }
110
+ },
111
+ "scripts": {
112
+ "build": "tsup",
113
+ "test": "vitest run",
114
+ "test:watch": "vitest",
115
+ "lint": "tsc --noEmit",
116
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
117
+ "verify:error-details-public": "node scripts/verify-error-details-public.mjs",
118
+ "check:publish": "attw --pack . --profile esm-only --ignore-rules cjs-resolves-to-esm && publint",
119
+ "clean": "rm -rf dist"
120
+ }
121
+ }
@@ -0,0 +1,439 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 ScriptX
3
+ //
4
+ // TurboModule codegen spec — D-05 locked surface (Phase 06 / RESEARCH §1.1).
5
+ //
6
+ // RULES OF THE BRIDGE (Phase 6, do NOT relax without a new D-decision):
7
+ // - Only flat, primitive-typed objects can be expressed here.
8
+ // - `T | null` is forbidden — use `?` optional (RESEARCH §1.4).
9
+ // - Recursive nested shapes (UITree, Envelope) MUST be typed as `UnsafeObject`;
10
+ // the JS facade in `./index.ts` re-asserts richer types via `as` casts.
11
+ // This is the documented escape hatch for facebook/react-native#36467 + #47113.
12
+ // (Bare `object` keyword is rejected by RN codegen as TSObjectKeyword —
13
+ // `UnsafeObject` is the opaque-object name React Native codegen recognizes.
14
+ // It is imported from our structural compatibility alias because React
15
+ // Native 0.87 hides the old deep-import declaration by default.)
16
+ // - The 4 report methods below (configure/openReporter/registerSensitiveRect/
17
+ // setExtra) plus the Plan 06.2-11 companion methods were the
18
+ // COMPLETE surface — adding another report method requires a phase
19
+ // D-decision (Plan 02/03 native impls inherit codegen headers).
20
+ // `addBreadcrumb` (Plan 4 / Task 14) IS that new D-decision: a manual
21
+ // breadcrumb escape hatch forwarding to the native singleton's coercion
22
+ // path (Tasks 5/9) — see its doc comment below.
23
+ // `recordScreen` (spec 2026-07-14) is the next one — the navigation screen marker.
24
+ // `reportCrash` (spec 2026-07-18) is the next D-decision after that — the
25
+ // ONLY sync method on this spec (non-void return forces sync codegen): the
26
+ // default-on ErrorUtils handler in `./errors.ts` must complete the fatal
27
+ // path before RN's own fatal handling kills the process.
28
+ // `setUser` (spec 2026-08-12) is the next D-decision after that — the
29
+ // self-declared identity surface. The bridge PARAMETER is `UnsafeObject`,
30
+ // NOT the named `EverframeUserSpec` alias, even though `EverframeUserSpec` is flat like
31
+ // ConfigOpts/Rect: codegen's ObjC generator only honours a parameter's `?`
32
+ // optionality for `GenericObjectTypeAnnotation` (what `UnsafeObject`
33
+ // resolves to). A named `TypeAliasTypeAnnotation` — what a struct alias
34
+ // like `ConfigOpts`/`Rect`/`EverframeUserSpec` resolves to — always emits a
35
+ // REQUIRED `StructName &` reference regardless of `?`
36
+ // (`GenerateModuleObjCpp/serializeMethod.js`, `TypeAliasTypeAnnotation`
37
+ // branch, ~:190-197 — there's a literal `TODO(T73943261): Support
38
+ // nullable object literals and aliases?` acknowledging the gap). Verified
39
+ // by running this repo's installed `@react-native/codegen@0.85.2` against
40
+ // a reduced spec: `setUser(user?: EverframeUserSpec)` generates
41
+ // `- (void)setUser:(JS::NativeEverframe::EverframeUserSpec &)user;` (required,
42
+ // non-nullable — silently breaks "no argument = clear"), while
43
+ // `setUser(user?: UnsafeObject)` generates
44
+ // `- (void)setUser:(NSDictionary *)user;` (nullable, matching
45
+ // `addBreadcrumb`'s `data?: UnsafeObject` above). This was harmless for
46
+ // `configure(opts: ConfigOpts)` only because that parameter is REQUIRED,
47
+ // never optional, so the alias-vs-UnsafeObject distinction never mattered
48
+ // there. `EverframeUserSpec` stays exported as the JS-FACING type (runtime.ts /
49
+ // contextSeam.ts / index.ts) — only the bridge parameter itself widens to
50
+ // `UnsafeObject`, same split `addBreadcrumb`'s `data` already uses.
51
+ // `T | null` stays forbidden; CLEARING is expressed by calling with no
52
+ // argument.
53
+ // `ConfigOpts.attachPinUi` (spec 2026-08-19) is the next D-decision after
54
+ // that — a flat optional STRING, not `'builtin' | 'custom' | 'off'`: RN
55
+ // codegen cannot express a string-literal union in a struct field any more
56
+ // than `setUser`'s D-decision above could express one as a bridge method
57
+ // parameter type — same codegen ceiling, different call site (a
58
+ // `ConfigOpts` field here, rather than a whole method's parameter there).
59
+ // Unlike `setUser`'s escape hatch, this one needs no `UnsafeObject`
60
+ // widening: it's a plain `string`, which codegen already handles natively
61
+ // in a struct field — the union is only lost at the TYPE level, not the
62
+ // VALUE level. Each native side re-parses the string into its own
63
+ // `AttachPinUi` enum (`enum AttachPinUi: String` on iOS, `enum class
64
+ // AttachPinUi` on Android) and coerces anything unrecognised — including
65
+ // an absent field, which decodes as `undefined` and never reaches native
66
+ // at all — to `.builtin`/`BUILTIN`. This rides `configure()`, not a new
67
+ // bridge method: the flag is a startup-time preference, not a per-call
68
+ // argument, so it belongs beside `apiKey`/`networkBodiesDisabled` on
69
+ // `ConfigOpts` — see `companion.ts`'s `everframe.companion.attachChallenge`
70
+ // event, the JS-facing half of this same D-decision.
71
+ // Session Vitals (spec 2026-09-06) is the next D-decision after that —
72
+ // FIVE methods (trackPlayer/detachPlayer/recordPlayerEvent/
73
+ // updatePlayerStats/trackVitals) and three flat ConfigOpts fields
74
+ // (vitalsEnabled/vitalsSampleRate/vitalsCaptureSourceQuery). All void.
75
+ // `recordPlayerEvent.t` is a REQUIRED number rather than `t?: number`:
76
+ // codegen's ObjC generator renders an optional number as `NSNumber *`
77
+ // while Kotlin gets `Double?` — a required `double` is the one shape both
78
+ // sides agree on, and JS always has the timestamp anyway.
79
+ // `trackVitals.dataJson` is a string, not UnsafeObject, because custom
80
+ // entry data may be a scalar or an array.
81
+ // `setExtraResolverActive`/`signalExtraResolverReady` (spec 2026-09-17
82
+ // setExtra-resolver) is the next D-decision after that — RN parity for
83
+ // the resolver form of `setExtra` core/web already have. Native asks JS
84
+ // for a fresh value right before draining pending attachments (mirrors
85
+ // the companion `reportRequested`/`signalCompanionReportRequestReady`
86
+ // handshake below exactly), bounded and fail-open; see both methods' own
87
+ // doc comments.
88
+ import type { TurboModule } from "react-native";
89
+ import { TurboModuleRegistry } from "react-native";
90
+ import type { UnsafeObject } from "./codegen-types";
91
+
92
+ /**
93
+ * Geometry rect crossing the bridge. Flat-object only; codegen cannot express
94
+ * the richer UI-tree `Rect` from @everframe/sdk-core in a spec position.
95
+ */
96
+ export type Rect = {
97
+ x: number;
98
+ y: number;
99
+ width: number;
100
+ height: number;
101
+ };
102
+
103
+ /**
104
+ * Configure-time options for the native Everframe runtime. Flat-object only.
105
+ * Rich variants (e.g., callbacks, function refs) MUST stay on the JS side.
106
+ */
107
+ export type ConfigOpts = {
108
+ apiKey?: string;
109
+ sdkVersion?: string;
110
+ /**
111
+ * If true, the native side captures a UIWindow/SurfaceFlinger screenshot
112
+ * on every `captureNow()`. Defaults to true.
113
+ */
114
+ captureScreenshot?: boolean;
115
+ /**
116
+ * Client veto for network body capture. `true` disables bodies regardless
117
+ * of server config; the server's `captureBodies` gate must still say ON for
118
+ * capture to happen at all. Flat because RN codegen rejects nested objects —
119
+ * the host-facing nested `networkBodies: { disabled }` is flattened here by
120
+ * `extractBridgeConfig`.
121
+ */
122
+ networkBodiesDisabled?: boolean;
123
+ /**
124
+ * Client veto for the install identifier (MAI meter spec 2026-08-27).
125
+ * `true` stops this app sending one; it can never force it on. Flat because
126
+ * RN codegen rejects nested objects — the host-facing nested
127
+ * `installIdentifier: { disabled }` is flattened here by
128
+ * `extractBridgeConfig`, the same constraint `networkBodiesDisabled` above
129
+ * documents. Absent defaults to `false` (identifier sent) on both natives,
130
+ * matching `EverframeConfig.installIdentifierEnabled`'s own `true` default
131
+ * once polarity is flipped.
132
+ */
133
+ installIdentifierDisabled?: boolean;
134
+ /**
135
+ * Built-in attach-PIN surface mode (spec 2026-08-19): 'builtin' (default —
136
+ * the native SDK presents the code itself), 'custom' (host renders it from
137
+ * onAttachChallenge; the device still announces the capability), 'off'
138
+ * (legacy one-click dashboard attach, no PIN). Flat string, not a union —
139
+ * codegen cannot express string-literal unions; the natives coerce unknown
140
+ * values to 'builtin'.
141
+ */
142
+ attachPinUi?: string;
143
+ /**
144
+ * Explicit companion device-identity override (naming spec 2026-08-24) —
145
+ * an MDM id or provisioning serial the host already trusts. Hashed
146
+ * (SHA-256 → UUID shape) natively before it ever reaches the announce
147
+ * `device` block — see `CompanionDeviceId.resolve` (iOS) /
148
+ * `CompanionDeviceId.resolve` (Android). Flat optional string, same
149
+ * codegen shape as `attachPinUi` above. `undefined`/absent falls through
150
+ * to each native side's own Keychain/SSAID-then-stored-UUID chain.
151
+ */
152
+ companionDeviceId?: string;
153
+ /**
154
+ * Companion on-screen name-badge visibility (naming spec 2026-08-24,
155
+ * controller ruling / Task 6b) — "a production app that finds it
156
+ * intrusive turns it off in one line". `undefined`/absent defaults to
157
+ * `true` (badge shown) on both natives, matching
158
+ * `CompanionBadgeOptions.enabled`'s own default. Flat because RN codegen
159
+ * rejects nested objects, same constraint `networkBodiesDisabled` above
160
+ * documents — the host-facing nested `companionBadge: { enabled }` is
161
+ * flattened here by `extractBridgeConfig`.
162
+ */
163
+ companionBadgeEnabled?: boolean;
164
+ /** Local veto for native mobile shake-to-report. Absent defaults to enabled. */
165
+ shakeToReportEnabled?: boolean;
166
+ /**
167
+ * Companion on-screen name-badge corner (naming spec 2026-08-24,
168
+ * controller ruling / Task 6b). Flat optional STRING, not a literal
169
+ * union — same codegen ceiling as `attachPinUi` above (RN codegen cannot
170
+ * express a string-literal union in a struct field): the host-facing
171
+ * `RuntimeConfig.companionBadge.position` narrows to the real
172
+ * `'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'` union and
173
+ * `extractBridgeConfig` passes it through unchanged onto this wire field.
174
+ * Each native side re-parses the string into its own
175
+ * `CompanionBadgePosition` enum, coercing `undefined`/an unrecognised
176
+ * value to `.bottomRight`/`BOTTOM_RIGHT` — the same default
177
+ * `CompanionBadgeOptions.position` already uses.
178
+ */
179
+ companionBadgePosition?: string;
180
+ /**
181
+ * Inline reporter theme (reporter branding spec 2026-08-25, RN slice) —
182
+ * 8 optional `#rrggbb` role strings, flattened from the host-facing nested
183
+ * `RuntimeConfig.theme` by `extractBridgeConfig` (RN codegen cannot express
184
+ * a nested object in a struct field — the `companionBadge` constraint
185
+ * above). Pure passthrough: NO hex validation happens on the RN side; each
186
+ * native ThemeResolver revalidates per-field and ignores invalid values.
187
+ * The theme only ever renders once the server entitles it (server
188
+ * `watermark: false`) — the entitlement gate lives natively and cannot be
189
+ * bypassed from here; free plan keeps the watermark (fail closed).
190
+ */
191
+ themeBackground?: string;
192
+ themeSurface?: string;
193
+ themeBorder?: string;
194
+ themeText?: string;
195
+ themeTextMuted?: string;
196
+ themeAccent?: string;
197
+ themeAccentForeground?: string;
198
+ themeDestructive?: string;
199
+ /**
200
+ * Session Vitals local config (spec 2026-09-06, RN). Three FLAT fields
201
+ * flattened from the host-facing nested `RuntimeConfig.vitals` by
202
+ * `extractBridgeConfig` — same codegen reason as `companionBadge*`.
203
+ * `vitalsEnabled`: absent = follow the dashboard toggle; `false` = opt out
204
+ * locally; `true` never forces it on. `vitalsSampleRate`: [0, 1], min()'d
205
+ * with the server rate, clamped natively; absent = server rate.
206
+ * `vitalsCaptureSourceQuery`: keep query strings on `source_change.src`
207
+ * (default false — signed CDN URLs carry tokens). Each native maps present
208
+ * fields onto its own `VitalsConfig` and leaves SDK defaults alone.
209
+ */
210
+ vitalsEnabled?: boolean;
211
+ vitalsSampleRate?: number;
212
+ vitalsCaptureSourceQuery?: boolean;
213
+ };
214
+
215
+ /**
216
+ * Host-declared user for self-declared recognition (spec 2026-08-12). Flat by
217
+ * design — RN codegen rejects recursive shapes, and this needs none.
218
+ *
219
+ * JS-FACING TYPE ONLY — this is what `runtime.ts`/`contextSeam.ts`/
220
+ * `index.ts` type their `setUser` as. It is NOT the type of `Spec.setUser`'s
221
+ * bridge parameter below: codegen only honours `?` optionality for
222
+ * `UnsafeObject`-typed params, not named aliases like this one (see the file
223
+ * header's `setUser` D-decision note for the verified codegen output), so
224
+ * the bridge method itself is typed `UnsafeObject` and this shape is
225
+ * re-asserted at the JS boundary instead.
226
+ */
227
+ export type EverframeUserSpec = {
228
+ id?: string;
229
+ email?: string;
230
+ displayName?: string;
231
+ };
232
+
233
+ export interface Spec extends TurboModule {
234
+ configure(opts: ConfigOpts): void;
235
+ /**
236
+ * Synchronous startup entry used by the current JS runtime. The legacy
237
+ * void configure method remains for already-compiled native callers, but
238
+ * React Native dispatches void TurboModule methods asynchronously.
239
+ */
240
+ configureSync(opts: ConfigOpts): boolean;
241
+ /**
242
+ * Opens the native reporter modal (TXReporterPresenter on iOS / Android).
243
+ * Captures screenshot+uiTree+metadata, lets the user annotate/redact/fill
244
+ * out the form, and resolves when they submit or cancel.
245
+ *
246
+ * Resolves with `{ status: 'submitted' | 'queued' | 'cancelled', reportId? }`.
247
+ * Typed `UnsafeObject` at codegen boundary; facade casts to `ReporterResult`.
248
+ */
249
+ openReporter(): Promise<UnsafeObject>;
250
+ registerSensitiveRect(viewTag: number, rect: Rect): void;
251
+ /**
252
+ * Set host-supplied free-form metadata for the next report. Single opaque
253
+ * string — callers JSON.stringify any structured payload themselves. The
254
+ * native side truncates at 2000 chars. Each call REPLACES the previous
255
+ * value. Auto-cleared after the next openReporter() resolves. Pass empty
256
+ * string to detach.
257
+ */
258
+ setExtra(value: string): void;
259
+ /**
260
+ * Extra-resolver presence flag (spec 2026-09-17 setExtra-resolver — RN
261
+ * parity with the resolver form core/web already have). JS calls this
262
+ * from EVERY `setExtra` call: `true` the instant the RESOLVER form
263
+ * registers, `false` the instant the string/object form pushes a plain
264
+ * value (which also supersedes any previously-registered resolver).
265
+ * Carries NO extra CONTENT, only a presence bit — this is not the "push
266
+ * the resolver's value eagerly" mistake the resolver's own doc comment
267
+ * warns against (see `contextSeam.ts`/`runtime.ts`). It exists purely so
268
+ * the native pre-capture wait (`signalExtraResolverReady` below) can be
269
+ * skipped ENTIRELY — no event emitted, no wait, zero added latency — for
270
+ * a string/object-only host, which is the common case and must see no
271
+ * behaviour change from this feature at all.
272
+ */
273
+ setExtraResolverActive(active: boolean): void;
274
+ /**
275
+ * Companion-precedent-shaped ack (mirrors `signalCompanionReportRequestReady`
276
+ * below exactly): called by the JS-side `everframe.extra.resolveRequested`
277
+ * listener once it has — IF a resolver is currently registered — invoked
278
+ * it, budgeted the result exactly like `@everframe/sdk-core`'s
279
+ * `resolveClientExtra`, and pushed it through the existing `setExtra`
280
+ * method above. Releases the native bridge's bounded wait right before
281
+ * `consumePendingAttachments`/`__consumePendingAttachments` drains.
282
+ * Bounded on the native side: if JS never calls back (old JS bundle,
283
+ * frozen thread, or the correlation id simply times out), native
284
+ * proceeds with whatever `extra` was last pushed — fail open, always; a
285
+ * report that never arrives is worse than one with stale `extra`.
286
+ */
287
+ signalExtraResolverReady(correlationId: string): void;
288
+ /**
289
+ * Manual escape hatch (Plan 4 / Task 14): drop a host-supplied marker into
290
+ * the native action-timeline chain. RN apps already inherit ALL native
291
+ * auto-capture (lifecycle/error/console/network-opt-in/tap/nav — Tasks
292
+ * 7-8/11-12) underneath RN; JS-side auto-capture (fetch/react-navigation/
293
+ * touch patches) is an explicit non-goal of this plan. `addBreadcrumb` and
294
+ * `recordScreen` (spec 2026-07-14) are the only JS-initiated crumb paths.
295
+ *
296
+ * Fire-and-forget, positional, fail-soft. NO validation/coercion happens
297
+ * on the bridge — it forwards straight to the platform singleton
298
+ * (`Everframe.shared.addBreadcrumb` on iOS / `Everframe.addBreadcrumb` on
299
+ * Android), which owns ALL coercion (unknown `kind` → `custom`, invalid
300
+ * `level` dropped rather than defaulted, `data` JSON-coerced) and gating
301
+ * (no-op pre-start / while killed). `data` is typed `UnsafeObject` — the
302
+ * documented codegen escape hatch for freeform objects (see file header).
303
+ */
304
+ addBreadcrumb(
305
+ message: string,
306
+ kind?: string,
307
+ level?: string,
308
+ data?: UnsafeObject,
309
+ ): void;
310
+
311
+ /**
312
+ * Navigation screen marker (spec 2026-07-14 — the D-decision for this
313
+ * method). Records "this screen is now visible"; the NATIVE side derives
314
+ * the `from → to` transition from its global previous-screen state — the
315
+ * same chain the Activity/ViewController auto-capture feeds — and owns
316
+ * all gating/coercion. Fire-and-forget, positional, fail-soft, exactly
317
+ * like `addBreadcrumb` above. `data` is the codegen `UnsafeObject`
318
+ * freeform-object escape hatch; `from`/`to` win over its keys.
319
+ */
320
+ recordScreen(name: string, data?: UnsafeObject): void;
321
+
322
+ /**
323
+ * Crash/error reporting (spec 2026-07-18). SYNCHRONOUS by design (non-void
324
+ * return forces a sync TurboModule method): the fatal path must complete
325
+ * before RN's default fatal handling kills the process. Input is the
326
+ * crash-facts JSON: { exceptionType, message, framesRaw[], mechanism,
327
+ * fatal, occurredAt }. Native builds/redacts/persists the envelope with
328
+ * state it already owns (crumb ring, device metadata, outbox).
329
+ * Returns true when the report was persisted.
330
+ */
331
+ reportCrash(crashJson: string): boolean;
332
+
333
+ // ---------------- Session Vitals (spec 2026-09-06) ----------------
334
+ //
335
+ // The D-decision for FIVE methods at once: the library-agnostic player
336
+ // bridge plus the custom log line. All void, fire-and-forget, positional
337
+ // (required args first), like `addBreadcrumb`. JS mints `token` from a
338
+ // per-process counter; it is bridge-internal and never reaches the wire —
339
+ // the native PlayerRegistry mints the wire `playerId`. Native wraps each
340
+ // token in a `RemotePlayerIntegration` behind the existing
341
+ // `trackPlayer(PlayerIntegration)` seam, so budgets, kill() gating,
342
+ // rotation reseed and bounds are the natives' — nothing library-specific
343
+ // crosses here. Unknown/duplicate/detached tokens are silent no-ops.
344
+
345
+ /** Register a remote player. A token already live is ignored. */
346
+ trackPlayer(
347
+ token: string,
348
+ library: string,
349
+ name?: string,
350
+ libraryVersion?: string,
351
+ ): void;
352
+ /** `handle.detach()` + drop the token. Native emits `player_detach`. */
353
+ detachPlayer(token: string): void;
354
+ /**
355
+ * Forward one phase-4 player event. `t` is REQUIRED — epoch ms stamped by
356
+ * JS when the library fired (bridge delivery is async; same clock as
357
+ * breadcrumbs). `type` is a plain string (codegen cannot express the
358
+ * enum); the native context's `emit` refuses anything outside
359
+ * `VitalsPlayerEventType`. `data` is the `UnsafeObject` escape hatch.
360
+ */
361
+ recordPlayerEvent(
362
+ token: string,
363
+ type: string,
364
+ t: number,
365
+ data?: UnsafeObject,
366
+ ): void;
367
+ /**
368
+ * Refresh the native snapshot cache: `{ bufferAheadMs, bandwidthEstimate?,
369
+ * bitrate?, width?, height?, droppedFrames? }`. `droppedFrames` is
370
+ * CUMULATIVE; native derives the delta. Adapters throttle to ~1/s.
371
+ */
372
+ updatePlayerStats(token: string, stats: UnsafeObject): void;
373
+ /**
374
+ * Custom log line on the session timeline. `dataJson` is a JSON STRING
375
+ * (the `reportCrash` precedent) because a custom entry legitimately carries
376
+ * scalars/arrays that `UnsafeObject` cannot express. Player-scoped when
377
+ * `token` resolves to a live player, else session-scoped.
378
+ */
379
+ trackVitals(name: string, dataJson?: string, token?: string): void;
380
+ /** Explicit handled capture; native enforces handled=true, fatal=false. */
381
+ captureHandledException(crashJson: string): boolean;
382
+
383
+ // ---------------- Phone-companion (Plan 06.2-11) ----------------
384
+ //
385
+ // Opens a TV-side RelayWSClient against the build-time-baked ingest URL
386
+ // (IngestEndpoint.url on each native SDK) and forwards
387
+ // `Everframe.shared.companion` state + pairUrl signals to JS via the
388
+ // platform's RN event-emitter (RCTDeviceEventEmitter on Android, a
389
+ // dedicated RCTEventEmitter subclass on iOS). The bridge owns at most ONE
390
+ // RelayWSClient per process.
391
+ //
392
+ // Emitted events (both platforms — see `src/companion.ts`):
393
+ // • `everframe.companion.state` → 'unpaired' | 'paired' | 'report_in_progress' | 'phone_disconnected'
394
+ // • `everframe.companion.pairUrl` → string | null
395
+ // • `everframe.companion.code` → string | null
396
+ // • `everframe.companion.attachedUserName` → string | null
397
+ // • `everframe.companion.resolvedName` → string | null (naming spec 2026-08-24)
398
+ // • `everframe.companion.attachChallenge` → { code, requestedByName, ttlMs } | null (spec 2026-08-19)
399
+ startCompanion(): void;
400
+ stopCompanion(): void;
401
+ /**
402
+ * Companion handshake: called by the JS-side `onReportRequested` listener
403
+ * once it is ready for native capture to proceed. (It used to walk the
404
+ * React fiber tree and attach it via `attachReactTree` first; both are
405
+ * gone — spec 2026-08-29.) Releases the native bridge's bounded wait.
406
+ *
407
+ * Bounded: if JS never calls back, the native side times out after
408
+ * ~250ms and captures anyway.
409
+ */
410
+ signalCompanionReportRequestReady(correlationId: string): void;
411
+ /**
412
+ * RN's `NativeEventEmitter` contract requires `addListener` /
413
+ * `removeListeners` to exist on the underlying native module — RN warns
414
+ * loudly otherwise. Both are intentional no-ops at the spec level: the
415
+ * native event-emitter subscriptions are installed by `startCompanion`.
416
+ */
417
+ addListener(eventName: string): void;
418
+ removeListeners(count: number): void;
419
+
420
+ /**
421
+ * Set or clear the active user. Forwards to the native singleton's
422
+ * `setUser`, which owns storage and gating. Call with NO argument to clear
423
+ * (the bridge forbids `T | null`).
424
+ *
425
+ * Typed `UnsafeObject`, NOT `EverframeUserSpec` — a named struct alias like
426
+ * `EverframeUserSpec` always generates as a REQUIRED ObjC reference regardless of
427
+ * its `?`, which would silently break "no argument = clear" (see the file
428
+ * header's D-decision note for the verified codegen output).
429
+ * `EverframeUserSpec` is the richer type the JS facade (`runtime.ts` /
430
+ * `contextSeam.ts` / `index.ts`) casts through at this boundary — same
431
+ * split `addBreadcrumb`'s `data` uses.
432
+ *
433
+ * Unverified by construction: this is a label the app asserts, never a
434
+ * credential. It groups reports in the dashboard and does nothing else.
435
+ */
436
+ setUser(user?: UnsafeObject): void;
437
+ }
438
+
439
+ export default TurboModuleRegistry.getEnforcing<Spec>("Everframe");
@@ -0,0 +1,11 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 ScriptX
3
+
4
+ /**
5
+ * React Native codegen recognizes the `UnsafeObject` identifier as its
6
+ * generic-object escape hatch. Keeping the structural TypeScript alias local
7
+ * avoids the legacy `react-native/Libraries/Types/CodegenTypes` deep import,
8
+ * whose declaration is disabled by default in React Native 0.87.
9
+ */
10
+ export type UnsafeObject = object;
11
+