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,591 @@
1
+ "use strict";
2
+
3
+ // Global string format function, similar to Python
4
+
5
+ import { strf } from "./string.format.js";
6
+
7
+ strf();
8
+
9
+ // MetaStreamIO modules
10
+ import { MetaStreamIOCart } from "./metastreamio.cart.js";
11
+ import { MetaStreamIOConstants } from "./metastreamio.constants.js";
12
+ import { MetaStreamIODate } from "./metastreamio.date.js";
13
+ import { MetaStreamIOEnvironment } from "./metastreamio.environment.js";
14
+ import { MetaStreamIOLogger } from "./metastreamio.logger.js";
15
+ import { MetaStreamIOAccountData } from "./metastreamio.account.js";
16
+ import { MetaStreamIONetwork } from "./metastreamio.network.js";
17
+ import { MetaStreamIOSession } from "./metastreamio.session.js";
18
+ import { MetaStreamIOUser } from "./metastreamio.user.js";
19
+ import { MetaStreamIOUserProperties } from "./metastreamio.userproperties.js";
20
+ import { MetaStreamIOUtils } from "./metastreamio.utility.js";
21
+ import { Queue } from "./metastreamio.queue.js";
22
+ import { MetaStreamIORecorder } from "./metastreamio.recorder.js";
23
+
24
+
25
+ // MetaStreamIO models
26
+ import { CartModel } from "./models/event.cart.js";
27
+ import { CartItemModel } from "./models/event.cartitem.js";
28
+ import { EventModel } from "./models/event.event.js";
29
+ import { EventParametersModel } from "./models/event.parameters.js";
30
+ import { EventParameterModel } from "./models/event.parameter.js";
31
+ import { AppConstructorModel } from "./models/constructor.app.js";
32
+ import { ConfigConstructorModel } from "./models/constructor.config.js";
33
+ import { UserConstructorModel } from "./models/constructor.user.js";
34
+
35
+ /*
36
+ *
37
+ * Main analytics interface class
38
+ *
39
+ */
40
+
41
+ class MetaStreamIO {
42
+ constructor({ app = {}, config = {}, user = {} } = {}) {
43
+ this.appConfig = this.validateConstructor(app, new AppConstructorModel());
44
+ this.config = this.validateConstructor(
45
+ config,
46
+ new ConfigConstructorModel()
47
+ );
48
+ this.userConfig = this.validateConstructor(
49
+ user,
50
+ new UserConstructorModel()
51
+ );
52
+ this.constant = new MetaStreamIOConstants();
53
+ this.date = new MetaStreamIODate();
54
+ this.logger = new MetaStreamIOLogger({
55
+ constants: this.constant,
56
+ logPrefix: this.constant.MetaStreamIO_Logger_Prefix,
57
+ loggingEnabled: this.config.logging,
58
+ loggingLevel: this.config.loggingLevel,
59
+ loggingCategories: this.config.loggingCategories,
60
+ loggingAlwaysError: this.config.loggingAlwaysError,
61
+ loggingAlwaysWarn: this.config.loggingAlwaysWarn,
62
+ });
63
+ this.utility = new MetaStreamIOUtils({
64
+ constants: this.constant,
65
+ date: this.date,
66
+ logger: this.logger,
67
+ });
68
+ this.cart = new MetaStreamIOCart({
69
+ constants: this.constant,
70
+ date: this.date,
71
+ logger: this.logger,
72
+ utility: this.utility,
73
+ });
74
+ this.environment = new MetaStreamIOEnvironment({
75
+ constants: this.constant,
76
+ logger: this.logger,
77
+ date: this.date,
78
+ });
79
+ this.network = new MetaStreamIONetwork({
80
+ constants: this.constant,
81
+ logger: this.logger,
82
+ silentMode: this.config.silentMode,
83
+ endpoints: this.appConfig.endpoints,
84
+ headers: this.appConfig.headers,
85
+ });
86
+ this.account = new MetaStreamIOAccountData({
87
+ constants: this.constant,
88
+ logger: this.logger,
89
+ utility: this.utility,
90
+ });
91
+ this.session = new MetaStreamIOSession({
92
+ constants: this.constant,
93
+ date: this.date,
94
+ environment: this.environment,
95
+ logger: this.logger,
96
+ network: this.network,
97
+ sessionLength: this.config.sessionLength,
98
+ utility: this.utility,
99
+ });
100
+ this.user = new MetaStreamIOUser({
101
+ constants: this.constant,
102
+ logger: this.logger,
103
+ });
104
+ this.userproperties = new MetaStreamIOUserProperties({
105
+ constants: this.constant,
106
+ logger: this.logger,
107
+ utility: this.utility,
108
+ });
109
+
110
+ this.queue = new Queue();
111
+
112
+ this.recorder = new MetaStreamIORecorder({
113
+ constants: this.constant,
114
+ logger: this.logger,
115
+ network: this.network,
116
+ config: this.config,
117
+ });
118
+
119
+ // Init global variables
120
+ this.previous = {};
121
+ this.app_id = this.utility.setAppId(this.appConfig.id);
122
+ this.app_environment = this.appConfig.environment;
123
+ this.channel = this.appConfig.channel;
124
+
125
+ if (this.userConfig.guestMode === true) {
126
+ this.start_session({
127
+ user_id: this.userConfig.user_id,
128
+ ciam_id: this.userConfig.ciam_id,
129
+ email_id: this.userConfig.email_id,
130
+ country: this.userConfig.country,
131
+ cart_id: this.userConfig.cart_id,
132
+ });
133
+ }
134
+ }
135
+
136
+ /*
137
+ * Session
138
+ */
139
+
140
+ start_session({
141
+ user_id = null,
142
+ ciam_id = null,
143
+ email_id = null,
144
+ country = null,
145
+ cart_id = null,
146
+ reset = false,
147
+ } = {}) {
148
+ let errors = [];
149
+ this.logger.log(
150
+ "session",
151
+ `start session :: user: <${user_id}> cart: <${cart_id}>`
152
+ );
153
+
154
+ if (reset) {
155
+ this.reset();
156
+ }
157
+
158
+ try {
159
+ this.user.set(user_id);
160
+ } catch (err) {
161
+ errors.push("user_id");
162
+ this.logger.log("user", "could not set user id :: " + err);
163
+ }
164
+
165
+ try {
166
+ this.user.setCiam(ciam_id);
167
+ } catch (err) {
168
+ errors.push("ciam_id");
169
+ this.logger.log("user", "could not set ciam id :: " + err);
170
+ }
171
+
172
+ try {
173
+ this.user.setEmail(email_id);
174
+ } catch (err) {
175
+ errors.push("email_id");
176
+ this.logger.log("user", "could not set email id :: " + err);
177
+ }
178
+
179
+ try {
180
+ this.user.setCountry(country);
181
+ } catch (err) {
182
+ errors.push("country");
183
+ this.logger.log("user", "could not set user country :: " + err);
184
+ }
185
+
186
+ this.cart.clear(cart_id);
187
+
188
+ try {
189
+ if (!this.session.session.id) {
190
+ const newSessionId = this.utility.generateRandomId(); // Assuming session uses something like this
191
+ this.session.createNewSession({
192
+ session_id: newSessionId,
193
+ session_source: null,
194
+ session_utm: {},
195
+ });
196
+ // Update recorder session ID
197
+ if (this.recorder) this.recorder.setSessionId(this.session.session.id);
198
+ }
199
+ } catch (err) {
200
+ errors.push("session");
201
+ this.logger.log("session", "could not create new session: " + err);
202
+ }
203
+ return errors;
204
+ }
205
+
206
+ reset() {
207
+ this.account.reset();
208
+ this.cart.reset();
209
+ this.environment.reset();
210
+ this.network.reset();
211
+ this.session.reset();
212
+ this.user.reset();
213
+ this.userproperties.reset();
214
+ if (this.recorder) this.recorder.stopRecording();
215
+ }
216
+
217
+ async validateSession() {
218
+ var errors = [];
219
+
220
+ this.logger.log("session", "validateSession() validating session");
221
+ if (!this.session.session.id || !this.cart.cart.id) {
222
+ try {
223
+ let _start_session = this.start_session();
224
+ if (_start_session.length === 0) {
225
+ this.logger.log("session", "validateSession() started new session");
226
+ } else {
227
+ errors.push(_start_session);
228
+ }
229
+ } catch (err) {
230
+ this.logger.log(
231
+ "session",
232
+ "validateSession() error starting new session: " + err
233
+ );
234
+ errors.push("validateSession() error starting new session: " + err);
235
+ }
236
+ } else {
237
+ this.logger.log(
238
+ "session",
239
+ `validateSession() did not start new session session <${this.session.session.id}> cart <${this.cart.cart.id}>`
240
+ );
241
+ }
242
+
243
+ if (!this.network.endpoint) {
244
+ await this.network
245
+ .testConnection()
246
+ .then((response) => {
247
+ this.logger.log(
248
+ "session",
249
+ `validateSession() testConnection returned: ${response}`
250
+ );
251
+ })
252
+ .catch((err) => {
253
+ this.logger.log(
254
+ "session",
255
+ `validateSession() testConnection error: ${err}`
256
+ );
257
+ errors.push("validateSession() network issue");
258
+ });
259
+ }
260
+
261
+ if (errors.length === 0) {
262
+ return Promise.resolve("success");
263
+ } else {
264
+ return Promise.reject(errors);
265
+ }
266
+ }
267
+
268
+ /*
269
+ * Settings
270
+ */
271
+
272
+ setAllowTrackCategories(categories = []) {
273
+ if (Array.isArray(categories) === true) {
274
+ this.config.allowTrackCategories = categories;
275
+ }
276
+ }
277
+
278
+ /*
279
+ * Track events
280
+ */
281
+
282
+ checkEventName(eventName) {
283
+ try {
284
+ if (typeof eventName !== "undefined" && eventName.length > 0) {
285
+ return true;
286
+ } else {
287
+ return false;
288
+ }
289
+ } catch (err) {
290
+ this.logger.log(
291
+ "event",
292
+ `checkEventName() error checking event name: ${err}`
293
+ );
294
+ return false;
295
+ }
296
+ }
297
+
298
+ testAllowedTrackCategory(category) {
299
+ if (Array.isArray(this.config.allowTrackCategories)) {
300
+ return this.config.allowTrackCategories.length === 0
301
+ ? true
302
+ : this.config.allowTrackCategories.includes(category);
303
+ } else {
304
+ return true;
305
+ }
306
+ }
307
+
308
+ trackEvent({
309
+ eventName,
310
+ eventParameters,
311
+ sendOnce = this.constant.MetaStreamIO_SendOnceDefault,
312
+ temporaryCart = false,
313
+ transactionId = null,
314
+ category = null,
315
+ } = {}) {
316
+ if (category !== null) {
317
+ if (this.testAllowedTrackCategory(category) === false) {
318
+ this.logger.warn(
319
+ "event",
320
+ `not allowed to track this category: ${category}`
321
+ );
322
+ return;
323
+ }
324
+ }
325
+ if (this.checkEventName(eventName) === true) {
326
+ let cart = temporaryCart.items
327
+ ? this.utility.copyObject(temporaryCart.list())
328
+ : this.utility.copyObject(this.cart.cart.list());
329
+ let lastCart = this.utility.copyObject(this.cart.lastCart);
330
+ let lastEventName = this.previous.event_name;
331
+ let tempEventParameters =
332
+ this.utility.castEventParameterTypes(eventParameters);
333
+ let lastEventParameters = this.utility.copyObject(
334
+ this.previous.event_params
335
+ );
336
+ let userProperties = this.utility.copyObject(this.userproperties.list());
337
+ let lastUserProperties = this.utility.copyObject(
338
+ this.previous.user_properties
339
+ );
340
+ let client_event_date = this.date.getEventDate();
341
+ let client_event_timestamp = this.date.getEventTimestamp();
342
+
343
+ // Get difference between previous event object and current
344
+ var eventParamDiff = this.utility.compareArrays({
345
+ newArray: tempEventParameters,
346
+ oldArray: lastEventParameters ? lastEventParameters : {},
347
+ });
348
+ var userPropertyDiff = this.utility.compareArrays({
349
+ newArray: userProperties,
350
+ oldArray: lastUserProperties ? lastUserProperties : {},
351
+ });
352
+ var cartDiff = this.utility.compareArrays({
353
+ newArray: cart,
354
+ oldArray: lastCart ? lastCart : {},
355
+ });
356
+
357
+ if (
358
+ sendOnce === true &&
359
+ eventName === lastEventName &&
360
+ eventParamDiff === false &&
361
+ userPropertyDiff === false &&
362
+ cartDiff === false
363
+ ) {
364
+ this.logger.log("event", this.constant.MetaStreamIO_Log_SendOnce);
365
+ } else {
366
+ let e = new EventModel({
367
+ account_balances: this.utility.copyObject(
368
+ this.account.account.list()
369
+ ),
370
+ account_type: this.account.account.type,
371
+ app: this.app_id,
372
+ app_environment: this.app_environment,
373
+ app_info: null,
374
+ app_performance: null,
375
+ cart: cart,
376
+ cart_id: temporaryCart ? temporaryCart.id : this.cart.cart.id,
377
+ channel: this.channel,
378
+ ciam_id: this.user.ciam_id,
379
+ client_event_date: client_event_date,
380
+ client_event_timestamp: client_event_timestamp,
381
+ device: null,
382
+ device_token: this.user.device_token,
383
+ email_id: this.user.email_id,
384
+ event_name: eventName,
385
+ event_params: tempEventParameters,
386
+ network: null,
387
+ session: this.utility.copyObject(
388
+ this.session.logSession(this.previous.event_time)
389
+ ),
390
+ transaction_id: transactionId,
391
+ user_id: this.user.id,
392
+ user_country: this.user.country,
393
+ user_properties: this.utility.copyObject(this.userproperties.list()),
394
+ });
395
+
396
+ this.storeEventMeta({
397
+ eventTimestamp: client_event_timestamp,
398
+ eventName: eventName,
399
+ eventParameters: this.utility.copyObject(tempEventParameters),
400
+ });
401
+ try {
402
+ this.queue.enqueue(e);
403
+ this.runQueue().catch((err) => {
404
+ this.logger.log("event", `could no run the queue: ${err}`);
405
+ });
406
+ } catch (err) {
407
+ this.logger.log("event", `trackEvent() QUEUE ${err}`);
408
+ }
409
+ }
410
+ }
411
+
412
+ // CLEAN UP
413
+ this.handleEventRules(eventName);
414
+ }
415
+
416
+ // Bypass any active shopping cart and submit a quick buy event
417
+
418
+ trackQuickBuy({
419
+ eventName,
420
+ eventParameters,
421
+ temporaryCart = null,
422
+ transactionId = null,
423
+ } = {}) {
424
+ var item = {};
425
+
426
+ if (temporaryCart && typeof temporaryCart === "object") {
427
+ let _tCart = new CartModel({
428
+ id: this.utility.generateRandomId(),
429
+ items: {
430
+ [temporaryCart.id]: this.validateConstructor(
431
+ temporaryCart,
432
+ new CartItemModel()
433
+ ),
434
+ },
435
+ });
436
+ this.trackEvent({
437
+ eventName: eventName,
438
+ eventParameters: eventParameters,
439
+ sendOnce: true,
440
+ temporaryCart: _tCart,
441
+ transactionId: transactionId,
442
+ });
443
+ }
444
+ }
445
+
446
+ async post_event(event_data) {
447
+ if (event_data) {
448
+ var status = await this.network
449
+ .postData({ data: event_data })
450
+ .then((data) => {
451
+ let _data = JSON.stringify(data);
452
+ this.logger.log(
453
+ "network",
454
+ this.constant.MetaStreamIO_Network_PostDataReturn.format(_data)
455
+ );
456
+ if (data.status == 200) {
457
+ this.logger.log(
458
+ "event",
459
+ this.constant.MetaStreamIO_Log_EventTracked.format(
460
+ event_data.event.event_name
461
+ )
462
+ );
463
+ return Promise.resolve(event_data);
464
+ } else if (data.status == 1) {
465
+ this.logger.warn(
466
+ "network",
467
+ this.constant.MetaStreamIO_Network_SilentMode
468
+ );
469
+ return Promise.resolve(event_data);
470
+ } else {
471
+ this.logger.error(
472
+ "event",
473
+ this.constant.MetaStreamIO_Log_EventTrackFailed.format(_data)
474
+ );
475
+ this.logger.warn(
476
+ "network",
477
+ this.constant.MetaStreamIO_Network_PostDataReturn.format(_data)
478
+ );
479
+ return Promise.reject(_data);
480
+ }
481
+ })
482
+ .catch((err) => {
483
+ this.logger.error("event", "<post_event> could not post: " + err);
484
+ return Promise.reject(err);
485
+ });
486
+ return status;
487
+ } else {
488
+ this.logger.error("event", "<post_event> event_data is undefined");
489
+ }
490
+ }
491
+
492
+ async runQueue() {
493
+ return this.queue.run(
494
+ async function (event) {
495
+ // Enrich
496
+ event.app_info = await this.environment.logAppInfo().catch(() => null);
497
+ event.app_performance = await this.environment
498
+ .logAppPerformance()
499
+ .catch(() => null);
500
+ event.device = await this.environment.logDevice().catch(() => null);
501
+ event.network = await this.environment
502
+ .logNetworkInfo()
503
+ .catch(() => null);
504
+
505
+ let response = await this.post_event(event.json())
506
+ .then((res) => {
507
+ this.logger.log(
508
+ "event",
509
+ "<runQueue> event processed, dequeued: " +
510
+ res["event"]["event_name"] +
511
+ " " +
512
+ res["event"]["session"]["id"]
513
+ );
514
+ return Promise.resolve();
515
+ })
516
+ .catch((err) => {
517
+ this.logger.error(
518
+ "event",
519
+ "<runQueue> this.post_event failed: " + err
520
+ );
521
+ this.logger.warn(
522
+ "event",
523
+ "could not post event, enqueueing again: " + err
524
+ );
525
+ try {
526
+ this.queue.enqueue(event);
527
+ } catch (err) {
528
+ this.logger.error(
529
+ "event",
530
+ "<runQueue> could not enqueue event: " + err
531
+ );
532
+ }
533
+ return Promise.reject(err);
534
+ });
535
+ }.bind(this)
536
+ );
537
+ }
538
+
539
+ async storeEventMeta({ eventTimestamp, eventName, eventParameters } = {}) {
540
+ this.previous.event_time = eventTimestamp;
541
+ this.previous.event_name = eventName;
542
+ this.previous.event_params = eventParameters;
543
+ this.previous.user_properties = this.utility.copyObject(
544
+ this.userproperties.properties
545
+ );
546
+ this.cart.lastCart = this.utility.copyObject(this.cart.cart.list());
547
+ }
548
+
549
+ handleEventRules(eventName) {
550
+ if (eventName === "purchase") {
551
+ this.handlePurchaseEvent();
552
+ }
553
+
554
+ if (eventName === "logout") {
555
+ this.logger.log("session"), "destroying session";
556
+ this.start_session({ reset: true });
557
+ }
558
+ }
559
+
560
+ handlePurchaseEvent() {
561
+ this.cart.clear();
562
+ }
563
+
564
+ validateConstructor(config = null, constructor = null) {
565
+ /* called before this.logger exists */
566
+ if (
567
+ typeof config === "object" &&
568
+ config !== null &&
569
+ typeof constructor === "object" &&
570
+ constructor !== null
571
+ ) {
572
+ let keys = Object.keys(constructor);
573
+ for (let _k in keys) {
574
+ if (keys[_k] in constructor) {
575
+ constructor[keys[_k]] = this.validateParameter(keys[_k], config);
576
+ }
577
+ }
578
+ }
579
+ return constructor;
580
+ }
581
+
582
+ validateParameter(key, config) {
583
+ if (key in config) {
584
+ return config[key];
585
+ } else {
586
+ return null;
587
+ }
588
+ }
589
+ }
590
+
591
+ export default MetaStreamIO;