diff --git a/docs/design/2026-09-15-sdk-design.md b/docs/design/2026-09-15-sdk-design.md index b6f7f37f..a103c928 100644 --- a/docs/design/2026-09-15-sdk-design.md +++ b/docs/design/2026-09-15-sdk-design.md @@ -14,7 +14,7 @@ The single most important finding behind this design: **iOS 7.x and Android 7.x ## 2. Goals -- Ship a 7.x-native React Native SDK for the two current native lines: Android **7.4.2** (7.3.0 first, pinned transitionally as `7.3.0-SNAPSHOT` while that release was pending — see the plan's Phase 3 rulings; 7.3.1 fixes bugsee-android #214–#221 found by the beta campaign; beta validation pinned `7.3.2-SNAPSHOT` (bugsee-android main plus PR #265), released as 7.4.0; 7.4.1 adds the touch-capture fix for bugsee-android #267; 7.4.2 adds the lifecycle and secure-rectangle work the beta campaign ran against) and iOS **7.0.0-beta7** (SPM only, iOS deployment target 15.0). +- Ship a 7.x-native React Native SDK for the two current native lines: Android **7.4.2** (7.3.0 first, pinned transitionally as `7.3.0-SNAPSHOT` while that release was pending — see the plan's Phase 3 rulings; 7.3.1 fixes bugsee-android #214–#221 found by the beta campaign; beta validation pinned `7.3.2-SNAPSHOT` (bugsee-android main plus PR #265), released as 7.4.0; 7.4.1 adds the touch-capture fix for bugsee-android #267; 7.4.2 adds the lifecycle and secure-rectangle work the beta campaign ran against) and iOS **7.0.0** (SPM only, iOS deployment target 15.0). - Expose the capabilities 7.x added and 6.x never had: breadcrumbs, notification relay, APM, user identity, hang/HTTP-error/frustration/anomaly detection, SDK status, report handlers. - Make the wrapper's option surface **provably** consistent with the native SDKs, enforced in CI rather than by review. - Work on bare React Native and on Expo, including Expo apps that regenerate native projects with `prebuild`. diff --git a/docs/design/plans/2026-09-16-implementation-plan.md b/docs/design/plans/2026-09-16-implementation-plan.md index 01515dee..31895c0d 100644 --- a/docs/design/plans/2026-09-16-implementation-plan.md +++ b/docs/design/plans/2026-09-16-implementation-plan.md @@ -18,7 +18,7 @@ Every phase's requirements implicitly include this section. - React Native floor **0.81.0**, New Architecture required. No `oldarch` source set, no legacy bridge fallback. 0.81 still allows opting out of the New Architecture; that is a documented requirement on the consumer, not a second code path. Hard technical floor is 0.80 (`codegenConfig.ios.modulesProvider`). - Android SDK **7.4.2** (7.3.0 first, pinned transitionally as `7.3.0-SNAPSHOT` while that release was pending — see Phase 3's rulings; 7.3.1 fixes bugsee-android #214–#221; beta validation pinned `7.3.2-SNAPSHOT`, bugsee-android main plus PR #265, released as 7.4.0; 7.4.1 adds the touch-capture fix for bugsee-android #267; 7.4.2 adds the lifecycle and secure-rectangle work the beta campaign ran against), Gradle plugin **4.0.8** (4.0.7 first; 4.0.8 uploads native symbols from the unstripped `merged_native_libs`, independent of `debugSymbolLevel`, with a bugsee-cli floor of 0.8.1), pinned exactly. Neither older pin carries what this wrapper needs: 7.2.0 has no wrapper channel, report-contract methods, `BugseeReportHandlerThread` or `com.bugsee.option.$$WRAPPER` consumer, and 4.0.6 strips every extension's provider (workbook 1.4). The plugin marker resolves from **Maven Central**, not the Gradle Plugin Portal. -- iOS SDK **7.0.0-beta7** from `https://github.com/bugsee/spm`, requirement `exact`. SwiftPM will not admit a prerelease into a range. iOS deployment target **15.0**. +- iOS SDK **7.0.0** from `https://github.com/bugsee/spm`, requirement `exact`. SwiftPM will not admit a prerelease into a range. iOS deployment target **15.0**. - Package `@bugsee/react-native`. `toSwiftName` maps it to `ReactNative`, which is **reserved**, so `react-native.config.js` pins `spm: { name: 'BugseeReactNative' }` and the SPM product name must match exactly. - All native versions live in **one** file, `native-versions.json`, consumed by the podspec, `Package.swift` and the Gradle module. The SPM pin and podspec URL must never disagree. - Every SDK entry point is called on the **main thread** on iOS. `launchWithToken:` off-main logs *"Incorrect bugsee launch…"* and misbehaves. diff --git a/examples/bare/e2e/launch-options.test.ts b/examples/bare/e2e/launch-options.test.ts index a8884271..42f727e7 100644 --- a/examples/bare/e2e/launch-options.test.ts +++ b/examples/bare/e2e/launch-options.test.ts @@ -334,7 +334,7 @@ const CASES: readonly Case[] = [ }, { name: 'max-pending-reports', - platforms: ['android'], + platforms: ['android', 'ios'], set: { 'com.bugsee.option.config.max-pending-reports': 1 }, uploads: 3, // Three uploads, offline: only the newest may be kept. diff --git a/examples/bare/scenarios/api-constants.ts b/examples/bare/scenarios/api-constants.ts index b195ee0e..b4cd84b7 100644 --- a/examples/bare/scenarios/api-constants.ts +++ b/examples/bare/scenarios/api-constants.ts @@ -28,6 +28,8 @@ export const READBACK_SHARED: Readonly> = { [`${P}capture.network.on-launch`]: true, [`${P}capture.screenshot`]: false, [`${P}capture.screenshot.scale`]: 0.5, + [`${P}config.max-pending-report-age`]: 7, + [`${P}config.max-pending-reports`]: 9, [`${P}capture.video`]: false, [`${P}capture.video.adaptive`]: true, [`${P}capture.video.frame-rate`]: 2, @@ -76,8 +78,6 @@ export const READBACK_ANDROID: Readonly> = { [`${P}capture.video.mode`]: 21, [`${P}capture.video.secure-scrolling`]: true, [`${P}capture.webview.domain-allowlist`]: 'example.com', - [`${P}config.max-pending-report-age`]: 7, - [`${P}config.max-pending-reports`]: 9, [`${P}config.report-handler-callback-timeout`]: 12, // config.report-processing-in-process=false files no report on the // WOD_LX1 (option-effects.test.ts OPT-081), which this run needs for the diff --git a/native-versions.json b/native-versions.json index 54c2b143..30bb9e8a 100644 --- a/native-versions.json +++ b/native-versions.json @@ -4,7 +4,7 @@ "gradlePlugin": "4.0.8" }, "ios": { - "sdk": "7.0.0-beta7", + "sdk": "7.0.0", "spmUrl": "https://github.com/bugsee/spm" } } diff --git a/packages/react-native-feedback/README.md b/packages/react-native-feedback/README.md index f8a6724f..fcfcbc02 100644 --- a/packages/react-native-feedback/README.md +++ b/packages/react-native-feedback/README.md @@ -25,7 +25,7 @@ yarn add @bugsee/react-native@beta @bugsee/react-native-feedback@beta No Expo config plugin. Autolinking adds `bugsee-android-feedback` on Android. On iOS the podspec vendors the `bugsee/feedback-spm` sources for the same -`7.0.0-beta7` pin as the core SDK, and React Native 0.87 resolves that +`7.0.0` pin as the core SDK, and React Native 0.87 resolves that package through Swift Package Manager. There is no `spm_dependency`: that helper does not embed the framework. diff --git a/packages/react-native-feedback/ios/Package.swift b/packages/react-native-feedback/ios/Package.swift index ee44eed1..7e5e674b 100644 --- a/packages/react-native-feedback/ios/Package.swift +++ b/packages/react-native-feedback/ios/Package.swift @@ -22,8 +22,8 @@ let package = Package( dependencies: [ .package(name: "ReactNative", path: "../../../../xcframeworks"), .package(name: "React-GeneratedCode", path: "../../../ios"), - .package(url: "https://github.com/bugsee/spm", exact: "7.0.0-beta7"), - .package(url: "https://github.com/bugsee/feedback-spm", exact: "7.0.0-beta7"), + .package(url: "https://github.com/bugsee/spm", exact: "7.0.0"), + .package(url: "https://github.com/bugsee/feedback-spm", exact: "7.0.0"), ], targets: [ .target( diff --git a/packages/react-native/ios/Support/Package.resolved b/packages/react-native/ios/Support/Package.resolved index fe5a48e6..7652b6d3 100644 --- a/packages/react-native/ios/Support/Package.resolved +++ b/packages/react-native/ios/Support/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/bugsee/spm", "state" : { - "revision" : "73ed98341d1243ffa7985f871417adcd0ad19799", - "version" : "7.0.0-beta7" + "revision" : "bbfdda2a9f1d7aadf73be6e94793b83d7a907aba", + "version" : "7.0.0" } } ], diff --git a/packages/react-native/ios/Support/Package.swift b/packages/react-native/ios/Support/Package.swift index 530416c5..c809cfcc 100644 --- a/packages/react-native/ios/Support/Package.swift +++ b/packages/react-native/ios/Support/Package.swift @@ -28,7 +28,7 @@ let package = Package( ], dependencies: [ // Exact, not a range: SwiftPM will not admit a prerelease into one. - .package(url: "https://github.com/bugsee/spm", exact: "7.0.0-beta7") + .package(url: "https://github.com/bugsee/spm", exact: "7.0.0") ], targets: [ .target( diff --git a/packages/react-native/ios/Support/Sources/BugseeRNSupport/include/BGSRNCreatedReportOps.h b/packages/react-native/ios/Support/Sources/BugseeRNSupport/include/BGSRNCreatedReportOps.h index 396e8758..73b9dc1a 100644 --- a/packages/react-native/ios/Support/Sources/BugseeRNSupport/include/BGSRNCreatedReportOps.h +++ b/packages/react-native/ios/Support/Sources/BugseeRNSupport/include/BGSRNCreatedReportOps.h @@ -1,5 +1,7 @@ #import #import +// The wrapper SPI (report contract, wrapper channel) is not in the umbrella from 7.0.0. +#import NS_ASSUME_NONNULL_BEGIN diff --git a/packages/react-native/src/options/AndroidLaunchOptions.ts b/packages/react-native/src/options/AndroidLaunchOptions.ts index 216a2cff..2947bc22 100644 --- a/packages/react-native/src/options/AndroidLaunchOptions.ts +++ b/packages/react-native/src/options/AndroidLaunchOptions.ts @@ -50,25 +50,6 @@ export class AndroidLaunchOptions extends BugseeLaunchOptions { this.$set('com.bugsee.option.detect.exit.bg_low_memory_as_error', value); } - /** Most reports kept waiting to be sent. Android 7.3.0. */ - get maxPendingReports(): number | undefined { - return this.$get('com.bugsee.option.config.max-pending-reports'); - } - set maxPendingReports(value: number | undefined) { - this.$set('com.bugsee.option.config.max-pending-reports', value); - } - - /** - * Oldest a report waiting to be sent may get, in days; `0` or less keeps - * reports until they are sent or evicted. Android 7.3.0. - */ - get maxPendingReportAge(): number | undefined { - return this.$get('com.bugsee.option.config.max-pending-report-age'); - } - set maxPendingReportAge(value: number | undefined) { - this.$set('com.bugsee.option.config.max-pending-report-age', value); - } - get triggerByNotification(): boolean | undefined { return this.$get('com.bugsee.option.reporting.triggers.notification-bar'); } diff --git a/packages/react-native/src/options/BugseeLaunchOptions.ts b/packages/react-native/src/options/BugseeLaunchOptions.ts index a1885dcc..a511f897 100644 --- a/packages/react-native/src/options/BugseeLaunchOptions.ts +++ b/packages/react-native/src/options/BugseeLaunchOptions.ts @@ -151,6 +151,25 @@ export abstract class BugseeLaunchOptions { this.$set('com.bugsee.option.config.max-data-size', value); } + /** Most reports kept waiting to be sent. Android 7.3.0, iOS 7.0.0. */ + get maxPendingReports(): number | undefined { + return this.$get('com.bugsee.option.config.max-pending-reports'); + } + set maxPendingReports(value: number | undefined) { + this.$set('com.bugsee.option.config.max-pending-reports', value); + } + + /** + * Oldest a report waiting to be sent may get, in days; `0` or less keeps + * reports until they are sent or evicted. Android 7.3.0, iOS 7.0.0. + */ + get maxPendingReportAge(): number | undefined { + return this.$get('com.bugsee.option.config.max-pending-report-age'); + } + set maxPendingReportAge(value: number | undefined) { + this.$set('com.bugsee.option.config.max-pending-report-age', value); + } + /** * Sets any option by its real `com.bugsee.option.*` key, surfaced or not. * `undefined` deletes, exactly as a first-class accessor does. diff --git a/packages/react-native/src/options/__tests__/accessors.test.ts b/packages/react-native/src/options/__tests__/accessors.test.ts index eb36636d..aaf098fb 100644 --- a/packages/react-native/src/options/__tests__/accessors.test.ts +++ b/packages/react-native/src/options/__tests__/accessors.test.ts @@ -24,6 +24,9 @@ const SHARED: [string, string, unknown][] = [ // iOS-only until Android 7.3.0 registered the same key, in the same unit // (megabytes) -- only the defaults differ (iOS 50, Android 150). ['maxDataSize', 'com.bugsee.option.config.max-data-size', 100], + // Android 7.3.0, iOS 7.0.0: the same keys and units on both. + ['maxPendingReports', 'com.bugsee.option.config.max-pending-reports', 12], + ['maxPendingReportAge', 'com.bugsee.option.config.max-pending-report-age', 7], ]; const IOS: [string, string, unknown][] = [ @@ -52,8 +55,6 @@ const ANDROID: [string, string, unknown][] = [ 'com.bugsee.option.detect.exit.bg_low_memory_as_error', true, ], - ['maxPendingReports', 'com.bugsee.option.config.max-pending-reports', 12], - ['maxPendingReportAge', 'com.bugsee.option.config.max-pending-report-age', 7], ]; type Bag = Record; diff --git a/packages/react-native/src/options/option-keys.json b/packages/react-native/src/options/option-keys.json index cf577e8b..0800232a 100644 --- a/packages/react-native/src/options/option-keys.json +++ b/packages/react-native/src/options/option-keys.json @@ -21,6 +21,8 @@ "com.bugsee.option.capture.webview.report-trigger", "com.bugsee.option.config.duration", "com.bugsee.option.config.max-data-size", + "com.bugsee.option.config.max-pending-report-age", + "com.bugsee.option.config.max-pending-reports", "com.bugsee.option.config.notify-flush-delay", "com.bugsee.option.config.wifi-only-upload", "com.bugsee.option.detect.anomaly", @@ -81,8 +83,6 @@ "com.bugsee.option.capture.video.mode", "com.bugsee.option.capture.video.secure-scrolling", "com.bugsee.option.capture.webview.domain-allowlist", - "com.bugsee.option.config.max-pending-report-age", - "com.bugsee.option.config.max-pending-reports", "com.bugsee.option.config.report-handler-callback-timeout", "com.bugsee.option.config.report-processing-in-process", "com.bugsee.option.detect.anr.sampling", diff --git a/scripts/__tests__/github-release.test.ts b/scripts/__tests__/github-release.test.ts index 6b67801c..3aa6f34e 100644 --- a/scripts/__tests__/github-release.test.ts +++ b/scripts/__tests__/github-release.test.ts @@ -47,7 +47,7 @@ function run(setup: Setup = {}) { }); writeFileSync( join(root, 'native-versions.json'), - JSON.stringify({ android: { sdk: '7.4.2', gradlePlugin: '4.0.8' }, ios: { sdk: '7.0.0-beta7' } }), + JSON.stringify({ android: { sdk: '7.4.2', gradlePlugin: '4.0.8' }, ios: { sdk: '7.0.0' } }), ); const tarballs = join(dir, 'tarballs'); mkdirSync(tarballs); @@ -148,7 +148,7 @@ describe('github-release.mjs', () => { expect(notes).toContain('@bugsee/react-native@7.0.0-beta3'); expect(notes).toContain('@bugsee/react-native-feedback@7.0.0-beta3'); expect(notes).toContain('`beta`, `latest`'); - expect(notes).toContain('Android SDK 7.4.2 (Gradle plugin 4.0.8), iOS SDK 7.0.0-beta7'); + expect(notes).toContain('Android SDK 7.4.2 (Gradle plugin 4.0.8), iOS SDK 7.0.0'); }); it('does not mark a stable version as a prerelease', () => { diff --git a/scripts/__tests__/native-versions.test.ts b/scripts/__tests__/native-versions.test.ts index 0dd56f3c..de0c2a20 100644 --- a/scripts/__tests__/native-versions.test.ts +++ b/scripts/__tests__/native-versions.test.ts @@ -15,7 +15,7 @@ describe('readNativeVersions', () => { expect(v.android.gradlePlugin).toBe('4.0.8'); // A released pin carries no snapshot provenance. expect(v.android).not.toHaveProperty('snapshotCommit'); - expect(v.ios.sdk).toBe('7.0.0-beta7'); + expect(v.ios.sdk).toBe('7.0.0'); expect(v.ios.spmUrl).toBe('https://github.com/bugsee/spm'); });