From 097ecc7f3e83d273c152c8f32b3e7d3a2310a8ad Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Tue, 17 Feb 2026 10:30:21 +0100 Subject: [PATCH 01/23] add native module --- .../com/expensify/chat/AppStartTimeModule.kt | 17 +++++++++++++++ .../expensify/chat/ExpensifyAppPackage.java | 1 + .../com/expensify/chat/MainApplication.kt | 1 + ios/AppDelegate.swift | 1 + ios/AppStartTime.h | 10 +++++++++ ios/AppStartTime.m | 21 +++++++++++++++++++ src/setup/telemetry/index.ts | 17 +++++++++++---- src/types/modules/react-native.d.ts | 5 +++++ 8 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt create mode 100644 ios/AppStartTime.h create mode 100644 ios/AppStartTime.m diff --git a/android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt b/android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt new file mode 100644 index 000000000000..7206abe12556 --- /dev/null +++ b/android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt @@ -0,0 +1,17 @@ +package com.expensify.chat + +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.module.annotations.ReactModule + +@ReactModule(name = AppStartTimeModule.NAME) +class AppStartTimeModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + companion object { + const val NAME = "AppStartTime" + var appStartTime: Double = 0.0 + } + + override fun getName(): String = NAME + + override fun getConstants(): Map = mapOf("APP_START_TIME" to appStartTime) +} diff --git a/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java b/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java index d8ef60e1d98d..98e98453673a 100644 --- a/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java +++ b/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java @@ -23,6 +23,7 @@ public List createNativeModules( modules.add(new ShareActionHandlerModule(reactContext)); modules.add(new AppStateTrackerModule(reactContext)); + modules.add(new AppStartTimeModule(reactContext)); return modules; } diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.kt b/android/app/src/main/java/com/expensify/chat/MainApplication.kt index bcbedc8ab4af..7d6283bbeb6a 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.kt +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.kt @@ -55,6 +55,7 @@ class MainApplication : MultiDexApplication(), ReactApplication { override fun onCreate() { super.onCreate() + AppStartTimeModule.appStartTime = System.currentTimeMillis().toDouble() ReactFontManager.getInstance().addCustomFont(this, "Custom Emoji Font", R.font.custom_emoji_font) ReactFontManager.getInstance().addCustomFont(this, "Expensify New Kansas", R.font.expensify_new_kansas) ReactFontManager.getInstance().addCustomFont(this, "Expensify Neue", R.font.expensify_neue) diff --git a/ios/AppDelegate.swift b/ios/AppDelegate.swift index cb2e6d5b1383..9b9ee5eb9c81 100644 --- a/ios/AppDelegate.swift +++ b/ios/AppDelegate.swift @@ -20,6 +20,7 @@ class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate { var reactNativeFactory: RCTReactNativeFactory? override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + AppStartTime.setAppStartTime(Date().timeIntervalSince1970 * 1000) let delegate = ReactNativeDelegate() let factory = RCTReactNativeFactory(delegate: delegate) delegate.dependencyProvider = RCTAppDependencyProvider() diff --git a/ios/AppStartTime.h b/ios/AppStartTime.h new file mode 100644 index 000000000000..a3f4d997a1bd --- /dev/null +++ b/ios/AppStartTime.h @@ -0,0 +1,10 @@ +#ifndef AppStartTime_h +#define AppStartTime_h + +#import + +@interface AppStartTime : NSObject ++ (void)setAppStartTime:(double)timestamp; +@end + +#endif /* AppStartTime_h */ diff --git a/ios/AppStartTime.m b/ios/AppStartTime.m new file mode 100644 index 000000000000..6cbae26d09bf --- /dev/null +++ b/ios/AppStartTime.m @@ -0,0 +1,21 @@ +#import "AppStartTime.h" + +@implementation AppStartTime + +static double appStartTime = 0; + ++ (void)setAppStartTime:(double)timestamp { + appStartTime = timestamp; +} + +RCT_EXPORT_MODULE(); + +- (NSDictionary *)constantsToExport { + return @{@"APP_START_TIME": @(appStartTime)}; +} + ++ (BOOL)requiresMainQueueSetup { + return YES; +} + +@end diff --git a/src/setup/telemetry/index.ts b/src/setup/telemetry/index.ts index 9ba378fa781a..5b9d14db0d0a 100644 --- a/src/setup/telemetry/index.ts +++ b/src/setup/telemetry/index.ts @@ -1,5 +1,5 @@ import * as Sentry from '@sentry/react-native'; -import {Platform} from 'react-native'; +import {NativeModules, Platform} from 'react-native'; import {isDevelopment} from '@libs/Environment/Environment'; import {startSpan} from '@libs/telemetry/activeSpans'; import {browserProfilingIntegration, navigationIntegration, tracingIntegration} from '@libs/telemetry/integrations'; @@ -13,9 +13,9 @@ export default function (): void { // With Sentry enabled in dev mode, profiling on iOS and Android does not work // If you want to enable Sentry in dev, set ENABLE_SENTRY_ON_DEV=true in .env // or comment out the condition below - if (isDevelopment() && !CONFIG.ENABLE_SENTRY_ON_DEV) { - return; - } + // if (isDevelopment() && !CONFIG.ENABLE_SENTRY_ON_DEV) { + // return; + // } const integrations = [navigationIntegration, tracingIntegration, browserProfilingIntegration].filter((integration) => !!integration); @@ -35,8 +35,17 @@ export default function (): void { enableLogs: true, }); + const appStartTimeModule = NativeModules.AppStartTime as {APP_START_TIME: number} | undefined; + const nativeAppStartTimeMs = Platform.OS !== 'web' ? appStartTimeModule?.APP_START_TIME : undefined; +console.log(`[Telemetry] Native app start time: ${nativeAppStartTimeMs}`); +console.log(`[Telemetry] Date.now(): ${Date.now()}`); + if (nativeAppStartTimeMs) { + console.log(`[Telemetry] Time spent in native before JS: ${Date.now() - nativeAppStartTimeMs}ms`); + } + startSpan(CONST.TELEMETRY.SPAN_APP_STARTUP, { name: CONST.TELEMETRY.SPAN_APP_STARTUP, op: CONST.TELEMETRY.SPAN_APP_STARTUP, + startTime: nativeAppStartTimeMs ?? undefined, }); } diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts index 3f9463f5ecd5..a745bdcc2e01 100644 --- a/src/types/modules/react-native.d.ts +++ b/src/types/modules/react-native.d.ts @@ -10,6 +10,10 @@ type AppStateTrackerModule = { getWasAppRelaunchedFromIcon: () => Promise; }; +type AppStartTimeModule = { + APP_START_TIME: number; +}; + type RNTextInputResetModule = { resetKeyboardInput: (nativeId: string) => void; }; @@ -54,6 +58,7 @@ declare module 'react-native' { } interface NativeModulesStatic { + AppStartTime: AppStartTimeModule; AppStateTracker: AppStateTrackerModule; BootSplash: BootSplashModule; RNTextInputReset: RNTextInputResetModule; From fce8d40f95b9ac8c4057dc1d0a6cb0feb91036fa Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Tue, 17 Feb 2026 15:04:21 +0100 Subject: [PATCH 02/23] modify span to start from native --- ios/Podfile.lock | 6 ++++++ src/setup/telemetry/index.ts | 6 +----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a51b84368e61..305e3824c9ff 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -176,6 +176,8 @@ PODS: - ExpoModulesCore - ExpoVideo (3.0.12): - ExpoModulesCore + - ExpoWebBrowser (15.0.10): + - ExpoModulesCore - EXTaskManager (14.0.9): - ExpoModulesCore - UMAppLoader @@ -4132,6 +4134,7 @@ DEPENDENCIES: - ExpoSecureStore (from `../node_modules/expo-secure-store/ios`) - ExpoStoreReview (from `../node_modules/expo-store-review/ios`) - ExpoVideo (from `../node_modules/expo-video/ios`) + - ExpoWebBrowser (from `../node_modules/expo-web-browser/ios`) - EXTaskManager (from `../node_modules/expo-task-manager/ios`) - fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) @@ -4347,6 +4350,8 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-store-review/ios" ExpoVideo: :path: "../node_modules/expo-video/ios" + ExpoWebBrowser: + :path: "../node_modules/expo-web-browser/ios" EXTaskManager: :path: "../node_modules/expo-task-manager/ios" fast_float: @@ -4626,6 +4631,7 @@ SPEC CHECKSUMS: ExpoSecureStore: 3f1b632d6d40bcc62b4983ef9199cd079592a50a ExpoStoreReview: 32bb43b6fae9c8db3e33cad69996dff3785eef5f ExpoVideo: 6907c4872886dce2720d3af20782eb6ee7734110 + ExpoWebBrowser: 17b064c621789e41d4816c95c93f429b84971f52 EXTaskManager: 6f1a66e4c8cc6df6e24c3d90928704bc3013eae5 fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 FBLazyVector: 941bef1c8eeabd9fe1f501e30a5220beee913886 diff --git a/src/setup/telemetry/index.ts b/src/setup/telemetry/index.ts index 5b9d14db0d0a..efe6e058548f 100644 --- a/src/setup/telemetry/index.ts +++ b/src/setup/telemetry/index.ts @@ -37,11 +37,7 @@ export default function (): void { const appStartTimeModule = NativeModules.AppStartTime as {APP_START_TIME: number} | undefined; const nativeAppStartTimeMs = Platform.OS !== 'web' ? appStartTimeModule?.APP_START_TIME : undefined; -console.log(`[Telemetry] Native app start time: ${nativeAppStartTimeMs}`); -console.log(`[Telemetry] Date.now(): ${Date.now()}`); - if (nativeAppStartTimeMs) { - console.log(`[Telemetry] Time spent in native before JS: ${Date.now() - nativeAppStartTimeMs}ms`); - } + startSpan(CONST.TELEMETRY.SPAN_APP_STARTUP, { name: CONST.TELEMETRY.SPAN_APP_STARTUP, From a332be7cf03c974dd7b201f1bac95ed58459a6c8 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Wed, 18 Feb 2026 16:33:18 +0100 Subject: [PATCH 03/23] add nitro module --- ios/AppStartTime.h | 10 -- ios/AppStartTime.m | 21 --- .../nitro/utils/HybridAppStartTimeModule.kt | 21 +++ .../HybridAppStartTimeModule.swift | 14 ++ modules/ExpensifyNitroUtils/nitro.json | 4 + .../ExpensifyNitroUtils+autolinking.cmake | 4 +- .../ExpensifyNitroUtils+autolinking.gradle | 2 +- .../android/ExpensifyNitroUtilsOnLoad.cpp | 12 +- .../android/ExpensifyNitroUtilsOnLoad.hpp | 2 +- .../generated/android/c++/JContact.hpp | 2 +- .../generated/android/c++/JContactFields.hpp | 2 +- .../c++/JHybridAppStartTimeModuleSpec.cpp | 49 +++++++ .../c++/JHybridAppStartTimeModuleSpec.hpp | 64 +++++++++ .../android/c++/JHybridContactsModuleSpec.cpp | 2 +- .../android/c++/JHybridContactsModuleSpec.hpp | 2 +- .../generated/android/c++/JStringHolder.hpp | 2 +- .../kotlin/com/margelo/nitro/utils/Contact.kt | 2 +- .../com/margelo/nitro/utils/ContactFields.kt | 2 +- .../nitro/utils/ExpensifyNitroUtilsOnLoad.kt | 2 +- .../utils/HybridAppStartTimeModuleSpec.kt | 54 ++++++++ .../nitro/utils/HybridContactsModuleSpec.kt | 2 +- .../com/margelo/nitro/utils/StringHolder.kt | 2 +- .../ios/ExpensifyNitroUtils+autolinking.rb | 2 +- .../ExpensifyNitroUtils-Swift-Cxx-Bridge.cpp | 19 ++- .../ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp | 28 +++- ...ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp | 7 +- .../ios/ExpensifyNitroUtilsAutolinking.mm | 10 +- .../ios/ExpensifyNitroUtilsAutolinking.swift | 17 ++- .../c++/HybridAppStartTimeModuleSpecSwift.cpp | 11 ++ .../c++/HybridAppStartTimeModuleSpecSwift.hpp | 73 ++++++++++ .../ios/c++/HybridContactsModuleSpecSwift.cpp | 2 +- .../ios/c++/HybridContactsModuleSpecSwift.hpp | 2 +- .../generated/ios/swift/Contact.swift | 2 +- .../generated/ios/swift/ContactFields.swift | 2 +- .../swift/Func_void_std__exception_ptr.swift | 2 +- .../Func_void_std__vector_Contact_.swift | 2 +- .../swift/HybridAppStartTimeModuleSpec.swift | 49 +++++++ .../HybridAppStartTimeModuleSpec_cxx.swift | 127 ++++++++++++++++++ .../ios/swift/HybridContactsModuleSpec.swift | 2 +- .../swift/HybridContactsModuleSpec_cxx.swift | 2 +- .../generated/ios/swift/StringHolder.swift | 2 +- .../nitrogen/generated/shared/c++/Contact.hpp | 2 +- .../generated/shared/c++/ContactFields.hpp | 2 +- .../c++/HybridAppStartTimeModuleSpec.cpp | 22 +++ .../c++/HybridAppStartTimeModuleSpec.hpp | 62 +++++++++ .../shared/c++/HybridContactsModuleSpec.cpp | 2 +- .../shared/c++/HybridContactsModuleSpec.hpp | 2 +- .../generated/shared/c++/StringHolder.hpp | 2 +- modules/ExpensifyNitroUtils/src/index.ts | 5 +- .../src/specs/AppStartTimeModule.nitro.ts | 18 +++ src/setup/telemetry/index.native.ts | 22 +++ src/setup/telemetry/index.web.ts | 12 ++ .../telemetry/{index.ts => setupSentry.ts} | 23 +--- src/types/modules/react-native.d.ts | 4 - 54 files changed, 730 insertions(+), 86 deletions(-) delete mode 100644 ios/AppStartTime.h delete mode 100644 ios/AppStartTime.m create mode 100644 modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt create mode 100644 modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.cpp create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.hpp create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridAppStartTimeModuleSpec.kt create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.cpp create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.hpp create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec.swift create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec_cxx.swift create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.cpp create mode 100644 modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.hpp create mode 100644 modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts create mode 100644 src/setup/telemetry/index.native.ts create mode 100644 src/setup/telemetry/index.web.ts rename src/setup/telemetry/{index.ts => setupSentry.ts} (66%) diff --git a/ios/AppStartTime.h b/ios/AppStartTime.h deleted file mode 100644 index a3f4d997a1bd..000000000000 --- a/ios/AppStartTime.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef AppStartTime_h -#define AppStartTime_h - -#import - -@interface AppStartTime : NSObject -+ (void)setAppStartTime:(double)timestamp; -@end - -#endif /* AppStartTime_h */ diff --git a/ios/AppStartTime.m b/ios/AppStartTime.m deleted file mode 100644 index 6cbae26d09bf..000000000000 --- a/ios/AppStartTime.m +++ /dev/null @@ -1,21 +0,0 @@ -#import "AppStartTime.h" - -@implementation AppStartTime - -static double appStartTime = 0; - -+ (void)setAppStartTime:(double)timestamp { - appStartTime = timestamp; -} - -RCT_EXPORT_MODULE(); - -- (NSDictionary *)constantsToExport { - return @{@"APP_START_TIME": @(appStartTime)}; -} - -+ (BOOL)requiresMainQueueSetup { - return YES; -} - -@end diff --git a/modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt b/modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt new file mode 100644 index 000000000000..8fe93add6624 --- /dev/null +++ b/modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt @@ -0,0 +1,21 @@ +package com.margelo.nitro.utils + +import android.content.Context +import com.margelo.nitro.NitroModules + +class HybridAppStartTimeModule : HybridAppStartTimeModuleSpec() { + override val memorySize: Long = 16L + + override fun recordAppStartTime() { + val context = NitroModules.applicationContext ?: return + val prefs = context.getSharedPreferences("AppStartTime", Context.MODE_PRIVATE) + prefs.edit().putLong("AppStartTime", System.currentTimeMillis()).apply() + } + + override val appStartTime: Double + get() { + val context = NitroModules.applicationContext ?: return 0.0 + val prefs = context.getSharedPreferences("AppStartTime", Context.MODE_PRIVATE) + return prefs.getLong("AppStartTime", 0L).toDouble() + } +} diff --git a/modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift b/modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift new file mode 100644 index 000000000000..691736ec029f --- /dev/null +++ b/modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift @@ -0,0 +1,14 @@ +import NitroModules +import Foundation + +final class HybridAppStartTimeModule: HybridAppStartTimeModuleSpec { + public var memorySize: Int { MemoryLayout.size } + + func recordAppStartTime() { + UserDefaults.standard.set(Date().timeIntervalSince1970 * 1000, forKey: "AppStartTime") + } + + var appStartTime: Double { + return UserDefaults.standard.double(forKey: "AppStartTime") + } +} diff --git a/modules/ExpensifyNitroUtils/nitro.json b/modules/ExpensifyNitroUtils/nitro.json index 783c10d6cf01..9999ffdba114 100644 --- a/modules/ExpensifyNitroUtils/nitro.json +++ b/modules/ExpensifyNitroUtils/nitro.json @@ -11,6 +11,10 @@ "ContactsModule": { "swift": "HybridContactsModule", "kotlin": "HybridContactsModule" + }, + "AppStartTimeModule": { + "swift": "HybridAppStartTimeModule", + "kotlin": "HybridAppStartTimeModule" } }, "ignorePaths": ["node_modules"] diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.cmake b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.cmake index bf50c81fedf4..90c9d6cab0e4 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.cmake +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.cmake @@ -2,7 +2,7 @@ # ExpensifyNitroUtils+autolinking.cmake # This file was generated by nitrogen. DO NOT MODIFY THIS FILE. # https://github.com/mrousavy/nitro -# Copyright © 2025 Marc Rousavy @ Margelo +# Copyright © 2026 Marc Rousavy @ Margelo # # This is a CMake file that adds all files generated by Nitrogen @@ -27,8 +27,10 @@ target_sources( # Autolinking Setup ../nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.cpp # Shared Nitrogen C++ sources + ../nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.cpp ../nitrogen/generated/shared/c++/HybridContactsModuleSpec.cpp # Android-specific Nitrogen C++ sources + ../nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.cpp ../nitrogen/generated/android/c++/JHybridContactsModuleSpec.cpp ) diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.gradle b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.gradle index 56f84b3fcacc..f199d0712989 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.gradle +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.gradle @@ -2,7 +2,7 @@ /// ExpensifyNitroUtils+autolinking.gradle /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// /// This is a Gradle file that adds all files generated by Nitrogen diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.cpp index 31fc81d050c7..00c1e6a59825 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.cpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.cpp @@ -2,7 +2,7 @@ /// ExpensifyNitroUtilsOnLoad.cpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #ifndef BUILDING_EXPENSIFYNITROUTILS_WITH_GENERATED_CMAKE_PROJECT @@ -15,6 +15,7 @@ #include #include +#include "JHybridAppStartTimeModuleSpec.hpp" #include "JHybridContactsModuleSpec.hpp" #include @@ -27,6 +28,7 @@ int initialize(JavaVM* vm) { return facebook::jni::initialize(vm, [] { // Register native JNI methods + margelo::nitro::utils::JHybridAppStartTimeModuleSpec::registerNatives(); margelo::nitro::utils::JHybridContactsModuleSpec::registerNatives(); // Register Nitro Hybrid Objects @@ -38,6 +40,14 @@ int initialize(JavaVM* vm) { return instance->cthis()->shared(); } ); + HybridObjectRegistry::registerHybridObjectConstructor( + "AppStartTimeModule", + []() -> std::shared_ptr { + static DefaultConstructableObject object("com/margelo/nitro/utils/HybridAppStartTimeModule"); + auto instance = object.create(); + return instance->cthis()->shared(); + } + ); }); } diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.hpp index 4667c2ca459e..f6235b868cbb 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtilsOnLoad.hpp @@ -2,7 +2,7 @@ /// ExpensifyNitroUtilsOnLoad.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #include diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContact.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContact.hpp index a00edf1fa640..2789f76a1836 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContact.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContact.hpp @@ -2,7 +2,7 @@ /// JContact.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContactFields.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContactFields.hpp index e805f27d8102..2cf3d29547bf 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContactFields.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JContactFields.hpp @@ -2,7 +2,7 @@ /// JContactFields.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.cpp new file mode 100644 index 000000000000..b4eb2b05e7d7 --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.cpp @@ -0,0 +1,49 @@ +/// +/// JHybridAppStartTimeModuleSpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +#include "JHybridAppStartTimeModuleSpec.hpp" + + + + + +namespace margelo::nitro::utils { + + jni::local_ref JHybridAppStartTimeModuleSpec::initHybrid(jni::alias_ref jThis) { + return makeCxxInstance(jThis); + } + + void JHybridAppStartTimeModuleSpec::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JHybridAppStartTimeModuleSpec::initHybrid), + }); + } + + size_t JHybridAppStartTimeModuleSpec::getExternalMemorySize() noexcept { + static const auto method = javaClassStatic()->getMethod("getMemorySize"); + return method(_javaPart); + } + + void JHybridAppStartTimeModuleSpec::dispose() noexcept { + static const auto method = javaClassStatic()->getMethod("dispose"); + method(_javaPart); + } + + // Properties + double JHybridAppStartTimeModuleSpec::getAppStartTime() { + static const auto method = javaClassStatic()->getMethod("getAppStartTime"); + auto __result = method(_javaPart); + return __result; + } + + // Methods + void JHybridAppStartTimeModuleSpec::recordAppStartTime() { + static const auto method = javaClassStatic()->getMethod("recordAppStartTime"); + method(_javaPart); + } + +} // namespace margelo::nitro::utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.hpp new file mode 100644 index 000000000000..135fb2db00d7 --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridAppStartTimeModuleSpec.hpp @@ -0,0 +1,64 @@ +/// +/// HybridAppStartTimeModuleSpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include +#include "HybridAppStartTimeModuleSpec.hpp" + + + + +namespace margelo::nitro::utils { + + using namespace facebook; + + class JHybridAppStartTimeModuleSpec: public jni::HybridClass, + public virtual HybridAppStartTimeModuleSpec { + public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/utils/HybridAppStartTimeModuleSpec;"; + static jni::local_ref initHybrid(jni::alias_ref jThis); + static void registerNatives(); + + protected: + // C++ constructor (called from Java via `initHybrid()`) + explicit JHybridAppStartTimeModuleSpec(jni::alias_ref jThis) : + HybridObject(HybridAppStartTimeModuleSpec::TAG), + HybridBase(jThis), + _javaPart(jni::make_global(jThis)) {} + + public: + ~JHybridAppStartTimeModuleSpec() override { + // Hermes GC can destroy JS objects on a non-JNI Thread. + jni::ThreadScope::WithClassLoader([&] { _javaPart.reset(); }); + } + + public: + size_t getExternalMemorySize() noexcept override; + void dispose() noexcept override; + + public: + inline const jni::global_ref& getJavaPart() const noexcept { + return _javaPart; + } + + public: + // Properties + double getAppStartTime() override; + + public: + // Methods + void recordAppStartTime() override; + + private: + friend HybridBase; + using HybridBase::HybridBase; + jni::global_ref _javaPart; + }; + +} // namespace margelo::nitro::utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.cpp index a97508ccac41..17499137b22a 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.cpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.cpp @@ -2,7 +2,7 @@ /// JHybridContactsModuleSpec.cpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #include "JHybridContactsModuleSpec.hpp" diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.hpp index 267335bf4d1f..c4977a2937c1 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JHybridContactsModuleSpec.hpp @@ -2,7 +2,7 @@ /// HybridContactsModuleSpec.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JStringHolder.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JStringHolder.hpp index 1e489ad6e243..babbbf5289c0 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JStringHolder.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/c++/JStringHolder.hpp @@ -2,7 +2,7 @@ /// JStringHolder.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/Contact.kt b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/Contact.kt index 8e973bbd49d8..327fe876dbbb 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/Contact.kt +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/Contact.kt @@ -2,7 +2,7 @@ /// Contact.kt /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// package com.margelo.nitro.utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ContactFields.kt b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ContactFields.kt index 2ccadba2b44f..619aed2f224f 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ContactFields.kt +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ContactFields.kt @@ -2,7 +2,7 @@ /// ContactFields.kt /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// package com.margelo.nitro.utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ExpensifyNitroUtilsOnLoad.kt b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ExpensifyNitroUtilsOnLoad.kt index df5cdbc9485a..f454ec43e2ff 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ExpensifyNitroUtilsOnLoad.kt +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/ExpensifyNitroUtilsOnLoad.kt @@ -2,7 +2,7 @@ /// ExpensifyNitroUtilsOnLoad.kt /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// package com.margelo.nitro.utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridAppStartTimeModuleSpec.kt b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridAppStartTimeModuleSpec.kt new file mode 100644 index 000000000000..a03637b06ae7 --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridAppStartTimeModuleSpec.kt @@ -0,0 +1,54 @@ +/// +/// HybridAppStartTimeModuleSpec.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.utils + +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.margelo.nitro.core.* + +/** + * A Kotlin class representing the AppStartTimeModule HybridObject. + * Implement this abstract class to create Kotlin-based instances of AppStartTimeModule. + */ +@DoNotStrip +@Keep +@Suppress( + "KotlinJniMissingFunction", "unused", + "RedundantSuppression", "RedundantUnitReturnType", "SimpleRedundantLet", + "LocalVariableName", "PropertyName", "PrivatePropertyName", "FunctionName" +) +abstract class HybridAppStartTimeModuleSpec: HybridObject() { + @DoNotStrip + private var mHybridData: HybridData = initHybrid() + + init { + super.updateNative(mHybridData) + } + + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + super.updateNative(hybridData) + } + + // Properties + @get:DoNotStrip + @get:Keep + abstract val appStartTime: Double + + // Methods + @DoNotStrip + @Keep + abstract fun recordAppStartTime(): Unit + + private external fun initHybrid(): HybridData + + companion object { + private const val TAG = "HybridAppStartTimeModuleSpec" + } +} diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridContactsModuleSpec.kt b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridContactsModuleSpec.kt index 0fd068247451..eb72823ea494 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridContactsModuleSpec.kt +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/HybridContactsModuleSpec.kt @@ -2,7 +2,7 @@ /// HybridContactsModuleSpec.kt /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// package com.margelo.nitro.utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/StringHolder.kt b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/StringHolder.kt index f901bdade52c..2b5330c8c4e2 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/StringHolder.kt +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/android/kotlin/com/margelo/nitro/utils/StringHolder.kt @@ -2,7 +2,7 @@ /// StringHolder.kt /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// package com.margelo.nitro.utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils+autolinking.rb b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils+autolinking.rb index 7c97cbfb8888..997952fe1fc7 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils+autolinking.rb +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils+autolinking.rb @@ -2,7 +2,7 @@ # ExpensifyNitroUtils+autolinking.rb # This file was generated by nitrogen. DO NOT MODIFY THIS FILE. # https://github.com/mrousavy/nitro -# Copyright © 2025 Marc Rousavy @ Margelo +# Copyright © 2026 Marc Rousavy @ Margelo # # This is a Ruby script that adds all files generated by Nitrogen diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.cpp index 3301e4226c02..b4ba285734f0 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.cpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.cpp @@ -2,17 +2,34 @@ /// ExpensifyNitroUtils-Swift-Cxx-Bridge.cpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #include "ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp" // Include C++ implementation defined types #include "ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp" +#include "HybridAppStartTimeModuleSpecSwift.hpp" #include "HybridContactsModuleSpecSwift.hpp" namespace margelo::nitro::utils::bridge::swift { + // pragma MARK: std::shared_ptr + std::shared_ptr create_std__shared_ptr_HybridAppStartTimeModuleSpec_(void* _Nonnull swiftUnsafePointer) noexcept { + ExpensifyNitroUtils::HybridAppStartTimeModuleSpec_cxx swiftPart = ExpensifyNitroUtils::HybridAppStartTimeModuleSpec_cxx::fromUnsafe(swiftUnsafePointer); + return std::make_shared(swiftPart); + } + void* _Nonnull get_std__shared_ptr_HybridAppStartTimeModuleSpec_(std__shared_ptr_HybridAppStartTimeModuleSpec_ cppType) noexcept { + std::shared_ptr swiftWrapper = std::dynamic_pointer_cast(cppType); + #ifdef NITRO_DEBUG + if (swiftWrapper == nullptr) [[unlikely]] { + throw std::runtime_error("Class \"HybridAppStartTimeModuleSpec\" is not implemented in Swift!"); + } + #endif + ExpensifyNitroUtils::HybridAppStartTimeModuleSpec_cxx& swiftPart = swiftWrapper->getSwiftPart(); + return swiftPart.toUnsafe(); + } + // pragma MARK: std::function& /* result */)> Func_void_std__vector_Contact_ create_Func_void_std__vector_Contact_(void* _Nonnull swiftClosureWrapper) noexcept { auto swiftClosure = ExpensifyNitroUtils::Func_void_std__vector_Contact_::fromUnsafe(swiftClosureWrapper); diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp index 81e525440f66..ebcb69c0ee02 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp @@ -2,7 +2,7 @@ /// ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once @@ -12,18 +12,23 @@ namespace margelo::nitro::utils { enum class ContactFields; } // Forward declaration of `Contact` to properly resolve imports. namespace margelo::nitro::utils { struct Contact; } +// Forward declaration of `HybridAppStartTimeModuleSpec` to properly resolve imports. +namespace margelo::nitro::utils { class HybridAppStartTimeModuleSpec; } // Forward declaration of `HybridContactsModuleSpec` to properly resolve imports. namespace margelo::nitro::utils { class HybridContactsModuleSpec; } // Forward declaration of `StringHolder` to properly resolve imports. namespace margelo::nitro::utils { struct StringHolder; } // Forward declarations of Swift defined types +// Forward declaration of `HybridAppStartTimeModuleSpec_cxx` to properly resolve imports. +namespace ExpensifyNitroUtils { class HybridAppStartTimeModuleSpec_cxx; } // Forward declaration of `HybridContactsModuleSpec_cxx` to properly resolve imports. namespace ExpensifyNitroUtils { class HybridContactsModuleSpec_cxx; } // Include C++ defined types #include "Contact.hpp" #include "ContactFields.hpp" +#include "HybridAppStartTimeModuleSpec.hpp" #include "HybridContactsModuleSpec.hpp" #include "StringHolder.hpp" #include @@ -42,6 +47,27 @@ namespace ExpensifyNitroUtils { class HybridContactsModuleSpec_cxx; } */ namespace margelo::nitro::utils::bridge::swift { + // pragma MARK: std::shared_ptr + /** + * Specialized version of `std::shared_ptr`. + */ + using std__shared_ptr_HybridAppStartTimeModuleSpec_ = std::shared_ptr; + std::shared_ptr create_std__shared_ptr_HybridAppStartTimeModuleSpec_(void* _Nonnull swiftUnsafePointer) noexcept; + void* _Nonnull get_std__shared_ptr_HybridAppStartTimeModuleSpec_(std__shared_ptr_HybridAppStartTimeModuleSpec_ cppType) noexcept; + + // pragma MARK: std::weak_ptr + using std__weak_ptr_HybridAppStartTimeModuleSpec_ = std::weak_ptr; + inline std__weak_ptr_HybridAppStartTimeModuleSpec_ weakify_std__shared_ptr_HybridAppStartTimeModuleSpec_(const std::shared_ptr& strong) noexcept { return strong; } + + // pragma MARK: Result + using Result_void_ = Result; + inline Result_void_ create_Result_void_() noexcept { + return Result::withValue(); + } + inline Result_void_ create_Result_void_(const std::exception_ptr& error) noexcept { + return Result::withError(error); + } + // pragma MARK: std::optional /** * Specialized version of `std::optional`. diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp index 1d6ea0e67519..52ea5f386373 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp @@ -2,7 +2,7 @@ /// ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once @@ -12,6 +12,8 @@ namespace margelo::nitro::utils { enum class ContactFields; } // Forward declaration of `Contact` to properly resolve imports. namespace margelo::nitro::utils { struct Contact; } +// Forward declaration of `HybridAppStartTimeModuleSpec` to properly resolve imports. +namespace margelo::nitro::utils { class HybridAppStartTimeModuleSpec; } // Forward declaration of `HybridContactsModuleSpec` to properly resolve imports. namespace margelo::nitro::utils { class HybridContactsModuleSpec; } // Forward declaration of `StringHolder` to properly resolve imports. @@ -20,6 +22,7 @@ namespace margelo::nitro::utils { struct StringHolder; } // Include C++ defined types #include "Contact.hpp" #include "ContactFields.hpp" +#include "HybridAppStartTimeModuleSpec.hpp" #include "HybridContactsModuleSpec.hpp" #include "StringHolder.hpp" #include @@ -40,6 +43,8 @@ namespace margelo::nitro::utils { struct StringHolder; } #include // Forward declarations of Swift defined types +// Forward declaration of `HybridAppStartTimeModuleSpec_cxx` to properly resolve imports. +namespace ExpensifyNitroUtils { class HybridAppStartTimeModuleSpec_cxx; } // Forward declaration of `HybridContactsModuleSpec_cxx` to properly resolve imports. namespace ExpensifyNitroUtils { class HybridContactsModuleSpec_cxx; } diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.mm b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.mm index a1aeccf77174..b3101413be34 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.mm +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.mm @@ -2,7 +2,7 @@ /// ExpensifyNitroUtilsAutolinking.mm /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #import @@ -11,6 +11,7 @@ #import #include "HybridContactsModuleSpecSwift.hpp" +#include "HybridAppStartTimeModuleSpecSwift.hpp" @interface ExpensifyNitroUtilsAutolinking : NSObject @end @@ -28,6 +29,13 @@ + (void) load { return hybridObject; } ); + HybridObjectRegistry::registerHybridObjectConstructor( + "AppStartTimeModule", + []() -> std::shared_ptr { + std::shared_ptr hybridObject = ExpensifyNitroUtils::ExpensifyNitroUtilsAutolinking::createAppStartTimeModule(); + return hybridObject; + } + ); } @end diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.swift index d3c891be34a8..b402dc07c98f 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/ExpensifyNitroUtilsAutolinking.swift @@ -2,7 +2,7 @@ /// ExpensifyNitroUtilsAutolinking.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// public final class ExpensifyNitroUtilsAutolinking { @@ -22,4 +22,19 @@ public final class ExpensifyNitroUtilsAutolinking { return __cxxWrapped.getCxxPart() }() } + + /** + * Creates an instance of a Swift class that implements `HybridAppStartTimeModuleSpec`, + * and wraps it in a Swift class that can directly interop with C++ (`HybridAppStartTimeModuleSpec_cxx`) + * + * This is generated by Nitrogen and will initialize the class specified + * in the `"autolinking"` property of `nitro.json` (in this case, `HybridAppStartTimeModule`). + */ + public static func createAppStartTimeModule() -> bridge.std__shared_ptr_HybridAppStartTimeModuleSpec_ { + let hybridObject = HybridAppStartTimeModule() + return { () -> bridge.std__shared_ptr_HybridAppStartTimeModuleSpec_ in + let __cxxWrapped = hybridObject.getCxxWrapper() + return __cxxWrapped.getCxxPart() + }() + } } diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.cpp new file mode 100644 index 000000000000..e9cb5771aaa3 --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.cpp @@ -0,0 +1,11 @@ +/// +/// HybridAppStartTimeModuleSpecSwift.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +#include "HybridAppStartTimeModuleSpecSwift.hpp" + +namespace margelo::nitro::utils { +} // namespace margelo::nitro::utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.hpp new file mode 100644 index 000000000000..8a0da8729b56 --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridAppStartTimeModuleSpecSwift.hpp @@ -0,0 +1,73 @@ +/// +/// HybridAppStartTimeModuleSpecSwift.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +#pragma once + +#include "HybridAppStartTimeModuleSpec.hpp" + +// Forward declaration of `HybridAppStartTimeModuleSpec_cxx` to properly resolve imports. +namespace ExpensifyNitroUtils { class HybridAppStartTimeModuleSpec_cxx; } + + + + + +#include "ExpensifyNitroUtils-Swift-Cxx-Umbrella.hpp" + +namespace margelo::nitro::utils { + + /** + * The C++ part of HybridAppStartTimeModuleSpec_cxx.swift. + * + * HybridAppStartTimeModuleSpecSwift (C++) accesses HybridAppStartTimeModuleSpec_cxx (Swift), and might + * contain some additional bridging code for C++ <> Swift interop. + * + * Since this obviously introduces an overhead, I hope at some point in + * the future, HybridAppStartTimeModuleSpec_cxx can directly inherit from the C++ class HybridAppStartTimeModuleSpec + * to simplify the whole structure and memory management. + */ + class HybridAppStartTimeModuleSpecSwift: public virtual HybridAppStartTimeModuleSpec { + public: + // Constructor from a Swift instance + explicit HybridAppStartTimeModuleSpecSwift(const ExpensifyNitroUtils::HybridAppStartTimeModuleSpec_cxx& swiftPart): + HybridObject(HybridAppStartTimeModuleSpec::TAG), + _swiftPart(swiftPart) { } + + public: + // Get the Swift part + inline ExpensifyNitroUtils::HybridAppStartTimeModuleSpec_cxx& getSwiftPart() noexcept { + return _swiftPart; + } + + public: + inline size_t getExternalMemorySize() noexcept override { + return _swiftPart.getMemorySize(); + } + void dispose() noexcept override { + _swiftPart.dispose(); + } + + public: + // Properties + inline double getAppStartTime() noexcept override { + return _swiftPart.getAppStartTime(); + } + + public: + // Methods + inline void recordAppStartTime() override { + auto __result = _swiftPart.recordAppStartTime(); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + } + + private: + ExpensifyNitroUtils::HybridAppStartTimeModuleSpec_cxx _swiftPart; + }; + +} // namespace margelo::nitro::utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.cpp index 5e4e6e495175..4ed87fe30a92 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.cpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.cpp @@ -2,7 +2,7 @@ /// HybridContactsModuleSpecSwift.cpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #include "HybridContactsModuleSpecSwift.hpp" diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.hpp index d5245138dbaf..0ec5342eccec 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/c++/HybridContactsModuleSpecSwift.hpp @@ -2,7 +2,7 @@ /// HybridContactsModuleSpecSwift.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Contact.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Contact.swift index 4b165d37a294..bc66c3e46d2b 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Contact.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Contact.swift @@ -2,7 +2,7 @@ /// Contact.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// import NitroModules diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/ContactFields.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/ContactFields.swift index c9a0cf007bb8..9f464ce24e0a 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/ContactFields.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/ContactFields.swift @@ -2,7 +2,7 @@ /// ContactFields.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// /** diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift index 8eaa9f12b2a1..a2ddc405ac6d 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift @@ -2,7 +2,7 @@ /// Func_void_std__exception_ptr.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// import NitroModules diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__vector_Contact_.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__vector_Contact_.swift index 26501cd5acaa..1dd498ba1629 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__vector_Contact_.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/Func_void_std__vector_Contact_.swift @@ -2,7 +2,7 @@ /// Func_void_std__vector_Contact_.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// import NitroModules diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec.swift new file mode 100644 index 000000000000..e3b9e50858fb --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec.swift @@ -0,0 +1,49 @@ +/// +/// HybridAppStartTimeModuleSpec.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +import Foundation +import NitroModules + +/// See ``HybridAppStartTimeModuleSpec`` +public protocol HybridAppStartTimeModuleSpec_protocol: HybridObject { + // Properties + var appStartTime: Double { get } + + // Methods + func recordAppStartTime() throws -> Void +} + +/// See ``HybridAppStartTimeModuleSpec`` +open class HybridAppStartTimeModuleSpec_base { + private weak var cxxWrapper: HybridAppStartTimeModuleSpec_cxx? = nil + public init() { } + public func getCxxWrapper() -> HybridAppStartTimeModuleSpec_cxx { + #if DEBUG + guard self is HybridAppStartTimeModuleSpec else { + fatalError("`self` is not a `HybridAppStartTimeModuleSpec`! Did you accidentally inherit from `HybridAppStartTimeModuleSpec_base` instead of `HybridAppStartTimeModuleSpec`?") + } + #endif + if let cxxWrapper = self.cxxWrapper { + return cxxWrapper + } else { + let cxxWrapper = HybridAppStartTimeModuleSpec_cxx(self as! HybridAppStartTimeModuleSpec) + self.cxxWrapper = cxxWrapper + return cxxWrapper + } + } +} + +/** + * A Swift base-protocol representing the AppStartTimeModule HybridObject. + * Implement this protocol to create Swift-based instances of AppStartTimeModule. + * ```swift + * class HybridAppStartTimeModule : HybridAppStartTimeModuleSpec { + * // ... + * } + * ``` + */ +public typealias HybridAppStartTimeModuleSpec = HybridAppStartTimeModuleSpec_protocol & HybridAppStartTimeModuleSpec_base diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec_cxx.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec_cxx.swift new file mode 100644 index 000000000000..3d54beba719d --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridAppStartTimeModuleSpec_cxx.swift @@ -0,0 +1,127 @@ +/// +/// HybridAppStartTimeModuleSpec_cxx.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +import Foundation +import NitroModules + +/** + * A class implementation that bridges HybridAppStartTimeModuleSpec over to C++. + * In C++, we cannot use Swift protocols - so we need to wrap it in a class to make it strongly defined. + * + * Also, some Swift types need to be bridged with special handling: + * - Enums need to be wrapped in Structs, otherwise they cannot be accessed bi-directionally (Swift bug: https://github.com/swiftlang/swift/issues/75330) + * - Other HybridObjects need to be wrapped/unwrapped from the Swift TCxx wrapper + * - Throwing methods need to be wrapped with a Result type, as exceptions cannot be propagated to C++ + */ +open class HybridAppStartTimeModuleSpec_cxx { + /** + * The Swift <> C++ bridge's namespace (`margelo::nitro::utils::bridge::swift`) + * from `ExpensifyNitroUtils-Swift-Cxx-Bridge.hpp`. + * This contains specialized C++ templates, and C++ helper functions that can be accessed from Swift. + */ + public typealias bridge = margelo.nitro.utils.bridge.swift + + /** + * Holds an instance of the `HybridAppStartTimeModuleSpec` Swift protocol. + */ + private var __implementation: any HybridAppStartTimeModuleSpec + + /** + * Holds a weak pointer to the C++ class that wraps the Swift class. + */ + private var __cxxPart: bridge.std__weak_ptr_HybridAppStartTimeModuleSpec_ + + /** + * Create a new `HybridAppStartTimeModuleSpec_cxx` that wraps the given `HybridAppStartTimeModuleSpec`. + * All properties and methods bridge to C++ types. + */ + public init(_ implementation: any HybridAppStartTimeModuleSpec) { + self.__implementation = implementation + self.__cxxPart = .init() + /* no base class */ + } + + /** + * Get the actual `HybridAppStartTimeModuleSpec` instance this class wraps. + */ + @inline(__always) + public func getHybridAppStartTimeModuleSpec() -> any HybridAppStartTimeModuleSpec { + return __implementation + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + public func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `HybridAppStartTimeModuleSpec_cxx`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + public class func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> HybridAppStartTimeModuleSpec_cxx { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } + + /** + * Gets (or creates) the C++ part of this Hybrid Object. + * The C++ part is a `std::shared_ptr`. + */ + public func getCxxPart() -> bridge.std__shared_ptr_HybridAppStartTimeModuleSpec_ { + let cachedCxxPart = self.__cxxPart.lock() + if cachedCxxPart.__convertToBool() { + return cachedCxxPart + } else { + let newCxxPart = bridge.create_std__shared_ptr_HybridAppStartTimeModuleSpec_(self.toUnsafe()) + __cxxPart = bridge.weakify_std__shared_ptr_HybridAppStartTimeModuleSpec_(newCxxPart) + return newCxxPart + } + } + + + + /** + * Get the memory size of the Swift class (plus size of any other allocations) + * so the JS VM can properly track it and garbage-collect the JS object if needed. + */ + @inline(__always) + public var memorySize: Int { + return MemoryHelper.getSizeOf(self.__implementation) + self.__implementation.memorySize + } + + /** + * Call dispose() on the Swift class. + * This _may_ be called manually from JS. + */ + @inline(__always) + public func dispose() { + self.__implementation.dispose() + } + + // Properties + public final var appStartTime: Double { + @inline(__always) + get { + return self.__implementation.appStartTime + } + } + + // Methods + @inline(__always) + public final func recordAppStartTime() -> bridge.Result_void_ { + do { + try self.__implementation.recordAppStartTime() + return bridge.create_Result_void_() + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_void_(__exceptionPtr) + } + } +} diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec.swift index 3c0165804127..3456cb65982b 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec.swift @@ -2,7 +2,7 @@ /// HybridContactsModuleSpec.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// import Foundation diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec_cxx.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec_cxx.swift index 04cbd1cfd732..80081c8acb78 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec_cxx.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/HybridContactsModuleSpec_cxx.swift @@ -2,7 +2,7 @@ /// HybridContactsModuleSpec_cxx.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// import Foundation diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/StringHolder.swift b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/StringHolder.swift index aa419e2f5914..5f9c0bd1b5b1 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/StringHolder.swift +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/ios/swift/StringHolder.swift @@ -2,7 +2,7 @@ /// StringHolder.swift /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// import NitroModules diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/Contact.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/Contact.hpp index 0a9128bad9a7..c30eb56e1820 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/Contact.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/Contact.hpp @@ -2,7 +2,7 @@ /// Contact.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/ContactFields.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/ContactFields.hpp index a00d7f799a59..df13271b6919 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/ContactFields.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/ContactFields.hpp @@ -2,7 +2,7 @@ /// ContactFields.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.cpp new file mode 100644 index 000000000000..90c53a80a53d --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.cpp @@ -0,0 +1,22 @@ +/// +/// HybridAppStartTimeModuleSpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +#include "HybridAppStartTimeModuleSpec.hpp" + +namespace margelo::nitro::utils { + + void HybridAppStartTimeModuleSpec::loadHybridMethods() { + // load base methods/properties + HybridObject::loadHybridMethods(); + // load custom methods/properties + registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridGetter("appStartTime", &HybridAppStartTimeModuleSpec::getAppStartTime); + prototype.registerHybridMethod("recordAppStartTime", &HybridAppStartTimeModuleSpec::recordAppStartTime); + }); + } + +} // namespace margelo::nitro::utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.hpp new file mode 100644 index 000000000000..75b174de7a6b --- /dev/null +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridAppStartTimeModuleSpec.hpp @@ -0,0 +1,62 @@ +/// +/// HybridAppStartTimeModuleSpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2026 Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + + + + + +namespace margelo::nitro::utils { + + using namespace margelo::nitro; + + /** + * An abstract base class for `AppStartTimeModule` + * Inherit this class to create instances of `HybridAppStartTimeModuleSpec` in C++. + * You must explicitly call `HybridObject`'s constructor yourself, because it is virtual. + * @example + * ```cpp + * class HybridAppStartTimeModule: public HybridAppStartTimeModuleSpec { + * public: + * HybridAppStartTimeModule(...): HybridObject(TAG) { ... } + * // ... + * }; + * ``` + */ + class HybridAppStartTimeModuleSpec: public virtual HybridObject { + public: + // Constructor + explicit HybridAppStartTimeModuleSpec(): HybridObject(TAG) { } + + // Destructor + ~HybridAppStartTimeModuleSpec() override = default; + + public: + // Properties + virtual double getAppStartTime() = 0; + + public: + // Methods + virtual void recordAppStartTime() = 0; + + protected: + // Hybrid Setup + void loadHybridMethods() override; + + protected: + // Tag for logging + static constexpr auto TAG = "AppStartTimeModule"; + }; + +} // namespace margelo::nitro::utils diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.cpp b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.cpp index 7f0cdb87283a..3f609e5bbcb2 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.cpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.cpp @@ -2,7 +2,7 @@ /// HybridContactsModuleSpec.cpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #include "HybridContactsModuleSpec.hpp" diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.hpp index 12aa95f90327..c9ffa5ed3cca 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/HybridContactsModuleSpec.hpp @@ -2,7 +2,7 @@ /// HybridContactsModuleSpec.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/StringHolder.hpp b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/StringHolder.hpp index 9d993b639a82..1f400597c645 100644 --- a/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/StringHolder.hpp +++ b/modules/ExpensifyNitroUtils/nitrogen/generated/shared/c++/StringHolder.hpp @@ -2,7 +2,7 @@ /// StringHolder.hpp /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. /// https://github.com/mrousavy/nitro -/// Copyright © 2025 Marc Rousavy @ Margelo +/// Copyright © 2026 Marc Rousavy @ Margelo /// #pragma once diff --git a/modules/ExpensifyNitroUtils/src/index.ts b/modules/ExpensifyNitroUtils/src/index.ts index 0317b02ddc64..29711d223966 100644 --- a/modules/ExpensifyNitroUtils/src/index.ts +++ b/modules/ExpensifyNitroUtils/src/index.ts @@ -1,7 +1,10 @@ import {NitroModules} from 'react-native-nitro-modules'; import type * as ContactsModuleSpec from './specs/ContactsModule.nitro'; +import type * as AppStartTimeModuleSpec from './specs/AppStartTimeModule.nitro'; const ContactsNitroModule = NitroModules.createHybridObject('ContactsModule'); +const AppStartTimeNitroModule = NitroModules.createHybridObject('AppStartTimeModule'); -export {ContactsNitroModule}; +export {ContactsNitroModule, AppStartTimeNitroModule}; export * from './specs/ContactsModule.nitro'; +export * from './specs/AppStartTimeModule.nitro'; diff --git a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts new file mode 100644 index 000000000000..79c71c7fbb1e --- /dev/null +++ b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts @@ -0,0 +1,18 @@ +import type {HybridObject} from 'react-native-nitro-modules'; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +interface AppStartTimeModule extends HybridObject<{ios: 'swift'; android: 'kotlin'}> { + /** + * Records the app start time. This should be called as early as possible + * in the native app lifecycle (before React Native initializes). + */ + recordAppStartTime(): void; + + /** + * Gets the recorded app start time in milliseconds since epoch. + * Returns 0 if recordAppStartTime() was never called. + */ + readonly appStartTime: number; +} + +export type {AppStartTimeModule}; diff --git a/src/setup/telemetry/index.native.ts b/src/setup/telemetry/index.native.ts new file mode 100644 index 000000000000..7e195afdc860 --- /dev/null +++ b/src/setup/telemetry/index.native.ts @@ -0,0 +1,22 @@ +import {AppStartTimeNitroModule} from '@expensify/nitro-utils'; +import {startSpan} from '@libs/telemetry/activeSpans'; +import CONST from '@src/CONST'; +import setupSentry from './setupSentry'; + +export default function (): void { + setupSentry(); + + + let nativeAppStartTimeMs: number | undefined; + try { + nativeAppStartTimeMs = AppStartTimeNitroModule.appStartTime; + } catch (error) { + nativeAppStartTimeMs = undefined; + } + + startSpan(CONST.TELEMETRY.SPAN_APP_STARTUP, { + name: CONST.TELEMETRY.SPAN_APP_STARTUP, + op: CONST.TELEMETRY.SPAN_APP_STARTUP, + startTime: nativeAppStartTimeMs ?? undefined, + }); +} diff --git a/src/setup/telemetry/index.web.ts b/src/setup/telemetry/index.web.ts new file mode 100644 index 000000000000..14c9f2db53b4 --- /dev/null +++ b/src/setup/telemetry/index.web.ts @@ -0,0 +1,12 @@ +import {startSpan} from '@libs/telemetry/activeSpans'; +import CONST from '@src/CONST'; +import setupSentry from './setupSentry'; + +export default function (): void { + setupSentry(); + + startSpan(CONST.TELEMETRY.SPAN_APP_STARTUP, { + name: CONST.TELEMETRY.SPAN_APP_STARTUP, + op: CONST.TELEMETRY.SPAN_APP_STARTUP, + }); +} diff --git a/src/setup/telemetry/index.ts b/src/setup/telemetry/setupSentry.ts similarity index 66% rename from src/setup/telemetry/index.ts rename to src/setup/telemetry/setupSentry.ts index efe6e058548f..1015cdc049fb 100644 --- a/src/setup/telemetry/index.ts +++ b/src/setup/telemetry/setupSentry.ts @@ -1,21 +1,18 @@ import * as Sentry from '@sentry/react-native'; -import {NativeModules, Platform} from 'react-native'; +import {Platform} from 'react-native'; import {isDevelopment} from '@libs/Environment/Environment'; -import {startSpan} from '@libs/telemetry/activeSpans'; import {browserProfilingIntegration, navigationIntegration, tracingIntegration} from '@libs/telemetry/integrations'; import processBeforeSendTransactions from '@libs/telemetry/middlewares'; import CONFIG from '@src/CONFIG'; -import CONST from '@src/CONST'; import pkg from '../../../package.json'; import makeDebugTransport from './debugTransport'; -export default function (): void { +function setupSentry(): void { // With Sentry enabled in dev mode, profiling on iOS and Android does not work // If you want to enable Sentry in dev, set ENABLE_SENTRY_ON_DEV=true in .env - // or comment out the condition below - // if (isDevelopment() && !CONFIG.ENABLE_SENTRY_ON_DEV) { - // return; - // } + if (isDevelopment() && !CONFIG.ENABLE_SENTRY_ON_DEV) { + return; + } const integrations = [navigationIntegration, tracingIntegration, browserProfilingIntegration].filter((integration) => !!integration); @@ -35,13 +32,7 @@ export default function (): void { enableLogs: true, }); - const appStartTimeModule = NativeModules.AppStartTime as {APP_START_TIME: number} | undefined; - const nativeAppStartTimeMs = Platform.OS !== 'web' ? appStartTimeModule?.APP_START_TIME : undefined; - - startSpan(CONST.TELEMETRY.SPAN_APP_STARTUP, { - name: CONST.TELEMETRY.SPAN_APP_STARTUP, - op: CONST.TELEMETRY.SPAN_APP_STARTUP, - startTime: nativeAppStartTimeMs ?? undefined, - }); } + +export default setupSentry; diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts index a745bdcc2e01..763f3193d7d0 100644 --- a/src/types/modules/react-native.d.ts +++ b/src/types/modules/react-native.d.ts @@ -10,9 +10,6 @@ type AppStateTrackerModule = { getWasAppRelaunchedFromIcon: () => Promise; }; -type AppStartTimeModule = { - APP_START_TIME: number; -}; type RNTextInputResetModule = { resetKeyboardInput: (nativeId: string) => void; @@ -58,7 +55,6 @@ declare module 'react-native' { } interface NativeModulesStatic { - AppStartTime: AppStartTimeModule; AppStateTracker: AppStateTrackerModule; BootSplash: BootSplashModule; RNTextInputReset: RNTextInputResetModule; From 1fa13d16e7497cda7f439ee6e61555ceaac7c76b Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Thu, 19 Feb 2026 11:07:31 +0100 Subject: [PATCH 04/23] lint fixes --- modules/ExpensifyNitroUtils/src/index.ts | 6 +++--- .../src/specs/AppStartTimeModule.nitro.ts | 2 +- src/setup/telemetry/index.native.ts | 1 - src/setup/telemetry/setupSentry.ts | 2 -- src/types/modules/react-native.d.ts | 1 - 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/modules/ExpensifyNitroUtils/src/index.ts b/modules/ExpensifyNitroUtils/src/index.ts index 29711d223966..c286888b9bbd 100644 --- a/modules/ExpensifyNitroUtils/src/index.ts +++ b/modules/ExpensifyNitroUtils/src/index.ts @@ -1,10 +1,10 @@ import {NitroModules} from 'react-native-nitro-modules'; import type * as ContactsModuleSpec from './specs/ContactsModule.nitro'; -import type * as AppStartTimeModuleSpec from './specs/AppStartTimeModule.nitro'; +import type AppStartTimeModule from './specs/AppStartTimeModule.nitro'; const ContactsNitroModule = NitroModules.createHybridObject('ContactsModule'); -const AppStartTimeNitroModule = NitroModules.createHybridObject('AppStartTimeModule'); +const AppStartTimeNitroModule = NitroModules.createHybridObject('AppStartTimeModule'); export {ContactsNitroModule, AppStartTimeNitroModule}; export * from './specs/ContactsModule.nitro'; -export * from './specs/AppStartTimeModule.nitro'; +export type {default as AppStartTimeModule} from './specs/AppStartTimeModule.nitro'; diff --git a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts index 79c71c7fbb1e..8479b01feceb 100644 --- a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts +++ b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts @@ -15,4 +15,4 @@ interface AppStartTimeModule extends HybridObject<{ios: 'swift'; android: 'kotli readonly appStartTime: number; } -export type {AppStartTimeModule}; +export default AppStartTimeModule; diff --git a/src/setup/telemetry/index.native.ts b/src/setup/telemetry/index.native.ts index 7e195afdc860..88032d12e163 100644 --- a/src/setup/telemetry/index.native.ts +++ b/src/setup/telemetry/index.native.ts @@ -6,7 +6,6 @@ import setupSentry from './setupSentry'; export default function (): void { setupSentry(); - let nativeAppStartTimeMs: number | undefined; try { nativeAppStartTimeMs = AppStartTimeNitroModule.appStartTime; diff --git a/src/setup/telemetry/setupSentry.ts b/src/setup/telemetry/setupSentry.ts index 1015cdc049fb..2130a8ca6968 100644 --- a/src/setup/telemetry/setupSentry.ts +++ b/src/setup/telemetry/setupSentry.ts @@ -31,8 +31,6 @@ function setupSentry(): void { beforeSendTransaction: processBeforeSendTransactions, enableLogs: true, }); - - } export default setupSentry; diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts index 763f3193d7d0..3f9463f5ecd5 100644 --- a/src/types/modules/react-native.d.ts +++ b/src/types/modules/react-native.d.ts @@ -10,7 +10,6 @@ type AppStateTrackerModule = { getWasAppRelaunchedFromIcon: () => Promise; }; - type RNTextInputResetModule = { resetKeyboardInput: (nativeId: string) => void; }; From c56710d3cbcbcbb2ca9397b5ff715de001ab447b Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Thu, 19 Feb 2026 11:15:03 +0100 Subject: [PATCH 05/23] lint fix --- .../com/margelo/nitro/utils/HybridAppStartTimeModule.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt b/modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt index 8fe93add6624..ddde08906f00 100644 --- a/modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt +++ b/modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt @@ -8,14 +8,14 @@ class HybridAppStartTimeModule : HybridAppStartTimeModuleSpec() { override fun recordAppStartTime() { val context = NitroModules.applicationContext ?: return - val prefs = context.getSharedPreferences("AppStartTime", Context.MODE_PRIVATE) - prefs.edit().putLong("AppStartTime", System.currentTimeMillis()).apply() + val sharedPreferences = context.getSharedPreferences("AppStartTime", Context.MODE_PRIVATE) + sharedPreferences.edit().putLong("AppStartTime", System.currentTimeMillis()).apply() } override val appStartTime: Double get() { val context = NitroModules.applicationContext ?: return 0.0 - val prefs = context.getSharedPreferences("AppStartTime", Context.MODE_PRIVATE) - return prefs.getLong("AppStartTime", 0L).toDouble() + val sharedPreferences = context.getSharedPreferences("AppStartTime", Context.MODE_PRIVATE) + return sharedPreferences.getLong("AppStartTime", 0L).toDouble() } } From b7251d84eb4b3451a3ee3beba1a79086f2b5ee63 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Thu, 19 Feb 2026 11:59:31 +0100 Subject: [PATCH 06/23] lint fix --- src/setup/telemetry/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/setup/telemetry/index.ts diff --git a/src/setup/telemetry/index.ts b/src/setup/telemetry/index.ts new file mode 100644 index 000000000000..ef9251fdc22d --- /dev/null +++ b/src/setup/telemetry/index.ts @@ -0,0 +1 @@ +export default function (): void {} From 427b616dacdc17334d7f2db873dee21b9781052a Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 11:16:29 +0100 Subject: [PATCH 07/23] Remove TurboModule in favor of NitroModule for app start time - Delete AppStartTimeModule.kt (TurboModule) which was unused by JS - Remove its registration from ExpensifyAppPackage - Replace AppStartTimeModule.appStartTime assignment in MainApplication with direct SharedPreferences write (matching what the NitroModule reads) - Replace AppStartTime.setAppStartTime() in AppDelegate with direct UserDefaults write (matching what the NitroModule reads) - Update Mobile-Expensify submodule to eliran/native-module-start-time HEAD The NitroModule (HybridAppStartTimeModule) is the single implementation. Native startup writes the timestamp to SharedPreferences/UserDefaults, JS reads it via AppStartTimeNitroModule.appStartTime and uses it to backdate the SPAN_APP_STARTUP Sentry span to true native launch time. Co-Authored-By: Claude Sonnet 4.6 --- .../com/expensify/chat/AppStartTimeModule.kt | 17 ----------------- .../com/expensify/chat/ExpensifyAppPackage.java | 1 - .../java/com/expensify/chat/MainApplication.kt | 5 ++++- ios/AppDelegate.swift | 2 +- 4 files changed, 5 insertions(+), 20 deletions(-) delete mode 100644 android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt diff --git a/android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt b/android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt deleted file mode 100644 index 7206abe12556..000000000000 --- a/android/app/src/main/java/com/expensify/chat/AppStartTimeModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.expensify.chat - -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReactContextBaseJavaModule -import com.facebook.react.module.annotations.ReactModule - -@ReactModule(name = AppStartTimeModule.NAME) -class AppStartTimeModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { - companion object { - const val NAME = "AppStartTime" - var appStartTime: Double = 0.0 - } - - override fun getName(): String = NAME - - override fun getConstants(): Map = mapOf("APP_START_TIME" to appStartTime) -} diff --git a/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java b/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java index 98e98453673a..d8ef60e1d98d 100644 --- a/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java +++ b/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java @@ -23,7 +23,6 @@ public List createNativeModules( modules.add(new ShareActionHandlerModule(reactContext)); modules.add(new AppStateTrackerModule(reactContext)); - modules.add(new AppStartTimeModule(reactContext)); return modules; } diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.kt b/android/app/src/main/java/com/expensify/chat/MainApplication.kt index 7d6283bbeb6a..261a3535408a 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.kt +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.kt @@ -55,7 +55,10 @@ class MainApplication : MultiDexApplication(), ReactApplication { override fun onCreate() { super.onCreate() - AppStartTimeModule.appStartTime = System.currentTimeMillis().toDouble() + getSharedPreferences("AppStartTime", MODE_PRIVATE) + .edit() + .putLong("AppStartTime", System.currentTimeMillis()) + .apply() ReactFontManager.getInstance().addCustomFont(this, "Custom Emoji Font", R.font.custom_emoji_font) ReactFontManager.getInstance().addCustomFont(this, "Expensify New Kansas", R.font.expensify_new_kansas) ReactFontManager.getInstance().addCustomFont(this, "Expensify Neue", R.font.expensify_neue) diff --git a/ios/AppDelegate.swift b/ios/AppDelegate.swift index 9b9ee5eb9c81..a4b2f45a3425 100644 --- a/ios/AppDelegate.swift +++ b/ios/AppDelegate.swift @@ -20,7 +20,7 @@ class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate { var reactNativeFactory: RCTReactNativeFactory? override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { - AppStartTime.setAppStartTime(Date().timeIntervalSince1970 * 1000) + UserDefaults.standard.set(Date().timeIntervalSince1970 * 1000, forKey: "AppStartTime") let delegate = ReactNativeDelegate() let factory = RCTReactNativeFactory(delegate: delegate) delegate.dependencyProvider = RCTAppDependencyProvider() From 7db52a5259fc5fee28f72872266ca2b113e79662 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 11:22:03 +0100 Subject: [PATCH 08/23] Update Mobile-Expensify submodule Co-Authored-By: Claude Sonnet 4.6 --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 10bc3c35f63b..a2ba9c08b655 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 10bc3c35f63b4517a42e7202d68b266e727b9a36 +Subproject commit a2ba9c08b65576f7dc3c1f44b04bf19b6cfb815d From abd94b7d0b9c9ced43f40a6635052f0fa6e23db0 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 11:23:41 +0100 Subject: [PATCH 09/23] Update Mobile-Expensify submodule Co-Authored-By: Claude Sonnet 4.6 --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index a2ba9c08b655..411bfb8ac101 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit a2ba9c08b65576f7dc3c1f44b04bf19b6cfb815d +Subproject commit 411bfb8ac101bac08fb95fc99a8a95ab045c8e75 From 5bb539e448457a6c666c04df568fb7b1c394cd94 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 11:28:22 +0100 Subject: [PATCH 10/23] Update Mobile-Expensify submodule Co-Authored-By: Claude Sonnet 4.6 --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 411bfb8ac101..d6ee136f8be9 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 411bfb8ac101bac08fb95fc99a8a95ab045c8e75 +Subproject commit d6ee136f8be9a5c9d3d60d94451fc2c22d1b98b1 From 713923a4dbdfc91d4436ace1ae8bc12f8f9fcdcf Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 11:49:03 +0100 Subject: [PATCH 11/23] Extract AppStartTime SharedPreferences key into a constant in MainApplication Co-Authored-By: Claude Sonnet 4.6 --- .../src/main/java/com/expensify/chat/MainApplication.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.kt b/android/app/src/main/java/com/expensify/chat/MainApplication.kt index 261a3535408a..185a8b736f6f 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.kt +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.kt @@ -28,6 +28,9 @@ import expo.modules.ReactNativeHostWrapper import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative class MainApplication : MultiDexApplication(), ReactApplication { + companion object { + private const val APP_START_TIME_PREFERENCES = "AppStartTime" + } override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(this, object : DefaultReactNativeHost(this) { override fun getUseDeveloperSupport() = BuildConfig.DEBUG @@ -55,9 +58,9 @@ class MainApplication : MultiDexApplication(), ReactApplication { override fun onCreate() { super.onCreate() - getSharedPreferences("AppStartTime", MODE_PRIVATE) + getSharedPreferences(APP_START_TIME_PREFERENCES, MODE_PRIVATE) .edit() - .putLong("AppStartTime", System.currentTimeMillis()) + .putLong(APP_START_TIME_PREFERENCES, System.currentTimeMillis()) .apply() ReactFontManager.getInstance().addCustomFont(this, "Custom Emoji Font", R.font.custom_emoji_font) ReactFontManager.getInstance().addCustomFont(this, "Expensify New Kansas", R.font.expensify_new_kansas) From 749d197e9ea379717017110df8b36f0305630fda Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 11:54:46 +0100 Subject: [PATCH 12/23] Extract AppStartTime UserDefaults key into a constant in Swift files Co-Authored-By: Claude Sonnet 4.6 --- ios/AppDelegate.swift | 3 ++- .../ios/appstarttime/HybridAppStartTimeModule.swift | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ios/AppDelegate.swift b/ios/AppDelegate.swift index a4b2f45a3425..125da0d943d1 100644 --- a/ios/AppDelegate.swift +++ b/ios/AppDelegate.swift @@ -20,7 +20,8 @@ class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate { var reactNativeFactory: RCTReactNativeFactory? override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { - UserDefaults.standard.set(Date().timeIntervalSince1970 * 1000, forKey: "AppStartTime") + let appStartTimePreferencesKey = "AppStartTime" + UserDefaults.standard.set(Date().timeIntervalSince1970 * 1000, forKey: appStartTimePreferencesKey) let delegate = ReactNativeDelegate() let factory = RCTReactNativeFactory(delegate: delegate) delegate.dependencyProvider = RCTAppDependencyProvider() diff --git a/modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift b/modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift index 691736ec029f..608902f72f53 100644 --- a/modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift +++ b/modules/ExpensifyNitroUtils/ios/appstarttime/HybridAppStartTimeModule.swift @@ -2,13 +2,15 @@ import NitroModules import Foundation final class HybridAppStartTimeModule: HybridAppStartTimeModuleSpec { + private static let appStartTimePreferencesKey = "AppStartTime" + public var memorySize: Int { MemoryLayout.size } func recordAppStartTime() { - UserDefaults.standard.set(Date().timeIntervalSince1970 * 1000, forKey: "AppStartTime") + UserDefaults.standard.set(Date().timeIntervalSince1970 * 1000, forKey: Self.appStartTimePreferencesKey) } var appStartTime: Double { - return UserDefaults.standard.double(forKey: "AppStartTime") + return UserDefaults.standard.double(forKey: Self.appStartTimePreferencesKey) } } From 66782479d1294d1742e37707cd048e9b2d972374 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 11:59:19 +0100 Subject: [PATCH 13/23] Update Mobile-Expensify submodule Co-Authored-By: Claude Sonnet 4.6 --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index d6ee136f8be9..cf10130ad784 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit d6ee136f8be9a5c9d3d60d94451fc2c22d1b98b1 +Subproject commit cf10130ad784016a57a11f42f4662c7af25a948f From 531199fd4003ee42c0339845af50db015f35af0f Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 13:00:10 +0100 Subject: [PATCH 14/23] Reset Mobile-Expensify submodule pointer to main Co-Authored-By: Claude Sonnet 4.6 --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index cc441dea586e..6d3ac7523c63 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit cc441dea586ed3cdfe3b0e6d694eb0d324a567ad +Subproject commit 6d3ac7523c634875c98010004232f2134f59700a From 38d9c0092cd2bb3f45ff46a84a09fcbaacb0480f Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 13:09:57 +0100 Subject: [PATCH 15/23] Revert index.ts to empty stub - Sentry setup is in platform-specific files Co-Authored-By: Claude Sonnet 4.6 --- src/setup/telemetry/index.ts | 43 +----------------------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/src/setup/telemetry/index.ts b/src/setup/telemetry/index.ts index 43fdcf1451e2..ef9251fdc22d 100644 --- a/src/setup/telemetry/index.ts +++ b/src/setup/telemetry/index.ts @@ -1,42 +1 @@ -import * as Sentry from '@sentry/react-native'; -import {Platform} from 'react-native'; -import {isDevelopment} from '@libs/Environment/Environment'; -import {startSpan} from '@libs/telemetry/activeSpans'; -import {browserProfilingIntegration, navigationIntegration, tracingIntegration, breadcrumbsIntegration, consoleIntegration} from '@libs/telemetry/integrations'; -import processBeforeSendTransactions from '@libs/telemetry/middlewares'; -import CONFIG from '@src/CONFIG'; -import CONST from '@src/CONST'; -import pkg from '../../../package.json'; -import makeDebugTransport from './debugTransport'; - -export default function (): void { - // With Sentry enabled in dev mode, profiling on iOS and Android does not work - // If you want to enable Sentry in dev, set ENABLE_SENTRY_ON_DEV=true in .env - // or comment out the condition below - if (isDevelopment() && !CONFIG.ENABLE_SENTRY_ON_DEV) { - return; - } - - const integrations = [navigationIntegration, tracingIntegration, browserProfilingIntegration, breadcrumbsIntegration, consoleIntegration].filter((integration) => !!integration); - - Sentry.init({ - dsn: CONFIG.SENTRY_DSN, - transport: isDevelopment() ? makeDebugTransport : undefined, - tracesSampleRate: 1.0, - // 1. Profiling for Android is currently disabled because it causes crashes sometimes. - // 2. When updating the profile sample rate, make sure it will not blow up our current limit in Sentry. - profilesSampleRate: Platform.OS === 'android' ? 0 : 0.3, - enableAutoPerformanceTracing: true, - enableUserInteractionTracing: true, - integrations, - environment: CONFIG.ENVIRONMENT, - release: `${pkg.name}@${pkg.version}`, - beforeSendTransaction: processBeforeSendTransactions, - enableLogs: true, - }); - - startSpan(CONST.TELEMETRY.SPAN_APP_STARTUP, { - name: CONST.TELEMETRY.SPAN_APP_STARTUP, - op: CONST.TELEMETRY.SPAN_APP_STARTUP, - }); -} +export default function (): void {} From 9f3192c6ada83dd13d5c3044b69f954d049f839f Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 14:51:33 +0100 Subject: [PATCH 16/23] Address AI reviewer comments on telemetry setup - Guard against 0 value from NitroModule (would backdate span to Unix epoch) - Use Log.warn instead of silent catch for NitroModule read failure - Add justification to eslint-disable comment in AppStartTimeModule spec Co-Authored-By: Claude Sonnet 4.6 --- .../src/specs/AppStartTimeModule.nitro.ts | 2 +- src/setup/telemetry/index.native.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts index 8479b01feceb..db7338e17552 100644 --- a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts +++ b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts @@ -1,6 +1,6 @@ import type {HybridObject} from 'react-native-nitro-modules'; -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- Nitro HybridObject specs require `interface` to extend HybridObject interface AppStartTimeModule extends HybridObject<{ios: 'swift'; android: 'kotlin'}> { /** * Records the app start time. This should be called as early as possible diff --git a/src/setup/telemetry/index.native.ts b/src/setup/telemetry/index.native.ts index 88032d12e163..a2a95a71f392 100644 --- a/src/setup/telemetry/index.native.ts +++ b/src/setup/telemetry/index.native.ts @@ -1,4 +1,5 @@ import {AppStartTimeNitroModule} from '@expensify/nitro-utils'; +import Log from '@libs/Log'; import {startSpan} from '@libs/telemetry/activeSpans'; import CONST from '@src/CONST'; import setupSentry from './setupSentry'; @@ -8,8 +9,10 @@ export default function (): void { let nativeAppStartTimeMs: number | undefined; try { - nativeAppStartTimeMs = AppStartTimeNitroModule.appStartTime; + const appStartTime = AppStartTimeNitroModule.appStartTime; + nativeAppStartTimeMs = appStartTime > 0 ? appStartTime : undefined; } catch (error) { + Log.warn('[Telemetry] Failed to read native app start time from NitroModule', {error}); nativeAppStartTimeMs = undefined; } From ca6e62abfab74b35eb5228fb4e1b702e072f475c Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 14:56:51 +0100 Subject: [PATCH 17/23] Remove redundant ?? undefined from startTime Co-Authored-By: Claude Sonnet 4.6 --- src/setup/telemetry/index.native.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setup/telemetry/index.native.ts b/src/setup/telemetry/index.native.ts index a2a95a71f392..9d092ac49c04 100644 --- a/src/setup/telemetry/index.native.ts +++ b/src/setup/telemetry/index.native.ts @@ -19,6 +19,6 @@ export default function (): void { startSpan(CONST.TELEMETRY.SPAN_APP_STARTUP, { name: CONST.TELEMETRY.SPAN_APP_STARTUP, op: CONST.TELEMETRY.SPAN_APP_STARTUP, - startTime: nativeAppStartTimeMs ?? undefined, + startTime: nativeAppStartTimeMs, }); } From 292d276870e340dcece679f9af07b27dd416e953 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 20 Feb 2026 15:06:53 +0100 Subject: [PATCH 18/23] Address AI reviewer comments on setupSentry and AppStartTimeModule spec - Restore breadcrumbsIntegration and consoleIntegration that were accidentally dropped in the setupSentry refactor - Add comment to recordAppStartTime() explaining it cannot be called from JS and that recording is done natively Co-Authored-By: Claude Sonnet 4.6 --- .../src/specs/AppStartTimeModule.nitro.ts | 8 ++++++-- src/setup/telemetry/setupSentry.ts | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts index db7338e17552..897a3a77fc20 100644 --- a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts +++ b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts @@ -3,8 +3,12 @@ import type {HybridObject} from 'react-native-nitro-modules'; // eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- Nitro HybridObject specs require `interface` to extend HybridObject interface AppStartTimeModule extends HybridObject<{ios: 'swift'; android: 'kotlin'}> { /** - * Records the app start time. This should be called as early as possible - * in the native app lifecycle (before React Native initializes). + * Records the app start time. + * NOTE: This method cannot be called from JS since it must run before React Native + * initializes. The actual recording is done natively — in MainApplication.onCreate() + * on Android and AppDelegate.didFinishLaunchingWithOptions() on iOS — by writing + * directly to SharedPreferences/UserDefaults. This method is kept in the spec for + * completeness and potential future use. */ recordAppStartTime(): void; diff --git a/src/setup/telemetry/setupSentry.ts b/src/setup/telemetry/setupSentry.ts index 2130a8ca6968..7a2db6ee92fe 100644 --- a/src/setup/telemetry/setupSentry.ts +++ b/src/setup/telemetry/setupSentry.ts @@ -1,7 +1,7 @@ import * as Sentry from '@sentry/react-native'; import {Platform} from 'react-native'; import {isDevelopment} from '@libs/Environment/Environment'; -import {browserProfilingIntegration, navigationIntegration, tracingIntegration} from '@libs/telemetry/integrations'; +import {breadcrumbsIntegration, browserProfilingIntegration, consoleIntegration, navigationIntegration, tracingIntegration} from '@libs/telemetry/integrations'; import processBeforeSendTransactions from '@libs/telemetry/middlewares'; import CONFIG from '@src/CONFIG'; import pkg from '../../../package.json'; @@ -14,7 +14,7 @@ function setupSentry(): void { return; } - const integrations = [navigationIntegration, tracingIntegration, browserProfilingIntegration].filter((integration) => !!integration); + const integrations = [navigationIntegration, tracingIntegration, browserProfilingIntegration, breadcrumbsIntegration, consoleIntegration].filter((integration) => !!integration); Sentry.init({ dsn: CONFIG.SENTRY_DSN, From 12938bb38ea1b6e70746f6d83668fc6fb68f98f5 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Mon, 23 Feb 2026 12:14:00 +0100 Subject: [PATCH 19/23] prettier fix --- modules/ExpensifyNitroUtils/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ExpensifyNitroUtils/src/index.ts b/modules/ExpensifyNitroUtils/src/index.ts index c286888b9bbd..5542986a2735 100644 --- a/modules/ExpensifyNitroUtils/src/index.ts +++ b/modules/ExpensifyNitroUtils/src/index.ts @@ -1,6 +1,6 @@ import {NitroModules} from 'react-native-nitro-modules'; -import type * as ContactsModuleSpec from './specs/ContactsModule.nitro'; import type AppStartTimeModule from './specs/AppStartTimeModule.nitro'; +import type * as ContactsModuleSpec from './specs/ContactsModule.nitro'; const ContactsNitroModule = NitroModules.createHybridObject('ContactsModule'); const AppStartTimeNitroModule = NitroModules.createHybridObject('AppStartTimeModule'); From bc4c361458285b935430fc928c06db227d9d47f0 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Tue, 24 Feb 2026 11:51:10 +0100 Subject: [PATCH 20/23] Add build_type Sentry tag to distinguish HybridApp vs standalone spans Co-Authored-By: Claude Sonnet 4.6 --- src/CONST/index.ts | 3 +++ src/setup/telemetry/setupSentry.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 72ede8cbdaae..0c7848fa89bc 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1774,6 +1774,9 @@ const CONST = { TAG_EXPENSE_HAS_RECEIPT: 'expense_has_receipt', TAG_EXPENSE_COMMAND: 'expense_command', TAG_EXPENSE_JSON_CODE: 'expense_json_code', + TAG_BUILD_TYPE: 'build_type', + BUILD_TYPE_HYBRID_APP: 'hybrid_app', + BUILD_TYPE_STANDALONE: 'standalone', // Span names SPAN_OPEN_REPORT: 'ManualOpenReport', SPAN_APP_STARTUP: 'ManualAppStartup', diff --git a/src/setup/telemetry/setupSentry.ts b/src/setup/telemetry/setupSentry.ts index 7a2db6ee92fe..ec0f042c8a95 100644 --- a/src/setup/telemetry/setupSentry.ts +++ b/src/setup/telemetry/setupSentry.ts @@ -4,6 +4,7 @@ import {isDevelopment} from '@libs/Environment/Environment'; import {breadcrumbsIntegration, browserProfilingIntegration, consoleIntegration, navigationIntegration, tracingIntegration} from '@libs/telemetry/integrations'; import processBeforeSendTransactions from '@libs/telemetry/middlewares'; import CONFIG from '@src/CONFIG'; +import CONST from '@src/CONST'; import pkg from '../../../package.json'; import makeDebugTransport from './debugTransport'; @@ -31,6 +32,8 @@ function setupSentry(): void { beforeSendTransaction: processBeforeSendTransactions, enableLogs: true, }); + + Sentry.setTag(CONST.TELEMETRY.TAG_BUILD_TYPE, CONFIG.IS_HYBRID_APP ? CONST.TELEMETRY.BUILD_TYPE_HYBRID_APP : CONST.TELEMETRY.BUILD_TYPE_STANDALONE); } export default setupSentry; From 4bed1846b9da326e0ec5f171b80de6d1fbe134fd Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 27 Feb 2026 16:11:09 +0100 Subject: [PATCH 21/23] pr fixes --- eslint.config.mjs | 7 +++++++ .../src/specs/AppStartTimeModule.nitro.ts | 17 ++++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 6cc65406f1d3..361e2b63b90a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -600,6 +600,13 @@ const config = defineConfig([ }, }, + { + files: ['modules/ExpensifyNitroUtils/src/**/*'], + rules: { + '@typescript-eslint/consistent-type-definitions': 'off', + }, + }, + globalIgnores([ '!**/.storybook', '!**/.github', diff --git a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts index 897a3a77fc20..f7aacafcb31c 100644 --- a/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts +++ b/modules/ExpensifyNitroUtils/src/specs/AppStartTimeModule.nitro.ts @@ -1,20 +1,11 @@ import type {HybridObject} from 'react-native-nitro-modules'; -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- Nitro HybridObject specs require `interface` to extend HybridObject interface AppStartTimeModule extends HybridObject<{ios: 'swift'; android: 'kotlin'}> { /** - * Records the app start time. - * NOTE: This method cannot be called from JS since it must run before React Native - * initializes. The actual recording is done natively — in MainApplication.onCreate() - * on Android and AppDelegate.didFinishLaunchingWithOptions() on iOS — by writing - * directly to SharedPreferences/UserDefaults. This method is kept in the spec for - * completeness and potential future use. - */ - recordAppStartTime(): void; - - /** - * Gets the recorded app start time in milliseconds since epoch. - * Returns 0 if recordAppStartTime() was never called. + * Gets the app start time in milliseconds since epoch. + * The native layer records this in MainApplication.onCreate() on Android + * and AppDelegate.didFinishLaunchingWithOptions() on iOS. + * Returns 0 if the start time was never recorded. */ readonly appStartTime: number; } From 0174bd776f2d5e4fbcebfa69b875ded94e9a5242 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 27 Feb 2026 16:20:30 +0100 Subject: [PATCH 22/23] ts error fix --- src/setup/telemetry/index.native.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setup/telemetry/index.native.ts b/src/setup/telemetry/index.native.ts index 9d092ac49c04..6de941cb40bd 100644 --- a/src/setup/telemetry/index.native.ts +++ b/src/setup/telemetry/index.native.ts @@ -9,7 +9,7 @@ export default function (): void { let nativeAppStartTimeMs: number | undefined; try { - const appStartTime = AppStartTimeNitroModule.appStartTime; + const appStartTime = (AppStartTimeNitroModule as {readonly appStartTime: number}).appStartTime; nativeAppStartTimeMs = appStartTime > 0 ? appStartTime : undefined; } catch (error) { Log.warn('[Telemetry] Failed to read native app start time from NitroModule', {error}); From 0053cef64d94c53deae4817aaf59ceb1eaf3155a Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Fri, 27 Feb 2026 16:33:06 +0100 Subject: [PATCH 23/23] Update Mobile-Expensify submodule to match main Co-Authored-By: Claude Sonnet 4.6 --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 0dbc7e13299f..4b42a1410a69 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 0dbc7e13299f65eaf911b6df5ea864f02fb4eb1f +Subproject commit 4b42a1410a69f339a947880222ffd0eedbdc0784