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,150 @@
1
+ "use strict";
2
+
3
+ import { strf } from "./string.format.js";
4
+
5
+ strf();
6
+
7
+ /*
8
+ *
9
+ * Console logger
10
+ *
11
+ */
12
+
13
+ class MetaStreamIOLogger {
14
+ constructor({
15
+ constants,
16
+ logPrefix,
17
+ loggingEnabled = false,
18
+ loggingLevel = "INFO",
19
+ loggingCategories = null,
20
+ loggingAlwaysWarn = true,
21
+ loggingAlwaysError = true,
22
+ } = {}) {
23
+ this.constant = constants;
24
+ this.logPrefix = logPrefix ? logPrefix : "";
25
+ this.loggingEnabled = loggingEnabled;
26
+ this.loggingCategories = loggingCategories;
27
+
28
+ this.level = { info: 1, warn: 2, error: 3 };
29
+
30
+ this.loggingLevel = this.enumLevel(loggingLevel);
31
+
32
+ this.alwaysWarn = loggingAlwaysWarn;
33
+ this.alwaysError = loggingAlwaysError;
34
+ }
35
+
36
+ enumLevel(level) {
37
+ switch (level) {
38
+ case "INFO":
39
+ return this.level.info;
40
+ break;
41
+ case "WARN":
42
+ return this.level.warn;
43
+ break;
44
+ case "ERROR":
45
+ return this.level.error;
46
+ break;
47
+ default:
48
+ return this.level.info;
49
+ }
50
+ }
51
+
52
+ checkCategory(category = null) {
53
+ if (
54
+ this.loggingCategories !== null &&
55
+ this.loggingCategories.length === 0
56
+ ) {
57
+ return true;
58
+ }
59
+ if (!Array.isArray(category)) {
60
+ category = [category];
61
+ }
62
+ for (let cat in category) {
63
+ if (category[cat] === null) {
64
+ return true;
65
+ } else if (
66
+ this.loggingCategories === null ||
67
+ this.loggingCategories === undefined
68
+ ) {
69
+ return true;
70
+ } else if (this.loggingCategories.includes(category[cat])) {
71
+ return true;
72
+ } else {
73
+ return false;
74
+ }
75
+ }
76
+ }
77
+
78
+ log(category = null, ...messages) {
79
+ if (
80
+ this.loggingEnabled == true &&
81
+ this.loggingLevel <= this.level.info &&
82
+ this.checkCategory(category)
83
+ ) {
84
+ console.log(this.logPrefix, `<${category}>`, messages.join(" "));
85
+ return true;
86
+ }
87
+ }
88
+ log_unformatted(category = null, ...messages) {
89
+ if (
90
+ this.loggingEnabled == true &&
91
+ this.loggingLevel <= this.level.info &&
92
+ this.checkCategory(category)
93
+ ) {
94
+ console.log(messages.join(" "));
95
+ return true;
96
+ }
97
+ }
98
+ json(category = null, data) {
99
+ if (
100
+ this.loggingEnabled == true &&
101
+ this.loggingLevel <= this.level.info &&
102
+ this.checkCategory(category)
103
+ ) {
104
+ console.log(this.logPrefix, `<${category}>`);
105
+ console.log(JSON.stringify(data, null, 4));
106
+ return true;
107
+ }
108
+ }
109
+ info(category = null, ...messages) {
110
+ if (
111
+ this.loggingEnabled == true &&
112
+ this.loggingLevel <= this.level.info &&
113
+ this.checkCategory(category)
114
+ ) {
115
+ console.log(this.logPrefix, `<${category}>`, messages.join(" "));
116
+ return true;
117
+ }
118
+ }
119
+ warn(category = null, ...messages) {
120
+ if (this.loggingEnabled && this.alwaysWarn) {
121
+ this._warn(category, messages);
122
+ } else if (
123
+ this.loggingEnabled == true &&
124
+ this.loggingLevel <= this.level.warn
125
+ ) {
126
+ this._warn(category, messages);
127
+ return true;
128
+ }
129
+ }
130
+ _warn(category, messages) {
131
+ console.warn(this.logPrefix, `<${category}>`, messages.join(" "));
132
+ }
133
+ error(category = null, ...messages) {
134
+ if (this.loggingEnabled && this.alwaysError) {
135
+ this._error(category, messages);
136
+ return true;
137
+ } else if (
138
+ this.loggingEnabled == true &&
139
+ this.loggingLevel <= this.level.error
140
+ ) {
141
+ this._error(category, messages);
142
+ return true;
143
+ }
144
+ }
145
+ _error(category, messages) {
146
+ console.error(this.logPrefix, `<${category}>`, messages.join(" "));
147
+ }
148
+ }
149
+
150
+ export { MetaStreamIOLogger };
@@ -0,0 +1,313 @@
1
+ "use strict";
2
+
3
+ import { strf } from "./string.format.js";
4
+ import AsyncStorage from "@react-native-async-storage/async-storage";
5
+ import NetInfo from "@react-native-community/netinfo";
6
+
7
+ strf();
8
+
9
+ const EVENT_QUEUE_KEY = "metastream_offline_events";
10
+
11
+ /*
12
+ *
13
+ * Network functions
14
+ *
15
+ */
16
+
17
+ class MetaStreamIONetwork {
18
+ constructor({ constants, endpoints, logger, silentMode, headers } = {}) {
19
+ this.silentMode = silentMode;
20
+ this.constant = constants;
21
+ this.endpoint = null;
22
+ this.endpoints = Array.isArray(endpoints) ? endpoints : [];
23
+ this.headers = headers;
24
+ this.logger = logger;
25
+
26
+ // Initialize offline handling
27
+ this.initOfflineHandling();
28
+ }
29
+
30
+ initOfflineHandling() {
31
+ // Flush on startup if connected
32
+ NetInfo.fetch().then(state => {
33
+ if (state.isConnected) {
34
+ this.flushEvents();
35
+ }
36
+ });
37
+
38
+ // Flush when network comes back online
39
+ NetInfo.addEventListener(state => {
40
+ if (state.isConnected) {
41
+ this.flushEvents();
42
+ }
43
+ });
44
+ }
45
+
46
+ reset() {
47
+ this.endpoint = null;
48
+ }
49
+
50
+ async testConnection() {
51
+ if (!this.endpoint || this.endpoint === null) {
52
+ for (let _e in this.endpoints) {
53
+ this.endpoint = await this.getData({ endpoint: this.endpoints[_e] })
54
+ .then((data) => {
55
+ try {
56
+ if (data.status === 200) {
57
+ return this.endpoints[_e];
58
+ }
59
+ } catch (err) {
60
+ return false;
61
+ }
62
+ })
63
+ .catch(() => { });
64
+ if (this.endpoint) {
65
+ this.logger.log(
66
+ "network",
67
+ this.constant.MetaStreamIO_Network_EndpointSet.format(this.endpoint)
68
+ );
69
+ break;
70
+ } else {
71
+ this.logger.log(
72
+ "network",
73
+ this.constant.MetaStreamIO_Network_EndpointTestFailed.format(
74
+ this.endpoint
75
+ )
76
+ );
77
+ this.logger.log(
78
+ "network",
79
+ this.constant.MetaStreamIO_Network_SilentModeEnabled
80
+ );
81
+ }
82
+ }
83
+ }
84
+
85
+ return Promise.resolve(this.endpoint);
86
+ }
87
+
88
+ async getData({ endpoint = this.endpoint } = {}) {
89
+ var rx;
90
+
91
+ let get_config = {
92
+ method: "GET",
93
+ // mode: "no-cors", // required for local testing
94
+ cache: "no-cache",
95
+ credentials: "same-origin",
96
+ redirect: "follow", // manual, *follow, error
97
+ referrerPolicy: "no-referrer", // no-referrer, *client
98
+ headers: {},
99
+ };
100
+
101
+ if (this.headers !== null) {
102
+ get_config.headers = Object.assign(get_config.headers, this.headers);
103
+ }
104
+
105
+ try {
106
+ await fetch(endpoint, get_config)
107
+ .then((response) => {
108
+ const contentType = response.headers.get("content-type");
109
+ if (!contentType || !contentType.includes("application/json")) {
110
+ return null;
111
+ } else {
112
+ return response;
113
+ }
114
+ })
115
+ .catch((err) => {
116
+ return Promise.resolve(err);
117
+ })
118
+ .then(async (response) => {
119
+ rx = {
120
+ body: await response.json(),
121
+ status: response.status,
122
+ };
123
+ })
124
+ .catch((err) => {
125
+ return {
126
+ body: err,
127
+ status: 400,
128
+ };
129
+ });
130
+ return rx;
131
+ } catch (err) {
132
+ return Promise.reject(err);
133
+ throw this.constant.MetaStreamIO_Network_GetDataIssue.format(
134
+ err,
135
+ endpoint
136
+ );
137
+ }
138
+ }
139
+
140
+ async postData({ data = {}, endpoint = null } = {}) {
141
+ var ret;
142
+
143
+ var _endpoint = this.endpoint + (endpoint ? endpoint : "");
144
+
145
+ this.logger.log(
146
+ "network-request",
147
+ this.constant.MetaStreamIO_Log_RequestObject
148
+ );
149
+ this.logger.json("network-request", data);
150
+
151
+ if (this.silentMode) {
152
+ return {
153
+ body: this.constant.MetaStreamIO_Network_SilentMode,
154
+ status: 1,
155
+ };
156
+ }
157
+
158
+ if (!this.endpoint) {
159
+ _endpoint = await this.testConnection()
160
+ .then((rx_endpoint) => {
161
+ return Promise.resolve(rx_endpoint + (endpoint ? endpoint : ""));
162
+ })
163
+ .catch((err) => err);
164
+ }
165
+
166
+ if (_endpoint) {
167
+ return await this.post({
168
+ data: data,
169
+ endpoint: _endpoint,
170
+ })
171
+ .then((post_return) => {
172
+ return Promise.resolve(post_return);
173
+ })
174
+ .catch((err) => {
175
+ return Promise.resolve(err);
176
+ });
177
+ } else {
178
+ // Network configuration failed, try to store offline if it looks like a network issue
179
+ this.logger.log("network", "No endpoint resolved, storing offline...");
180
+ // Use the first endpoint candidate if available for offline storage purpose
181
+ const fallbackEndpoint = this.endpoints.length > 0 ? this.endpoints[0] : null;
182
+ if (fallbackEndpoint) {
183
+ await this.storeOfflineEvent(fallbackEndpoint + (endpoint ? endpoint : ""), data);
184
+ return {
185
+ body: "Stored offline",
186
+ status: 200 // Fake success to prevent app error
187
+ };
188
+ }
189
+
190
+ return {
191
+ body: this.constant.MetaStreamIO_Network_PostDataIssue.format(
192
+ "attempted to reset network",
193
+ _endpoint
194
+ ),
195
+ status: 400,
196
+ };
197
+ }
198
+ }
199
+
200
+ async post({ data = {}, endpoint = this.endpoint } = {}) {
201
+ let rx = {};
202
+
203
+ let post_config = {
204
+ method: "POST",
205
+ // mode: "no-cors", // required for local testing
206
+ cache: "no-cache",
207
+ credentials: "same-origin",
208
+ headers: {
209
+ "Content-Type": "application/json",
210
+ },
211
+ redirect: "follow", // manual, *follow, error
212
+ referrerPolicy: "no-referrer", // no-referrer, *client
213
+ body: JSON.stringify(data),
214
+ };
215
+
216
+ if (this.headers !== null) {
217
+ post_config.headers = Object.assign(post_config.headers, this.headers);
218
+ }
219
+
220
+ let isOffline = false;
221
+ await NetInfo.fetch().then(state => {
222
+ if (!state.isConnected) {
223
+ isOffline = true;
224
+ }
225
+ });
226
+
227
+ if (isOffline) {
228
+ this.logger.log("network", "Offline detected. Storing event.");
229
+ await this.storeOfflineEvent(endpoint, data);
230
+ return { status: 200, body: "Stored offline" };
231
+ }
232
+
233
+ await fetch(endpoint, post_config)
234
+ .then((response) => {
235
+ let _contentType = response.headers.get("content-type");
236
+ if (!_contentType || !_contentType.includes("application/json")) {
237
+ return null;
238
+ } else {
239
+ rx.status = response.status;
240
+ return response;
241
+ }
242
+ })
243
+ .then(async (response) => {
244
+ rx.body = await response.json();
245
+ })
246
+ .catch(async (err) => {
247
+ this.logger.error("network", "fetch() response", err);
248
+ // Store offline on network error
249
+ await this.storeOfflineEvent(endpoint, data);
250
+ rx.status = 200; // Treat as success to deque
251
+ rx.body = "Stored offline on error";
252
+ });
253
+
254
+ return rx;
255
+ }
256
+
257
+ async storeOfflineEvent(endpoint, payload) {
258
+ try {
259
+ const existing = JSON.parse(await AsyncStorage.getItem(EVENT_QUEUE_KEY)) || [];
260
+ const newEvent = {
261
+ endpoint,
262
+ payload,
263
+ failedAt: new Date().toISOString(),
264
+ };
265
+ existing.push(newEvent);
266
+ await AsyncStorage.setItem(EVENT_QUEUE_KEY, JSON.stringify(existing));
267
+ this.logger.log("network", `Stored event locally. Queue size: ${existing.length}`);
268
+ } catch (error) {
269
+ this.logger.error("network", "Failed to store event:", error);
270
+ }
271
+ }
272
+
273
+ async flushEvents() {
274
+ try {
275
+ const stored = JSON.parse(await AsyncStorage.getItem(EVENT_QUEUE_KEY)) || [];
276
+ if (stored.length === 0) {
277
+ return;
278
+ }
279
+
280
+ this.logger.log("network", `Flushing ${stored.length} stored event(s)...`);
281
+ const remainingEvents = [];
282
+
283
+ for (const e of stored) {
284
+ try {
285
+ const response = await fetch(e.endpoint, {
286
+ method: "POST",
287
+ headers: { "Content-Type": "application/json" },
288
+ body: JSON.stringify(e.payload),
289
+ });
290
+
291
+ if (response.ok) {
292
+ this.logger.log("network", "Retried & sent event");
293
+ } else {
294
+ // Drop event if server rejects it (4xx, 5xx), avoid infinite loop
295
+ this.logger.warn("network", "Retry failed with non-OK status, dropping event");
296
+ }
297
+ } catch (err) {
298
+ // Keep if network error
299
+ remainingEvents.push(e);
300
+ }
301
+ }
302
+
303
+ await AsyncStorage.setItem(EVENT_QUEUE_KEY, JSON.stringify(remainingEvents));
304
+ if (remainingEvents.length < stored.length) {
305
+ this.logger.log("network", `Flush complete. Remaining: ${remainingEvents.length}`);
306
+ }
307
+ } catch (error) {
308
+ this.logger.error("network", "Failed to flush events:", error);
309
+ }
310
+ }
311
+
312
+ }
313
+ export { MetaStreamIONetwork };
@@ -0,0 +1,50 @@
1
+ import React, { Component } from 'react';
2
+ import { View, StyleSheet, Dimensions } from 'react-native';
3
+ import ViewShot from 'react-native-view-shot';
4
+
5
+ class MetaStreamProvider extends Component {
6
+ constructor(props) {
7
+ super(props);
8
+ this.viewShotRef = React.createRef();
9
+ this.tracker = props.tracker;
10
+
11
+ // Auto-start recording if tracker is available
12
+ if (this.tracker && this.tracker.recorder) {
13
+ // Small delay to ensure view is mounted
14
+ setTimeout(() => {
15
+ this.tracker.recorder.startRecording(this.viewShotRef);
16
+ }, 1000);
17
+ }
18
+ }
19
+
20
+ handleTouch(e, type) {
21
+ if (this.tracker && this.tracker.recorder) {
22
+ this.tracker.recorder.recordInteraction(type, e.nativeEvent);
23
+ }
24
+ }
25
+
26
+ render() {
27
+ const { children, style } = this.props;
28
+
29
+ return (
30
+ <ViewShot ref={this.viewShotRef} style={{ flex: 1 }} options={{ format: "jpg", quality: 0.5 }}>
31
+ <View
32
+ style={[styles.container, style]}
33
+ onTouchStart={(e) => this.handleTouch(e, 'touch_start')}
34
+ onTouchMove={(e) => this.handleTouch(e, 'touch_move')}
35
+ onTouchEnd={(e) => this.handleTouch(e, 'touch_end')}
36
+ >
37
+ {children}
38
+ </View>
39
+ </ViewShot>
40
+ );
41
+ }
42
+ }
43
+
44
+ const styles = StyleSheet.create({
45
+ container: {
46
+ flex: 1,
47
+ }
48
+ });
49
+
50
+ export { MetaStreamProvider };
@@ -0,0 +1,68 @@
1
+ // http://nickang.com
2
+
3
+ /**
4
+ * Implementation of Queue.
5
+ */
6
+ class Queue {
7
+ /**
8
+ * Create a queue.
9
+ */
10
+ constructor() {
11
+ this.store = {};
12
+ this.front = 0;
13
+ this.end = 0;
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Add item to end of queue.
19
+ * @param {*} The data to store in the position.
20
+ */
21
+ Queue.prototype.enqueue = function (data) {
22
+ this.store[this.end] = data;
23
+ this.end++;
24
+ };
25
+
26
+ /**
27
+ * Remove item from queue and return its data.
28
+ * @return {*} The data stored in item.
29
+ */
30
+ Queue.prototype.dequeue = function () {
31
+ if (this.front === this.end) return null;
32
+
33
+ const data = this.store[this.front];
34
+ delete this.store[this.front];
35
+ this.front++;
36
+ return data;
37
+ };
38
+
39
+ /**
40
+ * Return current size of queue.
41
+ * @return {number} Size of queue.
42
+ */
43
+ Queue.prototype.size = function () {
44
+ return this.end - this.front;
45
+ };
46
+
47
+ /**
48
+ * Return item at front of queue without dequeueing.
49
+ * @return {*} The data stored in item.
50
+ */
51
+ Queue.prototype.peek = function () {
52
+ if (this.size() === 0) return null;
53
+ return this.store[this.front];
54
+ };
55
+
56
+ /*
57
+ * The MetaStreamIO SAUCE
58
+ *
59
+ */
60
+ Queue.prototype.run = function (callback) {
61
+ while (this.size() > 0) {
62
+ callback(this.dequeue()).catch(err => {
63
+ console.error('<queue callback>', err);
64
+ });
65
+ }
66
+ };
67
+
68
+ export {Queue};