@everframe/react-native 1.5.0 → 1.6.1

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.
@@ -40,7 +40,7 @@ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
40
40
  # 1.2.0, so the range already asks for 1.2 while package.json is still 1.1.0.
41
41
  # The 1.2.0 release moves package.json to match.
42
42
  native_version_override = ENV['EVERFRAME_NATIVE_POD_VERSION'].to_s.strip
43
- native_minor_range = native_version_override.empty? ? '~> 1.5.0' : native_version_override
43
+ native_minor_range = native_version_override.empty? ? '~> 1.6.1' : native_version_override
44
44
 
45
45
  Pod::Spec.new do |s|
46
46
  s.name = 'EverframeRN'
package/README.md CHANGED
@@ -414,15 +414,22 @@ In a crash-only session:
414
414
  - Session replay uses the app's crash-only sampling rate, which is 0 by
415
415
  default. An error carries a replay only while the session records.
416
416
  - Network bodies aren't captured.
417
- - Crash and error capture, breadcrumbs, vitals, release health and the
418
- companion work as usual.
417
+ - Crash and error capture, breadcrumbs, vitals and release health work as
418
+ usual.
419
419
 
420
- A companion bond (a phone scanning the QR code, or a dashboard member
421
- attaching) upgrades the session. Replay and network bodies then follow the
422
- app's normal settings for the rest of the session, and recording starts at
423
- the bond. The reporter stays off: reports from an upgraded session come
424
- through the companion. See
425
- [crash-only sessions](../../docs/session-replay.md#crash-only-sessions).
420
+ See [crash-only sessions](../../docs/session-replay.md#crash-only-sessions).
421
+
422
+ ### Companion (removed)
423
+
424
+ Everframe Companion (phone / TV pairing) has been removed. The `companion`
425
+ namespace and `useCompanion()` remain as deprecated no-ops until the next
426
+ major version: `companion.start()` logs one warning and reaches no native
427
+ code, every `on*` subscription returns an unsubscribe and never fires, and
428
+ `useCompanion()` always returns `{ state: 'unpaired', running: false, … }`
429
+ with every other value `null`. The `attachPinUi`, `companionDeviceId` and
430
+ `companionBadge` config options are accepted and ignored. To capture from a
431
+ real device, link it under Project settings → Devices in the dashboard and use quick
432
+ capture.
426
433
 
427
434
  ## Navigation breadcrumbs
428
435
 
@@ -708,16 +715,23 @@ dashboard disable.
708
715
 
709
716
  In React Native and Expo development builds, use
710
717
  `shakeToReport: { enabled: !__DEV__ }` because the React Native development
711
- menu also uses shake. Production remains enabled by default.
718
+ menu also uses shake. Production remains enabled by default. This only stops
719
+ shake from opening the reporter: on a real phone, a development build still
720
+ takes a quick capture on shake, and a linked phone captures in any build (see
721
+ [Quick capture on phones](#quick-capture-on-phones)).
712
722
 
713
723
  #### Quick capture on simulators and emulators
714
724
 
715
725
  Debug builds on an iOS simulator or Android emulator can file a report without
716
- opening the reporter: double Shift on the simulator, or
717
- `npx @everframe/cli capture` (and `npx @everframe/cli hotkey` on macOS) from
718
- your terminal. Run `npx @everframe/cli login` once so captures are attributed
726
+ opening the reporter: press ⇧B in the app (outside a `TextInput`), or run
727
+ `npx @everframe/cli capture` from your terminal. iOS simulators also take the
728
+ other bindings the dashboard offers (double Shift, ⌘ combos); Android
729
+ emulators use the dashboard binding only when it is Shift plus a letter or
730
+ digit, and ⇧B otherwise. Run `npx @everframe/cli login` once so captures are attributed
719
731
  to you. It stays dark until the dashboard turns the capture hotkey on for the
720
- app, and never runs on devices or release builds. To opt this app out locally:
732
+ app. Real phones use shake instead; see
733
+ [Quick capture on phones](#quick-capture-on-phones). To opt this app out
734
+ locally (simulators, emulators and phones alike, including device linking):
721
735
 
722
736
  ```tsx
723
737
  <EverframeProvider
@@ -729,7 +743,112 @@ app, and never runs on devices or release builds. To opt this app out locally:
729
743
  dashboard disable. A session started with `capture.screenshot` off ignores quick
730
744
  capture.
731
745
 
732
- All other gestures and keys are host-owned. The host app
746
+ #### Quick capture on phones
747
+
748
+ On a real iPhone, iPad, or Android phone or tablet, **shake** takes a quick
749
+ capture: the same screenshot, replay window, logs, breadcrumbs and network as
750
+ ⇧B in a simulator, filed as a draft that you title on the dashboard. The native
751
+ iOS and Android SDKs do all of it; there is no JavaScript API and nothing to
752
+ add to your app. A shake captures when the device is linked, or when the build is a
753
+ debug build:
754
+
755
+ | Device | Shake |
756
+ | ----------------------- | ------------------------------------------------------------------------------------------------------ |
757
+ | Linked to you | Quick capture, a private draft for you. Toast `Captured · <your name>`. |
758
+ | Linked as a team device | Quick capture, a shared draft. Toast `Captured · team device`. |
759
+ | Unlinked, debug build | Quick capture, a shared draft. Toast `Captured · <device name>`. Also answers a dashboard link window. |
760
+ | Unlinked, release build | As before: the reporter opens if `shakeToReport` allows it. Also answers a dashboard link window. |
761
+
762
+ - **Link a phone.** On the dashboard, open **Project settings → Devices → Link a
763
+ device**, then shake the phone with the app running. A banner shows
764
+ `Linking to Everframe · 47` with the line
765
+ `A teammate is linking a device. If that's not you, ignore this.` Click the
766
+ same number on the dashboard; the phone shows `Linked to <your name>`.
767
+ Nothing links on its own: a teammate always picks the number. On iOS, if the
768
+ Keychain refuses to store the link, the phone shows `Linking failed` instead
769
+ and stays unlinked.
770
+ - **Team devices.** An admin can pick **Link as team device** instead. The
771
+ phone shows `Linked as team device`, and its captures go to the shared inbox
772
+ for whoever is on the dashboard.
773
+ - **Hand a phone over.** A linked phone keeps capturing for its owner. When
774
+ another teammate opens **Link a device** and the phone is shaken, the capture
775
+ is filed as usual and the banner shows a number; picking it moves the phone,
776
+ and that capture, to the new teammate.
777
+ - **Unlinking.** Unlink a phone under **Project settings → Devices**. It finds out at
778
+ its next capture or config fetch and behaves as unlinked again. A capture
779
+ refused this way is not filed anywhere and shows `This device was unlinked`.
780
+ Android also shows that toast when a config fetch reports the unlink; iOS
781
+ clears the link silently then.
782
+ - **Other toasts.** `Capture didn't upload` follows a capture whose upload was
783
+ rejected and not queued; `Capture failed` replaces `Captured` when the
784
+ screenshot or the evidence could not be taken.
785
+ - **Debug builds.** React Native sends `__DEV__` as the build type (override it
786
+ with `debugBuild`), so a Metro development build on a phone counts as debug
787
+ and a shake takes a shared capture without linking. In those builds the
788
+ React Native development menu also opens on the same shake, on both
789
+ platforms. To stop development builds from capturing, set
790
+ `quickCapture: { enabled: !__DEV__ }`, which also turns linking off for them.
791
+ - **`shakeToReport` controls only the reporter.** While quick capture or device
792
+ linking is on, the native shake detector runs whatever `shakeToReport` says,
793
+ and `shakeToReport` decides only whether an unlinked release build opens the
794
+ reporter. Linked and debug phones keep capturing with it off.
795
+ - **Replay.** With the dashboard's capture hotkey replay setting on, linked
796
+ phones (any build) and debug builds record session replay while quick capture
797
+ is armed, as simulators do.
798
+ - **End users see no change.** An unlinked release build never takes a quick
799
+ capture and never records replay because of it. The only new thing it can
800
+ show is the matching-number banner, if someone shakes it while a teammate has
801
+ a link window open.
802
+ - **Off switches.** The dashboard's per-app **Device linking** switch stops
803
+ phones from asking to link. The dashboard's capture hotkey switch,
804
+ `quickCapture: { enabled: false }` or `reporter: { disabled: true }` turn off
805
+ quick capture and linking together, and shake then behaves as before.
806
+ - **The token.** The device token is kept in the iOS Keychain, or encrypted
807
+ under an AndroidKeyStore key on Android. It is bound to the ingest endpoint
808
+ and SDK key that linked it, sent only there, and never logged. A linked
809
+ capture queued offline is sent later only while the same link is still
810
+ stored; otherwise it is dropped, never filed into another inbox.
811
+ - **Platform differences.** On Android, one long shake can fire the detector
812
+ more than once, so a shake within 2 seconds of a capture is ignored. Phones
813
+ and tablets are covered on both platforms. Apple TV behaves as before;
814
+ Android TV uses a remote gesture instead (below). The Android behavior ships
815
+ with the native Android SDK release that includes it.
816
+
817
+ #### Quick capture on Android TV
818
+
819
+ On Android TV the native Android SDK takes the same quick capture from a
820
+ remote gesture that the dashboard sets per app. The default is **holding
821
+ Play/Pause for 1.5 seconds**. Link the TV like a phone: open **Link a device**
822
+ on the dashboard, do the gesture on the TV, and click the number its banner
823
+ shows.
824
+
825
+ | Device | Remote gesture |
826
+ | ----------------------- | ------------------------------------------------------------------------------------------------------ |
827
+ | Linked to you | Quick capture, a private draft for you. Toast `Captured · <your name>`. |
828
+ | Linked as a team device | Quick capture, a shared draft. Toast `Captured · team device`. |
829
+ | Unlinked, debug build | Quick capture, a shared draft. Toast `Captured · <device name>`. Also answers a dashboard link window. |
830
+ | Unlinked, release build | Nothing visible. Only answers a dashboard link window. |
831
+
832
+ - **Bindings.** In the dashboard's Quick capture card a binding is a long
833
+ press, a sequence (keys in order within a time window) or a chord (keys held
834
+ together). **Record on device** sets one from the remote you actually have:
835
+ pick one of your linked TVs, relaunch the app or bring it to the foreground,
836
+ and press the keys while it shows `Recording remote keys for 10 seconds`.
837
+ - **Key handling.** An unlinked TV never has a key swallowed or changed, so
838
+ `TVEventHandler` sees every event as before. On a linked TV the first press
839
+ always reaches the app, so holding Play/Pause toggles playback once when the
840
+ press starts, before the capture. Once the gesture is recognized, a long
841
+ press's repeats are swallowed and its key-up arrives canceled; a sequence or
842
+ chord swallows only the key that completes it.
843
+ - **Debug builds** follow `__DEV__` (or `debugBuild`), as on phones.
844
+ - Everything else (end users, replay, takeover, unlinking, token storage and
845
+ the off switches) works as on phones. Apple TV gets no remote gesture yet.
846
+
847
+ For the full rules, see the iOS SDK README's "Real iPhones and iPads" section
848
+ and the Android SDK README's "Quick capture on real phones" and "Quick capture
849
+ on Android TV" sections.
850
+
851
+ Apart from quick capture, gestures and keys are host-owned. The host app
733
852
  calls `useEverframe().open()` (or the top-level `open()`)
734
853
  from whatever trigger makes sense for the target form factor.
735
854
 
@@ -1019,13 +1138,13 @@ Target annotations enrich supported automatic native observations, including IME
1019
1138
 
1020
1139
  ### Reporter boundaries and developer tools
1021
1140
 
1022
- Native phone reporter opens and companion report requests add this custom breadcrumb before freezing evidence:
1141
+ Native phone reporter opens add this custom breadcrumb before freezing evidence:
1023
1142
 
1024
1143
  ```json
1025
1144
  {"kind":"custom","message":"reporter_opened","data":{"source":"everframe_reporter","trigger":"button"}}
1026
1145
  ```
1027
1146
 
1028
- `trigger` is `button`, `shake`, `menu`, or `companion`. Pending text/scroll summaries are flushed before this boundary. Native shake uses `shake`; companion report requests use `companion`; existing `open()` calls use `button`. To identify a host menu entry explicitly, call `open({ trigger: 'menu' })`. Closing or cancelling the native flow adds `reporter_closed` with `data.source: 'everframe_reporter'` to the live trail. Both events retain breadcrumb capture/config gates.
1147
+ `trigger` is `button`, `shake`, `menu`, or `companion` (older builds only; Companion has been removed). Pending text/scroll summaries are flushed before this boundary. Native shake uses `shake`; existing `open()` calls use `button`. To identify a host menu entry explicitly, call `open({ trigger: 'menu' })`. Closing or cancelling the native flow adds `reporter_closed` with `data.source: 'everframe_reporter'` to the live trail. Both events retain breadcrumb capture/config gates.
1029
1148
 
1030
1149
  A reporter call crosses the React Native bridge after its native input can already have been recorded. It cannot prove that the previous tap or remote key opened the reporter. For a button, annotate its native host ref before interaction:
1031
1150
 
@@ -1037,7 +1156,7 @@ return <Pressable ref={reporterRef} onPress={() => void open()}><Text>Report</Te
1037
1156
 
1038
1157
  That target's tap/activation carries `data.origin: 'reporter'` and `data.trigger: 'button'`. On a remote, only Select/Enter activation is attributed to a `button` target; arrows, Menu and Play/Pause retain their ordinary meaning. An explicitly annotated `reporterTrigger: 'menu'` target attributes only its Menu activation. Attribution survives masking without retaining the target's text. Removing/recycling the bound ref removes attribution.
1039
1158
 
1040
- Hosts owning a reporting flow outside `open()` can `await markReporterOpened('menu')` before showing their reporter UI and `await markReporterClosed()` when it closes. These promises resolve after the native UI-thread boundary work; await them before adding subsequent host breadcrumbs or changing reporter UI. These explicit markers do not claim or remove earlier native keys: a TV event callback may run after native key capture. Use companion report-request boundaries when a host cannot attribute the original remote trigger. Never infer reporter intent from a button label, a Menu/Play/Pause key, or proximity to `open()`.
1159
+ Hosts owning a reporting flow outside `open()` can `await markReporterOpened('menu')` before showing their reporter UI and `await markReporterClosed()` when it closes. These promises resolve after the native UI-thread boundary work; await them before adding subsequent host breadcrumbs or changing reporter UI. These explicit markers do not claim or remove earlier native keys: a TV event callback may run after native key capture. Never infer reporter intent from a button label, a Menu/Play/Pause key, or proximity to `open()`.
1041
1160
 
1042
1161
  Native target capture adds `data.origin: 'devtools'` to supported taps and structured text/control/scroll observations whose native ancestry belongs to React Native LogBox, the native development menu, or Expo development-client UI. This comes from framework view/window/controller identity, an RN-owned development-menu controller, or a framework root module identity. In a development host, the inline LogBox notification/inspector is also registered by the exact React Native component exports through the existing React DevTools commit hook; application components with the same name are not attributed. This observer reads component identity and native refs, never warning text or component props, and removes registrations when their committed hosts disappear or the provider unmounts. Production JavaScript leaves this observer inert. A development JavaScript host can still attribute LogBox when its native SDK was built in Release mode. Display text such as “Dismiss” never grants an origin. A missing React DevTools hook, unavailable RN private module exports at runtime, initial asynchronous module loading, unknown framework versions and surfaces outside the native capture adapters leave attribution unavailable; origin tagging does not install a new dialog capture mechanism. The observer depends on the LogBox module paths in supported React Native versions; a future version removing those paths requires an SDK compatibility update before Metro can bundle it.
1043
1162
 
@@ -8,8 +8,7 @@
8
8
  // includeBuild("../../../packages/sdk-android/android") // surfaces :everframe-core, :everframe-reporter-ui
9
9
  // This library declares the two project deps below which resolve through the
10
10
  // composite-build mechanism. The on-device :everframe-tv Activity was removed
11
- // alongside the iOS tvOS modal — Android TV hosts route reporting through the
12
- // phone-companion (QR → phone browser SPA) flow via CompanionCaptureBridge.
11
+ // alongside the iOS tvOS modal.
13
12
  //
14
13
  // CODEGEN:
15
14
  // The `com.facebook.react` Gradle plugin reads `codegenConfig` from
@@ -81,17 +80,15 @@ android {
81
80
  }
82
81
  }
83
82
 
84
- // Task 11 (Plan 5) — `EverframeModuleTest.kt` / `EverframeCompanionModuleTest.kt`
85
- // exercise a `EverframeModule` contract that no longer exists on `main`
83
+ // Task 11 (Plan 5) — `EverframeModuleTest.kt` exercises a
84
+ // `EverframeModule` contract that no longer exists on `main`
86
85
  // (captureNow/submit/openAnnotationOverlay were removed by the
87
- // D-05/D-07 flip; `startCompanion()` now takes zero args;
88
- // `Companion.__setState`/`__setPairUrl` are `internal` to
89
- // :everframe-core and unreachable from this separate Gradle module) —
86
+ // D-05/D-07 flip) —
90
87
  // confirmed pre-existing and unrelated to Task 11 (Plan 4 Task 14 first
91
88
  // hit this reproducing against unmodified HEAD; see
92
89
  // .superpowers/sdd/task-11-report.md for the full compile-error dump).
93
90
  // `compileDebugUnitTestKotlin` compiles the entire `test` source set as
94
- // one Kotlin unit, so these two permanently-broken files block
91
+ // one Kotlin unit, so this permanently-broken file blocks
95
92
  // `RnReplayBridgeTest.kt` (Task 11's actual subject, itself fixed by the
96
93
  // `BridgeReactContext` swap in this same change) from ever compiling.
97
94
  // Excluded here — NOT deleted — pending a follow-up ticket to either
@@ -101,10 +98,7 @@ android {
101
98
  tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>()
102
99
  .matching { it.name.endsWith("UnitTestKotlin") } // compileDebugUnitTestKotlin + compileReleaseUnitTestKotlin
103
100
  .configureEach {
104
- exclude(
105
- "**/EverframeModuleTest.kt",
106
- "**/EverframeCompanionModuleTest.kt",
107
- )
101
+ exclude("**/EverframeModuleTest.kt")
108
102
  }
109
103
 
110
104
  // Derive the native-AAR range from this package's own npm version (single
@@ -130,7 +124,7 @@ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>()
130
124
  //
131
125
  // That window is not an edge case, it is every native minor. `package.json`
132
126
  // only reaches the new version when `changeset version` runs at RELEASE
133
- // time, so while the companion-attribution work sat unreleased, this file
127
+ // time, so while one such feature sat unreleased, this file
134
128
  // resolved `0.4.+` -> the stale 0.4.4 AAR while the bridge source called
135
129
  // APIs added in native 0.5.0. Gradle resolved it happily (0.4.4 was in
136
130
  // mavenLocal from an earlier release) and the failure surfaced as three
@@ -153,7 +147,7 @@ val rnSdkPkg = groovy.json.JsonSlurper()
153
147
  val rnSdkVersion = rnSdkPkg["version"] as String
154
148
  // Native 1.2.0 is the release that renamed the SDK key to `sdkKey`; the
155
149
  // bridge moves with it, ahead of package.json, which the 1.2.0 release bumps.
156
- val nativeMinorRange: String = nativeVersionOverride ?: "[1.5.0,1.6.0)"
150
+ val nativeMinorRange: String = nativeVersionOverride ?: "[1.6.1,1.7.0)"
157
151
  if (nativeVersionOverride != null) {
158
152
  logger.lifecycle(
159
153
  "[everframe-rn] native AAR pinned to $nativeVersionOverride via everframeNativeVersion " +
@@ -193,11 +187,10 @@ dependencies {
193
187
  // relying on transitive promotion.
194
188
  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
195
189
 
196
- // kotlinx-serialization-json — used by the companion capture provider
197
- // to serialize the UITree to JSON before gzipping it for the relay
198
- // tap-to-identify binary frame. Already on the classpath transitively
199
- // via :everframe-protocol (implementation-scoped there), but we need a
200
- // direct reference here to call the Json { } factory.
190
+ // kotlinx-serialization-json — used by the interaction-event
191
+ // registration to parse its options JSON. Already on the classpath
192
+ // transitively via :everframe-protocol (implementation-scoped there),
193
+ // but we need a direct reference here to call the Json factory.
201
194
  implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
202
195
 
203
196
  // Unit tests (Plan 06-03 Task 3). Versions mirror :everframe-core (see