@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.
- package/EverframeRN.podspec +88 -0
- package/LICENSE +21 -0
- package/NOTICE +8 -0
- package/README.md +505 -0
- package/android/build.gradle.kts +209 -0
- package/android/settings.gradle.kts +8 -0
- package/android/src/main/AndroidManifest.xml +9 -0
- package/android/src/main/java/dev/everframe/rn/EverframeModule.kt +1670 -0
- package/android/src/main/java/dev/everframe/rn/EverframePackage.kt +40 -0
- package/android/src/main/java/dev/everframe/rn/EverframeSensitiveViewManager.kt +20 -0
- package/android/src/main/java/dev/everframe/rn/RnVideoPrivacyAdapter.kt +65 -0
- package/dist/NativeEverframe.d.ts +308 -0
- package/dist/NativeEverframe.js +1 -0
- package/dist/browser-ZQAY6B4M.js +1 -0
- package/dist/chunk-LPIKPZNX.js +1 -0
- package/dist/chunk-QRPINMCR.js +1 -0
- package/dist/chunk-QZRTTQRS.js +1 -0
- package/dist/chunk-XFLFA52R.js +1 -0
- package/dist/chunk-XUSV3KOD.js +1 -0
- package/dist/index.d.ts +1006 -0
- package/dist/index.js +51 -0
- package/dist/integrations/console.d.ts +8 -0
- package/dist/integrations/console.js +1 -0
- package/dist/integrations/react-native-video.d.ts +44 -0
- package/dist/integrations/react-native-video.js +1 -0
- package/dist/integrations/react-navigation.d.ts +21 -0
- package/dist/integrations/react-navigation.js +1 -0
- package/dist/integrations/theoplayer.d.ts +37 -0
- package/dist/integrations/theoplayer.js +1 -0
- package/dist/types-D5e4kWaw.d.ts +12 -0
- package/ios/Sources/EverframeBridge.swift +1043 -0
- package/ios/Sources/EverframeEventEmitter.swift +204 -0
- package/ios/Sources/EverframeModule.h +36 -0
- package/ios/Sources/EverframeModule.mm +489 -0
- package/ios/Sources/RemoteVitalsBridge.swift +99 -0
- package/package.json +121 -0
- package/src/NativeEverframe.ts +439 -0
- 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
|
+
|