@debugbundle/sdk-react-native 0.1.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 (67) hide show
  1. package/DebugBundleReactNative.podspec +15 -0
  2. package/README.md +124 -0
  3. package/android/build.gradle +37 -0
  4. package/android/src/main/AndroidManifest.xml +1 -0
  5. package/android/src/main/java/com/debugbundle/reactnative/DebugBundleReactNativeModule.java +281 -0
  6. package/android/src/main/java/com/debugbundle/reactnative/DebugBundleReactNativePackage.java +20 -0
  7. package/app.plugin.js +52 -0
  8. package/dist/NativeDebugBundleReactNative.d.ts +13 -0
  9. package/dist/NativeDebugBundleReactNative.d.ts.map +1 -0
  10. package/dist/NativeDebugBundleReactNative.js +2 -0
  11. package/dist/app-state.d.ts +9 -0
  12. package/dist/app-state.d.ts.map +1 -0
  13. package/dist/app-state.js +10 -0
  14. package/dist/client.d.ts +36 -0
  15. package/dist/client.d.ts.map +1 -0
  16. package/dist/client.js +328 -0
  17. package/dist/console.d.ts +3 -0
  18. package/dist/console.d.ts.map +1 -0
  19. package/dist/console.js +35 -0
  20. package/dist/errors.d.ts +6 -0
  21. package/dist/errors.d.ts.map +1 -0
  22. package/dist/errors.js +42 -0
  23. package/dist/index.d.ts +25 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +59 -0
  26. package/dist/native.d.ts +7 -0
  27. package/dist/native.d.ts.map +1 -0
  28. package/dist/native.js +59 -0
  29. package/dist/navigation.d.ts +13 -0
  30. package/dist/navigation.d.ts.map +1 -0
  31. package/dist/navigation.js +26 -0
  32. package/dist/network.d.ts +14 -0
  33. package/dist/network.d.ts.map +1 -0
  34. package/dist/network.js +179 -0
  35. package/dist/probes.d.ts +4 -0
  36. package/dist/probes.d.ts.map +1 -0
  37. package/dist/probes.js +8 -0
  38. package/dist/react.d.ts +21 -0
  39. package/dist/react.d.ts.map +1 -0
  40. package/dist/react.js +36 -0
  41. package/dist/redaction.d.ts +12 -0
  42. package/dist/redaction.d.ts.map +1 -0
  43. package/dist/redaction.js +132 -0
  44. package/dist/testing.d.ts +9 -0
  45. package/dist/testing.d.ts.map +1 -0
  46. package/dist/testing.js +36 -0
  47. package/dist/types.d.ts +152 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +1 -0
  50. package/ios/DebugBundleReactNative.swift +125 -0
  51. package/ios/DebugBundleReactNativeBridge.m +28 -0
  52. package/package.json +99 -0
  53. package/src/NativeDebugBundleReactNative.ts +14 -0
  54. package/src/app-state.ts +17 -0
  55. package/src/client.ts +385 -0
  56. package/src/console.ts +38 -0
  57. package/src/errors.ts +64 -0
  58. package/src/index.ts +82 -0
  59. package/src/native.ts +79 -0
  60. package/src/navigation.tsx +37 -0
  61. package/src/network.ts +240 -0
  62. package/src/probes.ts +11 -0
  63. package/src/react-native-shim.d.ts +14 -0
  64. package/src/react.tsx +60 -0
  65. package/src/redaction.ts +165 -0
  66. package/src/testing.ts +45 -0
  67. package/src/types.ts +173 -0
@@ -0,0 +1,15 @@
1
+ Pod::Spec.new do |s|
2
+ s.name = "DebugBundleReactNative"
3
+ s.version = "0.1.0"
4
+ s.summary = "React Native wrapper for the DebugBundle mobile SDKs."
5
+ s.license = { :type => "AGPL-3.0-only" }
6
+ s.author = { "DebugBundle" => "support@debugbundle.com" }
7
+ s.homepage = "https://github.com/debugbundle/debugbundle-react-native"
8
+ s.source = { :git => "https://github.com/debugbundle/debugbundle-react-native.git", :tag => s.version.to_s }
9
+ s.platforms = { :ios => "15.0" }
10
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
11
+ s.swift_version = "5.10"
12
+
13
+ s.dependency "React-Core"
14
+ s.dependency "DebugBundle", "~> 0.1.1"
15
+ end
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # DebugBundle React Native
2
+
3
+ React Native SDK for DebugBundle mobile apps.
4
+
5
+ This package targets iOS and Android React Native apps. It is a mobile direct-ingestion SDK, not a browser relay host: it does not provide CORS, `allowedOrigins`, `transportMode`, or `/debugbundle/browser` helpers.
6
+
7
+ ## Status
8
+
9
+ Release candidate implementation:
10
+
11
+ - TypeScript facade and instance client.
12
+ - Safe degraded mode when the native module is unavailable, including Expo Go.
13
+ - JS-originated event enqueueing through a native module contract.
14
+ - React error boundary helper.
15
+ - React Navigation breadcrumb helpers.
16
+ - `fetch` and `XMLHttpRequest` instrumentation with target-scoped `X-DebugBundle-Trace-Id`.
17
+ - JS-side bounded serialization and redaction before native queue persistence.
18
+ - Android and iOS native wrappers that delegate queueing, config/status, request capture, crash/error capture, flushing, and probe trigger activation to the native SDK foundations.
19
+ - Clean-install React Native app smoke coverage for Android and iOS, including New Architecture codegen/autolinking.
20
+
21
+ Before public npm publication, publish or otherwise make the native `DebugBundle` iOS pod available to CocoaPods consumers. Local smoke tests inject the sibling Swift SDK pod path so the bridge can be validated before registry publication.
22
+
23
+ ## Install
24
+
25
+ ```sh
26
+ npm install @debugbundle/sdk-react-native
27
+ cd ios && pod install
28
+ ```
29
+
30
+ iOS autolinking resolves the `DebugBundleReactNative.podspec`, which depends on the native `DebugBundle` pod from the Swift SDK. Until that pod is published to the public CocoaPods specs repo, local validation must add the Swift SDK pod path to the app Podfile.
31
+
32
+ Android apps must enable core library desugaring because the native Android SDK
33
+ uses Java APIs that require desugaring on the SDK's minimum API level:
34
+
35
+ ```gradle
36
+ android {
37
+ compileOptions {
38
+ sourceCompatibility JavaVersion.VERSION_17
39
+ targetCompatibility JavaVersion.VERSION_17
40
+ coreLibraryDesugaringEnabled true
41
+ }
42
+ }
43
+
44
+ dependencies {
45
+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
46
+ }
47
+ ```
48
+
49
+ The Expo config plugin applies this Android Gradle configuration during prebuild.
50
+
51
+ ## Basic Setup
52
+
53
+ ```ts
54
+ import { DebugBundle } from "@debugbundle/sdk-react-native";
55
+
56
+ DebugBundle.init({
57
+ projectToken: process.env.EXPO_PUBLIC_DEBUGBUNDLE_TOKEN,
58
+ service: "checkout-mobile",
59
+ environment: __DEV__ ? "development" : "production",
60
+ releaseChannel: "app-store",
61
+ tracePropagationTargets: ["https://api.example.com"]
62
+ });
63
+ ```
64
+
65
+ Project tokens are write-only mobile ingestion tokens, but they are still extractable from the app binary and JS bundle. Do not treat them as a secret boundary.
66
+
67
+ ## Network Instrumentation
68
+
69
+ ```ts
70
+ import { instrumentDebugBundleNetwork } from "@debugbundle/sdk-react-native/network";
71
+
72
+ instrumentDebugBundleNetwork({
73
+ tracePropagationTargets: ["https://api.example.com"]
74
+ });
75
+ ```
76
+
77
+ Trace headers are added only to relative URLs or configured first-party targets. Request and response bodies are not captured by default.
78
+
79
+ ## React Error Boundary
80
+
81
+ ```tsx
82
+ import { DebugBundleErrorBoundary } from "@debugbundle/sdk-react-native/react";
83
+
84
+ export function App() {
85
+ return (
86
+ <DebugBundleErrorBoundary>
87
+ <CheckoutRoot />
88
+ </DebugBundleErrorBoundary>
89
+ );
90
+ }
91
+ ```
92
+
93
+ ## React Navigation
94
+
95
+ ```tsx
96
+ import { NavigationContainer } from "@react-navigation/native";
97
+ import {
98
+ createDebugBundleNavigationRef,
99
+ onDebugBundleNavigationReady,
100
+ onDebugBundleNavigationStateChange
101
+ } from "@debugbundle/sdk-react-native/navigation";
102
+
103
+ export const navigationRef = createDebugBundleNavigationRef();
104
+
105
+ export function AppNavigation() {
106
+ return (
107
+ <NavigationContainer
108
+ ref={navigationRef}
109
+ onReady={() => onDebugBundleNavigationReady(navigationRef)}
110
+ onStateChange={() => onDebugBundleNavigationStateChange(navigationRef)}
111
+ >
112
+ {/* navigators */}
113
+ </NavigationContainer>
114
+ );
115
+ }
116
+ ```
117
+
118
+ ## Expo
119
+
120
+ Expo development builds and prebuild are supported through the config plugin. Expo Go cannot load the native module, so the SDK reports degraded status and does not claim durable native queueing, native crash evidence, native device context, or remote-probe parity.
121
+
122
+ ## Release
123
+
124
+ The package publishes to npm from `v*` tags through GitHub Actions. Configure the repository secret `NPM_TOKEN`, make sure the tag matches `package.json` exactly, for example `v0.1.0`, and push the tag after the native Swift `DebugBundle` pod is available to CocoaPods consumers.
@@ -0,0 +1,37 @@
1
+ plugins {
2
+ id "com.android.library"
3
+ }
4
+
5
+ def isReactNativeHostBuild = rootProject.name != "debugbundle-react-native"
6
+ if (isReactNativeHostBuild) {
7
+ apply plugin: "com.facebook.react"
8
+ }
9
+
10
+ def hostKotlinVersion = rootProject.ext.has("kotlinVersion")
11
+ ? rootProject.ext.get("kotlinVersion")
12
+ : "2.1.20"
13
+
14
+ android {
15
+ namespace "com.debugbundle.reactnative"
16
+ compileSdk 36
17
+
18
+ defaultConfig {
19
+ minSdk 23
20
+ }
21
+
22
+ compileOptions {
23
+ sourceCompatibility JavaVersion.VERSION_17
24
+ targetCompatibility JavaVersion.VERSION_17
25
+ }
26
+ }
27
+
28
+ dependencies {
29
+ compileOnly "com.facebook.react:react-android:${rootProject.findProperty("reactNativeVersion") ?: "0.85.3"}"
30
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:${hostKotlinVersion}"
31
+ implementation platform("com.debugbundle:debugbundle-android-bom:0.1.2")
32
+ implementation("com.debugbundle:debugbundle-android") {
33
+ exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
34
+ exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib-jdk7"
35
+ exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib-jdk8"
36
+ }
37
+ }
@@ -0,0 +1 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" />
@@ -0,0 +1,281 @@
1
+ package com.debugbundle.reactnative;
2
+
3
+ import com.debugbundle.android.DebugBundle;
4
+ import com.debugbundle.android.DebugBundleConfig;
5
+ import com.debugbundle.android.DebugBundleLogLevel;
6
+ import com.debugbundle.android.DebugBundleRequestInfo;
7
+ import com.debugbundle.android.DebugBundleResponseInfo;
8
+ import com.facebook.react.bridge.Arguments;
9
+ import com.facebook.react.bridge.Promise;
10
+ import com.facebook.react.bridge.ReactApplicationContext;
11
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
12
+ import com.facebook.react.bridge.ReactMethod;
13
+ import com.facebook.react.bridge.ReadableMap;
14
+ import com.facebook.react.bridge.WritableMap;
15
+ import java.lang.reflect.Constructor;
16
+ import java.lang.reflect.Method;
17
+ import java.util.Collections;
18
+ import java.util.Locale;
19
+ import java.util.Map;
20
+
21
+ public final class DebugBundleReactNativeModule extends ReactContextBaseJavaModule {
22
+ public static final String NAME = "DebugBundleReactNative";
23
+
24
+ private final ReactApplicationContext reactContext;
25
+
26
+ public DebugBundleReactNativeModule(ReactApplicationContext reactContext) {
27
+ super(reactContext);
28
+ this.reactContext = reactContext;
29
+ }
30
+
31
+ @Override
32
+ public String getName() {
33
+ return NAME;
34
+ }
35
+
36
+ @ReactMethod
37
+ public void initialize(ReadableMap config, Promise promise) {
38
+ try {
39
+ DebugBundle.init(reactContext.getApplicationContext(), createConfig(config));
40
+ promise.resolve(stateMap());
41
+ } catch (Throwable ignored) {
42
+ promise.resolve(degradedState("android_initialize_failed"));
43
+ }
44
+ }
45
+
46
+ @ReactMethod
47
+ public void enqueueEvent(ReadableMap event, Promise promise) {
48
+ try {
49
+ String eventType = stringOrDefault(event, "event_type", "");
50
+ Map<String, Object> payload = hashMap(event, "payload");
51
+ DebugBundle debugBundle = DebugBundle.INSTANCE;
52
+
53
+ if ("frontend_exception".equals(eventType)) {
54
+ debugBundle.captureException(
55
+ new RuntimeException(stringValue(payload.get("error"), "React Native exception")),
56
+ payload);
57
+ } else if ("frontend_breadcrumb".equals(eventType)) {
58
+ debugBundle.captureBreadcrumb(
59
+ stringValue(payload.get("breadcrumb_type"), "react_native"),
60
+ null,
61
+ payload);
62
+ } else if ("log_event".equals(eventType)) {
63
+ debugBundle.captureLog(
64
+ stringValue(payload.get("message"), ""),
65
+ logLevel(stringValue(payload.get("level"), null)),
66
+ payload);
67
+ } else if ("request_event".equals(eventType)) {
68
+ ReadableMap correlation = event.hasKey("correlation") ? event.getMap("correlation") : null;
69
+ debugBundle.captureRequest(
70
+ new DebugBundleRequestInfo(
71
+ stringValue(payload.get("method"), "GET"),
72
+ stringValue(payload.get("url"), ""),
73
+ Collections.emptyMap(),
74
+ stringValue(payload.get("route_template"), null),
75
+ correlation == null ? null : correlation.getString("trace_id")),
76
+ new DebugBundleResponseInfo(
77
+ intValue(payload.get("response_status"), 0),
78
+ longValue(payload.get("duration_ms")),
79
+ Collections.emptyMap()),
80
+ payload,
81
+ false);
82
+ } else {
83
+ debugBundle.captureMessage(
84
+ "react_native_event:" + eventType,
85
+ DebugBundleLogLevel.Warning,
86
+ payload);
87
+ }
88
+ promise.resolve(null);
89
+ } catch (Throwable ignored) {
90
+ promise.resolve(null);
91
+ }
92
+ }
93
+
94
+ @ReactMethod
95
+ public void flush(Promise promise) {
96
+ try {
97
+ Method flushDefault = DebugBundle.class.getDeclaredMethod(
98
+ "flush-LRDsOJo$default",
99
+ DebugBundle.class,
100
+ long.class,
101
+ int.class,
102
+ Object.class);
103
+ flushDefault.invoke(null, DebugBundle.INSTANCE, 0L, 1, null);
104
+ promise.resolve(null);
105
+ } catch (Throwable ignored) {
106
+ promise.resolve(null);
107
+ }
108
+ }
109
+
110
+ @ReactMethod
111
+ public void getStatus(Promise promise) {
112
+ promise.resolve(stateMap());
113
+ }
114
+
115
+ @ReactMethod
116
+ public void setContext(String key, Object value, Promise promise) {
117
+ try {
118
+ DebugBundle.INSTANCE.setContext(key, value);
119
+ promise.resolve(null);
120
+ } catch (Throwable ignored) {
121
+ promise.resolve(null);
122
+ }
123
+ }
124
+
125
+ @ReactMethod
126
+ public void activateProbeTriggerToken(String token, Promise promise) {
127
+ try {
128
+ promise.resolve(DebugBundle.INSTANCE.activateProbeTriggerToken(token));
129
+ } catch (Throwable ignored) {
130
+ promise.resolve(false);
131
+ }
132
+ }
133
+
134
+ private DebugBundleConfig createConfig(ReadableMap config) throws ReflectiveOperationException {
135
+ Constructor<?> constructor = null;
136
+ for (Constructor<?> candidate : DebugBundleConfig.class.getDeclaredConstructors()) {
137
+ if (candidate.getParameterTypes().length == 34) {
138
+ constructor = candidate;
139
+ break;
140
+ }
141
+ }
142
+ if (constructor == null) {
143
+ throw new NoSuchMethodException("DebugBundleConfig default constructor");
144
+ }
145
+ constructor.setAccessible(true);
146
+
147
+ int mask = -1;
148
+ mask = useProvided(mask, 0);
149
+ mask = useProvided(mask, 1);
150
+ mask = useProvided(mask, 2);
151
+ mask = useProvided(mask, 3);
152
+ mask = useProvided(mask, 4);
153
+ mask = useProvided(mask, 10);
154
+ mask = useProvided(mask, 11);
155
+ mask = useProvided(mask, 12);
156
+ mask = useProvided(mask, 31);
157
+
158
+ return (DebugBundleConfig) constructor.newInstance(
159
+ stringOrDefault(config, "projectToken", ""),
160
+ booleanOrDefault(config, "enabled", true),
161
+ stringOrDefault(config, "environment", "production"),
162
+ stringOrDefault(config, "service", "react-native-app"),
163
+ stringOrDefault(config, "endpoint", DebugBundleConfig.DEFAULT_ENDPOINT),
164
+ 0,
165
+ 0L,
166
+ 0.0,
167
+ 0.0,
168
+ 0L,
169
+ stringOrDefault(config, "releaseChannel", "production"),
170
+ stringOrNull(config, "appVersion"),
171
+ stringOrNull(config, "buildNumber"),
172
+ 0,
173
+ 0,
174
+ false,
175
+ false,
176
+ false,
177
+ false,
178
+ DebugBundleLogLevel.Warning,
179
+ false,
180
+ Collections.emptySet(),
181
+ 0,
182
+ 0L,
183
+ 0L,
184
+ null,
185
+ null,
186
+ 0,
187
+ 0,
188
+ false,
189
+ Collections.emptySet(),
190
+ stringOrDefault(config, "sdkVersion", "0.1.0"),
191
+ mask,
192
+ null);
193
+ }
194
+
195
+ private WritableMap stateMap() {
196
+ WritableMap state = Arguments.createMap();
197
+ state.putString("status", DebugBundle.INSTANCE.getStatus().name().toLowerCase(Locale.ROOT));
198
+ Long lastEventAt = DebugBundle.INSTANCE.getLastEventAt();
199
+ if (lastEventAt == null) {
200
+ state.putNull("lastEventAt");
201
+ } else {
202
+ state.putDouble("lastEventAt", lastEventAt.doubleValue());
203
+ }
204
+ state.putBoolean("nativeModuleAvailable", true);
205
+ state.putNull("degradedReason");
206
+ return state;
207
+ }
208
+
209
+ private WritableMap degradedState(String reason) {
210
+ WritableMap state = Arguments.createMap();
211
+ state.putString("status", "degraded");
212
+ state.putNull("lastEventAt");
213
+ state.putBoolean("nativeModuleAvailable", true);
214
+ state.putString("degradedReason", reason);
215
+ return state;
216
+ }
217
+
218
+ private static int useProvided(int mask, int index) {
219
+ return mask & ~(1 << index);
220
+ }
221
+
222
+ private static Map<String, Object> hashMap(ReadableMap map, String key) {
223
+ ReadableMap nested = map.hasKey(key) ? map.getMap(key) : null;
224
+ if (nested == null) {
225
+ return Collections.emptyMap();
226
+ }
227
+ return nested.toHashMap();
228
+ }
229
+
230
+ private static String stringOrDefault(ReadableMap map, String key, String fallback) {
231
+ if (!map.hasKey(key) || map.isNull(key)) {
232
+ return fallback;
233
+ }
234
+ String value = map.getString(key);
235
+ return value == null ? fallback : value;
236
+ }
237
+
238
+ private static String stringOrNull(ReadableMap map, String key) {
239
+ if (!map.hasKey(key) || map.isNull(key)) {
240
+ return null;
241
+ }
242
+ return map.getString(key);
243
+ }
244
+
245
+ private static boolean booleanOrDefault(ReadableMap map, String key, boolean fallback) {
246
+ if (!map.hasKey(key) || map.isNull(key)) {
247
+ return fallback;
248
+ }
249
+ return map.getBoolean(key);
250
+ }
251
+
252
+ private static String stringValue(Object value, String fallback) {
253
+ return value == null ? fallback : value.toString();
254
+ }
255
+
256
+ private static int intValue(Object value, int fallback) {
257
+ return value instanceof Number ? ((Number) value).intValue() : fallback;
258
+ }
259
+
260
+ private static Long longValue(Object value) {
261
+ return value instanceof Number ? ((Number) value).longValue() : null;
262
+ }
263
+
264
+ private static DebugBundleLogLevel logLevel(String value) {
265
+ if (value == null) {
266
+ return DebugBundleLogLevel.Warning;
267
+ }
268
+ switch (value.toLowerCase(Locale.ROOT)) {
269
+ case "debug":
270
+ return DebugBundleLogLevel.Debug;
271
+ case "info":
272
+ return DebugBundleLogLevel.Info;
273
+ case "error":
274
+ return DebugBundleLogLevel.Error;
275
+ case "critical":
276
+ return DebugBundleLogLevel.Critical;
277
+ default:
278
+ return DebugBundleLogLevel.Warning;
279
+ }
280
+ }
281
+ }
@@ -0,0 +1,20 @@
1
+ package com.debugbundle.reactnative;
2
+
3
+ import com.facebook.react.ReactPackage;
4
+ import com.facebook.react.bridge.NativeModule;
5
+ import com.facebook.react.bridge.ReactApplicationContext;
6
+ import com.facebook.react.uimanager.ViewManager;
7
+ import java.util.Collections;
8
+ import java.util.List;
9
+
10
+ public final class DebugBundleReactNativePackage implements ReactPackage {
11
+ @Override
12
+ public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
13
+ return Collections.singletonList(new DebugBundleReactNativeModule(reactContext));
14
+ }
15
+
16
+ @Override
17
+ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
18
+ return Collections.emptyList();
19
+ }
20
+ }
package/app.plugin.js ADDED
@@ -0,0 +1,52 @@
1
+ import { createRunOncePlugin, withAndroidManifest, withAppBuildGradle, withInfoPlist } from "@expo/config-plugins";
2
+
3
+ function withDebugBundle(config, props = {}) {
4
+ const iosEnabled = props.ios !== false;
5
+ const androidEnabled = props.android !== false;
6
+
7
+ if (iosEnabled) {
8
+ config = withInfoPlist(config, (expoConfig) => {
9
+ expoConfig.modResults.DebugBundleEnabled = true;
10
+ return expoConfig;
11
+ });
12
+ }
13
+
14
+ if (androidEnabled) {
15
+ config = withAndroidManifest(config, (expoConfig) => {
16
+ const application = expoConfig.modResults.manifest.application?.[0];
17
+ if (application) {
18
+ application.$ = {
19
+ ...application.$,
20
+ "tools:targetApi": application.$?.["tools:targetApi"] ?? "31"
21
+ };
22
+ }
23
+ return expoConfig;
24
+ });
25
+
26
+ config = withAppBuildGradle(config, (expoConfig) => {
27
+ expoConfig.modResults.contents = withAndroidDesugaring(expoConfig.modResults.contents);
28
+ return expoConfig;
29
+ });
30
+ }
31
+
32
+ return config;
33
+ }
34
+
35
+ function withAndroidDesugaring(contents) {
36
+ let next = contents;
37
+ if (!next.includes("coreLibraryDesugaringEnabled true")) {
38
+ next = next.replace(
39
+ /android\s*\{\n/,
40
+ "android {\n compileOptions {\n sourceCompatibility JavaVersion.VERSION_17\n targetCompatibility JavaVersion.VERSION_17\n coreLibraryDesugaringEnabled true\n }\n"
41
+ );
42
+ }
43
+ if (!next.includes("com.android.tools:desugar_jdk_libs")) {
44
+ next = next.replace(
45
+ /dependencies\s*\{\n/,
46
+ 'dependencies {\n coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")\n'
47
+ );
48
+ }
49
+ return next;
50
+ }
51
+
52
+ export default createRunOncePlugin(withDebugBundle, "@debugbundle/sdk-react-native", "0.1.0");
@@ -0,0 +1,13 @@
1
+ import type { TurboModule } from "react-native";
2
+ import type { UnsafeObject } from "react-native/Libraries/Types/CodegenTypes";
3
+ export interface Spec extends TurboModule {
4
+ initialize(config: UnsafeObject): Promise<UnsafeObject>;
5
+ enqueueEvent(event: UnsafeObject): Promise<void>;
6
+ flush(): Promise<void>;
7
+ getStatus(): Promise<UnsafeObject>;
8
+ setContext(key: string, value: unknown): Promise<void>;
9
+ activateProbeTriggerToken?(token: string): Promise<boolean>;
10
+ }
11
+ declare const _default: Spec;
12
+ export default _default;
13
+ //# sourceMappingURL=NativeDebugBundleReactNative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeDebugBundleReactNative.d.ts","sourceRoot":"","sources":["../src/NativeDebugBundleReactNative.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AAG9E,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACxD,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IACnC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,yBAAyB,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7D;;AAED,wBAAgF"}
@@ -0,0 +1,2 @@
1
+ import { TurboModuleRegistry } from "react-native";
2
+ export default TurboModuleRegistry.getEnforcing("DebugBundleReactNative");
@@ -0,0 +1,9 @@
1
+ import type { DebugBundleClient } from "./types.js";
2
+ export interface AppStateLike {
3
+ currentState?: string;
4
+ addEventListener(event: "change", listener: (state: string) => void): {
5
+ remove: () => void;
6
+ };
7
+ }
8
+ export declare function instrumentDebugBundleAppState(appState: AppStateLike, client?: DebugBundleClient): () => void;
9
+ //# sourceMappingURL=app-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-state.d.ts","sourceRoot":"","sources":["../src/app-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG;QAAE,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAC9F;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAE,iBAA+B,GAAG,MAAM,IAAI,CAQzH"}
@@ -0,0 +1,10 @@
1
+ import { DebugBundle } from "./index.js";
2
+ export function instrumentDebugBundleAppState(appState, client = DebugBundle) {
3
+ const subscription = appState.addEventListener("change", (state) => {
4
+ client.recordBreadcrumb("app_state", { state });
5
+ if (state === "background" || state === "inactive") {
6
+ void client.flush();
7
+ }
8
+ });
9
+ return () => subscription.remove();
10
+ }
@@ -0,0 +1,36 @@
1
+ import type { DebugBundleCaptureContext, DebugBundleClient, DebugBundleConfig, DebugBundleLogLevel, DebugBundleProbeOptions, DebugBundleRequestInfo, DebugBundleResponseInfo, DebugBundleStatus, ResolvedDebugBundleConfig } from "./types.js";
2
+ export declare class DebugBundleReactNativeClient implements DebugBundleClient {
3
+ private config;
4
+ private nativeModule;
5
+ private nativeState;
6
+ private context;
7
+ private breadcrumbs;
8
+ private probeBuffers;
9
+ private jsProbeActivationExpiresAt;
10
+ private sessionSampledIn;
11
+ private sessionEventCount;
12
+ constructor(config?: DebugBundleConfig);
13
+ get status(): DebugBundleStatus;
14
+ get lastEventAt(): number | null;
15
+ init(config: DebugBundleConfig): void;
16
+ captureException(error: unknown, context?: DebugBundleCaptureContext): void;
17
+ captureError(error: unknown, context?: DebugBundleCaptureContext): void;
18
+ captureLog(message: string, level?: DebugBundleLogLevel, context?: DebugBundleCaptureContext): void;
19
+ captureRequest(request: DebugBundleRequestInfo, response: DebugBundleResponseInfo, context?: DebugBundleCaptureContext): void;
20
+ captureMessage(message: string, level?: DebugBundleLogLevel, context?: DebugBundleCaptureContext): void;
21
+ setContext(key: string, value: unknown): void;
22
+ probe(label: string, data: unknown | (() => unknown), options?: DebugBundleProbeOptions): void;
23
+ flush(): Promise<void>;
24
+ activateProbeTriggerToken(token: string): Promise<boolean>;
25
+ recordBreadcrumb(type: string, data?: Record<string, unknown>): void;
26
+ recordScreen(screenName: string, previousScreen?: string | null, source?: string): void;
27
+ private enqueue;
28
+ private canCapture;
29
+ private mergeContext;
30
+ private snapshotProbeData;
31
+ private hasActiveJsProbeActivation;
32
+ private shouldCaptureRequestEvent;
33
+ }
34
+ export declare function createDebugBundleClient(config?: DebugBundleConfig): DebugBundleReactNativeClient;
35
+ export declare function resolveConfig(config: DebugBundleConfig): ResolvedDebugBundleConfig;
36
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,yBAAyB,EACzB,iBAAiB,EACjB,iBAAiB,EAEjB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EAGjB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAYpB,qBAAa,4BAA6B,YAAW,iBAAiB;IACpE,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,WAAW,CAAkE;IACrF,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,YAAY,CAAqD;IACzE,OAAO,CAAC,0BAA0B,CAAK;IACvC,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,iBAAiB,CAAK;gBAElB,MAAM,GAAE,iBAAsB;IAO1C,IAAI,MAAM,IAAI,iBAAiB,CAE9B;IAED,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IA8BrC,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,yBAA8B,GAAG,IAAI;IAU/E,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,yBAA8B,GAAG,IAAI;IAI3E,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,mBAA+B,EAAE,OAAO,GAAE,yBAA8B,GAAG,IAAI;IAYlH,cAAc,CACZ,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,uBAAuB,EACjC,OAAO,GAAE,yBAA8B,GACtC,IAAI;IAsBP,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,mBAA+B,EAAE,OAAO,GAAE,yBAA8B,GAAG,IAAI;IAQtH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAO7C,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,EAAE,OAAO,GAAE,uBAA4B,GAAG,IAAI;IAmB5F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWhE,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IASxE,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,GAAG,IAAW,EAAE,MAAM,SAAqB,GAAG,IAAI;IAWzG,OAAO,CAAC,OAAO;IAoCf,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,0BAA0B;IAIlC,OAAO,CAAC,yBAAyB;CAGlC;AAED,wBAAgB,uBAAuB,CAAC,MAAM,GAAE,iBAAsB,GAAG,4BAA4B,CAEpG;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB,GAAG,yBAAyB,CAqClF"}