@rejourneyco/react-native 1.0.15 → 1.0.16

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.
@@ -44,6 +44,7 @@ import com.facebook.react.modules.network.NetworkingModule
44
44
  import okhttp3.OkHttpClient
45
45
  import com.rejourney.engine.DeviceRegistrar
46
46
  import com.rejourney.engine.DiagnosticLog
47
+ import com.rejourney.engine.RejourneyImpl
47
48
 
48
49
  import com.rejourney.platform.OEMDetector
49
50
  import com.rejourney.platform.SessionLifecycleService
@@ -856,6 +857,7 @@ class RejourneyModuleImpl(
856
857
 
857
858
  fun setSDKVersion(version: String) {
858
859
  sdkVersion = version
860
+ RejourneyImpl.sdkVersion = version
859
861
  }
860
862
 
861
863
  fun getSDKVersion(promise: Promise) {
@@ -302,19 +302,17 @@ class ReplayOrchestrator private constructor(private val context: Context) {
302
302
  }
303
303
  finalized = true
304
304
 
305
- SegmentDispatcher.shared.evaluateReplayRetention(sid, metrics) { _, _ ->
306
- SegmentDispatcher.shared.concludeReplay(
307
- sid,
308
- termMs,
309
- bgTimeMs,
310
- metrics,
311
- queueDepthAtFinalize,
312
- endReason = endReason,
313
- lifecycleVersion = lifecycleContractVersion
314
- ) { ok ->
315
- if (ok) clearRecovery()
316
- completion?.invoke(true, ok)
317
- }
305
+ SegmentDispatcher.shared.concludeReplay(
306
+ sid,
307
+ termMs,
308
+ bgTimeMs,
309
+ metrics,
310
+ queueDepthAtFinalize,
311
+ endReason = endReason,
312
+ lifecycleVersion = lifecycleContractVersion
313
+ ) { ok ->
314
+ if (ok) clearRecovery()
315
+ completion?.invoke(true, ok)
318
316
  }
319
317
 
320
318
  replayId = null
@@ -17,6 +17,7 @@
17
17
  package com.rejourney.recording
18
18
 
19
19
  import com.rejourney.engine.DiagnosticLog
20
+ import com.rejourney.engine.RejourneyImpl
20
21
  import kotlinx.coroutines.*
21
22
  import okhttp3.*
22
23
  import com.rejourney.recording.RejourneyNetworkInterceptor
@@ -285,6 +286,7 @@ class SegmentDispatcher private constructor() {
285
286
  val body = JSONObject().apply {
286
287
  put("sessionId", replayId)
287
288
  put("endedAt", concludedAt)
289
+ put("sdkVersion", RejourneyImpl.sdkVersion)
288
290
  if (backgroundDurationMs > 0) put("totalBackgroundTimeMs", backgroundDurationMs)
289
291
  metrics?.let { put("metrics", JSONObject(it)) }
290
292
  put("sdkTelemetry", buildSdkTelemetry(currentQueueDepth))
@@ -304,39 +306,6 @@ class SegmentDispatcher private constructor() {
304
306
  }
305
307
  }
306
308
 
307
- fun evaluateReplayRetention(
308
- replayId: String,
309
- metrics: Map<String, Any>,
310
- completion: (Boolean, String) -> Unit
311
- ) {
312
- val url = "$endpoint/api/ingest/replay/evaluate"
313
-
314
- val body = JSONObject().apply {
315
- put("sessionId", replayId)
316
- metrics.forEach { (key, value) -> put(key, value) }
317
- }
318
-
319
- val request = buildRequest(url, body)
320
-
321
- scope.launch {
322
- try {
323
- val response = httpClient.newCall(request).execute()
324
- val responseBody = response.body?.string()
325
-
326
- if (response.code == 200 && responseBody != null) {
327
- val json = JSONObject(responseBody)
328
- val retained = json.optBoolean("promoted", false)
329
- val reason = json.optString("reason", "unknown")
330
- completion(retained, reason)
331
- } else {
332
- completion(false, "request_failed")
333
- }
334
- } catch (e: Exception) {
335
- completion(false, "request_failed")
336
- }
337
- }
338
- }
339
-
340
309
  @Synchronized
341
310
  private fun canUploadNow(): Boolean {
342
311
  if (billingBlocked) return false
@@ -461,6 +430,7 @@ class SegmentDispatcher private constructor() {
461
430
  val body = JSONObject().apply {
462
431
  put("sessionId", upload.sessionId)
463
432
  put("sizeBytes", upload.payload.size)
433
+ put("sdkVersion", RejourneyImpl.sdkVersion)
464
434
 
465
435
  if (upload.contentType == "events") {
466
436
  put("contentType", "events")
@@ -22,6 +22,7 @@ import android.os.Handler
22
22
  import android.os.Looper
23
23
  import com.rejourney.engine.DiagnosticLog
24
24
  import com.rejourney.engine.DeviceRegistrar
25
+ import com.rejourney.engine.RejourneyImpl
25
26
  import com.rejourney.utility.gzipCompress
26
27
  import org.json.JSONArray
27
28
  import org.json.JSONObject
@@ -340,6 +341,7 @@ class TelemetryPipeline private constructor(private val context: Context) {
340
341
  put("isConstrained", orchestrator?.networkIsConstrained ?: false)
341
342
  put("isExpensive", orchestrator?.networkIsExpensive ?: false)
342
343
  put("appVersion", getAppVersion())
344
+ put("sdkVersion", RejourneyImpl.sdkVersion)
343
345
  put("appId", context.packageName)
344
346
  put("screenWidth", displayMetrics.widthPixels)
345
347
  put("screenHeight", displayMetrics.heightPixels)
@@ -78,6 +78,7 @@ public final class RejourneyImpl: NSObject {
78
78
  NotificationCenter.default.removeObserver(self)
79
79
  }
80
80
 
81
+ //NOTE: iOS cannot detect reliably app kill so we depend server side with the session reconciliation logic
81
82
  private func setupLifecycleListeners() {
82
83
  let center = NotificationCenter.default
83
84
  center.addObserver(self, selector: #selector(handleTermination), name: UIApplication.willTerminateNotification, object: nil)
@@ -258,20 +258,17 @@ public final class ReplayOrchestrator: NSObject {
258
258
  }
259
259
  _finalized = true
260
260
 
261
- SegmentDispatcher.shared.evaluateReplayRetention(replayId: sid, metrics: metrics) { [weak self] _, _ in
262
- guard let self else { return }
263
- SegmentDispatcher.shared.concludeReplay(
264
- replayId: sid,
265
- concludedAt: termMs,
266
- backgroundDurationMs: self._bgTimeMs,
267
- metrics: metrics,
268
- currentQueueDepth: queueDepthAtFinalize,
269
- endReason: endReason,
270
- lifecycleVersion: self.lifecycleContractVersion
271
- ) { [weak self] ok in
272
- if ok { self?._clearRecovery() }
273
- completion?(true, ok)
274
- }
261
+ SegmentDispatcher.shared.concludeReplay(
262
+ replayId: sid,
263
+ concludedAt: termMs,
264
+ backgroundDurationMs: _bgTimeMs,
265
+ metrics: metrics,
266
+ currentQueueDepth: queueDepthAtFinalize,
267
+ endReason: endReason,
268
+ lifecycleVersion: lifecycleContractVersion
269
+ ) { [weak self] ok in
270
+ if ok { self?._clearRecovery() }
271
+ completion?(true, ok)
275
272
  }
276
273
 
277
274
  replayId = nil
@@ -195,7 +195,11 @@ final class SegmentDispatcher {
195
195
  req.setValue("application/json", forHTTPHeaderField: "Content-Type")
196
196
  applyAuthHeaders(&req)
197
197
 
198
- var body: [String: Any] = ["sessionId": replayId, "endedAt": concludedAt]
198
+ var body: [String: Any] = [
199
+ "sessionId": replayId,
200
+ "endedAt": concludedAt,
201
+ "sdkVersion": RejourneyImpl.sdkVersion
202
+ ]
199
203
  if backgroundDurationMs > 0 { body["totalBackgroundTimeMs"] = backgroundDurationMs }
200
204
  if let m = metrics { body["metrics"] = m }
201
205
  body["sdkTelemetry"] = sdkTelemetrySnapshot(currentQueueDepth: currentQueueDepth)
@@ -218,39 +222,6 @@ final class SegmentDispatcher {
218
222
  }.resume()
219
223
  }
220
224
 
221
- func evaluateReplayRetention(replayId: String, metrics: [String: Any], completion: @escaping (Bool, String) -> Void) {
222
- guard let url = URL(string: "\(endpoint)/api/ingest/replay/evaluate") else {
223
- completion(false, "bad_url")
224
- return
225
- }
226
-
227
- var req = URLRequest(url: url)
228
- req.httpMethod = "POST"
229
- req.setValue("application/json", forHTTPHeaderField: "Content-Type")
230
- applyAuthHeaders(&req)
231
-
232
- var body: [String: Any] = ["sessionId": replayId]
233
- metrics.forEach { body[$0.key] = $0.value }
234
-
235
- do {
236
- req.httpBody = try JSONSerialization.data(withJSONObject: body)
237
- } catch {
238
- completion(false, "serialize_error")
239
- return
240
- }
241
-
242
- httpSession.dataTask(with: req) { data, resp, _ in
243
- guard let data, (resp as? HTTPURLResponse)?.statusCode == 200,
244
- let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
245
- completion(false, "request_failed")
246
- return
247
- }
248
- let retained = json["promoted"] as? Bool ?? false
249
- let reason = json["reason"] as? String ?? "unknown"
250
- completion(retained, reason)
251
- }.resume()
252
- }
253
-
254
225
  private func canUploadNow() -> Bool {
255
226
  if billingBlocked { return false }
256
227
  if circuitOpen {
@@ -382,7 +353,8 @@ final class SegmentDispatcher {
382
353
 
383
354
  var body: [String: Any] = [
384
355
  "sessionId": upload.sessionId,
385
- "sizeBytes": upload.payload.count
356
+ "sizeBytes": upload.payload.count,
357
+ "sdkVersion": RejourneyImpl.sdkVersion
386
358
  ]
387
359
 
388
360
  if upload.contentType == "events" {
@@ -354,6 +354,7 @@ public final class TelemetryPipeline: NSObject {
354
354
  "isConstrained": isConstrained,
355
355
  "isExpensive": isExpensive,
356
356
  "appVersion": appVersion,
357
+ "sdkVersion": RejourneyImpl.sdkVersion,
357
358
  "appId": appId,
358
359
  "screenWidth": Int(bounds.width),
359
360
  "screenHeight": Int(bounds.height),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rejourneyco/react-native",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "Rejourney Session Recording SDK for React Native",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",