iidrak-analytics-react 1.2.4

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 (37) hide show
  1. package/README.md +170 -0
  2. package/index.d.ts +1 -0
  3. package/index.js +4 -0
  4. package/metastreamio/metastreamio.account.js +65 -0
  5. package/metastreamio/metastreamio.cart.js +192 -0
  6. package/metastreamio/metastreamio.constants.js +256 -0
  7. package/metastreamio/metastreamio.date.js +41 -0
  8. package/metastreamio/metastreamio.environment.js +406 -0
  9. package/metastreamio/metastreamio.interface.js +591 -0
  10. package/metastreamio/metastreamio.logger.js +150 -0
  11. package/metastreamio/metastreamio.network.js +313 -0
  12. package/metastreamio/metastreamio.provider.js +50 -0
  13. package/metastreamio/metastreamio.queue.js +68 -0
  14. package/metastreamio/metastreamio.recorder.js +157 -0
  15. package/metastreamio/metastreamio.session.js +150 -0
  16. package/metastreamio/metastreamio.user.js +79 -0
  17. package/metastreamio/metastreamio.userproperties.js +76 -0
  18. package/metastreamio/metastreamio.utility.js +206 -0
  19. package/metastreamio/models/constructor.app.js +24 -0
  20. package/metastreamio/models/constructor.config.js +33 -0
  21. package/metastreamio/models/constructor.user.js +30 -0
  22. package/metastreamio/models/event.account.balance.js +12 -0
  23. package/metastreamio/models/event.account.js +22 -0
  24. package/metastreamio/models/event.appinfo.js +28 -0
  25. package/metastreamio/models/event.appperformance.js +25 -0
  26. package/metastreamio/models/event.cart.js +19 -0
  27. package/metastreamio/models/event.cartitem.js +34 -0
  28. package/metastreamio/models/event.device.js +55 -0
  29. package/metastreamio/models/event.event.js +88 -0
  30. package/metastreamio/models/event.network.js +27 -0
  31. package/metastreamio/models/event.parameter.js +12 -0
  32. package/metastreamio/models/event.parameters.js +38 -0
  33. package/metastreamio/models/event.session.js +24 -0
  34. package/metastreamio/models/event.session.utm.js +37 -0
  35. package/metastreamio/models/event.userproperty.js +14 -0
  36. package/metastreamio/string.format.js +7 -0
  37. package/package.json +21 -0
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+
3
+ import { strf } from "./string.format.js";
4
+ import ViewShot, { captureRef } from "react-native-view-shot";
5
+ import { Platform, Dimensions } from "react-native";
6
+
7
+ strf();
8
+
9
+ class MetaStreamIORecorder {
10
+ constructor({ constants, logger, network, config } = {}) {
11
+ this.constant = constants;
12
+ this.logger = logger;
13
+ this.network = network;
14
+ this.config = config;
15
+
16
+ this.isRecording = false;
17
+ this.sessionId = null;
18
+ this.endpoint = null;
19
+ this.intervalId = null;
20
+
21
+ // Default to first endpoint if specific one not provided
22
+ this.endpoint = config.recordingEndpoint || (this.network.endpoints.length > 0 ? this.network.endpoints[0].replace(/:[0-9]+/, "") + ":8000" : null);
23
+
24
+ // Use lower quality by default to save bandwidth
25
+ this.quality = config.quality || 0.5;
26
+ this.fps = config.fps || 2; // Frames per second (0.5s interval)
27
+ }
28
+
29
+ setSessionId(id) {
30
+ this.sessionId = id;
31
+ }
32
+
33
+ async startRecording(viewRef) {
34
+ if (this.isRecording || !this.sessionId || !this.endpoint) {
35
+ if (!this.endpoint) this.logger.warn("recorder", "No recording endpoint configured");
36
+ return;
37
+ }
38
+
39
+ try {
40
+ this.logger.log("recorder", `Starting session recording for ${this.sessionId} to ${this.endpoint}`);
41
+
42
+ // 1. Initialize Session on Python Server
43
+ // Note: We use a separate fetch here because the payload format is different from standard analytics
44
+ await fetch(`${this.endpoint}/sessions`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({
48
+ device_info: {
49
+ width: Dimensions.get('window').width,
50
+ height: Dimensions.get('window').height,
51
+ platform: Platform.OS,
52
+ sessionId: this.sessionId // Pass our analytics session ID
53
+ }
54
+ })
55
+ }).then(async res => {
56
+ if (res.ok) {
57
+ const data = await res.json();
58
+ // Server might return its own ID, but we want to map them.
59
+ // For simplicity, we assume server respects ours or we track the mapping.
60
+ // In this demo, the server generates a timestamp ID. That's fine.
61
+ this.recorderSessionId = data.session_id;
62
+ this.isRecording = true;
63
+ this.startLoop(viewRef);
64
+ } else {
65
+ this.logger.error("recorder", "Failed to start session on recording server");
66
+ }
67
+ }).catch(err => {
68
+ this.logger.error("recorder", "Connection error to recording server: " + err);
69
+ });
70
+
71
+ } catch (err) {
72
+ this.logger.error("recorder", "Start recording error: " + err);
73
+ }
74
+ }
75
+
76
+ stopRecording() {
77
+ if (this.intervalId) {
78
+ clearInterval(this.intervalId);
79
+ this.intervalId = null;
80
+ }
81
+ this.isRecording = false;
82
+ this.logger.log("recorder", "Stopped recording");
83
+ }
84
+
85
+ startLoop(viewRef) {
86
+ const intervalMs = 1000 / this.fps;
87
+
88
+ this.intervalId = setInterval(async () => {
89
+ if (!viewRef.current) return;
90
+
91
+ try {
92
+ const uri = await captureRef(viewRef, {
93
+ format: "jpg",
94
+ quality: this.quality,
95
+ result: "tmpfile"
96
+ });
97
+
98
+ this.uploadFrame(uri);
99
+ } catch (e) {
100
+ // Silent fail on capture error to avoid log spam
101
+ }
102
+ }, intervalMs);
103
+ }
104
+
105
+ async uploadFrame(uri) {
106
+ if (!this.recorderSessionId) return;
107
+
108
+ const formData = new FormData();
109
+ const duration = 1.0 / this.fps;
110
+ const timestamp = Date.now() / 1000;
111
+
112
+ formData.append('timestamp', String(timestamp));
113
+ formData.append('duration', String(duration));
114
+ formData.append('file', {
115
+ uri: uri,
116
+ type: 'image/jpeg',
117
+ name: 'screenshot.jpg',
118
+ });
119
+
120
+ try {
121
+ await fetch(`${this.endpoint}/sessions/${this.recorderSessionId}/screenshot`, {
122
+ method: 'POST',
123
+ body: formData,
124
+ headers: {
125
+ 'Content-Type': 'multipart/form-data',
126
+ }
127
+ });
128
+ } catch (e) {
129
+ // Network error, drop frame
130
+ }
131
+ }
132
+
133
+ // Record interactions (Touch events)
134
+ async recordInteraction(type, nativeEvent) {
135
+ if (!this.isRecording || !this.recorderSessionId) return;
136
+
137
+ const { pageX, pageY } = nativeEvent;
138
+ const { width, height } = Dimensions.get('window');
139
+
140
+ const event = {
141
+ type,
142
+ x: pageX / width,
143
+ y: pageY / height,
144
+ timestamp: Date.now() / 1000
145
+ };
146
+
147
+ try {
148
+ fetch(`${this.endpoint}/sessions/${this.recorderSessionId}/events`, {
149
+ method: 'POST',
150
+ headers: { 'Content-Type': 'application/json' },
151
+ body: JSON.stringify([event])
152
+ }).catch(() => { });
153
+ } catch (e) { }
154
+ }
155
+ }
156
+
157
+ export { MetaStreamIORecorder };
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+
3
+ import { strf } from "./string.format.js";
4
+
5
+ strf();
6
+
7
+ import { SessionModel } from "./models/event.session.js";
8
+ import { UtmModel } from "./models/event.session.utm.js";
9
+
10
+ /*
11
+ *
12
+ * Session management
13
+ *
14
+ */
15
+
16
+ class MetaStreamIOSession {
17
+ constructor({
18
+ constants,
19
+ date,
20
+ environment,
21
+ logger,
22
+ network,
23
+ sessionLength,
24
+ utility,
25
+ } = {}) {
26
+ this.constant = constants;
27
+ this.date = date;
28
+ this.environment = environment;
29
+ this.logger = logger;
30
+ this.network = network;
31
+ this.session_length = sessionLength
32
+ ? sessionLength
33
+ : this.constant.MetaStreamIO_SessionLengthSeconds;
34
+ this.session = new SessionModel();
35
+ this.utility = utility;
36
+ }
37
+
38
+ reset() {
39
+ this.session = new SessionModel();
40
+ }
41
+
42
+ generateNewSessionId(session_id) {
43
+ if (session_id) {
44
+ return session_id;
45
+ } else {
46
+ return this.utility.generateRandomId();
47
+ }
48
+ }
49
+
50
+ setSource(source = null) {
51
+ this.session.source = source ? source : null;
52
+ return this.session.source;
53
+ }
54
+
55
+ setUTM({
56
+ utm_source = null,
57
+ utm_medium = null,
58
+ utm_campaign = null,
59
+ utm_term = null,
60
+ utm_content = null,
61
+ } = {}) {
62
+ this.session.utm = new UtmModel({
63
+ utm_source: utm_source ? utm_source : null,
64
+ utm_medium: utm_medium ? utm_medium : null,
65
+ utm_campaign: utm_campaign ? utm_campaign : null,
66
+ utm_term: utm_term ? utm_term : null,
67
+ utm_content: utm_content ? utm_content : null,
68
+ }).list();
69
+ return this.session.utm;
70
+ }
71
+
72
+ createNewSession({
73
+ session_id = null,
74
+ session_source = null,
75
+ session_utm = null,
76
+ } = {}) {
77
+ let _id, _source, _start_time, _utm;
78
+
79
+ try {
80
+ _id = this.generateNewSessionId(session_id);
81
+ } catch (err) {
82
+ this.logger.warn(
83
+ "session",
84
+ "<createNewSession> could not generate / set new id: " + err
85
+ );
86
+ _id = null;
87
+ }
88
+
89
+ try {
90
+ _source = session_source ? session_source : null;
91
+ } catch {
92
+ source = null;
93
+ }
94
+
95
+ try {
96
+ _start_time = this.date.getEventTimestamp();
97
+ } catch {
98
+ _start_time = null;
99
+ }
100
+
101
+ try {
102
+ _utm = this.setUTM(session_utm);
103
+ } catch (err) {
104
+ this.logger.warn("session", "could not set session UTM: " + err);
105
+ }
106
+
107
+ this.session = new SessionModel({
108
+ id: _id,
109
+ source: _source,
110
+ start_time: _start_time,
111
+ utm: _utm,
112
+ });
113
+ }
114
+
115
+ logSession({ last_event_time = null } = {}) {
116
+ if (last_event_time) {
117
+ if (!this.checkSessionIsValid(last_event_time)) {
118
+ this.logger.warn("session", "session expired - starting new session");
119
+ this.createNewSession();
120
+ }
121
+ }
122
+ return this.utility.copyObject(this.session);
123
+ }
124
+
125
+ checkSessionIsValid(last_event_time) {
126
+ try {
127
+ let current_time = this.date.getEventTimestamp();
128
+ let session_length_seconds = (current_time - last_event_time) / 1e6;
129
+ this.logger.log(
130
+ "session",
131
+ "<checkSessionIsValid> current session length: ",
132
+ session_length_seconds
133
+ );
134
+ if (!last_event_time || session_length_seconds > this.session.length) {
135
+ return false;
136
+ } else {
137
+ return true;
138
+ }
139
+ } catch (err) {
140
+ this.logger.log(
141
+ "session",
142
+ "<checkSessionIsValid> problem checking session length: ",
143
+ err
144
+ );
145
+ return false;
146
+ }
147
+ }
148
+ }
149
+
150
+ export { MetaStreamIOSession };
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+
3
+ import { strf } from "./string.format.js";
4
+
5
+ strf();
6
+
7
+ class MetaStreamIOUser {
8
+ constructor({
9
+ constants = null,
10
+ logger = null,
11
+ id = null,
12
+ ciam_id = null,
13
+ email_id = null,
14
+ country = null,
15
+ } = {}) {
16
+ this.constant = constants;
17
+ this.logger = logger;
18
+ this.set(id);
19
+ this.setCountry(country);
20
+ this.setCiam(ciam_id);
21
+ this.setEmail(email_id);
22
+ }
23
+
24
+ reset() {
25
+ this.set();
26
+ this.setCiam();
27
+ this.setDeviceToken();
28
+ this.setEmail();
29
+ }
30
+
31
+ set(id = null) {
32
+ if (id !== null) {
33
+ this.id = id;
34
+ } else {
35
+ this.id = this.constant.MetaStreamIO_User_Guest;
36
+ }
37
+
38
+ this.logger.log(
39
+ "user",
40
+ this.constant.MetaStreamIO_Log_UserIdSet.format(this.id)
41
+ );
42
+ }
43
+
44
+ setCiam(id = null) {
45
+ this.ciam_id = id;
46
+ this.logger.log(
47
+ "user",
48
+ this.constant.MetaStreamIO_Log_CIAMIdSet.format(this.ciam_id)
49
+ );
50
+ }
51
+
52
+ setCountry(country = null) {
53
+ this.country = country;
54
+ this.logger.log(
55
+ "user",
56
+ this.constant.MetaStreamIO_Log_UserCountrySet.format(this.country)
57
+ );
58
+ }
59
+
60
+ setDeviceToken(device_token = null) {
61
+ this.device_token = device_token;
62
+ this.logger.log(
63
+ "user",
64
+ this.constant.MetaStreamIO_Log_PushDeviceTokenSet.format(
65
+ this.device_token
66
+ )
67
+ );
68
+ }
69
+
70
+ setEmail(email = null) {
71
+ this.email_id = email;
72
+ this.logger.log(
73
+ "user",
74
+ this.constant.MetaStreamIO_Log_EmailIdSet.format(this.email_id)
75
+ );
76
+ }
77
+ }
78
+
79
+ export { MetaStreamIOUser };
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+
3
+ import { strf } from "./string.format.js";
4
+
5
+ strf();
6
+
7
+ import { UserPropertyModel } from "./models/event.userproperty.js";
8
+
9
+ /*
10
+ *
11
+ * Environment class
12
+ *
13
+ */
14
+
15
+ class MetaStreamIOUserProperties {
16
+ constructor({ constants, logger, stored_user_properties, utility } = {}) {
17
+ this.constant = constants;
18
+ this.logger = logger;
19
+ this.properties = stored_user_properties ? stored_user_properties : {};
20
+ this.utility = utility;
21
+ }
22
+
23
+ reset() {
24
+ this.properties = {};
25
+ }
26
+
27
+ delete({ key } = {}) {
28
+ if (key in this.properties) {
29
+ delete this.properties[key];
30
+ }
31
+ return null;
32
+ }
33
+
34
+ get({ key } = {}) {
35
+ if (key in this.properties) {
36
+ return this.properties[key];
37
+ } else {
38
+ return null;
39
+ }
40
+ }
41
+
42
+ set({ key, value } = {}) {
43
+ let value_type = this.utility.type_to_name(value);
44
+
45
+ this.properties[key] = new UserPropertyModel({
46
+ key: key,
47
+ value_type: value_type,
48
+ value: value,
49
+ });
50
+
51
+ this.logger.log(
52
+ "userproperties",
53
+ this.constant.MetaStreamIO_Log_UserPropertySet.format(
54
+ key,
55
+ JSON.stringify(value),
56
+ value_type
57
+ )
58
+ );
59
+
60
+ return this.get({ key: key });
61
+ }
62
+
63
+ list() {
64
+ let properties = Object.keys(this.properties);
65
+ let list = [];
66
+ for (let property of properties) {
67
+ list.push({
68
+ key: this.properties[property].key,
69
+ value: this.properties[property].value_type_value,
70
+ });
71
+ }
72
+ return list;
73
+ }
74
+ }
75
+
76
+ export { MetaStreamIOUserProperties };
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+
3
+ import { strf } from "./string.format.js";
4
+
5
+ strf();
6
+
7
+ /*
8
+ *
9
+ * Utilities class
10
+ *
11
+ */
12
+
13
+ class MetaStreamIOUtils {
14
+ constructor({ constants, date, logger } = {}) {
15
+ this.date = date;
16
+ this.logger = logger;
17
+ this.constant = constants;
18
+ }
19
+
20
+ generateRandomId() {
21
+ return (
22
+ String(this.date.getEventTimestamp() * Math.random()) +
23
+ ":" +
24
+ String(Math.floor(1000 + (9999 - 1000) * Math.random()))
25
+ );
26
+ }
27
+
28
+ // Check if input is an integer
29
+ isInteger(n) {
30
+ if (n != null) {
31
+ return Math.ceil(parseFloat(n)) === n;
32
+ } else {
33
+ return false;
34
+ }
35
+ }
36
+
37
+ // Return the type of a given input
38
+ type_to_name(value) {
39
+ var type = typeof value;
40
+ if (type == "number") {
41
+ if (this.isInteger(value) === true) {
42
+ type = "integer";
43
+ } else {
44
+ type = "float";
45
+ }
46
+ }
47
+ return type;
48
+ }
49
+
50
+ // Make a distinct copy of an object
51
+ copyObject(input) {
52
+ try {
53
+ return JSON.parse(JSON.stringify(input));
54
+ // return clone;
55
+ } catch {
56
+ return {};
57
+ }
58
+ }
59
+
60
+ // Flatten an object
61
+ flattenArray(source, delimiter = ".", filter) {
62
+ var result = {};
63
+ (function flat(obj, stack) {
64
+ try {
65
+ Object.keys(obj).forEach(function (k) {
66
+ var s = stack.concat([k]);
67
+ var v = obj[k];
68
+ if (filter && filter(k, v)) return;
69
+ if (typeof v === "object") flat(v, s);
70
+ else result[s.join(delimiter)] = v;
71
+ });
72
+ } catch (err) {
73
+ return {};
74
+ }
75
+ })(source, []);
76
+ return result;
77
+ }
78
+
79
+ // Compare two objects
80
+ compareArrays({ newArray, oldArray } = {}) {
81
+ var nK = this.flattenArray(newArray);
82
+ var oK = this.flattenArray(oldArray);
83
+ if (Object.keys(nK).length !== Object.keys(oK).length) {
84
+ return true;
85
+ }
86
+ if (nK != null || nK != {}) {
87
+ if (oK != null || oK != {}) {
88
+ for (let x in nK) {
89
+ if (nK[x] !== oK[x]) {
90
+ return true;
91
+ }
92
+ }
93
+ } else {
94
+ return true;
95
+ }
96
+ }
97
+ return false;
98
+ }
99
+
100
+ // Convert event object to a list of objects
101
+ eventObjToList(input = {}) {
102
+ var output = [];
103
+ var iK = Object.keys(input);
104
+ if (iK.length > 0) {
105
+ for (let x of iK) {
106
+ let val = {};
107
+ val["key"] = x;
108
+ val["value"] = input[x];
109
+ output.push(val);
110
+ }
111
+ }
112
+ return output;
113
+ }
114
+
115
+ // Convert cart object to a list of objects with the bundle id as the key for each
116
+ cartObjToList(input = {}) {
117
+ var output = [];
118
+ var iK = Object.keys(input);
119
+ if (iK.length > 0) {
120
+ for (let x of iK) {
121
+ let bundle = {};
122
+ bundle["bundle_id"] = x;
123
+ let target = Object.assign({}, bundle, input[x]);
124
+ output.push(target);
125
+ }
126
+ }
127
+ return output;
128
+ }
129
+
130
+ // Data hygiene: return only input or null
131
+ validateData(input) {
132
+ if (input !== "undefined" && input !== null) {
133
+ return input;
134
+ } else {
135
+ return null;
136
+ }
137
+ }
138
+
139
+ setAppId(id) {
140
+ if (typeof id !== "undefined" && id.length > 0) {
141
+ this.logger.log(
142
+ "project",
143
+ this.constant.MetaStreamIO_IO_ProjectIdSet.format(id)
144
+ );
145
+ return id;
146
+ } else {
147
+ this.logger.warn(
148
+ "project",
149
+ this.constant.MetaStreamIO_IO_ProjectIdNotSet
150
+ );
151
+ return null;
152
+ }
153
+ }
154
+
155
+ sleep(ms) {
156
+ return new Promise((resolve) => setTimeout(resolve, ms));
157
+ }
158
+
159
+ castEventParameterTypes(eventParameters) {
160
+ try {
161
+ let castEventParameters = [];
162
+ eventParameters.forEach((parameter) => {
163
+ let value_type = this.type_to_name(parameter.value);
164
+ let temp_param = {};
165
+ temp_param["key"] = parameter.key;
166
+ temp_param["value"] = { ["" + value_type]: parameter.value };
167
+ castEventParameters.push(temp_param);
168
+ });
169
+ return castEventParameters;
170
+ } catch (err) {
171
+ return [];
172
+ }
173
+ }
174
+
175
+ async checkBlockingProcess(checkVariable) {
176
+ return new Promise(async (resolve, reject) => {
177
+ var max_retries = 5;
178
+ var retry = 0;
179
+ while (checkVariable === false && retry < max_retries) {
180
+ await this.sleep(500);
181
+ retry++;
182
+ continue;
183
+ }
184
+ if (checkVariable === true) {
185
+ resolve(checkVariable);
186
+ } else {
187
+ reject(Object.keys(checkVariable));
188
+ }
189
+ });
190
+ }
191
+
192
+ async makeBlockingProcess(checkVariable, fn, args) {
193
+ checkVariable = true;
194
+ let function_call = await fn(args)
195
+ .then((result) => {
196
+ return Promise.resolve(result);
197
+ })
198
+ .catch((result) => {
199
+ return Promise.reject(result);
200
+ });
201
+ checkVariable = false;
202
+ return function_call;
203
+ }
204
+ }
205
+
206
+ export { MetaStreamIOUtils };
@@ -0,0 +1,24 @@
1
+ export class AppConstructorModel {
2
+ constructor({
3
+ id = null,
4
+ channel = null,
5
+ environment = null,
6
+ endpoints = null,
7
+ headers = null,
8
+ } = {}) {
9
+ this.id = id;
10
+ this.channel = channel;
11
+ this.environment = environment;
12
+ this.endpoints = endpoints;
13
+ this.headers = headers;
14
+ }
15
+ json() {
16
+ return {
17
+ id: this.id,
18
+ channel: this.channel,
19
+ environment: this.environment,
20
+ endpoints: this.endpoints,
21
+ headers: this.headers,
22
+ };
23
+ }
24
+ }