@react-native-firebase/crashlytics 26.4.0 → 27.0.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 (28) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/RNFBCrashlytics.podspec +7 -1
  3. package/android/build.gradle +7 -0
  4. package/android/src/main/java/io/invertase/firebase/crashlytics/Constants.kt +42 -0
  5. package/android/src/main/java/io/invertase/firebase/crashlytics/{JavaScriptError.java → JavaScriptError.kt} +4 -6
  6. package/android/src/main/java/io/invertase/firebase/crashlytics/ReactNativeFirebaseCrashlyticsNativeHelper.kt +45 -0
  7. package/android/src/main/java/io/invertase/firebase/crashlytics/{UnhandledPromiseRejection.java → UnhandledPromiseRejection.kt} +4 -6
  8. package/android/src/test/java/io/invertase/firebase/crashlytics/ConstantsAndJsErrorTypesTest.java +84 -0
  9. package/android/src/test/java/io/invertase/firebase/crashlytics/ReactNativeFirebaseCrashlyticsNativeHelperTest.java +108 -0
  10. package/dist/module/version.js +1 -1
  11. package/dist/typescript/lib/index.d.ts +1 -1
  12. package/dist/typescript/lib/version.d.ts +1 -1
  13. package/ios/RNFBCrashlytics/RNFBCrashlyticsDebuggerProbe.swift +121 -0
  14. package/ios/RNFBCrashlytics/RNFBCrashlyticsHelper.h +58 -0
  15. package/ios/RNFBCrashlytics/RNFBCrashlyticsHelper.m +109 -0
  16. package/ios/RNFBCrashlytics/RNFBCrashlyticsModule.mm +39 -71
  17. package/ios/RNFBCrashlytics.xcodeproj/project.pbxproj +14 -0
  18. package/ios/RNFBCrashlyticsUnitTests/HostStubs/Firebase/FIRCrashlyticsHostStub.m +207 -0
  19. package/ios/RNFBCrashlyticsUnitTests/HostStubs/Firebase/Firebase.h +47 -0
  20. package/ios/RNFBCrashlyticsUnitTests/RNFBCrashlyticsDebuggerProbeTests.swift +112 -0
  21. package/ios/RNFBCrashlyticsUnitTests/RNFBCrashlyticsHelperHostStubTests.m +119 -0
  22. package/ios/RNFBCrashlyticsUnitTests/RNFBCrashlyticsUnitTests.xcodeproj/project.pbxproj +261 -0
  23. package/ios/RNFBCrashlyticsUnitTests/RNFBCrashlyticsUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBCrashlyticsUnitTests.xcscheme +69 -0
  24. package/ios_config.sh +28 -5
  25. package/lib/version.ts +1 -1
  26. package/package.json +4 -4
  27. package/android/src/main/java/io/invertase/firebase/crashlytics/Constants.java +0 -29
  28. package/android/src/main/java/io/invertase/firebase/crashlytics/ReactNativeFirebaseCrashlyticsNativeHelper.java +0 -18
package/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [27.0.0](https://github.com/invertase/react-native-firebase/compare/v26.4.0...v27.0.0) (2026-10-19)
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ - **app, sdk:** bump Firebase Android 35, Apple 13, and JS 13
11
+
12
+ ### Features
13
+
14
+ - **app, sdk:** bump Firebase Android 35, Apple 13, and JS 13 ([0ca03d1](https://github.com/invertase/react-native-firebase/commit/0ca03d11b0c271fb37cfbee8a0c3074a21969f0b))
15
+ - **test-expo:** add Expo Router example with a route per package ([#9313](https://github.com/invertase/react-native-firebase/issues/9313)) ([50a946a](https://github.com/invertase/react-native-firebase/commit/50a946ab4f6c11670890940b55e8bb71f6332dcf))
16
+
17
+ ### Bug Fixes
18
+
19
+ - **crashlytics, ios:** resolve target-folder GoogleService-Info.plist for SPM dSYM upload ([a2b7e57](https://github.com/invertase/react-native-firebase/commit/a2b7e5789b6df07d3aa2729f734582de6a5feb92)), closes [#9304](https://github.com/invertase/react-native-firebase/issues/9304)
20
+
6
21
  ## [26.4.0](https://github.com/invertase/react-native-firebase/compare/v26.3.3...v26.4.0) (2026-09-05)
7
22
 
8
23
  **Note:** Version bump only for package @react-native-firebase/crashlytics
@@ -32,8 +32,14 @@ Pod::Spec.new do |s|
32
32
  s.tvos.deployment_target = firebase_tvos_target
33
33
  s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}'
34
34
  s.private_header_files = "ios/**/*.h"
35
- s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*'
35
+ # CocoaPods FileList uses FNM_PATHNAME: `ios/*UnitTests/**` does not match nested
36
+ # files under HostStubs; use `ios/*UnitTests/**/*` (same as sibling packages).
37
+ s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*', 'ios/*UnitTests/**/*'
38
+ s.swift_version = '5.10'
39
+
40
+ # DEFINES_MODULE is required for the generated RNFBCrashlytics-Swift.h interface.
36
41
  s.pod_target_xcconfig = {
42
+ "DEFINES_MODULE" => "YES",
37
43
  "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ios/generated/RNFBCrashlyticsTurboModules\" \"$(PODS_TARGET_SRCROOT)/ios/generated\"",
38
44
  "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES",
39
45
  }
@@ -13,6 +13,7 @@ buildscript {
13
13
 
14
14
  dependencies {
15
15
  classpath("com.android.tools.build:gradle:8.4.0")
16
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.findProperty('kotlinVersion') ?: '2.4.0'}")
16
17
  }
17
18
  }
18
19
  }
@@ -21,6 +22,8 @@ plugins {
21
22
  id "io.invertase.gradle.build" version "1.5"
22
23
  }
23
24
 
25
+ apply plugin: "org.jetbrains.kotlin.android"
26
+
24
27
  def appProject
25
28
  if (findProject(':@react-native-firebase_app')) {
26
29
  appProject = project(':@react-native-firebase_app')
@@ -99,6 +102,10 @@ dependencies {
99
102
  implementation platform("com.google.firebase:firebase-bom:${ReactNative.ext.getVersion("firebase", "bom")}")
100
103
  implementation "com.google.firebase:firebase-crashlytics"
101
104
  implementation "com.google.firebase:firebase-crashlytics-ndk"
105
+
106
+ testImplementation "junit:junit:4.13.2"
107
+ testImplementation "org.robolectric:robolectric:4.14.1"
108
+ testImplementation "org.mockito:mockito-core:5.14.2"
102
109
  }
103
110
 
104
111
  ReactNative.shared.applyPackageVersion()
@@ -0,0 +1,42 @@
1
+ package io.invertase.firebase.crashlytics
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ /**
21
+ * Preference / meta / JSON keys for Crashlytics init. Historical Java shape was a
22
+ * package-private class of `static final String` fields; Kotlin [object] + `@JvmField`
23
+ * keeps `import static …Constants.*` and `Constants.KEY_…` working for same-module Java.
24
+ */
25
+ internal object Constants {
26
+ @JvmField
27
+ val KEY_CRASHLYTICS_NDK_ENABLED: String = "crashlytics_ndk_enabled"
28
+
29
+ @JvmField
30
+ val KEY_CRASHLYTICS_DEBUG_ENABLED: String = "crashlytics_debug_enabled"
31
+
32
+ @JvmField
33
+ val KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED: String = "crashlytics_auto_collection_enabled"
34
+
35
+ @JvmField
36
+ val KEY_CRASHLYTICS_IS_ERROR_GENERATION_ON_JS_CRASH_ENABLED: String =
37
+ "crashlytics_is_error_generation_on_js_crash_enabled"
38
+
39
+ @JvmField
40
+ val KEY_CRASHLYTICS_JAVASCRIPT_EXCEPTION_HANDLER_CHAINING_ENABLED: String =
41
+ "crashlytics_javascript_exception_handler_chaining_enabled"
42
+ }
@@ -1,4 +1,4 @@
1
- package io.invertase.firebase.crashlytics;
1
+ package io.invertase.firebase.crashlytics
2
2
 
3
3
  /*
4
4
  * Copyright (c) 2016-present Invertase Limited & Contributors
@@ -21,8 +21,6 @@ package io.invertase.firebase.crashlytics;
21
21
  * This class is purely cosmetic - to indicate on the Crashlytics console that it's a JavaScript
22
22
  * error rather than the generic `java.lang.Exception`.
23
23
  */
24
- class JavaScriptError extends Exception {
25
- JavaScriptError(String message) {
26
- super(message);
27
- }
28
- }
24
+ internal class JavaScriptError(
25
+ message: String,
26
+ ) : Exception(message)
@@ -0,0 +1,45 @@
1
+ package io.invertase.firebase.crashlytics
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import com.google.firebase.crashlytics.FirebaseCrashlytics
21
+
22
+ /**
23
+ * Public static helpers for native/Android callers that need Crashlytics without going through the
24
+ * TurboModule. Historical Java shape was a class of static methods; Kotlin [object] + `@JvmStatic`
25
+ * keeps `ReactNativeFirebaseCrashlyticsNativeHelper.recordNativeException(...)` working for Java.
26
+ */
27
+ object ReactNativeFirebaseCrashlyticsNativeHelper {
28
+ @JvmStatic
29
+ fun recordNativeException(throwable: Throwable) {
30
+ FirebaseCrashlytics.getInstance().recordException(throwable)
31
+ }
32
+
33
+ @JvmStatic
34
+ fun log(message: String) {
35
+ FirebaseCrashlytics.getInstance().log(message)
36
+ }
37
+
38
+ @JvmStatic
39
+ fun setCustomKey(
40
+ key: String,
41
+ value: String,
42
+ ) {
43
+ FirebaseCrashlytics.getInstance().setCustomKey(key, value)
44
+ }
45
+ }
@@ -1,4 +1,4 @@
1
- package io.invertase.firebase.crashlytics;
1
+ package io.invertase.firebase.crashlytics
2
2
 
3
3
  /*
4
4
  * Copyright (c) 2016-present Invertase Limited & Contributors
@@ -21,8 +21,6 @@ package io.invertase.firebase.crashlytics;
21
21
  * This class is purely cosmetic - to indicate on the Crashlytics console that it's an
22
22
  * UnhandledPromiseRejection JS error rather than the generic `java.lang.Exception`.
23
23
  */
24
- class UnhandledPromiseRejection extends Exception {
25
- UnhandledPromiseRejection(String message) {
26
- super(message);
27
- }
28
- }
24
+ internal class UnhandledPromiseRejection(
25
+ message: String,
26
+ ) : Exception(message)
@@ -0,0 +1,84 @@
1
+ package io.invertase.firebase.crashlytics;
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import static io.invertase.firebase.crashlytics.Constants.KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED;
21
+ import static io.invertase.firebase.crashlytics.Constants.KEY_CRASHLYTICS_DEBUG_ENABLED;
22
+ import static io.invertase.firebase.crashlytics.Constants.KEY_CRASHLYTICS_IS_ERROR_GENERATION_ON_JS_CRASH_ENABLED;
23
+ import static io.invertase.firebase.crashlytics.Constants.KEY_CRASHLYTICS_JAVASCRIPT_EXCEPTION_HANDLER_CHAINING_ENABLED;
24
+ import static io.invertase.firebase.crashlytics.Constants.KEY_CRASHLYTICS_NDK_ENABLED;
25
+ import static org.junit.Assert.assertEquals;
26
+ import static org.junit.Assert.assertTrue;
27
+
28
+ import java.lang.reflect.Field;
29
+ import java.lang.reflect.Modifier;
30
+ import org.junit.Test;
31
+
32
+ /**
33
+ * JVM coverage for Kotlin-ported {@link Constants}, {@link JavaScriptError}, and {@link
34
+ * UnhandledPromiseRejection}. Asserts preference-key string values, Java static-field shape for
35
+ * InitProvider static imports, and cosmetic Crashlytics console type names.
36
+ */
37
+ public class ConstantsAndJsErrorTypesTest {
38
+
39
+ @Test
40
+ public void constants_stringValuesMatchExpectedKeys() {
41
+ assertEquals("crashlytics_ndk_enabled", KEY_CRASHLYTICS_NDK_ENABLED);
42
+ assertEquals("crashlytics_debug_enabled", KEY_CRASHLYTICS_DEBUG_ENABLED);
43
+ assertEquals("crashlytics_auto_collection_enabled", KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED);
44
+ assertEquals(
45
+ "crashlytics_is_error_generation_on_js_crash_enabled",
46
+ KEY_CRASHLYTICS_IS_ERROR_GENERATION_ON_JS_CRASH_ENABLED);
47
+ assertEquals(
48
+ "crashlytics_javascript_exception_handler_chaining_enabled",
49
+ KEY_CRASHLYTICS_JAVASCRIPT_EXCEPTION_HANDLER_CHAINING_ENABLED);
50
+ }
51
+
52
+ @Test
53
+ public void constants_fieldsArePublicStaticForJavaStaticImport() throws Exception {
54
+ String[] names = {
55
+ "KEY_CRASHLYTICS_NDK_ENABLED",
56
+ "KEY_CRASHLYTICS_DEBUG_ENABLED",
57
+ "KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED",
58
+ "KEY_CRASHLYTICS_IS_ERROR_GENERATION_ON_JS_CRASH_ENABLED",
59
+ "KEY_CRASHLYTICS_JAVASCRIPT_EXCEPTION_HANDLER_CHAINING_ENABLED",
60
+ };
61
+ for (String name : names) {
62
+ Field field = Constants.class.getField(name);
63
+ int modifiers = field.getModifiers();
64
+ assertTrue(name, Modifier.isPublic(modifiers));
65
+ assertTrue(name, Modifier.isStatic(modifiers));
66
+ assertTrue(name, Modifier.isFinal(modifiers));
67
+ assertEquals(name, String.class, field.getType());
68
+ }
69
+ }
70
+
71
+ @Test
72
+ public void javaScriptError_constructsWithMessageAndCosmeticSimpleName() {
73
+ JavaScriptError error = new JavaScriptError("js-boom");
74
+ assertEquals("js-boom", error.getMessage());
75
+ assertEquals("JavaScriptError", error.getClass().getSimpleName());
76
+ }
77
+
78
+ @Test
79
+ public void unhandledPromiseRejection_constructsWithMessageAndCosmeticSimpleName() {
80
+ UnhandledPromiseRejection error = new UnhandledPromiseRejection("promise-boom");
81
+ assertEquals("promise-boom", error.getMessage());
82
+ assertEquals("UnhandledPromiseRejection", error.getClass().getSimpleName());
83
+ }
84
+ }
@@ -0,0 +1,108 @@
1
+ package io.invertase.firebase.crashlytics;
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import static org.junit.Assert.assertSame;
21
+ import static org.junit.Assert.assertTrue;
22
+ import static org.mockito.Mockito.mock;
23
+ import static org.mockito.Mockito.mockStatic;
24
+ import static org.mockito.Mockito.verify;
25
+
26
+ import com.google.firebase.crashlytics.FirebaseCrashlytics;
27
+ import java.lang.reflect.Method;
28
+ import java.lang.reflect.Modifier;
29
+ import java.util.Arrays;
30
+ import org.junit.Test;
31
+ import org.junit.runner.RunWith;
32
+ import org.mockito.MockedStatic;
33
+ import org.robolectric.RobolectricTestRunner;
34
+
35
+ /**
36
+ * JVM coverage for {@link ReactNativeFirebaseCrashlyticsNativeHelper}. Stubs {@link
37
+ * FirebaseCrashlytics#getInstance()} via mockito-mockstatic so the helper can be exercised without
38
+ * initializing the Firebase SDK. Robolectric supplies an Android runtime for Firebase class
39
+ * loading; AndroidTest-AD-1.
40
+ */
41
+ @RunWith(RobolectricTestRunner.class)
42
+ public class ReactNativeFirebaseCrashlyticsNativeHelperTest {
43
+
44
+ @Test
45
+ public void javaStaticShapePreservedForNativeCallers() throws Exception {
46
+ assertTrue(Modifier.isPublic(ReactNativeFirebaseCrashlyticsNativeHelper.class.getModifiers()));
47
+ assertTrue(Modifier.isFinal(ReactNativeFirebaseCrashlyticsNativeHelper.class.getModifiers()));
48
+ assertSame(
49
+ ReactNativeFirebaseCrashlyticsNativeHelper.INSTANCE,
50
+ ReactNativeFirebaseCrashlyticsNativeHelper.INSTANCE);
51
+
52
+ Method record =
53
+ ReactNativeFirebaseCrashlyticsNativeHelper.class.getMethod(
54
+ "recordNativeException", Throwable.class);
55
+ Method log = ReactNativeFirebaseCrashlyticsNativeHelper.class.getMethod("log", String.class);
56
+ Method setCustomKey =
57
+ ReactNativeFirebaseCrashlyticsNativeHelper.class.getMethod(
58
+ "setCustomKey", String.class, String.class);
59
+
60
+ for (Method method : Arrays.asList(record, log, setCustomKey)) {
61
+ assertTrue(method.getName(), Modifier.isStatic(method.getModifiers()));
62
+ assertTrue(method.getName(), Modifier.isPublic(method.getModifiers()));
63
+ }
64
+ }
65
+
66
+ @Test
67
+ public void recordNativeException_forwardsToFirebaseCrashlytics() {
68
+ FirebaseCrashlytics crashlytics = mock(FirebaseCrashlytics.class);
69
+ Throwable throwable = new RuntimeException("native-boom");
70
+
71
+ try (MockedStatic<FirebaseCrashlytics> firebaseCrashlytics =
72
+ mockStatic(FirebaseCrashlytics.class)) {
73
+ firebaseCrashlytics.when(FirebaseCrashlytics::getInstance).thenReturn(crashlytics);
74
+
75
+ ReactNativeFirebaseCrashlyticsNativeHelper.recordNativeException(throwable);
76
+
77
+ verify(crashlytics).recordException(throwable);
78
+ }
79
+ }
80
+
81
+ @Test
82
+ public void log_forwardsToFirebaseCrashlytics() {
83
+ FirebaseCrashlytics crashlytics = mock(FirebaseCrashlytics.class);
84
+
85
+ try (MockedStatic<FirebaseCrashlytics> firebaseCrashlytics =
86
+ mockStatic(FirebaseCrashlytics.class)) {
87
+ firebaseCrashlytics.when(FirebaseCrashlytics::getInstance).thenReturn(crashlytics);
88
+
89
+ ReactNativeFirebaseCrashlyticsNativeHelper.log("native-log");
90
+
91
+ verify(crashlytics).log("native-log");
92
+ }
93
+ }
94
+
95
+ @Test
96
+ public void setCustomKey_forwardsToFirebaseCrashlytics() {
97
+ FirebaseCrashlytics crashlytics = mock(FirebaseCrashlytics.class);
98
+
99
+ try (MockedStatic<FirebaseCrashlytics> firebaseCrashlytics =
100
+ mockStatic(FirebaseCrashlytics.class)) {
101
+ firebaseCrashlytics.when(FirebaseCrashlytics::getInstance).thenReturn(crashlytics);
102
+
103
+ ReactNativeFirebaseCrashlyticsNativeHelper.setCustomKey("k", "v");
104
+
105
+ verify(crashlytics).setCustomKey("k", "v");
106
+ }
107
+ }
108
+ }
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
 
3
3
  // Generated by genversion.
4
- export const version = '26.4.0';
4
+ export const version = '27.0.0';
5
5
  //# sourceMappingURL=version.js.map
@@ -1,7 +1,7 @@
1
1
  import type { FirebaseApp } from '@react-native-firebase/app';
2
2
  import './types/internal';
3
3
  import type { Crashlytics } from './types/crashlytics';
4
- export declare const SDK_VERSION = "26.4.0";
4
+ export declare const SDK_VERSION = "27.0.0";
5
5
  export declare function getCrashlytics(app?: FirebaseApp): Crashlytics;
6
6
  export declare function checkForUnsentReports(crashlytics: Crashlytics): Promise<boolean>;
7
7
  export declare function deleteUnsentReports(crashlytics: Crashlytics): Promise<void>;
@@ -1,2 +1,2 @@
1
- export declare const version = "26.4.0";
1
+ export declare const version = "27.0.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import Darwin
18
+ import Foundation
19
+
20
+ /**
21
+ * Debugger-attach detection previously inline in `RNFBCrashlyticsModule.mm`
22
+ * (`-isDebuggerAttached`).
23
+ *
24
+ * Pre-port contracts:
25
+ * - Once-token / dispatch_once-style caching of the result
26
+ * - `sysctl` `CTL_KERN` / `KERN_PROC` / `KERN_PROC_PID` / `getpid()` → `kinfo_proc`
27
+ * - `sysctl` failure → ELog-equivalent + treat as not attached (then still evaluate
28
+ * `P_TRACED` on the returned buffer, matching the pre-port control flow)
29
+ * - `P_TRACED` bit set → true
30
+ *
31
+ * Foundation + Darwin only so unit tests do not link Firebase / React.
32
+ */
33
+ @objc(RNFBCrashlyticsDebuggerProbe)
34
+ public final class RNFBCrashlyticsDebuggerProbe: NSObject {
35
+
36
+ /// Injectable `sysctl` seam for unit tests. Production uses `makeDefaultSysctl()`.
37
+ typealias SysctlProbe = (
38
+ _ name: UnsafeMutablePointer<Int32>,
39
+ _ namelen: u_int,
40
+ _ oldp: UnsafeMutableRawPointer?,
41
+ _ oldlenp: UnsafeMutablePointer<Int>,
42
+ _ newp: UnsafeMutableRawPointer?,
43
+ _ newlen: Int
44
+ ) -> Int32
45
+
46
+ private static let lock = NSLock()
47
+ private static var cachedResult: Bool?
48
+ /// Mirrors `static dispatch_once_t` — evaluate at most once in production path.
49
+ private static var onceTokenConsumed = false
50
+
51
+ /// Test hook: replace `sysctl`. Restored by `resetForTesting()`.
52
+ static var sysctlImpl: SysctlProbe = makeDefaultSysctl()
53
+
54
+ private static func makeDefaultSysctl() -> SysctlProbe {
55
+ { name, namelen, oldp, oldlenp, newp, newlen in
56
+ Darwin.sysctl(name, namelen, oldp, oldlenp, newp, newlen)
57
+ }
58
+ }
59
+
60
+ /// Pre-port `-isDebuggerAttached` (once-cached).
61
+ @objc
62
+ public static func isDebuggerAttached() -> Bool {
63
+ lock.lock()
64
+ defer { lock.unlock() }
65
+ if onceTokenConsumed, let cached = cachedResult {
66
+ return cached
67
+ }
68
+ let value = evaluateIsDebuggerAttached(using: sysctlImpl)
69
+ cachedResult = value
70
+ onceTokenConsumed = true
71
+ return value
72
+ }
73
+
74
+ /// Clears once-cache and restores the default `sysctl` implementation (tests only).
75
+ static func resetForTesting() {
76
+ lock.lock()
77
+ defer { lock.unlock() }
78
+ cachedResult = nil
79
+ onceTokenConsumed = false
80
+ sysctlImpl = makeDefaultSysctl()
81
+ }
82
+
83
+ /// Evaluates without consuming the production once-cache (tests only).
84
+ static func evaluateUncachedForTesting(using probe: SysctlProbe) -> Bool {
85
+ evaluateIsDebuggerAttached(using: probe)
86
+ }
87
+
88
+ /// Core logic matching the pre-port `dispatch_once` body.
89
+ private static func evaluateIsDebuggerAttached(using probe: SysctlProbe) -> Bool {
90
+ var debuggerIsAttached = false
91
+
92
+ var info = kinfo_proc()
93
+ var infoSize = MemoryLayout<kinfo_proc>.size
94
+ var name: [Int32] = [
95
+ CTL_KERN,
96
+ KERN_PROC,
97
+ KERN_PROC_PID,
98
+ getpid(),
99
+ ]
100
+
101
+ // `name` is always 4 elements — `baseAddress` is non-nil.
102
+ let sysctlResult = name.withUnsafeMutableBufferPointer { nameBuf -> Int32 in
103
+ probe(nameBuf.baseAddress!, 4, &info, &infoSize, nil, 0)
104
+ }
105
+
106
+ if sysctlResult == -1 {
107
+ // ELog is NSLog with function/line prefix (RNFBSharedUtils.h).
108
+ let err = String(cString: strerror(errno))
109
+ NSLog(
110
+ "%@ [Line %d] Crashlytics ERROR: Checking for a running debugger via sysctl() failed: %@",
111
+ #function, #line, err)
112
+ debuggerIsAttached = false
113
+ }
114
+
115
+ if !debuggerIsAttached && (info.kp_proc.p_flag & P_TRACED) != 0 {
116
+ debuggerIsAttached = true
117
+ }
118
+
119
+ return debuggerIsAttached
120
+ }
121
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+
20
+ // Plain Objective-C helper (see docs/ios-spm.mdx and
21
+ // okf-bundle/ios-spm-native-imports.md) that owns every call touching
22
+ // `FIRCrashlytics` / exception models for RNFBCrashlyticsModule, plus the
23
+ // Swift debugger probe. This keeps RNFBCrashlyticsModule.mm free of Firebase
24
+ // Crashlytics imports and `*-Swift.h`: under SPM an Objective-C++ (.mm)
25
+ // TurboModule cannot `@import` Firebase (or parse a Swift-generated header
26
+ // that uses module imports) when C++ modules are disabled (required by React
27
+ // Native's JSI headers).
28
+ @interface RNFBCrashlyticsHelper : NSObject
29
+
30
+ /** Cached `sysctl` debugger-attach probe (Swift `RNFBCrashlyticsDebuggerProbe`). */
31
+ + (BOOL)isDebuggerAttached;
32
+
33
+ + (void)checkForUnsentReportsWithCompletion:(void (^)(BOOL unsentReports))completion;
34
+
35
+ + (void)deleteUnsentReports;
36
+
37
+ + (BOOL)didCrashDuringPreviousExecution;
38
+
39
+ + (void)log:(NSString *)message;
40
+
41
+ + (void)sendUnsentReports;
42
+
43
+ + (void)setCustomValue:(NSString *)value forKey:(NSString *)key;
44
+
45
+ /** Applies each entry via `setCustomValue:forKey:` (Module setAttributes path). */
46
+ + (void)setCustomKeysAndValues:(NSDictionary *)attributes;
47
+
48
+ + (void)setUserID:(NSString *)userId;
49
+
50
+ /**
51
+ * Records a JS exception model.
52
+ * Each frame dictionary uses keys: `fn` (symbol), `file`, `line` (number).
53
+ */
54
+ + (void)recordJavaScriptErrorWithMessage:(NSString *)message
55
+ frames:(NSArray<NSDictionary *> *)frames
56
+ isUnhandledPromiseRejection:(BOOL)isUnhandledPromiseRejection;
57
+
58
+ @end