@rejourneyco/react-native 1.0.7

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 (105) hide show
  1. package/README.md +29 -0
  2. package/android/build.gradle.kts +135 -0
  3. package/android/consumer-rules.pro +10 -0
  4. package/android/proguard-rules.pro +1 -0
  5. package/android/src/main/AndroidManifest.xml +15 -0
  6. package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +860 -0
  7. package/android/src/main/java/com/rejourney/engine/DeviceRegistrar.kt +290 -0
  8. package/android/src/main/java/com/rejourney/engine/DiagnosticLog.kt +385 -0
  9. package/android/src/main/java/com/rejourney/engine/RejourneyImpl.kt +512 -0
  10. package/android/src/main/java/com/rejourney/platform/OEMDetector.kt +173 -0
  11. package/android/src/main/java/com/rejourney/platform/PerfTiming.kt +384 -0
  12. package/android/src/main/java/com/rejourney/platform/SessionLifecycleService.kt +160 -0
  13. package/android/src/main/java/com/rejourney/platform/Telemetry.kt +301 -0
  14. package/android/src/main/java/com/rejourney/platform/WindowUtils.kt +100 -0
  15. package/android/src/main/java/com/rejourney/recording/AnrSentinel.kt +129 -0
  16. package/android/src/main/java/com/rejourney/recording/EventBuffer.kt +330 -0
  17. package/android/src/main/java/com/rejourney/recording/InteractionRecorder.kt +519 -0
  18. package/android/src/main/java/com/rejourney/recording/ReplayOrchestrator.kt +740 -0
  19. package/android/src/main/java/com/rejourney/recording/SegmentDispatcher.kt +559 -0
  20. package/android/src/main/java/com/rejourney/recording/StabilityMonitor.kt +238 -0
  21. package/android/src/main/java/com/rejourney/recording/TelemetryPipeline.kt +633 -0
  22. package/android/src/main/java/com/rejourney/recording/ViewHierarchyScanner.kt +232 -0
  23. package/android/src/main/java/com/rejourney/recording/VisualCapture.kt +474 -0
  24. package/android/src/main/java/com/rejourney/utility/DataCompression.kt +63 -0
  25. package/android/src/main/java/com/rejourney/utility/ImageBlur.kt +412 -0
  26. package/android/src/main/java/com/rejourney/utility/ViewIdentifier.kt +169 -0
  27. package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +232 -0
  28. package/android/src/newarch/java/com/rejourney/RejourneyPackage.kt +40 -0
  29. package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +268 -0
  30. package/android/src/oldarch/java/com/rejourney/RejourneyPackage.kt +23 -0
  31. package/ios/Engine/DeviceRegistrar.swift +288 -0
  32. package/ios/Engine/DiagnosticLog.swift +387 -0
  33. package/ios/Engine/RejourneyImpl.swift +719 -0
  34. package/ios/Recording/AnrSentinel.swift +142 -0
  35. package/ios/Recording/EventBuffer.swift +326 -0
  36. package/ios/Recording/InteractionRecorder.swift +428 -0
  37. package/ios/Recording/ReplayOrchestrator.swift +624 -0
  38. package/ios/Recording/SegmentDispatcher.swift +492 -0
  39. package/ios/Recording/StabilityMonitor.swift +223 -0
  40. package/ios/Recording/TelemetryPipeline.swift +547 -0
  41. package/ios/Recording/ViewHierarchyScanner.swift +156 -0
  42. package/ios/Recording/VisualCapture.swift +675 -0
  43. package/ios/Rejourney.h +38 -0
  44. package/ios/Rejourney.mm +375 -0
  45. package/ios/Utility/DataCompression.swift +55 -0
  46. package/ios/Utility/ImageBlur.swift +89 -0
  47. package/ios/Utility/RuntimeMethodSwap.swift +41 -0
  48. package/ios/Utility/ViewIdentifier.swift +37 -0
  49. package/lib/commonjs/NativeRejourney.js +40 -0
  50. package/lib/commonjs/components/Mask.js +88 -0
  51. package/lib/commonjs/index.js +1443 -0
  52. package/lib/commonjs/sdk/autoTracking.js +1087 -0
  53. package/lib/commonjs/sdk/constants.js +166 -0
  54. package/lib/commonjs/sdk/errorTracking.js +187 -0
  55. package/lib/commonjs/sdk/index.js +50 -0
  56. package/lib/commonjs/sdk/metricsTracking.js +205 -0
  57. package/lib/commonjs/sdk/navigation.js +128 -0
  58. package/lib/commonjs/sdk/networkInterceptor.js +375 -0
  59. package/lib/commonjs/sdk/utils.js +433 -0
  60. package/lib/commonjs/sdk/version.js +13 -0
  61. package/lib/commonjs/types/expo-router.d.js +2 -0
  62. package/lib/commonjs/types/index.js +2 -0
  63. package/lib/module/NativeRejourney.js +38 -0
  64. package/lib/module/components/Mask.js +83 -0
  65. package/lib/module/index.js +1341 -0
  66. package/lib/module/sdk/autoTracking.js +1059 -0
  67. package/lib/module/sdk/constants.js +154 -0
  68. package/lib/module/sdk/errorTracking.js +177 -0
  69. package/lib/module/sdk/index.js +26 -0
  70. package/lib/module/sdk/metricsTracking.js +187 -0
  71. package/lib/module/sdk/navigation.js +120 -0
  72. package/lib/module/sdk/networkInterceptor.js +364 -0
  73. package/lib/module/sdk/utils.js +412 -0
  74. package/lib/module/sdk/version.js +7 -0
  75. package/lib/module/types/expo-router.d.js +2 -0
  76. package/lib/module/types/index.js +2 -0
  77. package/lib/typescript/NativeRejourney.d.ts +160 -0
  78. package/lib/typescript/components/Mask.d.ts +54 -0
  79. package/lib/typescript/index.d.ts +117 -0
  80. package/lib/typescript/sdk/autoTracking.d.ts +226 -0
  81. package/lib/typescript/sdk/constants.d.ts +138 -0
  82. package/lib/typescript/sdk/errorTracking.d.ts +47 -0
  83. package/lib/typescript/sdk/index.d.ts +24 -0
  84. package/lib/typescript/sdk/metricsTracking.d.ts +75 -0
  85. package/lib/typescript/sdk/navigation.d.ts +48 -0
  86. package/lib/typescript/sdk/networkInterceptor.d.ts +62 -0
  87. package/lib/typescript/sdk/utils.d.ts +193 -0
  88. package/lib/typescript/sdk/version.d.ts +6 -0
  89. package/lib/typescript/types/index.d.ts +618 -0
  90. package/package.json +122 -0
  91. package/rejourney.podspec +23 -0
  92. package/src/NativeRejourney.ts +185 -0
  93. package/src/components/Mask.tsx +93 -0
  94. package/src/index.ts +1555 -0
  95. package/src/sdk/autoTracking.ts +1245 -0
  96. package/src/sdk/constants.ts +155 -0
  97. package/src/sdk/errorTracking.ts +231 -0
  98. package/src/sdk/index.ts +25 -0
  99. package/src/sdk/metricsTracking.ts +227 -0
  100. package/src/sdk/navigation.ts +152 -0
  101. package/src/sdk/networkInterceptor.ts +423 -0
  102. package/src/sdk/utils.ts +442 -0
  103. package/src/sdk/version.ts +6 -0
  104. package/src/types/expo-router.d.ts +7 -0
  105. package/src/types/index.ts +709 -0
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Copyright 2026 Rejourney
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ package com.rejourney.recording
18
+
19
+ import android.content.Context
20
+ import com.rejourney.engine.DiagnosticLog
21
+ import org.json.JSONObject
22
+ import java.io.File
23
+ import java.io.FileWriter
24
+ import java.io.RandomAccessFile
25
+ import java.util.concurrent.locks.ReentrantLock
26
+ import kotlin.concurrent.withLock
27
+
28
+ /**
29
+ * Write-first event buffer for crash-safe event persistence.
30
+ * Events are written to disk on append for crash safety.
31
+ * JSONL format (one JSON object per line).
32
+ * Android implementation aligned with iOS EventBuffer.swift
33
+ */
34
+ class EventBuffer private constructor(private val context: Context) {
35
+
36
+ companion object {
37
+ @Volatile
38
+ private var instance: EventBuffer? = null
39
+
40
+ fun getInstance(context: Context): EventBuffer {
41
+ return instance ?: synchronized(this) {
42
+ instance ?: EventBuffer(context.applicationContext).also { instance = it }
43
+ }
44
+ }
45
+
46
+ val shared: EventBuffer?
47
+ get() = instance
48
+
49
+ // Static methods matching iOS API
50
+
51
+ /**
52
+ * Returns list of session IDs that have pending data on disk
53
+ */
54
+ @JvmStatic
55
+ fun getPendingSessions(context: Context): List<String> {
56
+ val pendingRoot = File(context.cacheDir, "rj_pending")
57
+ if (!pendingRoot.exists()) return emptyList()
58
+
59
+ return pendingRoot.listFiles()?.mapNotNull { dir ->
60
+ val eventsFile = File(dir, "events.jsonl")
61
+ if (eventsFile.exists()) dir.name else null
62
+ } ?: emptyList()
63
+ }
64
+
65
+ /**
66
+ * Read events from a specific session's pending data
67
+ */
68
+ @JvmStatic
69
+ fun readEventsForSession(context: Context, sessionId: String): List<Map<String, Any?>> {
70
+ val eventsFile = File(context.cacheDir, "rj_pending/$sessionId/events.jsonl")
71
+ if (!eventsFile.exists()) return emptyList()
72
+
73
+ val events = mutableListOf<Map<String, Any?>>()
74
+
75
+ try {
76
+ eventsFile.forEachLine { line ->
77
+ if (line.isNotBlank()) {
78
+ try {
79
+ val json = JSONObject(line)
80
+ events.add(json.toMap())
81
+ } catch (_: Exception) { }
82
+ }
83
+ }
84
+ } catch (e: Exception) {
85
+ DiagnosticLog.debugStorage("READ", sessionId, false, e.message ?: "")
86
+ }
87
+
88
+ return events
89
+ }
90
+
91
+ /**
92
+ * Clear all data for a specific session
93
+ */
94
+ @JvmStatic
95
+ fun clearSession(context: Context, sessionId: String) {
96
+ val sessionDir = File(context.cacheDir, "rj_pending/$sessionId")
97
+ sessionDir.deleteRecursively()
98
+ }
99
+
100
+ /**
101
+ * Get metadata for a specific session
102
+ */
103
+ @JvmStatic
104
+ fun getSessionMetadata(context: Context, sessionId: String): Map<String, Any?>? {
105
+ val metaFile = File(context.cacheDir, "rj_pending/$sessionId/buffer_meta.json")
106
+ if (!metaFile.exists()) return null
107
+
108
+ return try {
109
+ val json = JSONObject(metaFile.readText())
110
+ json.toMap()
111
+ } catch (_: Exception) {
112
+ null
113
+ }
114
+ }
115
+ }
116
+
117
+ private val lock = ReentrantLock()
118
+ private var sessionId: String? = null
119
+ private var eventsFile: File? = null
120
+ private var metaFile: File? = null
121
+ private var fileWriter: FileWriter? = null
122
+ private var eventCount: Int = 0
123
+ private var lastEventTimestamp: Long = 0
124
+ private var pendingRootPath: File? = null
125
+ private var isShutdown = false
126
+
127
+ val currentEventCount: Int
128
+ get() = lock.withLock { eventCount }
129
+
130
+ val currentLastEventTimestamp: Long
131
+ get() = lock.withLock { lastEventTimestamp }
132
+
133
+ // Public API
134
+
135
+ fun configure(sessionId: String) {
136
+ lock.withLock {
137
+ closeFileWriter()
138
+
139
+ this.sessionId = sessionId
140
+ isShutdown = false
141
+
142
+ pendingRootPath = File(context.cacheDir, "rj_pending")
143
+ val sessionDir = File(pendingRootPath, sessionId)
144
+
145
+ try {
146
+ sessionDir.mkdirs()
147
+ } catch (e: Exception) {
148
+ DiagnosticLog.debugStorage("CONFIGURE", sessionId, false, "Failed to create directory: ${e.message}")
149
+ return
150
+ }
151
+
152
+ eventsFile = File(sessionDir, "events.jsonl")
153
+ metaFile = File(sessionDir, "buffer_meta.json")
154
+
155
+ countExistingEvents()
156
+ openFileWriter()
157
+
158
+ DiagnosticLog.debugStorage("CONFIGURE", sessionId, true, "Ready with $eventCount existing events")
159
+ }
160
+ }
161
+
162
+ fun appendEvent(event: Map<String, Any?>): Boolean {
163
+ lock.withLock {
164
+ if (isShutdown) {
165
+ DiagnosticLog.debugStorage("APPEND", event["type"]?.toString() ?: "unknown", false, "Buffer is shutdown")
166
+ return false
167
+ }
168
+
169
+ return writeEventToDisk(event)
170
+ }
171
+ }
172
+
173
+ fun flush(): Boolean {
174
+ lock.withLock {
175
+ val writer = fileWriter ?: return false
176
+
177
+ return try {
178
+ writer.flush()
179
+ saveMeta()
180
+ true
181
+ } catch (e: Exception) {
182
+ DiagnosticLog.debugStorage("FLUSH", sessionId ?: "", false, e.message ?: "")
183
+ false
184
+ }
185
+ }
186
+ }
187
+
188
+ fun shutdown() {
189
+ lock.withLock {
190
+ isShutdown = true
191
+ saveMeta()
192
+ closeFileWriter()
193
+ }
194
+ }
195
+
196
+ fun readPendingEvents(): List<Map<String, Any?>> {
197
+ lock.withLock {
198
+ val file = eventsFile
199
+ if (file == null || !file.exists()) return emptyList()
200
+
201
+ val events = mutableListOf<Map<String, Any?>>()
202
+
203
+ try {
204
+ file.forEachLine { line ->
205
+ if (line.isNotBlank()) {
206
+ try {
207
+ val json = JSONObject(line)
208
+ events.add(json.toMap())
209
+ } catch (_: Exception) { }
210
+ }
211
+ }
212
+ } catch (e: Exception) {
213
+ DiagnosticLog.debugStorage("READ", sessionId ?: "", false, e.message ?: "")
214
+ }
215
+
216
+ return events
217
+ }
218
+ }
219
+
220
+ fun clearEvents() {
221
+ lock.withLock {
222
+ closeFileWriter()
223
+
224
+ eventsFile?.delete()
225
+ metaFile?.delete()
226
+
227
+ eventCount = 0
228
+ lastEventTimestamp = 0
229
+
230
+ openFileWriter()
231
+ }
232
+ }
233
+
234
+ fun clearSession(sessionId: String) {
235
+ val sessionDir = File(context.cacheDir, "rj_pending/$sessionId")
236
+ sessionDir.deleteRecursively()
237
+ }
238
+
239
+ fun getPendingSessions(): List<String> {
240
+ return Companion.getPendingSessions(context)
241
+ }
242
+
243
+ fun readEventsForSession(sessionId: String): List<Map<String, Any?>> {
244
+ return Companion.readEventsForSession(context, sessionId)
245
+ }
246
+
247
+ // Private Implementation
248
+
249
+ private fun writeEventToDisk(event: Map<String, Any?>): Boolean {
250
+ val writer = fileWriter ?: return false
251
+
252
+ return try {
253
+ val json = JSONObject(event)
254
+ writer.write(json.toString())
255
+ writer.write("\n")
256
+ writer.flush()
257
+
258
+ eventCount++
259
+ lastEventTimestamp = System.currentTimeMillis()
260
+
261
+ // Save meta every 10 events
262
+ if (eventCount % 10 == 0) {
263
+ saveMeta()
264
+ }
265
+
266
+ true
267
+ } catch (e: Exception) {
268
+ DiagnosticLog.debugStorage("WRITE", event["type"]?.toString() ?: "unknown", false, e.message ?: "")
269
+ false
270
+ }
271
+ }
272
+
273
+ private fun countExistingEvents() {
274
+ val file = eventsFile
275
+ if (file == null || !file.exists()) {
276
+ eventCount = 0
277
+ return
278
+ }
279
+
280
+ eventCount = try {
281
+ file.readLines().count { it.isNotBlank() }
282
+ } catch (_: Exception) {
283
+ 0
284
+ }
285
+ }
286
+
287
+ private fun openFileWriter() {
288
+ val file = eventsFile ?: return
289
+
290
+ try {
291
+ fileWriter = FileWriter(file, true)
292
+ } catch (e: Exception) {
293
+ DiagnosticLog.debugStorage("OPEN", sessionId ?: "", false, e.message ?: "")
294
+ }
295
+ }
296
+
297
+ private fun closeFileWriter() {
298
+ try {
299
+ fileWriter?.close()
300
+ } catch (_: Exception) { }
301
+ fileWriter = null
302
+ }
303
+
304
+ private fun saveMeta() {
305
+ val file = metaFile ?: return
306
+
307
+ try {
308
+ val meta = JSONObject().apply {
309
+ put("sessionId", sessionId)
310
+ put("eventCount", eventCount)
311
+ put("lastEventTimestamp", lastEventTimestamp)
312
+ put("savedAt", System.currentTimeMillis())
313
+ }
314
+ file.writeText(meta.toString())
315
+ } catch (_: Exception) { }
316
+ }
317
+ }
318
+
319
+ // Extension to convert JSONObject to Map
320
+ private fun JSONObject.toMap(): Map<String, Any?> {
321
+ val map = mutableMapOf<String, Any?>()
322
+ keys().forEach { key ->
323
+ map[key] = when (val value = get(key)) {
324
+ is JSONObject -> value.toMap()
325
+ JSONObject.NULL -> null
326
+ else -> value
327
+ }
328
+ }
329
+ return map
330
+ }