iidrak-analytics-react 1.2.4 → 1.2.6

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.
package/README.md CHANGED
@@ -58,6 +58,9 @@ const iidrakConfig = {
58
58
 
59
59
  // SDK Configuration
60
60
  config: {
61
+ // Application Name for Session Grouping (Recommended)
62
+ appName: "your-app-name",
63
+
61
64
  // Session Replay Endpoint (Required to enable recording)
62
65
  recordingEndpoint: "https://your-replay-server.com",
63
66
 
@@ -114,6 +114,7 @@ class MetaStreamIO {
114
114
  logger: this.logger,
115
115
  network: this.network,
116
116
  config: this.config,
117
+ user: this.userConfig,
117
118
  });
118
119
 
119
120
  // Init global variables
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
 
3
3
  import { strf } from "./string.format.js";
4
- import ViewShot, { captureRef } from "react-native-view-shot";
4
+ import { captureRef } from "react-native-view-shot";
5
5
  import { Platform, Dimensions } from "react-native";
6
6
 
7
7
  strf();
8
8
 
9
9
  class MetaStreamIORecorder {
10
- constructor({ constants, logger, network, config } = {}) {
10
+ constructor({ constants, logger, network, config, user } = {}) {
11
11
  this.constant = constants;
12
12
  this.logger = logger;
13
13
  this.network = network;
@@ -24,6 +24,11 @@ class MetaStreamIORecorder {
24
24
  // Use lower quality by default to save bandwidth
25
25
  this.quality = config.quality || 0.5;
26
26
  this.fps = config.fps || 2; // Frames per second (0.5s interval)
27
+ // If user_id is provided in user config, use it as app_id (per user requirement)
28
+ // Otherwise fallback to app_id in general config or "default"
29
+ // Priority: config.appName > user.user_id > config.app_id > "default"
30
+ this.app_id = config.appName ? config.appName : ((user && user.user_id) ? user.user_id : (config.app_id || "default"));
31
+ this.lastBase64 = null;
27
32
  }
28
33
 
29
34
  setSessionId(id) {
@@ -41,7 +46,7 @@ class MetaStreamIORecorder {
41
46
 
42
47
  // 1. Initialize Session on Python Server
43
48
  // Note: We use a separate fetch here because the payload format is different from standard analytics
44
- await fetch(`${this.endpoint}/sessions`, {
49
+ await fetch(`${this.endpoint}/apps/${this.app_id}/sessions`, {
45
50
  method: 'POST',
46
51
  headers: { 'Content-Type': 'application/json' },
47
52
  body: JSON.stringify({
@@ -84,25 +89,55 @@ class MetaStreamIORecorder {
84
89
 
85
90
  startLoop(viewRef) {
86
91
  const intervalMs = 1000 / this.fps;
87
-
92
+ this.lastUploadTime = 0;
93
+ console.log("Starting loop");
88
94
  this.intervalId = setInterval(async () => {
89
95
  if (!viewRef.current) return;
90
96
 
91
97
  try {
92
- const uri = await captureRef(viewRef, {
93
- format: "jpg",
98
+ // Capture as base64 for comparison and direct upload
99
+ // Resize to width 400px (height maintained automatically) to reduce size
100
+ // Use PNG to ensure deterministic output for diffing
101
+ const base64 = await captureRef(viewRef, {
102
+ format: "png",
94
103
  quality: this.quality,
95
- result: "tmpfile"
104
+ width: 400,
105
+ result: "base64"
96
106
  });
97
107
 
98
- this.uploadFrame(uri);
108
+ let isDuplicate = false;
109
+ if (this.lastBase64) {
110
+ if (this.lastBase64 === base64) {
111
+ isDuplicate = true;
112
+ console.log("DBG:: Duplicate frame");
113
+ } else {
114
+ console.log("DBG:: New frame");
115
+ this.lastBase64 = base64;
116
+ }
117
+ }
118
+
119
+ const now = Date.now();
120
+ // Logic:
121
+ // If NEW frame: Upload immediately.
122
+ // If DUPLICATE frame:
123
+ // Only upload if it's been > 5 seconds since last upload (Keepalive)
124
+ // This reduces chatter significantly.
125
+
126
+ const timeSinceLastUpload = (now - this.lastUploadTime) / 1000;
127
+
128
+ if (!isDuplicate || timeSinceLastUpload > 5.0) {
129
+ console.log("DBG:: Uploading frame");
130
+ this.uploadFrame(base64, isDuplicate);
131
+ this.lastUploadTime = now;
132
+ this.lastBase64 = base64;
133
+ }
99
134
  } catch (e) {
100
135
  // Silent fail on capture error to avoid log spam
101
136
  }
102
137
  }, intervalMs);
103
138
  }
104
139
 
105
- async uploadFrame(uri) {
140
+ async uploadFrame(data, isDuplicate) {
106
141
  if (!this.recorderSessionId) return;
107
142
 
108
143
  const formData = new FormData();
@@ -111,14 +146,19 @@ class MetaStreamIORecorder {
111
146
 
112
147
  formData.append('timestamp', String(timestamp));
113
148
  formData.append('duration', String(duration));
114
- formData.append('file', {
115
- uri: uri,
116
- type: 'image/jpeg',
117
- name: 'screenshot.jpg',
118
- });
149
+
150
+ if (isDuplicate) {
151
+ formData.append('is_duplicate', 'true');
152
+ } else {
153
+ formData.append('file', {
154
+ uri: 'data:image/png;base64,' + data,
155
+ type: 'image/png',
156
+ name: 'screenshot.png',
157
+ });
158
+ }
119
159
 
120
160
  try {
121
- await fetch(`${this.endpoint}/sessions/${this.recorderSessionId}/screenshot`, {
161
+ await fetch(`${this.endpoint}/apps/${this.app_id}/sessions/${this.recorderSessionId}/screenshot`, {
122
162
  method: 'POST',
123
163
  body: formData,
124
164
  headers: {
@@ -145,7 +185,7 @@ class MetaStreamIORecorder {
145
185
  };
146
186
 
147
187
  try {
148
- fetch(`${this.endpoint}/sessions/${this.recorderSessionId}/events`, {
188
+ fetch(`${this.endpoint}/apps/${this.app_id}/sessions/${this.recorderSessionId}/events`, {
149
189
  method: 'POST',
150
190
  headers: { 'Content-Type': 'application/json' },
151
191
  body: JSON.stringify([event])
@@ -8,6 +8,7 @@ export class ConfigConstructorModel {
8
8
  sessionLength = null,
9
9
  silentMode = null,
10
10
  allowTrackCategories = [],
11
+ appName = null,
11
12
  } = {}) {
12
13
  this.logging = logging;
13
14
  this.loggingLevel = loggingLevel;
@@ -17,6 +18,7 @@ export class ConfigConstructorModel {
17
18
  this.sessionLength = sessionLength;
18
19
  this.silentMode = silentMode;
19
20
  this.allowTrackCategories = allowTrackCategories;
21
+ this.appName = appName;
20
22
  }
21
23
  json() {
22
24
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iidrak-analytics-react",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "react native client for metastreamio",
5
5
  "peerDependencies": {
6
6
  "@react-native-async-storage/async-storage": ">=2.2.0",