@rejourneyco/react-native 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/android/build.gradle.kts +135 -0
  2. package/android/consumer-rules.pro +10 -0
  3. package/android/proguard-rules.pro +1 -0
  4. package/android/src/main/AndroidManifest.xml +15 -0
  5. package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +2981 -0
  6. package/android/src/main/java/com/rejourney/capture/ANRHandler.kt +206 -0
  7. package/android/src/main/java/com/rejourney/capture/ActivityTracker.kt +98 -0
  8. package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +1553 -0
  9. package/android/src/main/java/com/rejourney/capture/CaptureHeuristics.kt +375 -0
  10. package/android/src/main/java/com/rejourney/capture/CrashHandler.kt +153 -0
  11. package/android/src/main/java/com/rejourney/capture/MotionEvent.kt +215 -0
  12. package/android/src/main/java/com/rejourney/capture/SegmentUploader.kt +512 -0
  13. package/android/src/main/java/com/rejourney/capture/VideoEncoder.kt +773 -0
  14. package/android/src/main/java/com/rejourney/capture/ViewHierarchyScanner.kt +633 -0
  15. package/android/src/main/java/com/rejourney/capture/ViewSerializer.kt +286 -0
  16. package/android/src/main/java/com/rejourney/core/Constants.kt +117 -0
  17. package/android/src/main/java/com/rejourney/core/Logger.kt +93 -0
  18. package/android/src/main/java/com/rejourney/core/Types.kt +124 -0
  19. package/android/src/main/java/com/rejourney/lifecycle/SessionLifecycleService.kt +162 -0
  20. package/android/src/main/java/com/rejourney/network/DeviceAuthManager.kt +747 -0
  21. package/android/src/main/java/com/rejourney/network/HttpClientProvider.kt +16 -0
  22. package/android/src/main/java/com/rejourney/network/NetworkMonitor.kt +272 -0
  23. package/android/src/main/java/com/rejourney/network/UploadManager.kt +1363 -0
  24. package/android/src/main/java/com/rejourney/network/UploadWorker.kt +492 -0
  25. package/android/src/main/java/com/rejourney/privacy/PrivacyMask.kt +645 -0
  26. package/android/src/main/java/com/rejourney/touch/GestureClassifier.kt +233 -0
  27. package/android/src/main/java/com/rejourney/touch/KeyboardTracker.kt +158 -0
  28. package/android/src/main/java/com/rejourney/touch/TextInputTracker.kt +181 -0
  29. package/android/src/main/java/com/rejourney/touch/TouchInterceptor.kt +591 -0
  30. package/android/src/main/java/com/rejourney/utils/EventBuffer.kt +284 -0
  31. package/android/src/main/java/com/rejourney/utils/OEMDetector.kt +154 -0
  32. package/android/src/main/java/com/rejourney/utils/PerfTiming.kt +235 -0
  33. package/android/src/main/java/com/rejourney/utils/Telemetry.kt +297 -0
  34. package/android/src/main/java/com/rejourney/utils/WindowUtils.kt +84 -0
  35. package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +187 -0
  36. package/android/src/newarch/java/com/rejourney/RejourneyPackage.kt +40 -0
  37. package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +218 -0
  38. package/android/src/oldarch/java/com/rejourney/RejourneyPackage.kt +23 -0
  39. package/ios/Capture/RJANRHandler.h +42 -0
  40. package/ios/Capture/RJANRHandler.m +328 -0
  41. package/ios/Capture/RJCaptureEngine.h +275 -0
  42. package/ios/Capture/RJCaptureEngine.m +2062 -0
  43. package/ios/Capture/RJCaptureHeuristics.h +80 -0
  44. package/ios/Capture/RJCaptureHeuristics.m +903 -0
  45. package/ios/Capture/RJCrashHandler.h +46 -0
  46. package/ios/Capture/RJCrashHandler.m +313 -0
  47. package/ios/Capture/RJMotionEvent.h +183 -0
  48. package/ios/Capture/RJMotionEvent.m +183 -0
  49. package/ios/Capture/RJPerformanceManager.h +100 -0
  50. package/ios/Capture/RJPerformanceManager.m +373 -0
  51. package/ios/Capture/RJPixelBufferDownscaler.h +42 -0
  52. package/ios/Capture/RJPixelBufferDownscaler.m +85 -0
  53. package/ios/Capture/RJSegmentUploader.h +146 -0
  54. package/ios/Capture/RJSegmentUploader.m +778 -0
  55. package/ios/Capture/RJVideoEncoder.h +247 -0
  56. package/ios/Capture/RJVideoEncoder.m +1036 -0
  57. package/ios/Capture/RJViewControllerTracker.h +73 -0
  58. package/ios/Capture/RJViewControllerTracker.m +508 -0
  59. package/ios/Capture/RJViewHierarchyScanner.h +215 -0
  60. package/ios/Capture/RJViewHierarchyScanner.m +1464 -0
  61. package/ios/Capture/RJViewSerializer.h +119 -0
  62. package/ios/Capture/RJViewSerializer.m +498 -0
  63. package/ios/Core/RJConstants.h +124 -0
  64. package/ios/Core/RJConstants.m +88 -0
  65. package/ios/Core/RJLifecycleManager.h +85 -0
  66. package/ios/Core/RJLifecycleManager.m +308 -0
  67. package/ios/Core/RJLogger.h +61 -0
  68. package/ios/Core/RJLogger.m +211 -0
  69. package/ios/Core/RJTypes.h +176 -0
  70. package/ios/Core/RJTypes.m +66 -0
  71. package/ios/Core/Rejourney.h +64 -0
  72. package/ios/Core/Rejourney.mm +2495 -0
  73. package/ios/Network/RJDeviceAuthManager.h +94 -0
  74. package/ios/Network/RJDeviceAuthManager.m +967 -0
  75. package/ios/Network/RJNetworkMonitor.h +68 -0
  76. package/ios/Network/RJNetworkMonitor.m +267 -0
  77. package/ios/Network/RJRetryManager.h +73 -0
  78. package/ios/Network/RJRetryManager.m +325 -0
  79. package/ios/Network/RJUploadManager.h +267 -0
  80. package/ios/Network/RJUploadManager.m +2296 -0
  81. package/ios/Privacy/RJPrivacyMask.h +163 -0
  82. package/ios/Privacy/RJPrivacyMask.m +922 -0
  83. package/ios/Rejourney.h +63 -0
  84. package/ios/Touch/RJGestureClassifier.h +130 -0
  85. package/ios/Touch/RJGestureClassifier.m +333 -0
  86. package/ios/Touch/RJTouchInterceptor.h +169 -0
  87. package/ios/Touch/RJTouchInterceptor.m +772 -0
  88. package/ios/Utils/RJEventBuffer.h +112 -0
  89. package/ios/Utils/RJEventBuffer.m +358 -0
  90. package/ios/Utils/RJGzipUtils.h +33 -0
  91. package/ios/Utils/RJGzipUtils.m +89 -0
  92. package/ios/Utils/RJKeychainManager.h +48 -0
  93. package/ios/Utils/RJKeychainManager.m +111 -0
  94. package/ios/Utils/RJPerfTiming.h +209 -0
  95. package/ios/Utils/RJPerfTiming.m +264 -0
  96. package/ios/Utils/RJTelemetry.h +92 -0
  97. package/ios/Utils/RJTelemetry.m +320 -0
  98. package/ios/Utils/RJWindowUtils.h +66 -0
  99. package/ios/Utils/RJWindowUtils.m +133 -0
  100. package/lib/commonjs/NativeRejourney.js +40 -0
  101. package/lib/commonjs/components/Mask.js +79 -0
  102. package/lib/commonjs/index.js +1381 -0
  103. package/lib/commonjs/sdk/autoTracking.js +1259 -0
  104. package/lib/commonjs/sdk/constants.js +151 -0
  105. package/lib/commonjs/sdk/errorTracking.js +199 -0
  106. package/lib/commonjs/sdk/index.js +50 -0
  107. package/lib/commonjs/sdk/metricsTracking.js +204 -0
  108. package/lib/commonjs/sdk/navigation.js +151 -0
  109. package/lib/commonjs/sdk/networkInterceptor.js +412 -0
  110. package/lib/commonjs/sdk/utils.js +363 -0
  111. package/lib/commonjs/types/expo-router.d.js +2 -0
  112. package/lib/commonjs/types/index.js +2 -0
  113. package/lib/module/NativeRejourney.js +38 -0
  114. package/lib/module/components/Mask.js +72 -0
  115. package/lib/module/index.js +1284 -0
  116. package/lib/module/sdk/autoTracking.js +1233 -0
  117. package/lib/module/sdk/constants.js +145 -0
  118. package/lib/module/sdk/errorTracking.js +189 -0
  119. package/lib/module/sdk/index.js +12 -0
  120. package/lib/module/sdk/metricsTracking.js +187 -0
  121. package/lib/module/sdk/navigation.js +143 -0
  122. package/lib/module/sdk/networkInterceptor.js +401 -0
  123. package/lib/module/sdk/utils.js +342 -0
  124. package/lib/module/types/expo-router.d.js +2 -0
  125. package/lib/module/types/index.js +2 -0
  126. package/lib/typescript/NativeRejourney.d.ts +147 -0
  127. package/lib/typescript/components/Mask.d.ts +39 -0
  128. package/lib/typescript/index.d.ts +117 -0
  129. package/lib/typescript/sdk/autoTracking.d.ts +204 -0
  130. package/lib/typescript/sdk/constants.d.ts +120 -0
  131. package/lib/typescript/sdk/errorTracking.d.ts +32 -0
  132. package/lib/typescript/sdk/index.d.ts +9 -0
  133. package/lib/typescript/sdk/metricsTracking.d.ts +58 -0
  134. package/lib/typescript/sdk/navigation.d.ts +33 -0
  135. package/lib/typescript/sdk/networkInterceptor.d.ts +47 -0
  136. package/lib/typescript/sdk/utils.d.ts +148 -0
  137. package/lib/typescript/types/index.d.ts +624 -0
  138. package/package.json +102 -0
  139. package/rejourney.podspec +21 -0
  140. package/src/NativeRejourney.ts +165 -0
  141. package/src/components/Mask.tsx +80 -0
  142. package/src/index.ts +1459 -0
  143. package/src/sdk/autoTracking.ts +1373 -0
  144. package/src/sdk/constants.ts +134 -0
  145. package/src/sdk/errorTracking.ts +231 -0
  146. package/src/sdk/index.ts +11 -0
  147. package/src/sdk/metricsTracking.ts +232 -0
  148. package/src/sdk/navigation.ts +157 -0
  149. package/src/sdk/networkInterceptor.ts +440 -0
  150. package/src/sdk/utils.ts +369 -0
  151. package/src/types/expo-router.d.ts +7 -0
  152. package/src/types/index.ts +739 -0
@@ -0,0 +1,111 @@
1
+ //
2
+ // RJKeychainManager.m
3
+ // Rejourney
4
+ //
5
+ // Secure Keychain storage implementation.
6
+ //
7
+ // Copyright (c) 2026 Rejourney
8
+ //
9
+
10
+ #import "RJKeychainManager.h"
11
+ #import "../Core/RJLogger.h"
12
+ #import <Security/Security.h>
13
+
14
+ static NSString *const kRJKeychainServiceName = @"com.rejourney.sdk";
15
+
16
+ @implementation RJKeychainManager
17
+
18
+ #pragma mark - Singleton
19
+
20
+ + (instancetype)sharedManager {
21
+ static RJKeychainManager *instance = nil;
22
+ static dispatch_once_t onceToken;
23
+ dispatch_once(&onceToken, ^{
24
+ instance = [[self alloc] init];
25
+ });
26
+ return instance;
27
+ }
28
+
29
+ #pragma mark - Query Building
30
+
31
+ - (NSMutableDictionary *)baseQueryForKey:(NSString *)key {
32
+ return [@{
33
+ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
34
+ (__bridge id)kSecAttrService : kRJKeychainServiceName,
35
+ (__bridge id)kSecAttrAccount : key,
36
+ (__bridge id)kSecAttrAccessible :
37
+ (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
38
+ } mutableCopy];
39
+ }
40
+
41
+ #pragma mark - Storage Operations
42
+
43
+ - (BOOL)setString:(NSString *)value forKey:(NSString *)key {
44
+ if (!value || !key)
45
+ return NO;
46
+
47
+
48
+ [self deleteValueForKey:key];
49
+
50
+ NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
51
+ if (!valueData)
52
+ return NO;
53
+
54
+ NSMutableDictionary *query = [self baseQueryForKey:key];
55
+ query[(__bridge id)kSecValueData] = valueData;
56
+
57
+ OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
58
+
59
+ if (status == errSecSuccess) {
60
+ RJLogDebug(@"Keychain: Stored value for key '%@'", key);
61
+ return YES;
62
+ } else {
63
+ RJLogWarning(@"Keychain: Failed to store value for key '%@' (status: %d)",
64
+ key, (int)status);
65
+ return NO;
66
+ }
67
+ }
68
+
69
+ - (nullable NSString *)stringForKey:(NSString *)key {
70
+ if (!key)
71
+ return nil;
72
+
73
+ NSMutableDictionary *query = [self baseQueryForKey:key];
74
+ query[(__bridge id)kSecReturnData] = @YES;
75
+ query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
76
+
77
+ CFDataRef dataRef = NULL;
78
+ OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query,
79
+ (CFTypeRef *)&dataRef);
80
+
81
+ if (status == errSecSuccess && dataRef) {
82
+ NSData *data = (__bridge_transfer NSData *)dataRef;
83
+ return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
84
+ }
85
+
86
+ return nil;
87
+ }
88
+
89
+ - (BOOL)deleteValueForKey:(NSString *)key {
90
+ if (!key)
91
+ return NO;
92
+
93
+ NSMutableDictionary *query = [self baseQueryForKey:key];
94
+ OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
95
+
96
+ return status == errSecSuccess || status == errSecItemNotFound;
97
+ }
98
+
99
+ - (void)clearAll {
100
+ NSDictionary *query = @{
101
+ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
102
+ (__bridge id)kSecAttrService : kRJKeychainServiceName
103
+ };
104
+
105
+ OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
106
+ if (status == errSecSuccess) {
107
+ RJLogDebug(@"Keychain: Cleared all Rejourney items");
108
+ }
109
+ }
110
+
111
+ @end
@@ -0,0 +1,209 @@
1
+ //
2
+ // RJPerfTiming.h
3
+ // Rejourney
4
+ //
5
+ // Wall-clock CPU timing using mach_absolute_time() with in-memory aggregation.
6
+ // Provides µs-level timing for internal SDK performance validation.
7
+ //
8
+ // Usage:
9
+ // - Enable by defining RJ_PERF=1 at compile time
10
+ // - Accumulates metrics in-memory, dumps periodically (every 5s or 100 frames)
11
+ // - Extremely low overhead (~20-30ns per timing call)
12
+ // - Works in release builds
13
+ //
14
+ // Licensed under the Apache License, Version 2.0 (the "License");
15
+ // you may not use this file except in compliance with the License.
16
+ // You may obtain a copy of the License at
17
+ //
18
+ // http://www.apache.org/licenses/LICENSE-2.0
19
+ //
20
+ // Unless required by applicable law or agreed to in writing, software
21
+ // distributed under the License is distributed on an "AS IS" BASIS,
22
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
+ // See the License for the specific language governing permissions and
24
+ // limitations under the License.
25
+ //
26
+ // Copyright (c) 2026 Rejourney
27
+ //
28
+
29
+ #import <Foundation/Foundation.h>
30
+
31
+ NS_ASSUME_NONNULL_BEGIN
32
+
33
+ // ============================================================================
34
+ // COMPILE-TIME SWITCH
35
+ // Define RJ_PERF=1 in your build settings to enable performance timing
36
+ // Ship production with RJ_PERF=0 or undefined
37
+ // ============================================================================
38
+ #ifndef RJ_PERF
39
+ // Force enable for testing - change to 0 for production
40
+ #define RJ_PERF 1
41
+ #endif
42
+
43
+ // ============================================================================
44
+ // TIMING MACROS (zero-cost when disabled)
45
+ // ============================================================================
46
+ #if RJ_PERF
47
+
48
+ /// Start timing a section. Call at the beginning of the code block to time.
49
+ #define RJ_TIME_START uint64_t __rj_t0 = rj_perf_now()
50
+
51
+ /// End timing and accumulate to the specified metric.
52
+ /// @param metric One of: RJPerfMetricFrame, RJPerfMetricScreenshot, etc.
53
+ #define RJ_TIME_END(metric) rj_perf_record(metric, __rj_t0, rj_perf_now())
54
+
55
+ /// Start timing with a custom variable name (for nested timing).
56
+ #define RJ_TIME_START_NAMED(name) uint64_t __rj_t0_##name = rj_perf_now()
57
+
58
+ /// End timing with a custom variable name.
59
+ #define RJ_TIME_END_NAMED(name, metric) \
60
+ rj_perf_record(metric, __rj_t0_##name, rj_perf_now())
61
+
62
+ /// Dump metrics if enough time has passed (call periodically from main loop).
63
+ #define RJ_PERF_DUMP_IF_NEEDED() rj_perf_dump_if_needed()
64
+
65
+ /// Force dump metrics immediately.
66
+ #define RJ_PERF_DUMP() rj_perf_dump()
67
+
68
+ /// Reset all metrics.
69
+ #define RJ_PERF_RESET() rj_perf_reset()
70
+
71
+ #else
72
+
73
+ // No-op when disabled
74
+ #define RJ_TIME_START
75
+ #define RJ_TIME_END(metric)
76
+ #define RJ_TIME_START_NAMED(name)
77
+ #define RJ_TIME_END_NAMED(name, metric)
78
+ #define RJ_PERF_DUMP_IF_NEEDED()
79
+ #define RJ_PERF_DUMP()
80
+ #define RJ_PERF_RESET()
81
+
82
+ #endif
83
+
84
+ // ============================================================================
85
+ // METRIC TYPES
86
+ // ============================================================================
87
+
88
+ /// Performance metrics that can be tracked.
89
+ typedef NS_ENUM(NSInteger, RJPerfMetric) {
90
+ /// Total frame processing time (screenshot + encode + upload)
91
+ RJPerfMetricFrame = 0,
92
+
93
+ /// Screenshot capture time (UIGraphics rendering)
94
+ RJPerfMetricScreenshot,
95
+
96
+ /// Raw Core Animation/Graphics rendering time (layer.render or
97
+ /// drawViewHierarchy)
98
+ RJPerfMetricRender,
99
+
100
+ /// Privacy mask drawing time
101
+ RJPerfMetricPrivacyMask,
102
+
103
+ /// View hierarchy scanning time
104
+ RJPerfMetricViewScan,
105
+
106
+ /// View hierarchy serialization time
107
+ RJPerfMetricViewSerialize,
108
+
109
+ /// Video encoding time (H.264 compression)
110
+ RJPerfMetricEncode,
111
+
112
+ /// Pixel buffer creation time (UIImage -> CVPixelBuffer)
113
+ RJPerfMetricPixelBuffer,
114
+
115
+ /// Downscaling time (vImage)
116
+ RJPerfMetricDownscale,
117
+
118
+ /// Buffer allocation time (CVPixelBufferPool)
119
+ RJPerfMetricBufferAlloc,
120
+
121
+ /// Encoder append time (pixel buffer -> H.264)
122
+ RJPerfMetricEncodeAppend,
123
+
124
+ /// Segment upload time (network)
125
+ RJPerfMetricUpload,
126
+
127
+ /// Number of metric types (keep last)
128
+ RJPerfMetricCount
129
+ };
130
+
131
+ // ============================================================================
132
+ // C INTERFACE (for maximum performance)
133
+ // ============================================================================
134
+
135
+ #if RJ_PERF
136
+
137
+ /// Get current timestamp (mach_absolute_time).
138
+ FOUNDATION_EXPORT uint64_t rj_perf_now(void);
139
+
140
+ /// Record a timing measurement.
141
+ /// @param metric The metric to record to
142
+ /// @param start Start timestamp from rj_perf_now()
143
+ /// @param end End timestamp from rj_perf_now()
144
+ FOUNDATION_EXPORT void rj_perf_record(RJPerfMetric metric, uint64_t start,
145
+ uint64_t end);
146
+
147
+ /// Dump metrics if more than 5 seconds have passed since last dump.
148
+ FOUNDATION_EXPORT void rj_perf_dump_if_needed(void);
149
+
150
+ /// Force dump metrics immediately.
151
+ FOUNDATION_EXPORT void rj_perf_dump(void);
152
+
153
+ /// Reset all accumulated metrics.
154
+ FOUNDATION_EXPORT void rj_perf_reset(void);
155
+
156
+ /// Get a snapshot of current metrics (for programmatic access).
157
+ /// Returns dictionary with avg/max/count for each metric.
158
+ FOUNDATION_EXPORT
159
+ NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *
160
+ rj_perf_snapshot(void);
161
+
162
+ #endif
163
+
164
+ // ============================================================================
165
+ // OBJECTIVE-C INTERFACE (for convenience)
166
+ // ============================================================================
167
+
168
+ /**
169
+ * RJPerfTiming provides wall-clock CPU timing with in-memory aggregation.
170
+ *
171
+ * This class is a thin wrapper around the C functions for ObjC convenience.
172
+ * For hot paths, use the C macros directly for best performance.
173
+ *
174
+ * ## Example Usage
175
+ *
176
+ * ```objc
177
+ * // In a hot loop:
178
+ * RJ_TIME_START;
179
+ * [self doExpensiveWork];
180
+ * RJ_TIME_END(RJPerfMetricFrame);
181
+ *
182
+ * // Periodically (e.g., in capture timer):
183
+ * RJ_PERF_DUMP_IF_NEEDED();
184
+ *
185
+ * // Or get metrics programmatically:
186
+ * NSDictionary *metrics = [RJPerfTiming snapshot];
187
+ * ```
188
+ */
189
+ @interface RJPerfTiming : NSObject
190
+
191
+ /// Whether performance timing is enabled (compile-time).
192
+ + (BOOL)isEnabled;
193
+
194
+ /// Get current metrics snapshot.
195
+ + (nullable NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *)
196
+ snapshot;
197
+
198
+ /// Force dump metrics to console.
199
+ + (void)dump;
200
+
201
+ /// Reset all metrics.
202
+ + (void)reset;
203
+
204
+ /// Get human-readable name for a metric.
205
+ + (NSString *)nameForMetric:(RJPerfMetric)metric;
206
+
207
+ @end
208
+
209
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,264 @@
1
+ //
2
+ // RJPerfTiming.m
3
+ // Rejourney
4
+ //
5
+ // Wall-clock CPU timing implementation using mach_absolute_time().
6
+ //
7
+ // Licensed under the Apache License, Version 2.0 (the "License");
8
+ // you may not use this file except in compliance with the License.
9
+ // You may obtain a copy of the License at
10
+ //
11
+ // http://www.apache.org/licenses/LICENSE-2.0
12
+ //
13
+ // Unless required by applicable law or agreed to in writing, software
14
+ // distributed under the License is distributed on an "AS IS" BASIS,
15
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ // See the License for the specific language governing permissions and
17
+ // limitations under the License.
18
+ //
19
+ // Copyright (c) 2026 Rejourney
20
+ //
21
+
22
+ #import "RJPerfTiming.h"
23
+ #import "../Core/RJLogger.h"
24
+ #import <mach/mach_time.h>
25
+ #import <os/lock.h>
26
+
27
+ #if RJ_PERF
28
+
29
+ static mach_timebase_info_data_t rj_timebase;
30
+
31
+ static BOOL rj_perf_initialized = NO;
32
+
33
+ __attribute__((constructor)) static void RJPerfTimingInit(void) {
34
+ mach_timebase_info(&rj_timebase);
35
+ rj_perf_initialized = YES;
36
+ RJLogInfo(@"[Rejourney PERF] ✅ Performance timing initialized (RJ_PERF=1)");
37
+ }
38
+
39
+ static inline double rj_ms(uint64_t start, uint64_t end) {
40
+ return (double)(end - start) * rj_timebase.numer / rj_timebase.denom /
41
+ 1000000.0;
42
+ }
43
+
44
+ static const char *const rj_metric_names[] = {
45
+ "frame_total", "screenshot_ui", "render_draw", "privacy_mask",
46
+ "view_scan", "view_serialize", "encode_h264", "pixel_buffer",
47
+ "downscale", "buffer_alloc", "encode_append", "upload_net"};
48
+
49
+ static double rj_totals[RJPerfMetricCount] = {0};
50
+
51
+ static double rj_maxes[RJPerfMetricCount] = {0};
52
+
53
+ static uint64_t rj_counts[RJPerfMetricCount] = {0};
54
+
55
+ static uint64_t rj_last_dump = 0;
56
+
57
+ static const double RJ_DUMP_INTERVAL_MS = 5000.0; // 5s
58
+
59
+ static const uint64_t RJ_MIN_SAMPLES = 5;
60
+
61
+ static os_unfair_lock rj_perf_lock = OS_UNFAIR_LOCK_INIT;
62
+
63
+ uint64_t rj_perf_now(void) { return mach_absolute_time(); }
64
+
65
+ void rj_perf_record(RJPerfMetric metric, uint64_t start, uint64_t end) {
66
+ if (metric < 0 || metric >= RJPerfMetricCount)
67
+ return;
68
+
69
+ double ms = rj_ms(start, end);
70
+
71
+ // IMMEDIATE LOGGING (Request by user)
72
+ // Pinpoints main thread blockers
73
+ BOOL isMain = [NSThread isMainThread];
74
+ const char *threadName = isMain ? "MAIN" : "BG";
75
+
76
+ // Log critical main thread hitches (> 4ms) visibly
77
+ // Or just log everything as requested ("intense logging")
78
+ // Using specific emoji to highlight potential issues
79
+ if (isMain && ms > 4.0) {
80
+ RJLogInfo(@"[RJ-PERF] ⚠️ [%s] %s: %.2fms", threadName, rj_metric_names[metric],
81
+ ms);
82
+ } else {
83
+ RJLogInfo(@"[RJ-PERF] [%s] %s: %.2fms", threadName, rj_metric_names[metric],
84
+ ms);
85
+ }
86
+
87
+ os_unfair_lock_lock(&rj_perf_lock);
88
+ rj_counts[metric]++;
89
+ rj_totals[metric] += ms;
90
+ if (ms > rj_maxes[metric]) {
91
+ rj_maxes[metric] = ms;
92
+ }
93
+ os_unfair_lock_unlock(&rj_perf_lock);
94
+ }
95
+
96
+ void rj_perf_dump_if_needed(void) {
97
+ uint64_t now = rj_perf_now();
98
+
99
+ if (rj_last_dump != 0 && rj_ms(rj_last_dump, now) < RJ_DUMP_INTERVAL_MS) {
100
+ return;
101
+ }
102
+
103
+ os_unfair_lock_lock(&rj_perf_lock);
104
+
105
+ if (rj_last_dump != 0 && rj_ms(rj_last_dump, now) < RJ_DUMP_INTERVAL_MS) {
106
+ os_unfair_lock_unlock(&rj_perf_lock);
107
+ return;
108
+ }
109
+
110
+ uint64_t total_samples = 0;
111
+ for (int i = 0; i < RJPerfMetricCount; i++) {
112
+ total_samples += rj_counts[i];
113
+ }
114
+
115
+ if (total_samples < RJ_MIN_SAMPLES) {
116
+ os_unfair_lock_unlock(&rj_perf_lock);
117
+ return;
118
+ }
119
+
120
+ rj_last_dump = now;
121
+
122
+ NSMutableString *log =
123
+ [NSMutableString stringWithString:@"[Rejourney PERF SUMMARY]"];
124
+
125
+ for (int i = 0; i < RJPerfMetricCount; i++) {
126
+ if (rj_counts[i] > 0) {
127
+ double avg = rj_totals[i] / rj_counts[i];
128
+ [log appendFormat:@" %s=%llu/%.1f/%.1fms", rj_metric_names[i],
129
+ (unsigned long long)rj_counts[i], avg, rj_maxes[i]];
130
+ }
131
+ }
132
+
133
+ os_unfair_lock_unlock(&rj_perf_lock);
134
+
135
+ RJLogInfo(@"%@", log);
136
+ }
137
+
138
+ void rj_perf_dump(void) {
139
+ os_unfair_lock_lock(&rj_perf_lock);
140
+
141
+ uint64_t total_samples = 0;
142
+ for (int i = 0; i < RJPerfMetricCount; i++) {
143
+ total_samples += rj_counts[i];
144
+ }
145
+
146
+ if (total_samples == 0) {
147
+ os_unfair_lock_unlock(&rj_perf_lock);
148
+ RJLogInfo(@"[Rejourney PERF] No samples collected");
149
+ return;
150
+ }
151
+
152
+ NSMutableString *log = [NSMutableString stringWithString:@"\n"];
153
+ [log appendString:@"╔════════════════════════════════════════════════════════"
154
+ @"══════╗\n"];
155
+ [log appendString:@"║ REJOURNEY SDK PERFORMANCE METRICS (ms) "
156
+ @" ║\n"];
157
+ [log appendString:@"╠════════════════════════════════════════════════════════"
158
+ @"══════╣\n"];
159
+ [log appendFormat:@"║ %-16s │ %8s │ %10s │ %10s ║\n", "METRIC", "COUNT",
160
+ "AVG (ms)", "MAX (ms)"];
161
+ [log appendString:@"╠════════════════════════════════════════════════════════"
162
+ @"══════╣\n"];
163
+
164
+ for (int i = 0; i < RJPerfMetricCount; i++) {
165
+ if (rj_counts[i] > 0) {
166
+ double avg = rj_totals[i] / rj_counts[i];
167
+ [log appendFormat:@"║ %-16s │ %8llu │ %10.2f │ %10.2f ║\n",
168
+ rj_metric_names[i], (unsigned long long)rj_counts[i],
169
+ avg, rj_maxes[i]];
170
+ }
171
+ }
172
+
173
+ [log appendString:
174
+ @"╚══════════════════════════════════════════════════════════════╝"];
175
+
176
+ rj_last_dump = rj_perf_now();
177
+
178
+ os_unfair_lock_unlock(&rj_perf_lock);
179
+
180
+ RJLogInfo(@"%@", log);
181
+ }
182
+
183
+ void rj_perf_reset(void) {
184
+ os_unfair_lock_lock(&rj_perf_lock);
185
+
186
+ for (int i = 0; i < RJPerfMetricCount; i++) {
187
+ rj_totals[i] = 0;
188
+ rj_maxes[i] = 0;
189
+ rj_counts[i] = 0;
190
+ }
191
+ rj_last_dump = 0;
192
+
193
+ os_unfair_lock_unlock(&rj_perf_lock);
194
+
195
+ RJLogInfo(@"[Rejourney PERF] Metrics reset");
196
+ }
197
+
198
+ NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *
199
+ rj_perf_snapshot(void) {
200
+ NSMutableDictionary *result = [NSMutableDictionary dictionary];
201
+
202
+ os_unfair_lock_lock(&rj_perf_lock);
203
+
204
+ for (int i = 0; i < RJPerfMetricCount; i++) {
205
+ if (rj_counts[i] > 0) {
206
+ NSString *name = [NSString stringWithUTF8String:rj_metric_names[i]];
207
+ double avg = rj_totals[i] / rj_counts[i];
208
+
209
+ result[name] = @{
210
+ @"count" : @(rj_counts[i]),
211
+ @"avg_us" : @(avg),
212
+ @"max_us" : @(rj_maxes[i]),
213
+ @"total_us" : @(rj_totals[i])
214
+ };
215
+ }
216
+ }
217
+
218
+ os_unfair_lock_unlock(&rj_perf_lock);
219
+
220
+ return [result copy];
221
+ }
222
+
223
+ #endif
224
+
225
+ @implementation RJPerfTiming
226
+
227
+ + (BOOL)isEnabled {
228
+ #if RJ_PERF
229
+ return YES;
230
+ #else
231
+ return NO;
232
+ #endif
233
+ }
234
+
235
+ + (NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *)snapshot {
236
+ #if RJ_PERF
237
+ return rj_perf_snapshot();
238
+ #else
239
+ return nil;
240
+ #endif
241
+ }
242
+
243
+ + (void)dump {
244
+ #if RJ_PERF
245
+ rj_perf_dump();
246
+ #endif
247
+ }
248
+
249
+ + (void)reset {
250
+ #if RJ_PERF
251
+ rj_perf_reset();
252
+ #endif
253
+ }
254
+
255
+ + (NSString *)nameForMetric:(RJPerfMetric)metric {
256
+ #if RJ_PERF
257
+ if (metric >= 0 && metric < RJPerfMetricCount) {
258
+ return [NSString stringWithUTF8String:rj_metric_names[metric]];
259
+ }
260
+ #endif
261
+ return @"unknown";
262
+ }
263
+
264
+ @end
@@ -0,0 +1,92 @@
1
+ //
2
+ // RJTelemetry.h
3
+ // Rejourney SDK Telemetry
4
+ //
5
+ // Provides observability metrics for SDK health monitoring.
6
+ // Tracks upload success rates, retry counts, circuit breaker events, and memory
7
+ // pressure.
8
+ //
9
+
10
+ #import <Foundation/Foundation.h>
11
+
12
+ NS_ASSUME_NONNULL_BEGIN
13
+
14
+ /// Telemetry event types
15
+ typedef NS_ENUM(NSInteger, RJTelemetryEventType) {
16
+ RJTelemetryEventUploadSuccess,
17
+ RJTelemetryEventUploadFailure,
18
+ RJTelemetryEventRetryAttempt,
19
+ RJTelemetryEventCircuitBreakerOpen,
20
+ RJTelemetryEventCircuitBreakerClose,
21
+ RJTelemetryEventMemoryPressureEviction,
22
+ RJTelemetryEventOfflineQueuePersist,
23
+ RJTelemetryEventOfflineQueueRestore,
24
+ RJTelemetryEventSessionStart,
25
+ RJTelemetryEventSessionEnd,
26
+ RJTelemetryEventCrashDetected,
27
+ RJTelemetryEventTokenRefresh,
28
+ };
29
+
30
+ /// SDK health metrics snapshot
31
+ @interface RJTelemetryMetrics : NSObject
32
+
33
+ @property(nonatomic, assign, readonly) NSInteger uploadSuccessCount;
34
+ @property(nonatomic, assign, readonly) NSInteger uploadFailureCount;
35
+ @property(nonatomic, assign, readonly) NSInteger retryAttemptCount;
36
+ @property(nonatomic, assign, readonly) NSInteger circuitBreakerOpenCount;
37
+ @property(nonatomic, assign, readonly) NSInteger memoryEvictionCount;
38
+ @property(nonatomic, assign, readonly) NSInteger offlinePersistCount;
39
+ @property(nonatomic, assign, readonly) NSInteger sessionStartCount;
40
+ @property(nonatomic, assign, readonly) NSInteger crashCount;
41
+ @property(nonatomic, assign, readonly) NSInteger anrCount;
42
+ @property(nonatomic, assign, readonly) double uploadSuccessRate;
43
+ @property(nonatomic, assign, readonly) NSTimeInterval avgUploadDurationMs;
44
+ @property(nonatomic, assign, readonly) NSInteger currentQueueDepth;
45
+ @property(nonatomic, strong, readonly) NSDate *lastUploadTime;
46
+ @property(nonatomic, strong, readonly) NSDate *lastRetryTime;
47
+
48
+ @end
49
+
50
+ /// Telemetry collector for SDK observability
51
+ @interface RJTelemetry : NSObject
52
+
53
+ /// Shared instance
54
+ + (instancetype)sharedInstance;
55
+
56
+ /// Record a telemetry event
57
+ - (void)recordEvent:(RJTelemetryEventType)eventType;
58
+
59
+ /// Record an event with additional context
60
+ - (void)recordEvent:(RJTelemetryEventType)eventType
61
+ metadata:(nullable NSDictionary<NSString *, id> *)metadata;
62
+
63
+ /// Record upload duration for latency tracking
64
+ - (void)recordUploadDuration:(NSTimeInterval)durationMs
65
+ success:(BOOL)success
66
+ byteCount:(NSUInteger)bytes;
67
+
68
+ /// Record memory pressure eviction
69
+ - (void)recordFrameEviction:(NSUInteger)bytesEvicted
70
+ frameCount:(NSInteger)count;
71
+
72
+ /// Record retry queue depth
73
+ - (void)recordQueueDepth:(NSInteger)depth;
74
+
75
+ /// Record an ANR event
76
+ - (void)recordANR;
77
+
78
+ /// Get current metrics snapshot
79
+ - (RJTelemetryMetrics *)currentMetrics;
80
+
81
+ /// Get metrics as dictionary for reporting
82
+ - (NSDictionary<NSString *, id> *)metricsAsDictionary;
83
+
84
+ /// Reset all metrics (typically on session end)
85
+ - (void)resetMetrics;
86
+
87
+ /// Export metrics to console for debugging (only in DEBUG builds)
88
+ - (void)logCurrentMetrics;
89
+
90
+ @end
91
+
92
+ NS_ASSUME_NONNULL_END