@driveflux/web-analytics 1.2.0 → 1.3.1

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.
@@ -0,0 +1,11 @@
1
+ type Config = {
2
+ ga: {
3
+ measurementId: string;
4
+ apiSecret: string;
5
+ };
6
+ };
7
+ export declare let config: Config;
8
+ export declare const resetConfig: () => Config;
9
+ export declare const setConfig: <Key extends keyof Config>(key: Key, value: Config[Key]) => void;
10
+ export {};
11
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,KAAK,MAAM,GAAG;IACb,EAAE,EAAE;QACH,aAAa,EAAE,MAAM,CAAA;QACrB,SAAS,EAAE,MAAM,CAAA;KACjB,CAAA;CACD,CAAA;AASD,eAAO,IAAI,MAAM,EAAE,MAAqD,CAAA;AAExE,eAAO,MAAM,WAAW,cAGvB,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,GAAG,SAAS,MAAM,MAAM,OAC5C,GAAG,SACD,MAAM,CAAC,GAAG,CAAC,SAGlB,CAAA"}
package/dist/config.js ADDED
@@ -0,0 +1,15 @@
1
+ import { singleton } from '@driveflux/singleton';
2
+ const getConfig = ()=>({
3
+ ga: {
4
+ measurementId: process.env.GA_MEASUREMENT_ID,
5
+ apiSecret: process.env.GA_API_SECRET
6
+ }
7
+ });
8
+ export let config = singleton('webAnalyticsConfig', getConfig());
9
+ export const resetConfig = ()=>{
10
+ config = singleton('webAnalyticsConfig', getConfig(), true);
11
+ return config;
12
+ };
13
+ export const setConfig = (key, value)=>{
14
+ config[key] = value;
15
+ };
@@ -0,0 +1,9 @@
1
+ export * from './config.js';
2
+ import type { JsonObject } from 'type-fest';
3
+ import type { ServerUserData } from './types.js';
4
+ export declare const trackServerMultiple: (user: ServerUserData, events: {
5
+ name: string;
6
+ data?: JsonObject;
7
+ }[]) => Promise<void>;
8
+ export declare const trackServer: (user: ServerUserData, name: string, data?: JsonObject) => Promise<void>;
9
+ //# sourceMappingURL=track-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track-server.d.ts","sourceRoot":"","sources":["../src/track-server.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAE3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAQhD,eAAO,MAAM,mBAAmB,SACzB,cAAc,UACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,UAAU,CAAA;CAAE,EAAE,kBAuE7C,CAAA;AAED,eAAO,MAAM,WAAW,SACjB,cAAc,QACd,MAAM,SACL,UAAU,kBAC8B,CAAA"}
@@ -0,0 +1,66 @@
1
+ export * from './config.js';
2
+ import { enhancedFetch } from '@driveflux/fetch';
3
+ import { config } from './config';
4
+ import { convertUserData, extractGA4ClientId, extractGA4SessionId, getCurrentTimestampMicros } from './utils.js';
5
+ export const trackServerMultiple = async (user, events)=>{
6
+ if (events.length > 1) {
7
+ console.log('🚨🚨🚨🗄️ firing multiple server events', events);
8
+ const filtered = events.filter((e)=>!!e.name);
9
+ if (filtered.length !== events.length) {
10
+ console.log('Not all events have names');
11
+ return;
12
+ }
13
+ } else {
14
+ console.log('🚨🚨🚨🗄️ firing server event', events?.[0]?.name, events?.[0]?.data);
15
+ if (!events?.[0]?.name) {
16
+ console.error('The name of the event is missing');
17
+ return;
18
+ }
19
+ }
20
+ const measurementId = config.ga.measurementId;
21
+ const apiSecret = config.ga.apiSecret;
22
+ if (!measurementId || !apiSecret) {
23
+ console.log('The configuration is not set up correctly.');
24
+ return;
25
+ }
26
+ const clientId = extractGA4ClientId(user.clientIdCookie);
27
+ const sessionId = extractGA4SessionId(user.sessionIdCookie);
28
+ if (!clientId || !sessionId) {
29
+ console.log('The user client id or session id are not provided');
30
+ return;
31
+ }
32
+ const userData = user.data ? {
33
+ user_data: await convertUserData(user.data)
34
+ } : {};
35
+ const url = `https://www.google-analytics.com/mp/collect?measurement_id=${measurementId}&api_secret=${apiSecret}`;
36
+ const payload = {
37
+ client_id: clientId,
38
+ timestamp_micros: getCurrentTimestampMicros(),
39
+ events: events.map((e)=>{
40
+ if (e.name) {
41
+ return {
42
+ name: e.name,
43
+ params: {
44
+ ...userData,
45
+ ...e.data,
46
+ session_id: sessionId
47
+ }
48
+ };
49
+ }
50
+ return null;
51
+ })
52
+ };
53
+ await enhancedFetch(url, {
54
+ method: 'POST',
55
+ headers: {
56
+ 'Content-Type': 'application/json'
57
+ },
58
+ body: JSON.stringify(payload)
59
+ });
60
+ };
61
+ export const trackServer = async (user, name, data)=>trackServerMultiple(user, [
62
+ {
63
+ name,
64
+ data
65
+ }
66
+ ]);
package/dist/track.d.ts CHANGED
@@ -1,29 +1,10 @@
1
+ import type { UserLikeData } from './types';
1
2
  declare global {
2
3
  interface Window {
3
4
  fluxDataLayer?: object[];
4
5
  }
5
6
  }
6
7
  type ClearMode = 'clearItems';
7
- interface Address {
8
- name?: string | null;
9
- street1: string;
10
- street2?: string | null;
11
- city: string;
12
- state: string;
13
- country: string;
14
- postalCode: string;
15
- }
16
- interface UserLikeData {
17
- id: string;
18
- email: string;
19
- phoneNumber?: string | null;
20
- firstName?: string | null;
21
- lastName?: string | null;
22
- addresses?: {
23
- home?: Address | null;
24
- billing?: Address | null;
25
- } | null;
26
- }
27
8
  export declare function getGA4ClientId(): string | null;
28
9
  export declare const safeSendGTMEvent: (event: Record<string, any>) => Promise<void>;
29
10
  export declare const useTrackEvent: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"AAIA,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;KACxB;CACD;AAED,KAAK,SAAS,GAAG,YAAY,CAAA;AAE7B,UAAU,OAAO;IAChB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,YAAY;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;QACrB,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;KACxB,GAAG,IAAI,CAAA;CACR;AA6BD,wBAAgB,cAAc,kBAc7B;AAuCD,eAAO,MAAM,gBAAgB,UAAiB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,kBAOhE,CAAA;AAED,eAAO,MAAM,aAAa;uBAKZ,MAAM,cACL,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,cACnB,SAAS;6BA4B2B,YAAY;CAkC9D,CAAA;AAED,eAAO,MAAM,iBAAiB,cAClB,MAAM,cACL,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,SAmC/B,CAAA"}
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,SAAS,CAAA;AAG7D,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;KACxB;CACD;AAED,KAAK,SAAS,GAAG,YAAY,CAAA;AAa7B,wBAAgB,cAAc,kBAW7B;AAED,eAAO,MAAM,gBAAgB,UAAiB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,kBAOhE,CAAA;AAED,eAAO,MAAM,aAAa;uBAKZ,MAAM,cACL,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,cACnB,SAAS;6BA4B2B,YAAY;CAkC9D,CAAA;AAED,eAAO,MAAM,iBAAiB,cAClB,MAAM,cACL,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,SAmC/B,CAAA"}
package/dist/track.js CHANGED
@@ -1,392 +1,52 @@
1
- function _array_like_to_array(arr, len) {
2
- if (len == null || len > arr.length) len = arr.length;
3
- for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4
- return arr2;
5
- }
6
- function _array_without_holes(arr) {
7
- if (Array.isArray(arr)) return _array_like_to_array(arr);
8
- }
9
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
10
- try {
11
- var info = gen[key](arg);
12
- var value = info.value;
13
- } catch (error) {
14
- reject(error);
15
- return;
16
- }
17
- if (info.done) {
18
- resolve(value);
19
- } else {
20
- Promise.resolve(value).then(_next, _throw);
21
- }
22
- }
23
- function _async_to_generator(fn) {
24
- return function() {
25
- var self = this, args = arguments;
26
- return new Promise(function(resolve, reject) {
27
- var gen = fn.apply(self, args);
28
- function _next(value) {
29
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
30
- }
31
- function _throw(err) {
32
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
33
- }
34
- _next(undefined);
35
- });
36
- };
37
- }
38
- function _define_property(obj, key, value) {
39
- if (key in obj) {
40
- Object.defineProperty(obj, key, {
41
- value: value,
42
- enumerable: true,
43
- configurable: true,
44
- writable: true
45
- });
46
- } else {
47
- obj[key] = value;
48
- }
49
- return obj;
50
- }
51
- function _iterable_to_array(iter) {
52
- if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
53
- }
54
- function _non_iterable_spread() {
55
- throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
56
- }
57
- function _object_spread(target) {
58
- for(var i = 1; i < arguments.length; i++){
59
- var source = arguments[i] != null ? arguments[i] : {};
60
- var ownKeys = Object.keys(source);
61
- if (typeof Object.getOwnPropertySymbols === "function") {
62
- ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
63
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
64
- }));
65
- }
66
- ownKeys.forEach(function(key) {
67
- _define_property(target, key, source[key]);
68
- });
69
- }
70
- return target;
71
- }
72
- function _to_consumable_array(arr) {
73
- return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
74
- }
75
- function _unsupported_iterable_to_array(o, minLen) {
76
- if (!o) return;
77
- if (typeof o === "string") return _array_like_to_array(o, minLen);
78
- var n = Object.prototype.toString.call(o).slice(8, -1);
79
- if (n === "Object" && o.constructor) n = o.constructor.name;
80
- if (n === "Map" || n === "Set") return Array.from(n);
81
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
82
- }
83
- function _ts_generator(thisArg, body) {
84
- var f, y, t, g, _ = {
85
- label: 0,
86
- sent: function() {
87
- if (t[0] & 1) throw t[1];
88
- return t[1];
89
- },
90
- trys: [],
91
- ops: []
92
- };
93
- return g = {
94
- next: verb(0),
95
- "throw": verb(1),
96
- "return": verb(2)
97
- }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
98
- return this;
99
- }), g;
100
- function verb(n) {
101
- return function(v) {
102
- return step([
103
- n,
104
- v
105
- ]);
106
- };
107
- }
108
- function step(op) {
109
- if (f) throw new TypeError("Generator is already executing.");
110
- while(_)try {
111
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
112
- if (y = 0, t) op = [
113
- op[0] & 2,
114
- t.value
115
- ];
116
- switch(op[0]){
117
- case 0:
118
- case 1:
119
- t = op;
120
- break;
121
- case 4:
122
- _.label++;
123
- return {
124
- value: op[1],
125
- done: false
126
- };
127
- case 5:
128
- _.label++;
129
- y = op[1];
130
- op = [
131
- 0
132
- ];
133
- continue;
134
- case 7:
135
- op = _.ops.pop();
136
- _.trys.pop();
137
- continue;
138
- default:
139
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
140
- _ = 0;
141
- continue;
142
- }
143
- if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
144
- _.label = op[1];
145
- break;
146
- }
147
- if (op[0] === 6 && _.label < t[1]) {
148
- _.label = t[1];
149
- t = op;
150
- break;
151
- }
152
- if (t && _.label < t[2]) {
153
- _.label = t[2];
154
- _.ops.push(op);
155
- break;
156
- }
157
- if (t[2]) _.ops.pop();
158
- _.trys.pop();
159
- continue;
160
- }
161
- op = body.call(thisArg, _);
162
- } catch (e) {
163
- op = [
164
- 6,
165
- e
166
- ];
167
- y = 0;
168
- } finally{
169
- f = t = 0;
170
- }
171
- if (op[0] & 5) throw op[1];
172
- return {
173
- value: op[0] ? op[1] : void 0,
174
- done: true
175
- };
176
- }
177
- }
178
1
  import { sendGTMEvent } from '@next/third-parties/google';
179
2
  import isEqual from 'lodash/isEqual.js';
180
3
  import { useCallback, useEffect, useRef } from 'react';
181
- //dataLayer.push({ items: undefined })
182
- var eventsQueue = new Set();
183
- var TIMEOUT_TO_CLEAR_EVENTS = 500;
184
- var drainEvents = function() {
185
- var events = _to_consumable_array(eventsQueue);
4
+ import { convertUserData, extractGA4ClientId } from './utils';
5
+ const eventsQueue = new Set();
6
+ const TIMEOUT_TO_CLEAR_EVENTS = 500;
7
+ const drainEvents = ()=>{
8
+ const events = [
9
+ ...eventsQueue
10
+ ];
186
11
  eventsQueue.clear();
187
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
188
- try {
189
- for(var _iterator = events[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
190
- var event = _step.value;
191
- sendGTMEvent(event);
192
- }
193
- } catch (err) {
194
- _didIteratorError = true;
195
- _iteratorError = err;
196
- } finally{
197
- try {
198
- if (!_iteratorNormalCompletion && _iterator.return != null) {
199
- _iterator.return();
200
- }
201
- } finally{
202
- if (_didIteratorError) {
203
- throw _iteratorError;
204
- }
205
- }
12
+ for (const event of events){
13
+ sendGTMEvent(event);
206
14
  }
207
15
  };
208
16
  export function getGA4ClientId() {
209
17
  if (typeof document === 'undefined') {
210
18
  return null;
211
19
  }
212
- var cookies = document.cookie.split(';');
213
- var gaCookie = cookies.find(function(cookie) {
214
- return cookie.trim().startsWith('_ga=');
215
- });
20
+ const cookies = document.cookie.split(';');
21
+ const gaCookie = cookies.find((cookie)=>cookie.trim().startsWith('_ga='));
216
22
  if (gaCookie) {
217
- var matches = gaCookie.split('.');
218
- if (matches.length > 2) {
219
- return "".concat(matches[2], ".").concat(matches[3]) // Returns the GA4 client ID
220
- ;
221
- }
23
+ return extractGA4ClientId(gaCookie);
222
24
  }
223
25
  return null // If no GA cookie is found or format is unexpected
224
26
  ;
225
27
  }
226
- function hashData(input) {
227
- return _hashData.apply(this, arguments);
228
- }
229
- function _hashData() {
230
- _hashData = _async_to_generator(function(input) {
231
- var encoder, data, hashBuffer, hashArray, hashHex;
232
- return _ts_generator(this, function(_state) {
233
- switch(_state.label){
234
- case 0:
235
- encoder = new TextEncoder();
236
- data = encoder.encode(input);
237
- return [
238
- 4,
239
- crypto.subtle.digest('SHA-256', data)
240
- ];
241
- case 1:
242
- hashBuffer = _state.sent();
243
- hashArray = Array.from(new Uint8Array(hashBuffer)) // Convert buffer to byte array
244
- ;
245
- hashHex = hashArray.map(function(b) {
246
- return b.toString(16).padStart(2, '0');
247
- }).join('') // Convert bytes to hex string
248
- ;
249
- return [
250
- 2,
251
- hashHex
252
- ];
253
- }
254
- });
255
- });
256
- return _hashData.apply(this, arguments);
257
- }
258
- var convertUserData = function() {
259
- var _ref = _async_to_generator(function(dataInput) {
260
- var _dataInput_addresses, _dataInput_addresses1, userAddress, _tmp, _tmp1, _tmp2, _tmp3, _tmp4, _tmp5;
261
- return _ts_generator(this, function(_state) {
262
- switch(_state.label){
263
- case 0:
264
- userAddress = ((_dataInput_addresses = dataInput.addresses) === null || _dataInput_addresses === void 0 ? void 0 : _dataInput_addresses.home) || ((_dataInput_addresses1 = dataInput.addresses) === null || _dataInput_addresses1 === void 0 ? void 0 : _dataInput_addresses1.billing);
265
- _tmp = {
266
- user_id: dataInput.id
267
- };
268
- return [
269
- 4,
270
- hashData(dataInput.email)
271
- ];
272
- case 1:
273
- _tmp.email = _state.sent();
274
- if (!dataInput.phoneNumber) return [
275
- 3,
276
- 3
277
- ];
278
- return [
279
- 4,
280
- hashData(dataInput.phoneNumber)
281
- ];
282
- case 2:
283
- _tmp1 = _state.sent();
284
- return [
285
- 3,
286
- 4
287
- ];
288
- case 3:
289
- _tmp1 = undefined;
290
- _state.label = 4;
291
- case 4:
292
- _tmp.phone_number = _tmp1;
293
- if (!userAddress) return [
294
- 3,
295
- 11
296
- ];
297
- _tmp3 = {};
298
- if (!dataInput.firstName) return [
299
- 3,
300
- 6
301
- ];
302
- return [
303
- 4,
304
- hashData(dataInput.firstName)
305
- ];
306
- case 5:
307
- _tmp4 = _state.sent();
308
- return [
309
- 3,
310
- 7
311
- ];
312
- case 6:
313
- _tmp4 = undefined;
314
- _state.label = 7;
315
- case 7:
316
- _tmp3.first_name = _tmp4;
317
- if (!dataInput.lastName) return [
318
- 3,
319
- 9
320
- ];
321
- return [
322
- 4,
323
- hashData(dataInput.lastName)
324
- ];
325
- case 8:
326
- _tmp5 = _state.sent();
327
- return [
328
- 3,
329
- 10
330
- ];
331
- case 9:
332
- _tmp5 = undefined;
333
- _state.label = 10;
334
- case 10:
335
- _tmp2 = (_tmp3.last_name = _tmp5, _tmp3.street = [
336
- userAddress.street1,
337
- userAddress.street2
338
- ].join(', '), _tmp3.city = userAddress.city, _tmp3.region = userAddress.state, _tmp3.postal_code = userAddress.postalCode, _tmp3.country = userAddress.country, _tmp3);
339
- return [
340
- 3,
341
- 12
342
- ];
343
- case 11:
344
- _tmp2 = undefined;
345
- _state.label = 12;
346
- case 12:
347
- return [
348
- 2,
349
- (_tmp.address = _tmp2, _tmp)
350
- ];
351
- }
352
- });
353
- });
354
- return function convertUserData(dataInput) {
355
- return _ref.apply(this, arguments);
356
- };
357
- }();
358
- export var safeSendGTMEvent = function() {
359
- var _ref = _async_to_generator(function(event) {
360
- return _ts_generator(this, function(_state) {
361
- if (!window.fluxDataLayer) {
362
- eventsQueue.add(event);
363
- return [
364
- 2
365
- ];
366
- }
367
- sendGTMEvent(event);
368
- return [
369
- 2
370
- ];
371
- });
372
- });
373
- return function safeSendGTMEvent(event) {
374
- return _ref.apply(this, arguments);
375
- };
376
- }();
377
- export var useTrackEvent = function() {
378
- var userData = useRef();
379
- var track = useCallback(function(eventName, eventData, clearMode) {
28
+ export const safeSendGTMEvent = async (event)=>{
29
+ if (!window.fluxDataLayer) {
30
+ eventsQueue.add(event);
31
+ return;
32
+ }
33
+ sendGTMEvent(event);
34
+ };
35
+ export const useTrackEvent = ()=>{
36
+ const userData = useRef();
37
+ const track = useCallback((eventName, eventData, clearMode)=>{
380
38
  console.log('🚨🚨🚨 firing event', eventName, eventData);
381
39
  if (!eventName) {
382
40
  console.error('No event name provided');
383
41
  return;
384
42
  }
385
- var event = _object_spread({
386
- event: eventName
387
- }, userData.current ? {
388
- user_data: userData.current
389
- } : {}, eventData);
43
+ const event = {
44
+ event: eventName,
45
+ ...userData.current ? {
46
+ user_data: userData.current
47
+ } : {},
48
+ ...eventData
49
+ };
390
50
  if (clearMode === 'clearItems') {
391
51
  safeSendGTMEvent({
392
52
  items: undefined
@@ -394,77 +54,56 @@ export var useTrackEvent = function() {
394
54
  }
395
55
  safeSendGTMEvent(event);
396
56
  }, []);
397
- var setUserData = useCallback(function() {
398
- var _ref = _async_to_generator(function(dataInput) {
399
- return _ts_generator(this, function(_state) {
400
- switch(_state.label){
401
- case 0:
402
- return [
403
- 4,
404
- convertUserData(dataInput)
405
- ];
406
- case 1:
407
- userData.current = _state.sent();
408
- localStorage.setItem('ud', Buffer.from(JSON.stringify(userData.current), 'utf8').toString('base64'));
409
- return [
410
- 2
411
- ];
412
- }
413
- });
414
- });
415
- return function(dataInput) {
416
- return _ref.apply(this, arguments);
417
- };
418
- }(), []);
419
- useEffect(function() {
420
- var interval = setInterval(function() {
57
+ const setUserData = useCallback(async (dataInput)=>{
58
+ userData.current = await convertUserData(dataInput);
59
+ localStorage.setItem('ud', Buffer.from(JSON.stringify(userData.current), 'utf8').toString('base64'));
60
+ }, []);
61
+ useEffect(()=>{
62
+ const interval = setInterval(()=>{
421
63
  if (window.fluxDataLayer) {
422
64
  drainEvents();
423
65
  clearInterval(interval);
424
66
  }
425
67
  }, TIMEOUT_TO_CLEAR_EVENTS);
426
- return function() {
427
- return clearInterval(interval);
428
- };
68
+ return ()=>clearInterval(interval);
429
69
  }, []);
430
- useEffect(function() {
431
- var ud = localStorage.getItem('ud');
70
+ useEffect(()=>{
71
+ const ud = localStorage.getItem('ud');
432
72
  if (!ud) {
433
73
  return;
434
74
  }
435
75
  try {
436
- var json = Buffer.from(ud, 'base64').toString('utf8');
76
+ const json = Buffer.from(ud, 'base64').toString('utf8');
437
77
  userData.current = JSON.parse(json);
438
78
  } catch (e) {}
439
79
  }, []);
440
80
  return {
441
- track: track,
442
- setUserData: setUserData
81
+ track,
82
+ setUserData
443
83
  };
444
84
  };
445
- export var useAutoTrackEvent = function(eventName, eventData) {
446
- var previousEventData = useRef();
447
- var firedFirstEvent = useRef(false);
448
- useEffect(function() {
449
- var interval = setInterval(function() {
85
+ export const useAutoTrackEvent = (eventName, eventData)=>{
86
+ const previousEventData = useRef();
87
+ const firedFirstEvent = useRef(false);
88
+ useEffect(()=>{
89
+ const interval = setInterval(()=>{
450
90
  if (window.fluxDataLayer) {
451
91
  drainEvents();
452
92
  clearInterval(interval);
453
93
  }
454
94
  }, TIMEOUT_TO_CLEAR_EVENTS);
455
- return function() {
456
- return clearInterval(interval);
457
- };
95
+ return ()=>clearInterval(interval);
458
96
  }, []);
459
- useEffect(function() {
97
+ useEffect(()=>{
460
98
  if (isEqual(previousEventData.current, eventData) && firedFirstEvent.current) {
461
99
  return;
462
100
  }
463
101
  firedFirstEvent.current = true;
464
102
  console.log('🚨🚨🚨 firing event', eventName, eventData);
465
- var event = _object_spread({
466
- event: eventName
467
- }, eventData);
103
+ const event = {
104
+ event: eventName,
105
+ ...eventData
106
+ };
468
107
  safeSendGTMEvent(event);
469
108
  previousEventData.current = eventData;
470
109
  }, [
@@ -0,0 +1,40 @@
1
+ export interface Address {
2
+ name?: string | null;
3
+ street1: string;
4
+ street2?: string | null;
5
+ city: string;
6
+ state: string;
7
+ country: string;
8
+ postalCode: string;
9
+ }
10
+ export interface UserLikeData {
11
+ id: string;
12
+ email: string;
13
+ phoneNumber?: string | null;
14
+ firstName?: string | null;
15
+ lastName?: string | null;
16
+ addresses?: {
17
+ home?: Address | null;
18
+ billing?: Address | null;
19
+ } | null;
20
+ }
21
+ export interface TrackingUserData {
22
+ user_id: string;
23
+ email: string;
24
+ phone_number?: string;
25
+ address?: {
26
+ first_name?: string;
27
+ last_name?: string;
28
+ street?: string;
29
+ city?: string;
30
+ region?: string;
31
+ postal_code?: string;
32
+ country?: string;
33
+ };
34
+ }
35
+ export interface ServerUserData {
36
+ clientIdCookie: string;
37
+ sessionIdCookie: string;
38
+ data?: UserLikeData;
39
+ }
40
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;QACrB,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;KACxB,GAAG,IAAI,CAAA;CACR;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,OAAO,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACD;AAED,MAAM,WAAW,cAAc;IAC9B,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,IAAI,CAAC,EAAE,YAAY,CAAA;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,7 @@
1
+ import type { TrackingUserData, UserLikeData } from './types';
2
+ export declare function hashData(input: string): Promise<string>;
3
+ export declare const getCurrentTimestampMicros: () => string;
4
+ export declare const extractGA4ClientId: (gaCookie: string) => string | null;
5
+ export declare const extractGA4SessionId: (gaCookie: string) => number | null;
6
+ export declare const convertUserData: (dataInput: UserLikeData) => Promise<TrackingUserData>;
7
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE7D,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,mBAO3C;AAED,eAAO,MAAM,yBAAyB,QAAO,MAK5C,CAAA;AAED,eAAO,MAAM,kBAAkB,aAAc,MAAM,kBAMlD,CAAA;AAED,eAAO,MAAM,mBAAmB,aAAc,MAAM,kBAMnD,CAAA;AAED,eAAO,MAAM,eAAe,cAChB,YAAY,KACrB,OAAO,CAAC,gBAAgB,CAwB1B,CAAA"}
package/dist/utils.js ADDED
@@ -0,0 +1,50 @@
1
+ export async function hashData(input) {
2
+ const encoder = new TextEncoder();
3
+ const data = encoder.encode(input);
4
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
5
+ const hashArray = Array.from(new Uint8Array(hashBuffer)) // Convert buffer to byte array
6
+ ;
7
+ const hashHex = hashArray.map((b)=>b.toString(16).padStart(2, '0')).join('') // Convert bytes to hex string
8
+ ;
9
+ return hashHex;
10
+ }
11
+ export const getCurrentTimestampMicros = ()=>{
12
+ const now = new Date();
13
+ const epochMillis = now.getTime();
14
+ const epochMicros = epochMillis * 1000;
15
+ return epochMicros.toString();
16
+ };
17
+ export const extractGA4ClientId = (gaCookie)=>{
18
+ const matches = gaCookie.split('.');
19
+ if (matches.length > 2) {
20
+ return `${matches[2]}.${matches[3]}`;
21
+ }
22
+ return null;
23
+ };
24
+ export const extractGA4SessionId = (gaCookie)=>{
25
+ const matches = gaCookie.split('.');
26
+ if (matches.length > 2) {
27
+ return Number.parseInt(`${matches[2]}`);
28
+ }
29
+ return null;
30
+ };
31
+ export const convertUserData = async (dataInput)=>{
32
+ const userAddress = dataInput.addresses?.home || dataInput.addresses?.billing;
33
+ return {
34
+ user_id: dataInput.id,
35
+ email: await hashData(dataInput.email),
36
+ phone_number: dataInput.phoneNumber ? await hashData(dataInput.phoneNumber) : undefined,
37
+ address: userAddress ? {
38
+ first_name: dataInput.firstName ? await hashData(dataInput.firstName) : undefined,
39
+ last_name: dataInput.lastName ? await hashData(dataInput.lastName) : undefined,
40
+ street: [
41
+ userAddress.street1,
42
+ userAddress.street2
43
+ ].join(', '),
44
+ city: userAddress.city,
45
+ region: userAddress.state,
46
+ postal_code: userAddress.postalCode,
47
+ country: userAddress.country
48
+ } : undefined
49
+ };
50
+ };
package/package.json CHANGED
@@ -1,17 +1,23 @@
1
1
  {
2
2
  "name": "@driveflux/web-analytics",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./track": {
7
7
  "types": "./dist/track.d.ts",
8
8
  "import": "./dist/track.js"
9
+ },
10
+ "./track-server": {
11
+ "types": "./dist/track-server.d.ts",
12
+ "import": "./dist/track-server.js"
9
13
  }
10
14
  },
11
15
  "files": [
12
16
  "dist"
13
17
  ],
14
18
  "dependencies": {
19
+ "@driveflux/fetch": "6.2.1",
20
+ "@driveflux/singleton": "1.2.0",
15
21
  "@next/third-parties": "^14.2.5",
16
22
  "lodash": "^4.17.21"
17
23
  },
@@ -25,6 +31,7 @@
25
31
  "@types/react": "^18.3.3",
26
32
  "del-cli": "^5.1.0",
27
33
  "react": "^18.3.1",
34
+ "type-fest": "^4.23.0",
28
35
  "typescript": "^5.5.4"
29
36
  },
30
37
  "peerDependencies": {