@phystack/hub-client 4.4.29

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 (113) hide show
  1. package/.prettierignore +10 -0
  2. package/.prettierrc +10 -0
  3. package/CHANGELOG.md +1202 -0
  4. package/README-MEDIASTREAM.md +124 -0
  5. package/README.md +302 -0
  6. package/dist/constants/constants.d.ts +7 -0
  7. package/dist/constants/constants.d.ts.map +1 -0
  8. package/dist/constants/constants.js +10 -0
  9. package/dist/constants/constants.js.map +1 -0
  10. package/dist/helpers/browser.helper.d.ts +5 -0
  11. package/dist/helpers/browser.helper.d.ts.map +1 -0
  12. package/dist/helpers/browser.helper.js +19 -0
  13. package/dist/helpers/browser.helper.js.map +1 -0
  14. package/dist/helpers/cache.helper.d.ts +6 -0
  15. package/dist/helpers/cache.helper.d.ts.map +1 -0
  16. package/dist/helpers/cache.helper.js +46 -0
  17. package/dist/helpers/cache.helper.js.map +1 -0
  18. package/dist/helpers/date.helper.d.ts +4 -0
  19. package/dist/helpers/date.helper.d.ts.map +1 -0
  20. package/dist/helpers/date.helper.js +13 -0
  21. package/dist/helpers/date.helper.js.map +1 -0
  22. package/dist/helpers/session.helper.d.ts +13 -0
  23. package/dist/helpers/session.helper.d.ts.map +1 -0
  24. package/dist/helpers/session.helper.js +88 -0
  25. package/dist/helpers/session.helper.js.map +1 -0
  26. package/dist/helpers/shorten-look-ups.helper.d.ts +3 -0
  27. package/dist/helpers/shorten-look-ups.helper.d.ts.map +1 -0
  28. package/dist/helpers/shorten-look-ups.helper.js +80 -0
  29. package/dist/helpers/shorten-look-ups.helper.js.map +1 -0
  30. package/dist/helpers/signals-client.helper.d.ts +9 -0
  31. package/dist/helpers/signals-client.helper.d.ts.map +1 -0
  32. package/dist/helpers/signals-client.helper.js +44 -0
  33. package/dist/helpers/signals-client.helper.js.map +1 -0
  34. package/dist/helpers/signals.helper.d.ts +19 -0
  35. package/dist/helpers/signals.helper.d.ts.map +1 -0
  36. package/dist/helpers/signals.helper.js +48 -0
  37. package/dist/helpers/signals.helper.js.map +1 -0
  38. package/dist/helpers/wrtc/browser.d.ts +3 -0
  39. package/dist/helpers/wrtc/browser.d.ts.map +1 -0
  40. package/dist/helpers/wrtc/browser.js +11 -0
  41. package/dist/helpers/wrtc/browser.js.map +1 -0
  42. package/dist/helpers/wrtc/index.d.ts +5 -0
  43. package/dist/helpers/wrtc/index.d.ts.map +1 -0
  44. package/dist/helpers/wrtc/index.js +30 -0
  45. package/dist/helpers/wrtc/index.js.map +1 -0
  46. package/dist/helpers/wrtc/node.d.ts +3 -0
  47. package/dist/helpers/wrtc/node.d.ts.map +1 -0
  48. package/dist/helpers/wrtc/node.js +18 -0
  49. package/dist/helpers/wrtc/node.js.map +1 -0
  50. package/dist/index.d.ts +109 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +1013 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/services/online-status-subscription.service.d.ts +28 -0
  55. package/dist/services/online-status-subscription.service.d.ts.map +1 -0
  56. package/dist/services/online-status-subscription.service.js +96 -0
  57. package/dist/services/online-status-subscription.service.js.map +1 -0
  58. package/dist/services/phyhub-connection.service.d.ts +20 -0
  59. package/dist/services/phyhub-connection.service.d.ts.map +1 -0
  60. package/dist/services/phyhub-connection.service.js +176 -0
  61. package/dist/services/phyhub-connection.service.js.map +1 -0
  62. package/dist/services/signals.service.d.ts +97 -0
  63. package/dist/services/signals.service.d.ts.map +1 -0
  64. package/dist/services/signals.service.js +536 -0
  65. package/dist/services/signals.service.js.map +1 -0
  66. package/dist/services/webrtc/datachannel.d.ts +10 -0
  67. package/dist/services/webrtc/datachannel.d.ts.map +1 -0
  68. package/dist/services/webrtc/datachannel.js +290 -0
  69. package/dist/services/webrtc/datachannel.js.map +1 -0
  70. package/dist/services/webrtc/mediastream.d.ts +10 -0
  71. package/dist/services/webrtc/mediastream.d.ts.map +1 -0
  72. package/dist/services/webrtc/mediastream.js +396 -0
  73. package/dist/services/webrtc/mediastream.js.map +1 -0
  74. package/dist/services/webrtc/peer-connection-ice.d.ts +32 -0
  75. package/dist/services/webrtc/peer-connection-ice.d.ts.map +1 -0
  76. package/dist/services/webrtc/peer-connection-ice.js +483 -0
  77. package/dist/services/webrtc/peer-connection-ice.js.map +1 -0
  78. package/dist/types/signal.types.d.ts +354 -0
  79. package/dist/types/signal.types.d.ts.map +1 -0
  80. package/dist/types/signal.types.js +53 -0
  81. package/dist/types/signal.types.js.map +1 -0
  82. package/dist/types/twin.types.d.ts +705 -0
  83. package/dist/types/twin.types.d.ts.map +1 -0
  84. package/dist/types/twin.types.js +21 -0
  85. package/dist/types/twin.types.js.map +1 -0
  86. package/dist/types/webrtc.types.d.ts +41 -0
  87. package/dist/types/webrtc.types.d.ts.map +1 -0
  88. package/dist/types/webrtc.types.js +3 -0
  89. package/dist/types/webrtc.types.js.map +1 -0
  90. package/package.json +50 -0
  91. package/src/constants/constants.ts +12 -0
  92. package/src/helpers/browser.helper.ts +15 -0
  93. package/src/helpers/cache.helper.ts +52 -0
  94. package/src/helpers/date.helper.ts +8 -0
  95. package/src/helpers/session.helper.ts +96 -0
  96. package/src/helpers/shorten-look-ups.helper.ts +75 -0
  97. package/src/helpers/signals-client.helper.ts +54 -0
  98. package/src/helpers/signals.helper.ts +41 -0
  99. package/src/helpers/wrtc/browser.ts +9 -0
  100. package/src/helpers/wrtc/index.ts +32 -0
  101. package/src/helpers/wrtc/node.ts +16 -0
  102. package/src/index.ts +1429 -0
  103. package/src/services/online-status-subscription.service.ts +127 -0
  104. package/src/services/phyhub-connection.service.ts +213 -0
  105. package/src/services/signals.service.ts +783 -0
  106. package/src/services/webrtc/datachannel.ts +421 -0
  107. package/src/services/webrtc/mediastream.ts +602 -0
  108. package/src/services/webrtc/peer-connection-ice.ts +689 -0
  109. package/src/types/lodash.d.ts +3 -0
  110. package/src/types/signal.types.ts +382 -0
  111. package/src/types/twin.types.ts +803 -0
  112. package/src/types/webrtc.types.ts +48 -0
  113. package/tsconfig.json +45 -0
@@ -0,0 +1,783 @@
1
+ import {
2
+ CheckoutEvent,
3
+ CheckoutProps,
4
+ Client,
5
+ DataRequestTypeEnum,
6
+ DataResidencyEnum,
7
+ Event,
8
+ EventTypeEnum,
9
+ InitSignalPayload,
10
+ PurchaseEvent,
11
+ PurchaseProps,
12
+ RequestData,
13
+ SendDataOptions,
14
+ Session,
15
+ SignalInstance,
16
+ TrackEvent,
17
+ } from '../types/signal.types';
18
+ import { isBrowser, getOnlineStatusSubscription } from '../helpers/browser.helper';
19
+ import { DEFAULT_MAX_SESSION_LAST_ACTIVITY_MINS } from '../constants/constants';
20
+ import { getClientInfo } from '../helpers/signals-client.helper';
21
+ import { getDateString, getDifInMins } from '../helpers/date.helper';
22
+ import { cacheSession, generateSession, setLastActivityCache } from '../helpers/session.helper';
23
+ import { getEdgeAppInitProps, getSessionFromInstance } from '../helpers/signals.helper';
24
+ import { cache, cacheData, flushCacheOnce } from '../helpers/cache.helper';
25
+ import shortenKeys from '../helpers/shorten-look-ups.helper';
26
+ import { PhyHubClient } from '../index';
27
+ import { z } from 'zod';
28
+
29
+ const tenantIdSchema = z
30
+ .string()
31
+ .regex(/^[a-zA-Z0-9]{24}$/, 'Invalid tenant ID format (must be 24 alphanumeric characters)');
32
+
33
+ const spaceIdSchema = z
34
+ .string()
35
+ .regex(/^[a-zA-Z0-9]{24}$/, 'Invalid space ID format (must be 24 alphanumeric characters)');
36
+
37
+ const clientIdSchema = z.string().regex(/^[a-zA-Z0-9=\-_]{24,36}$/, 'Invalid client ID format');
38
+
39
+ const ipSchema = z.string().refine(
40
+ value =>
41
+ // Very simplified IPv4 check:
42
+ /^(?:\d{1,3}\.){3}\d{1,3}$/.test(value) ||
43
+ // Very simplified IPv6 check:
44
+ /^([\da-f]{1,4}:){7}[\da-f]{1,4}$/i.test(value),
45
+ {
46
+ message: 'Invalid IP address (must be a valid IPv4 or IPv6)',
47
+ }
48
+ );
49
+
50
+ const eventSchema = z.object({
51
+ captureId: z.string().optional(),
52
+ categoryId: z.string().optional(),
53
+ clientId: clientIdSchema.optional(),
54
+ dataResidency: z.nativeEnum(DataResidencyEnum),
55
+ eventTime: z.string().optional(),
56
+ eventType: z.string().regex(/^[A-Z0-9_]{5,60}$/),
57
+ interaction: z.boolean(),
58
+ int1: z.number().int().optional(),
59
+ int2: z.number().int().optional(),
60
+ int3: z.number().int().optional(),
61
+ int4: z.number().int().optional(),
62
+ int5: z.number().int().optional(),
63
+ ip: ipSchema.optional(),
64
+ productId: z.string().optional(),
65
+ public: z.number().optional(),
66
+ sessionId: z.string().max(36),
67
+ spaceId: spaceIdSchema,
68
+ stateful: z.boolean().optional(),
69
+ str1: z.string().max(200).optional(),
70
+ str2: z.string().max(200).optional(),
71
+ str3: z.string().max(200).optional(),
72
+ str4: z.string().max(200).optional(),
73
+ str5: z.string().max(200).optional(),
74
+ tenantId: tenantIdSchema,
75
+ });
76
+
77
+ const defaultSignalInstance: SignalInstance = {
78
+ // Session
79
+ tenantId: '',
80
+ sessionId: '',
81
+ sessionCreated: '',
82
+ environment: '',
83
+ dataResidency: DataResidencyEnum.EU, // Default to EU
84
+ country: '',
85
+ locationAccuracy: undefined,
86
+ latitude: undefined,
87
+ longitude: undefined,
88
+ spaceId: '',
89
+ appId: '',
90
+ appVersion: undefined,
91
+ installationId: '',
92
+ installationVersion: undefined,
93
+ deviceId: null,
94
+ clientId: undefined,
95
+ accessId: '',
96
+ accessToken: '',
97
+ ip: undefined,
98
+ // Client Specific
99
+ clientUserAgent: isBrowser ? navigator?.userAgent : undefined,
100
+ clientCreated: getDateString(),
101
+ // Internal
102
+ lastActivity: '',
103
+ };
104
+
105
+ export class SignalsService {
106
+ private instance = defaultSignalInstance;
107
+ private maxSessionLastActivityMins = DEFAULT_MAX_SESSION_LAST_ACTIVITY_MINS;
108
+ private isOnline = false;
109
+ private requiredInitParams = [
110
+ 'tenantId',
111
+ 'environment',
112
+ 'dataResidency',
113
+ 'country',
114
+ 'appId',
115
+ 'installationId',
116
+ ];
117
+ private readonly hubClient: PhyHubClient;
118
+
119
+ constructor(hubClient: PhyHubClient, initParams: InitSignalPayload) {
120
+ this.hubClient = hubClient;
121
+ this.initialize(initParams);
122
+ }
123
+
124
+ // todo: refactor to isInitialized or something?
125
+ private validateObjectKeys<T extends Record<string, any>>(obj: T, requiredKeys: string[]): void {
126
+ const missingKeys = requiredKeys.filter(key => !(key in obj));
127
+
128
+ if (missingKeys.length > 0) {
129
+ throw new Error(`Missing required keys: ${missingKeys.join(', ')} from payload`);
130
+ }
131
+ }
132
+
133
+ private updateLastActivity = () => {
134
+ const lastActivityCache = setLastActivityCache(getDateString());
135
+ this.instance.lastActivity = lastActivityCache || getDateString();
136
+ };
137
+
138
+ private sendOrCacheData = async (
139
+ type: DataRequestTypeEnum,
140
+ data: RequestData,
141
+ options?: SendDataOptions
142
+ ): Promise<any> => {
143
+ try {
144
+ if (!this.isOnline && this.instance.clientUserAgent) {
145
+ throw new Error('Currently offline');
146
+ }
147
+
148
+ // TODO: handle response
149
+ const expectResponse = options && options.expectResponse ? options.expectResponse : false;
150
+ this.send(type, data, expectResponse);
151
+ const response = undefined;
152
+
153
+ if (this.instance.clientUserAgent && cache && cache.length) {
154
+ flushCacheOnce(this.sendOrCacheData);
155
+ }
156
+
157
+ return response;
158
+ } catch (err) {
159
+ if (this.instance.clientUserAgent && cache) {
160
+ const { expectResponse } = options ?? {};
161
+ cacheData(type, data);
162
+ if (expectResponse) {
163
+ throw new Error(err as string);
164
+ }
165
+ } else {
166
+ throw err;
167
+ }
168
+ }
169
+ };
170
+
171
+ private trackEvent = async (event: TrackEvent, options?: SendDataOptions) => {
172
+ this.validateObjectKeys(this.instance, this.requiredInitParams);
173
+
174
+ this.updateLastActivity();
175
+
176
+ const eventData: Event = {
177
+ tenantId: this.instance.tenantId,
178
+ spaceId: this.instance.spaceId,
179
+ eventTime: getDateString(),
180
+ dataResidency: this.instance.dataResidency,
181
+ sessionId: this.instance.sessionId,
182
+ clientId: this.instance.clientId,
183
+ ...event,
184
+ };
185
+
186
+ return this.sendOrCacheData(DataRequestTypeEnum.EVENT, eventData, options);
187
+ };
188
+
189
+ private startSessionTracker = () => {
190
+ setInterval(async () => {
191
+ const isExpiredSession =
192
+ getDifInMins(getDateString(), this.instance.lastActivity) >=
193
+ this.maxSessionLastActivityMins;
194
+ if (isExpiredSession) {
195
+ await this.createSession();
196
+ }
197
+ }, 60000);
198
+ };
199
+
200
+ private subscribeToOnlineState() {
201
+ getOnlineStatusSubscription().subscribe(({ isOnline, message }) => {
202
+ this.isOnline = isOnline;
203
+
204
+ if (isBrowser) {
205
+ this.validateObjectKeys(this.instance, this.requiredInitParams);
206
+ if (isOnline) {
207
+ this.sendAppOnline(message);
208
+ } else {
209
+ this.sendAppOffline(message);
210
+ }
211
+ }
212
+ });
213
+ }
214
+
215
+ /**
216
+ * Everytime gridapp loads
217
+ */
218
+ private sendAppStart = () =>
219
+ this.trackEvent({
220
+ eventType: EventTypeEnum.APP_START,
221
+ interaction: false,
222
+ });
223
+
224
+ private sendData = async (data: RequestData, _options: SendDataOptions) => {
225
+ const jsonData = shortenKeys(data);
226
+ const { type } = _options;
227
+ this.hubClient.sendSignal(type, jsonData);
228
+
229
+ // Fire and forget, no need to implement expect response
230
+ // const { expectResponse } = options ?? {};
231
+ // if (expectResponse) {}
232
+ };
233
+
234
+ // used internally to send signals by sendOrCacheData
235
+ private send = (
236
+ type: DataRequestTypeEnum,
237
+ data: RequestData,
238
+ expectResponse: boolean = false
239
+ ) => {
240
+ switch (type) {
241
+ case DataRequestTypeEnum.EVENT:
242
+ this.sendEvent(data as Event, expectResponse);
243
+ return;
244
+ case DataRequestTypeEnum.CHECKOUT:
245
+ this.sendCheckout(data as CheckoutEvent);
246
+ return;
247
+ case DataRequestTypeEnum.PURCHASE:
248
+ this.sendPurchase(data as PurchaseEvent);
249
+ return;
250
+ case DataRequestTypeEnum.SESSION:
251
+ this.sendSession(data as Session, expectResponse);
252
+ return;
253
+ case DataRequestTypeEnum.CLIENT:
254
+ this.sendClient(data as Client, expectResponse);
255
+ return;
256
+ default:
257
+ throw new Error(`Unsupported type ${type}`);
258
+ }
259
+ };
260
+
261
+ public getInstanceProps = () => {
262
+ return this.instance;
263
+ };
264
+
265
+ public createSession = async (instanceParams?: Partial<SignalInstance>) => {
266
+ // override this.instance with params before creating a session
267
+ if (instanceParams) {
268
+ this.instance = {
269
+ ...this.instance,
270
+ ...instanceParams,
271
+ };
272
+ }
273
+
274
+ this.validateObjectKeys(this.instance, this.requiredInitParams);
275
+
276
+ const { sessionId, sessionCreated } = generateSession({
277
+ forceCreateNewSession: true,
278
+ maxSessionLastActivityMins: this.maxSessionLastActivityMins,
279
+ });
280
+ this.instance.sessionId = sessionId;
281
+ this.instance.sessionCreated = sessionCreated;
282
+
283
+ this.updateLastActivity();
284
+
285
+ return this.sendOrCacheData(DataRequestTypeEnum.SESSION, getSessionFromInstance(this.instance));
286
+ };
287
+
288
+ public initialize(signalParams: InitSignalPayload) {
289
+ if (this.instance.sessionId) {
290
+ throw new Error('Signals already initialized');
291
+ } else {
292
+ this.validateObjectKeys<InitSignalPayload>(signalParams, this.requiredInitParams);
293
+
294
+ this.instance = {
295
+ ...this.instance,
296
+ ...signalParams,
297
+ };
298
+
299
+ this.maxSessionLastActivityMins =
300
+ typeof signalParams.createNewSessionAfterLastActivityMins === 'number'
301
+ ? signalParams.createNewSessionAfterLastActivityMins
302
+ : this.maxSessionLastActivityMins;
303
+
304
+ const clientInfo = getClientInfo(this.instance);
305
+ this.instance.clientId = clientInfo.clientId;
306
+ this.instance.clientCreated = clientInfo.clientCreated ?? getDateString();
307
+ let sessionId = signalParams.sessionId ? signalParams.sessionId : '';
308
+ let sessionCreated = '';
309
+ let isSessionFromCache = false;
310
+
311
+ if (sessionId) {
312
+ sessionCreated = getDateString();
313
+ if (isBrowser) {
314
+ cacheSession(sessionId, sessionCreated);
315
+ }
316
+ } else {
317
+ const generatedSession = generateSession({
318
+ maxSessionLastActivityMins: this.maxSessionLastActivityMins,
319
+ forceCreateNewSession:
320
+ typeof signalParams.useValidCachedSessionOnInit === 'boolean'
321
+ ? !signalParams.useValidCachedSessionOnInit
322
+ : false,
323
+ });
324
+ sessionId = generatedSession.sessionId;
325
+ sessionCreated = generatedSession.sessionCreated;
326
+ isSessionFromCache = generatedSession.isFromCache;
327
+ }
328
+
329
+ this.instance.sessionId = sessionId;
330
+ this.instance.sessionCreated = sessionCreated;
331
+ this.updateLastActivity();
332
+
333
+ if (isBrowser) {
334
+ this.subscribeToOnlineState();
335
+ this.startSessionTracker();
336
+ }
337
+
338
+ return Promise.all([
339
+ ...(isSessionFromCache
340
+ ? []
341
+ : [
342
+ this.sendOrCacheData(
343
+ DataRequestTypeEnum.SESSION,
344
+ getSessionFromInstance(this.instance)
345
+ ),
346
+ ]),
347
+ ...(isSessionFromCache ? [] : [this.sendAppStart()]),
348
+ ...(!this.instance.clientId
349
+ ? []
350
+ : [
351
+ this.sendOrCacheData(DataRequestTypeEnum.CLIENT, {
352
+ tenantId: this.instance.tenantId,
353
+ clientId: this.instance.clientId,
354
+ clientCreated: this.instance.clientCreated,
355
+ clientUserAgent: this.instance.clientUserAgent,
356
+ dataResidency: this.instance.dataResidency,
357
+ country: this.instance.country,
358
+ latitude: this.instance.latitude,
359
+ longitude: this.instance.longitude,
360
+ locationAccuracy: this.instance.locationAccuracy,
361
+ clientIp: this.instance.ip ?? this.instance.clientIp ?? undefined,
362
+ }),
363
+ ]),
364
+ ]);
365
+ }
366
+ }
367
+
368
+ public initializeEdgeApp = (signalParams: InitSignalPayload | {} = {}) => {
369
+ const edgeParams = getEdgeAppInitProps();
370
+ const params: InitSignalPayload = {
371
+ ...edgeParams,
372
+ ...signalParams,
373
+ };
374
+
375
+ this.validateObjectKeys<InitSignalPayload>(params, this.requiredInitParams);
376
+
377
+ this.instance = {
378
+ ...this.instance,
379
+ ...params,
380
+ };
381
+ };
382
+
383
+ public sendAppOnline = (message?: string) => {
384
+ return this.trackEvent({
385
+ eventType: EventTypeEnum.APP_ONLINE,
386
+ interaction: false,
387
+ str1: message,
388
+ });
389
+ };
390
+
391
+ public sendAppOffline = (message?: string) => {
392
+ return this.trackEvent({
393
+ eventType: EventTypeEnum.APP_OFFLINE,
394
+ interaction: false,
395
+ str1: message,
396
+ });
397
+ };
398
+
399
+ public sendEvent = (event: Event, expectResponse?: boolean) => {
400
+ const parsedEvent = eventSchema.parse(event);
401
+ return this.sendData(parsedEvent, {
402
+ expectResponse,
403
+ type: DataRequestTypeEnum.EVENT,
404
+ });
405
+ };
406
+
407
+ private sendTransactionEvent = (
408
+ transactionData: CheckoutProps | PurchaseProps,
409
+ eventType: 'PURCHASE' | 'CHECKOUT'
410
+ ) => {
411
+ const { transactionId, currency, revenue, products } = transactionData;
412
+ const productEventType = `${eventType}_PRODUCT`;
413
+ products.forEach(product => {
414
+ this.trackEvent({
415
+ eventType: productEventType,
416
+ productId: product.id,
417
+ categoryId: product.categoryId,
418
+ interaction: true,
419
+ int1: product.quantity,
420
+ int2: product.price,
421
+ str1: transactionId,
422
+ str2: product.name,
423
+ str3: currency,
424
+ });
425
+ });
426
+ return this.trackEvent({
427
+ eventType: eventType,
428
+ interaction: true,
429
+ int1: revenue,
430
+ str1: transactionId,
431
+ str2: currency,
432
+ });
433
+ };
434
+
435
+ public sendPurchase = (purchaseData: PurchaseProps) => {
436
+ return this.sendTransactionEvent(purchaseData, EventTypeEnum.PURCHASE);
437
+ };
438
+
439
+ public sendCheckout = (checkoutData: CheckoutProps) => {
440
+ return this.sendTransactionEvent(checkoutData, EventTypeEnum.CHECKOUT);
441
+ };
442
+
443
+ public sendSession = (session: Session, expectResponse?: boolean) => {
444
+ return this.sendData(session, {
445
+ expectResponse,
446
+ type: DataRequestTypeEnum.SESSION,
447
+ });
448
+ };
449
+
450
+ public sendClient = (client: Client, expectResponse?: boolean) => {
451
+ return this.sendData(client, {
452
+ expectResponse,
453
+ type: DataRequestTypeEnum.CLIENT,
454
+ });
455
+ };
456
+
457
+ /**
458
+ * When the order process starts.
459
+ * Used for Click and Collect, restaurants, or any other order process
460
+ */
461
+ public sendProcessOrderStart = () => {
462
+ return this.trackEvent({
463
+ eventType: EventTypeEnum.PROCESS_ORDER_START,
464
+ interaction: true,
465
+ });
466
+ };
467
+
468
+ /**
469
+ * When the order process ends.
470
+ * Used for Click and Collect, restaurants, or any other order process
471
+ */
472
+ public sendProcessOrderEnd = () => {
473
+ return this.trackEvent({
474
+ eventType: EventTypeEnum.PROCESS_ORDER_END,
475
+ interaction: true,
476
+ });
477
+ };
478
+
479
+ /**
480
+ * When the order process was successful.
481
+ * Sent before sendProcessOrderEnd (PROCESS_ORDER_END)
482
+ */
483
+ public sendProcessOrderSuccess = () => {
484
+ return this.trackEvent({
485
+ eventType: EventTypeEnum.PROCESS_ORDER_SUCCESS,
486
+ interaction: true,
487
+ });
488
+ };
489
+
490
+ /**
491
+ * When the order process failed.
492
+ * Sent before sendProcessOrderEnd (PROCESS_ORDER_END)
493
+ */
494
+ public sendProcessOrderFailed = () => {
495
+ return this.trackEvent({
496
+ eventType: EventTypeEnum.PROCESS_ORDER_FAILED,
497
+ interaction: true,
498
+ });
499
+ };
500
+
501
+ /**
502
+ * Represents each item in the order.
503
+ * Add item amout/price later, for orders with known amount/price
504
+ */
505
+ public sendOrderItem = ({
506
+ orderId,
507
+ itemId,
508
+ itemType,
509
+ }: {
510
+ orderId: string;
511
+ itemId: string;
512
+ itemType: string;
513
+ }) => {
514
+ return this.trackEvent({
515
+ eventType: EventTypeEnum.ORDER_ITEM,
516
+ interaction: true,
517
+ str1: orderId,
518
+ str2: itemId,
519
+ str3: itemType,
520
+ });
521
+ };
522
+
523
+ /**
524
+ * Represents each item in the order that was successfully delivered
525
+ */
526
+ public sendProcessOrderItemDelivered = ({
527
+ orderId,
528
+ itemId,
529
+ }: {
530
+ orderId: string;
531
+ itemId: string;
532
+ }) => {
533
+ return this.trackEvent({
534
+ eventType: EventTypeEnum.PROCESS_ORDER_ITEM_DELIVERED,
535
+ interaction: true,
536
+ str1: orderId,
537
+ str2: itemId,
538
+ });
539
+ };
540
+
541
+ /**
542
+ * Represents each item in the order that was failed to be delivered
543
+ */
544
+ public sendProcessOrderItemFailed = ({
545
+ orderId,
546
+ itemId,
547
+ }: {
548
+ orderId: string;
549
+ itemId: string;
550
+ }) => {
551
+ return this.trackEvent({
552
+ eventType: EventTypeEnum.PROCESS_ORDER_ITEM_FAILED,
553
+ interaction: true,
554
+ str1: orderId,
555
+ str2: itemId,
556
+ });
557
+ };
558
+
559
+ /**
560
+ * Authentication success event
561
+ */
562
+ public sendAuthenticationSuccess = () => {
563
+ return this.trackEvent({
564
+ eventType: EventTypeEnum.AUTHENTICATION_SUCCESS,
565
+ interaction: true,
566
+ });
567
+ };
568
+
569
+ /**
570
+ * Authentication failed event
571
+ */
572
+ public sendAuthenticationFailed = () => {
573
+ return this.trackEvent({
574
+ eventType: EventTypeEnum.AUTHENTICATION_FAILED,
575
+ interaction: true,
576
+ });
577
+ };
578
+
579
+ /**
580
+ * Generic barcode scan event
581
+ */
582
+ public sendScanBarcode = ({ barcode }: { barcode: string }) => {
583
+ return this.trackEvent({
584
+ eventType: EventTypeEnum.SCAN_BARCODE,
585
+ interaction: true,
586
+ str1: barcode,
587
+ });
588
+ };
589
+
590
+ /**
591
+ * Media finished event. Send this event after a piece of content has been played
592
+ * @param id - The id of the media content
593
+ * @param type - The type of the media content
594
+ * @param name - The name of the media content
595
+ * @param duration - The duration of the media content in milliseconds
596
+ * @param tags - The list of tags of the media content
597
+ */
598
+ public sendMediaFinished = ({
599
+ id,
600
+ type,
601
+ name,
602
+ duration,
603
+ tags = [],
604
+ }: {
605
+ id: string;
606
+ type: string;
607
+ name: string;
608
+ duration: number;
609
+ tags?: string[];
610
+ }) => {
611
+ return this.trackEvent({
612
+ eventType: EventTypeEnum.MEDIA_FINISHED,
613
+ interaction: false,
614
+ str1: id,
615
+ str2: type,
616
+ str3: name,
617
+ str4: tags.length > 0 ? tags.join(',') : undefined,
618
+ int1: duration,
619
+ });
620
+ };
621
+
622
+ /**
623
+ * Custom event
624
+ */
625
+ public sendCustomEvent = async (event: TrackEvent) => {
626
+ return this.trackEvent(event);
627
+ };
628
+
629
+ /**
630
+ * Browsing products under a category
631
+ */
632
+ public sendCategoryView = ({ categoryId }: { categoryId: string }) => {
633
+ return this.trackEvent({
634
+ eventType: EventTypeEnum.CATEGORY_VIEW,
635
+ categoryId,
636
+ interaction: true,
637
+ });
638
+ };
639
+
640
+ /**
641
+ * Viewing a specific product page
642
+ */
643
+ public sendProductView = ({ productId }: { productId: string }) => {
644
+ return this.trackEvent({
645
+ eventType: EventTypeEnum.PRODUCT_VIEW,
646
+ productId,
647
+ interaction: true,
648
+ });
649
+ };
650
+
651
+ /**
652
+ * Adding a product to the cart
653
+ */
654
+ public sendCartAdd = ({ productId, quantity }: { productId: string; quantity: number }) => {
655
+ return this.trackEvent({
656
+ eventType: EventTypeEnum.CART_ADD,
657
+ productId,
658
+ interaction: true,
659
+ int1: quantity, // quantity
660
+ });
661
+ };
662
+
663
+ /**
664
+ * Viewing the cart page
665
+ */
666
+ public sendCartView = () => {
667
+ return this.trackEvent({
668
+ eventType: EventTypeEnum.CART_VIEW,
669
+ interaction: true,
670
+ });
671
+ };
672
+
673
+ /**
674
+ * Removing a product from the cart
675
+ */
676
+ public sendCartRemove = ({ productId, quantity }: { productId: string; quantity: number }) => {
677
+ return this.trackEvent({
678
+ eventType: EventTypeEnum.CART_REMOVE,
679
+ interaction: true,
680
+ productId,
681
+ int1: quantity, //quantity
682
+ });
683
+ };
684
+
685
+ /**
686
+ * Clear the cart
687
+ */
688
+ public sendCartClear = () => {
689
+ return this.trackEvent({
690
+ eventType: EventTypeEnum.CART_CLEAR,
691
+ interaction: true,
692
+ });
693
+ };
694
+
695
+ /**
696
+ * Searching a product, category, or anything in the app
697
+ */
698
+ public sendSearch = ({ searchQueryString }: { searchQueryString: string }) => {
699
+ return this.trackEvent({
700
+ eventType: EventTypeEnum.SEARCH,
701
+ interaction: true,
702
+ str1: searchQueryString,
703
+ });
704
+ };
705
+
706
+ /**
707
+ * Searching a product, category, or anything in the app
708
+ */
709
+ public sendSearchClear = () => {
710
+ return this.trackEvent({
711
+ eventType: EventTypeEnum.SEARCH_CLEAR,
712
+ interaction: true,
713
+ });
714
+ };
715
+
716
+ /**
717
+ * User's rate of the experience
718
+ */
719
+ public sendRating = ({
720
+ rating,
721
+ interactionDelay,
722
+ comment,
723
+ }: {
724
+ rating: 1 | 2 | 3 | 4 | 5;
725
+ interactionDelay?: number;
726
+ comment?: string;
727
+ }) => {
728
+ return this.trackEvent({
729
+ eventType: EventTypeEnum.RATING,
730
+ interaction: true,
731
+ int1: rating,
732
+ int2: interactionDelay,
733
+ str1: comment,
734
+ });
735
+ };
736
+
737
+ /**
738
+ * User's feedback of the experience
739
+ */
740
+ public sendFeedback = ({
741
+ feedback,
742
+ rating,
743
+ }: {
744
+ feedback: string;
745
+ rating?: 1 | 2 | 3 | 4 | 5;
746
+ }) => {
747
+ return this.trackEvent({
748
+ eventType: EventTypeEnum.FEEDBACK,
749
+ interaction: true,
750
+ str1: feedback,
751
+ str2: rating?.toString() ?? '',
752
+ });
753
+ };
754
+
755
+ public sendQrScan = () => {
756
+ return this.trackEvent({
757
+ eventType: EventTypeEnum.QR_RUN,
758
+ interaction: true,
759
+ });
760
+ };
761
+
762
+ /**
763
+ * Setting state key, value and expiry duration (in ms)
764
+ */
765
+ public setState = ({
766
+ key,
767
+ value,
768
+ expiryDuration,
769
+ }: {
770
+ key: string;
771
+ value: string | number;
772
+ expiryDuration: number;
773
+ }) => {
774
+ return this.trackEvent({
775
+ eventType: (key || '').toUpperCase(),
776
+ interaction: false,
777
+ str1: typeof value === 'string' ? value : undefined,
778
+ int1: typeof value === 'number' ? value : undefined,
779
+ stateful: true,
780
+ public: expiryDuration,
781
+ });
782
+ };
783
+ }