@splendidlabz/tracking 0.1.21 → 0.2.0

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.
package/dist/fb.js DELETED
@@ -1,949 +0,0 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define(factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.FB = factory());
5
- })(this, (function () { 'use strict';
6
-
7
- /**
8
- * Gets a cookie by name
9
- * Thanks to https://stackoverflow.com/a/21125098
10
- * @param {string} name Cookie name
11
- * @returns string Cookie value
12
- */
13
- function getCookie(name) {
14
- const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
15
- if (match) return match[2]
16
- }
17
-
18
- async function sha256Hash(string) {
19
- const utf8 = new TextEncoder().encode(string);
20
- const hashBuffer = await crypto.subtle.digest('SHA-256', utf8);
21
- const hashArray = Array.from(new Uint8Array(hashBuffer));
22
- const hashHex = hashArray
23
- .map(bytes => bytes.toString(16).padStart(2, '0'))
24
- .join('');
25
- return hashHex
26
- }
27
-
28
- // For browsers only
29
- // Check the node version for node
30
- async function randomString(length = 10) {
31
- return crypto.getRandomValues(new Uint32Array(length)).join('')
32
- }
33
-
34
- function isEmpty(obj) {
35
- if (typeof obj === 'undefined') return true
36
- if (obj === null) return true
37
- if (Array.isArray(obj)) return obj.length === 0
38
- return Object.keys(obj).length === 0
39
- }
40
-
41
- /**
42
- * Split on object up based on the keys provided.
43
- * @param {Object} obj
44
- * @param {Array} keys
45
- * @returns
46
- */
47
- function splitObject(obj, keys) {
48
- const picked = {};
49
- const omitted = { ...obj };
50
-
51
- keys.forEach(key => {
52
- if (key in obj) {
53
- picked[key] = obj[key];
54
- delete omitted[key];
55
- }
56
- });
57
-
58
- return { picked, omitted }
59
- }
60
-
61
- async function formatUserData(data) {
62
- if (isEmpty(data)) return {}
63
-
64
- // Lowercase all the values
65
- for (const [key, value] of Object.entries(data)) {
66
- data[key] = value.toLowerCase();
67
- }
68
-
69
- const {
70
- email,
71
- phone,
72
- firstName,
73
- lastName,
74
- birthdate,
75
- gender,
76
- city,
77
- state,
78
- zip,
79
- country,
80
- } = data;
81
-
82
- const ret = {};
83
-
84
- if (email) ret.em = await sha256Hash(email);
85
- if (phone) ret.ph = await sha256Hash(phone);
86
- if (firstName) ret.fn = await sha256Hash(firstName);
87
- if (lastName) ret.ln = await sha256Hash(lastName);
88
- if (birthdate) ret.db = await sha256Hash(birthdate);
89
- if (gender) ret.ge = await sha256Hash(gender);
90
- if (city) ret.ct = await sha256Hash(city.replace(' ', ''));
91
-
92
- if (country) {
93
- const c = COUNTRY_CODES[country];
94
- ret.country = await sha256Hash(c);
95
-
96
- if (c === 'us' && state) {
97
- ret.st = await sha256Hash(US_STATE_CODES[state]);
98
- }
99
- if (c !== 'us' && state) {
100
- ret.st = await sha256Hash(state.replace(' ', '').replace('-', ''));
101
- }
102
- }
103
- if (zip) ret.zp = await sha256Hash(zip);
104
- return ret
105
- }
106
-
107
- const US_STATE_CODES = {
108
- alabama: 'al',
109
- alaska: 'ak',
110
- 'american samoa': 'as',
111
- arizona: 'az',
112
- arkansas: 'ar',
113
- 'baker island': 'bi',
114
- california: 'ca',
115
- colorado: 'co',
116
- connecticut: 'ct',
117
- delaware: 'de',
118
- 'district of columbia': 'dc',
119
- florida: 'fl',
120
- 'federated states of micronesia': 'fm',
121
- georgia: 'ga',
122
- guam: 'gu',
123
- hawaii: 'hi',
124
- 'howland island': 'hi',
125
- idaho: 'id',
126
- illinois: 'il',
127
- indiana: 'in',
128
- iowa: 'ia',
129
- 'jarvis island': 'ji',
130
- 'johnston atoll': 'ja',
131
- kansas: 'ks',
132
- kentucky: 'ky',
133
- 'kingman reef': 'kr',
134
- louisiana: 'la',
135
- maine: 'me',
136
- 'marshall islands': 'mh',
137
- maryland: 'md',
138
- massachusetts: 'ma',
139
- michigan: 'mi',
140
- 'midway islands': 'mi',
141
- minnesota: 'mn',
142
- mississippi: 'ms',
143
- missouri: 'mo',
144
- montana: 'mt',
145
- 'navassa island': 'ni',
146
- nebraska: 'ne',
147
- nevada: 'nv',
148
- 'new hampshire': 'nh',
149
- 'new jersey': 'nj',
150
- 'new mexico': 'nm',
151
- 'new york': 'ny',
152
- 'north carolina': 'nc',
153
- 'north dakota': 'nd',
154
- 'northern mariana islands': 'mp',
155
- ohio: 'oh',
156
- oklahoma: 'ok',
157
- oregon: 'or',
158
- palau: 'pw',
159
- 'palmyra atoll': 'pa',
160
- pennsylvania: 'pa',
161
- 'puerto rico': 'pr',
162
- 'rhode island': 'ri',
163
- 'south carolina': 'sc',
164
- 'south dakota': 'sd',
165
- tennessee: 'tn',
166
- texas: 'tx',
167
- 'u.s. minor outlying islands': 'um',
168
- utah: 'ut',
169
- vermont: 'vt',
170
- virginia: 'va',
171
- 'virgin islands of the u.s.': 'vi',
172
- 'wake island': 'wi',
173
- washington: 'wa',
174
- 'west virginia': 'wv',
175
- wisconsin: 'wi',
176
- wyoming: 'wy',
177
- };
178
-
179
- const COUNTRY_CODES = {
180
- afghanistan: 'af',
181
- 'åland islands': 'ax',
182
- albania: 'al',
183
- algeria: 'dz',
184
- 'american samoa': 'as',
185
- andorra: 'ad',
186
- angola: 'ao',
187
- anguilla: 'ai',
188
- antarctica: 'aq',
189
- 'antigua and barbuda': 'ag',
190
- argentina: 'ar',
191
- armenia: 'am',
192
- aruba: 'aw',
193
- australia: 'au',
194
- austria: 'at',
195
- azerbaijan: 'az',
196
- bahamas: 'bs',
197
- bahrain: 'bh',
198
- bangladesh: 'bd',
199
- barbados: 'bb',
200
- belarus: 'by',
201
- belgium: 'be',
202
- belize: 'bz',
203
- benin: 'bj',
204
- bermuda: 'bm',
205
- bhutan: 'bt',
206
- 'bolivia (plurinational state of)': 'bo',
207
- 'bonaire, sint eustatius and saba': 'bq',
208
- 'bosnia and herzegovina': 'ba',
209
- botswana: 'bw',
210
- 'bouvet island': 'bv',
211
- brazil: 'br',
212
- 'british indian ocean territory': 'io',
213
- 'brunei darussalam': 'bn',
214
- brunei: 'bn',
215
- bulgaria: 'bg',
216
- 'burkina faso': 'bf',
217
- burundi: 'bi',
218
- 'cabo verde': 'cv',
219
- cambodia: 'kh',
220
- cameroon: 'cm',
221
- canada: 'ca',
222
- 'cayman islands': 'ky',
223
- 'central african republic': 'cf',
224
- chad: 'td',
225
- chile: 'cl',
226
- china: 'cn',
227
- 'christmas island': 'cx',
228
- 'cocos (keeling) islands': 'cc',
229
- colombia: 'co',
230
- comoros: 'km',
231
- 'democratic republic of the congo': 'cd',
232
- 'cook islands': 'ck',
233
- 'costa rica': 'cr',
234
- "côte d'ivoire": 'ci',
235
- croatia: 'hr',
236
- cuba: 'cu',
237
- curaçao: 'cw',
238
- cyprus: 'cy',
239
- czechia: 'cz',
240
- denmark: 'dk',
241
- djibouti: 'dj',
242
- dominica: 'dm',
243
- 'dominican republic': 'do',
244
- ecuador: 'ec',
245
- egypt: 'eg',
246
- 'el salvador': 'sv',
247
- 'equatorial guinea': 'gq',
248
- eritrea: 'er',
249
- estonia: 'ee',
250
- eswatini: 'sz',
251
- ethiopia: 'et',
252
- 'falkland islands': 'fk',
253
- 'faroe islands': 'fo',
254
- fiji: 'fj',
255
- finland: 'fi',
256
- france: 'fr',
257
- 'french guiana': 'gf',
258
- 'french polynesia': 'pf',
259
- 'french southern territories': 'tf',
260
- gabon: 'ga',
261
- gambia: 'gm',
262
- georgia: 'ge',
263
- germany: 'de',
264
- ghana: 'gh',
265
- gibraltar: 'gi',
266
- greece: 'gr',
267
- greenland: 'gl',
268
- grenada: 'gd',
269
- guadeloupe: 'gp',
270
- guam: 'gu',
271
- guatemala: 'gt',
272
- guernsey: 'gg',
273
- guinea: 'gn',
274
- 'guinea-bissau': 'gw',
275
- guyana: 'gy',
276
- haiti: 'ht',
277
- 'heard island and mcdonald islands': 'hm',
278
- 'holy see': 'va',
279
- honduras: 'hn',
280
- 'hong kong': 'hk',
281
- hungary: 'hu',
282
- iceland: 'is',
283
- india: 'in',
284
- indonesia: 'id',
285
- iran: 'ir',
286
- iraq: 'iq',
287
- ireland: 'ie',
288
- 'isle of man': 'im',
289
- israel: 'il',
290
- italy: 'it',
291
- jamaica: 'jm',
292
- japan: 'jp',
293
- jersey: 'je',
294
- jordan: 'jo',
295
- kazakhstan: 'kz',
296
- kenya: 'ke',
297
- kiribati: 'ki',
298
- 'north korea': 'kp',
299
- 'south korea': 'kr',
300
- kuwait: 'kw',
301
- kyrgyzstan: 'kg',
302
- laos: 'la',
303
- latvia: 'lv',
304
- lebanon: 'lb',
305
- lesotho: 'ls',
306
- liberia: 'lr',
307
- libya: 'ly',
308
- liechtenstein: 'li',
309
- lithuania: 'lt',
310
- luxembourg: 'lu',
311
- macao: 'mo',
312
- madagascar: 'mg',
313
- malawi: 'mw',
314
- malaysia: 'my',
315
- maldives: 'mv',
316
- mali: 'ml',
317
- malta: 'mt',
318
- 'marshall islands': 'mh',
319
- martinique: 'mq',
320
- mauritania: 'mr',
321
- mauritius: 'mu',
322
- mayotte: 'yt',
323
- mexico: 'mx',
324
- micronesia: 'fm',
325
- moldova: 'md',
326
- monaco: 'mc',
327
- mongolia: 'mn',
328
- montenegro: 'me',
329
- montserrat: 'ms',
330
- morocco: 'ma',
331
- mozambique: 'mz',
332
- myanmar: 'mm',
333
- namibia: 'na',
334
- nauru: 'nr',
335
- nepal: 'np',
336
- netherlands: 'nl',
337
- 'new caledonia': 'nc',
338
- 'new zealand': 'nz',
339
- nicaragua: 'ni',
340
- niger: 'ne',
341
- nigeria: 'ng',
342
- niue: 'nu',
343
- 'norfolk island': 'nf',
344
- 'north macedonia': 'mk',
345
- 'northern mariana islands': 'mp',
346
- norway: 'no',
347
- oman: 'om',
348
- pakistan: 'pk',
349
- palau: 'pw',
350
- palestine: 'ps',
351
- panama: 'pa',
352
- 'papua new guinea': 'pg',
353
- paraguay: 'py',
354
- peru: 'pe',
355
- philippines: 'ph',
356
- pitcairn: 'pn',
357
- poland: 'pl',
358
- portugal: 'pt',
359
- 'puerto rico': 'pr',
360
- qatar: 'qa',
361
- réunion: 're',
362
- romania: 'ro',
363
- 'russian federation': 'ru',
364
- rwanda: 'rw',
365
- 'saint barthélemy': 'bl',
366
- 'saint helena': 'sh',
367
- 'saint kitts and nevis': 'kn',
368
- 'saint lucia': 'lc',
369
- 'saint martin': 'mf',
370
- 'saint pierre and miquelon': 'pm',
371
- 'saint vincent and the grenadines': 'vc',
372
- samoa: 'ws',
373
- 'san marino': 'sm',
374
- 'sao tome and principe': 'st',
375
- 'saudi arabia': 'sa',
376
- senegal: 'sn',
377
- serbia: 'rs',
378
- seychelles: 'sc',
379
- 'sierra leone': 'sl',
380
- singapore: 'sg',
381
- 'sint maarten': 'sx',
382
- slovakia: 'sk',
383
- slovenia: 'si',
384
- 'solomon islands': 'sb',
385
- somalia: 'so',
386
- 'south africa': 'za',
387
- 'south georgia and the south sandwich islands': 'gs',
388
- 'south sudan': 'ss',
389
- spain: 'es',
390
- 'sri lanka': 'lk',
391
- sudan: 'sd',
392
- suriname: 'sr',
393
- 'svalbard and jan mayen': 'sj',
394
- sweden: 'se',
395
- switzerland: 'ch',
396
- 'syrian arab republic': 'sy',
397
- taiwan: 'tw',
398
- tajikistan: 'tj',
399
- tanzania: 'tz',
400
- thailand: 'th',
401
- 'timor-leste': 'tl',
402
- togo: 'tg',
403
- tokelau: 'tk',
404
- tonga: 'to',
405
- 'trinidad and tobago': 'tt',
406
- tunisia: 'tn',
407
- türkiye: 'tr',
408
- turkmenistan: 'tm',
409
- 'turks and caicos islands': 'tc',
410
- tuvalu: 'tv',
411
- uganda: 'ug',
412
- ukraine: 'ua',
413
- 'united arab emirates': 'ae',
414
- 'united kingdom': 'gb',
415
- 'united states minor outlying islands': 'um',
416
- 'united states': 'us',
417
- uruguay: 'uy',
418
- uzbekistan: 'uz',
419
- vanuatu: 'vu',
420
- venezuela: 've',
421
- 'viet nam': 'vn',
422
- 'british virgin islands': 'vg',
423
- 'u.s. virgin islands': 'vi',
424
- 'wallis and futuna': 'wf',
425
- 'western sahara': 'eh',
426
- yemen: 'ye',
427
- zambia: 'zm',
428
- zimbabwe: 'zw',
429
- };
430
-
431
- function createRequestOptions(options = {}) {
432
- const opts = Object.assign({}, options);
433
-
434
- // Note: headers get mutated after setHeaders is called.
435
- // This is why we get the content type here to know what the user originally set.
436
-
437
- const headers = new Headers(options.headers);
438
- const userContentType = headers.get('content-type');
439
-
440
- opts.url = setUrl(opts);
441
- opts.method = setMethod(opts);
442
- opts.headers = setHeaders(opts);
443
-
444
- // If Content Type is set explicitly, we expect the user to pass in the appropriate data. So we don't treat the body
445
- opts.body = !userContentType ? setBody(opts) : opts.body;
446
- return opts
447
- }
448
-
449
- /**
450
- * Appends queries to URL
451
- * @param {Object} opts
452
- */
453
- function setUrl(options) {
454
- const { url, queries, query, params, param } = options;
455
-
456
- // Merge queries, query, and params — treat them as the same item
457
- // So users don't have to remember singular or plural forms
458
- const q = Object.assign({}, queries, query, params, param);
459
-
460
- if (isEmptyObject(q)) return options.url
461
-
462
- const searchParams = new URLSearchParams(q);
463
- return `${url}?${searchParams.toString()}`
464
- }
465
-
466
- function isEmptyObject(obj) {
467
- return (
468
- obj && // 👈 null and undefined check
469
- Object.keys(obj).length === 0 &&
470
- Object.getPrototypeOf(obj) === Object.prototype
471
- )
472
- }
473
-
474
- function setMethod(options) {
475
- // Method set to GET by default unless otherwise specified
476
- const method = options.method || 'get';
477
- return method
478
- }
479
-
480
- // ========================
481
- // Set Headers
482
- // We set the headers depending on the request body and method
483
- // ========================
484
- function setHeaders(options) {
485
- let headers = new Headers(options.headers);
486
- headers = contentTypeHeader(options, headers);
487
- headers = authHeader(options, headers);
488
-
489
- return headers
490
- }
491
-
492
- function contentTypeHeader(options, headers) {
493
- // For preflight requests, we don't want to set headers.
494
- // This allows requests to remain simple.
495
- if (options.method === 'options') return headers
496
-
497
- // For GET requests, we also don't want to set headers.
498
- // This allows requests to remain simple.
499
- if (options.method === 'get') return headers
500
-
501
- // If a content type is aleady set, we return the content type as is.
502
- // This allows users to set their own content type.
503
- if (headers.get('content-type')) return headers
504
-
505
- // If the body is a string, we assume it's a query string.
506
- // So we set headers to Content-Type: application/x-www-form-urlencoded.
507
- if (typeof options.body === 'string') {
508
- headers.set('content-type', 'application/x-www-form-urlencoded');
509
- return headers
510
- }
511
-
512
- // If the body is an object and not FormData, we set it to `application/json`. Checking for FormData is important here because Form Data requires another content type.
513
- if (typeof options.body === 'object' && !isFormData(options.body)) {
514
- headers.set('content-type', 'application/json');
515
- return headers
516
- }
517
-
518
- // What's left here is FormData.
519
- // We don't set the content type here because fetch will set it automatically.
520
- return headers
521
- }
522
-
523
- // Sets the auth headers as necessary
524
- function authHeader(options, headers) {
525
- // If no auth options, means we don't have to set Authorization headers
526
- const { auth } = options;
527
- if (!auth) return headers
528
-
529
- // Set Bearer authentication when user passes in a string into auth
530
- if (typeof auth === 'string') {
531
- headers.set('Authorization', `Bearer ${auth}`);
532
- return headers
533
- }
534
-
535
- // Set Basic Authentication headers when user passes in username and password into auth.
536
- const btoa = getBtoa();
537
-
538
- // Password field can be empty for implicit grant
539
- const { username, password = '' } = auth;
540
-
541
- if (!username) {
542
- throw new Error(
543
- 'Username required to create Authorization Header for a Basic Authentication'
544
- )
545
- }
546
-
547
- const encodedValue = btoa(`${username}:${password}`);
548
- headers.set('Authorization', `Basic ${encodedValue}`);
549
- return headers
550
- }
551
-
552
- // Gets Btoa for creating basic auth.
553
- function getBtoa() {
554
- if (typeof window !== 'undefined' && window.btoa) {
555
- return window.btoa
556
- }
557
-
558
- return function (string) {
559
- return Buffer.from(string).toString('base64')
560
- }
561
- }
562
-
563
- // ========================
564
- // Set Body
565
- // ========================
566
- function setBody(options) {
567
- // Return empty body for preflight requests
568
- const method = options.method;
569
- if (['get', 'head', 'options'].includes(method)) return
570
-
571
- // If the body is form data, we return it as it is because users will have to set it up appropriately themselves.
572
- if (isFormData(options.body)) return options.body
573
-
574
- // If the body is a string, we assume it's a query string.
575
- // We ask users to use toQueryString to convert an object to a query string as they send in the request.
576
- if (typeof options.body === 'string') return options.body
577
-
578
- // If it's an object, we convert it to JSON
579
- if (typeof options.body === 'object') {
580
- return JSON.stringify(options.body)
581
- }
582
-
583
- // If the above conditions don't trigger, we return the body as is.
584
- // One example that will reach here is FormData
585
- return options.body
586
- }
587
-
588
- // Checks if body is FormData
589
- // Only works on browsers.
590
- // Returns false in Node because Node doesn't have FormData.
591
- function isFormData(body) {
592
- if (typeof window === 'undefined') return false
593
- return body instanceof FormData
594
- }
595
-
596
- function handleResponse(response, options) {
597
- // Lets user use custom response parser because some people want to do so.
598
- // See https://github.com/zellwk/zl-fetch/issues/2
599
- if (options?.customResponseParser) {
600
- return response
601
- }
602
-
603
- const contentType = response.headers.get('content-type');
604
- const type = getResponseType(contentType);
605
- return parseResponse(response, { ...options, type })
606
- }
607
-
608
- /**
609
- * Formats all errors into zlFetch style error
610
- * @param {Object} error - The error object
611
- */
612
- function handleError(error) {
613
- if (error.message === 'Failed to fetch') {
614
- /* eslint-disable */
615
- return Promise.reject({ error })
616
- /* eslint-enable */
617
- }
618
- return Promise.reject(error)
619
- }
620
-
621
- // ========================
622
- // Internal Functions
623
- // ========================
624
- function getResponseType(type) {
625
- if (!type) return null // Handles 204 No Content
626
- if (type.includes('json')) return 'json'
627
- if (type.includes('text')) return 'text'
628
- if (type.includes('blob')) return 'blob'
629
- if (type.includes('x-www-form-urlencoded')) return 'formData'
630
-
631
- // Need to check for FormData, Blob and ArrayBuffer content types
632
- throw new Error(`zlFetch does not support content-type ${type} yet`)
633
- }
634
-
635
- async function parseResponse(response, options) {
636
- // Parse formData into JavaScript object
637
- if (options.type === 'formData') {
638
- let body = await response.text();
639
- const query = new URLSearchParams(body);
640
- body = Object.fromEntries(query);
641
- return createOutput({ response, body, options })
642
- }
643
-
644
- const body = await response[options.type]();
645
- return createOutput({ response, body, options })
646
- }
647
-
648
- function createOutput({ response, body, options }) {
649
- const headers = getHeaders(response);
650
- const returnValue = {
651
- body,
652
- headers,
653
- response,
654
- status: response.status,
655
- statusText: response.statusText,
656
- };
657
-
658
- // Resolves if successful response
659
- // Rejects if unsuccessful response
660
- if (!options.returnError) {
661
- return response.ok
662
- ? Promise.resolve(returnValue)
663
- : Promise.reject(returnValue)
664
- }
665
-
666
- // Returns both successful and unsuccessful response
667
- if (options.returnError) {
668
- let data;
669
- let error;
670
-
671
- if (response.ok) {
672
- data = returnValue;
673
- error = null;
674
- } else {
675
- data = null;
676
- error = returnValue;
677
- }
678
-
679
- return Promise.resolve({
680
- response: data,
681
- error,
682
- })
683
- }
684
- }
685
-
686
- function getHeaders(response) {
687
- return response.headers.entries
688
- ? getBrowserFetchHeaders(response)
689
- : getNodeFetchHeaders(response)
690
- }
691
-
692
- // window.fetch response headers contains entries method.
693
- function getBrowserFetchHeaders(response) {
694
- const headers = {};
695
- for (const [header, value] of response.headers.entries()) {
696
- headers[header] = value;
697
- }
698
- return headers
699
- }
700
-
701
- // Node fetch response headers does not contain entries method.
702
- function getNodeFetchHeaders(response) {
703
- const headers = {};
704
- const h = response.headers._headers;
705
- for (const header in h) {
706
- headers[header] = h[header].join('');
707
- }
708
- return headers
709
- }
710
-
711
- /**
712
- * Main Fetch Function
713
- * @param {string} url - endpoint
714
- * @param {object} options - zlFetch options
715
- * @param {string} options.method - HTTP method
716
- * @param {object} options.headers - HTTP headers
717
- * @param {object} options.body - Body content
718
- * @param {string} options.auth - Authentication information
719
- * @param {string} options.debug - Logs the request options for debugging
720
- * @param {string} options.returnError - Returns the error instead of rejecting it
721
- * @param {string} options.customResponseParser - Use a custome response parser
722
- */
723
-
724
- function coreFetch(url, options) {
725
- return fetchInstance({ url, ...options })
726
- }
727
- // ========================
728
- // Internal Functions
729
- // ========================
730
- async function fetchInstance(options) {
731
- const requestOptions = createRequestOptions(options);
732
-
733
- // Remove options that are not native to a fetch request
734
- delete requestOptions.fetch;
735
- delete requestOptions.queries;
736
- delete requestOptions.query;
737
- delete requestOptions.params;
738
- delete requestOptions.param;
739
- delete requestOptions.auth;
740
- delete requestOptions.debug;
741
- delete requestOptions.returnError;
742
-
743
- // Performs the fetch request
744
- return fetch(requestOptions.url, requestOptions)
745
- .then(response => handleResponse(response, options))
746
- .then(response => {
747
- if (!options.debug) return response
748
- return { ...response, debug: debugHeaders(requestOptions) }
749
- })
750
- .catch(handleError)
751
- }
752
-
753
- function debugHeaders(requestOptions) {
754
- const clone = Object.assign({}, requestOptions);
755
- const headers = {};
756
- for (const [header, value] of clone.headers) {
757
- headers[header] = value;
758
- }
759
- clone.headers = headers;
760
- return clone
761
- }
762
-
763
- function createShorthandMethods(fn) {
764
- const methods = ['get', 'post', 'put', 'patch', 'delete'];
765
-
766
- for (const method of methods) {
767
- fn[method] = function (url, options) {
768
- return coreFetch(url, {
769
- ...options,
770
- method,
771
- })
772
- };
773
- }
774
-
775
- return fn
776
- }
777
-
778
- let fn = coreFetch;
779
- fn = createShorthandMethods(fn);
780
-
781
- var zlFetch = fn;
782
-
783
- // TODO: Figure a way to put the Pixel Code into the DOM... if possible!
784
- function FB({ pixelID, testEventCode, capiEndpoint }) {
785
- const _fb = {
786
- options: { pixelID, testEventCode, capiEndpoint },
787
-
788
- // Initializes Facebook
789
- init() {
790
- !(function (f, b, e, v, n, t, s) {
791
- if (f.fbq) return
792
- n = f.fbq = function () {
793
- n.callMethod
794
- ? n.callMethod.apply(n, arguments)
795
- : n.queue.push(arguments);
796
- };
797
- if (!f._fbq) f._fbq = n;
798
- n.push = n;
799
- n.loaded = !0;
800
- n.version = '2.0';
801
- n.queue = [];
802
- t = b.createElement(e);
803
- t.async = !0;
804
- t.src = v;
805
- s = b.getElementsByTagName(e)[0];
806
- s.parentNode.insertBefore(t, s);
807
- })(
808
- window,
809
- document,
810
- 'script',
811
- 'https://connect.facebook.net/en_US/fbevents.js'
812
- );
813
- fbq('init', pixelID);
814
- },
815
-
816
- async sendEvent(eventName, props = {}) {
817
- const eventData = await _fb.createFBEvent(eventName, props);
818
-
819
- // Question whether we want to verbose log this thing in the future so users can know whether these events are sent.
820
- _fb.sendPixelEvent(eventData);
821
- return _fb.sendCAPIEvent(eventData)
822
- },
823
-
824
- async createFBEvent(eventName, props = {}) {
825
- const { eventURL, actionSource, ...rest } = props;
826
-
827
- const { picked: userProperties, omitted: customData } = splitObject(
828
- rest,
829
- [...USER_PROPERTIES_TO_HASH, ...USER_PROPERTIES_NOT_TO_HASH]
830
- );
831
-
832
- const { picked: userPropsToHash, omitted: otherUserProps } = splitObject(
833
- userProperties,
834
- USER_PROPERTIES_TO_HASH
835
- );
836
-
837
- const userData = {
838
- ...(await formatUserData(userPropsToHash)),
839
- ...otherUserProps,
840
- };
841
-
842
- const ret = {
843
- // Data for both Pixel and CAPI
844
- pixelID,
845
- eventID: await randomString(),
846
- eventName: eventName,
847
- userData,
848
- customData,
849
-
850
- // Data for CAPI only
851
- fbp: getCookie('_fbp'),
852
- fbc: getCookie('_fbc'),
853
- eventTime: Math.floor(new Date() / 1000),
854
- eventURL: eventURL || window.location.href,
855
- actionSource: actionSource || 'website',
856
- };
857
- if (testEventCode) ret.testEventCode = testEventCode;
858
-
859
- return ret
860
- },
861
-
862
- // Facebook Pixel Code
863
- // Pixel Standard Reference
864
- // https://developers.facebook.com/docs/meta-pixel/reference#standard-events
865
- sendPixelEvent(data) {
866
- const {
867
- eventID,
868
- eventName,
869
- userData = {},
870
- customData = {},
871
- pixelID,
872
- } = data;
873
- const props = { ...userData, ...customData };
874
-
875
- let action = 'track';
876
- let evtName = eventName;
877
- if (evtName === 'init') action = 'init';
878
-
879
- // When we use fbq init, we have to add the pixelID instead of the event name as the 2nd parameter.
880
- if (action === 'init') evtName = pixelID;
881
-
882
- // If the event is a custom event, we need to use `trackCustom` instead of `track`.
883
- if (action !== 'init' && !standardEvents.includes(evtName))
884
- action = 'trackCustom';
885
-
886
- fbq(action, evtName, props, { eventID });
887
- },
888
-
889
- // CAPI Parameters: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
890
- sendCAPIEvent(data) {
891
- return zlFetch.post(capiEndpoint, { body: data })
892
- },
893
- };
894
-
895
- return _fb
896
- }
897
-
898
- const standardEvents = [
899
- 'AddPaymentInfo',
900
- 'AddToCart',
901
- 'AddToWishlist',
902
- 'CompleteRegistration',
903
- 'Contact',
904
- 'CustomizeProduct',
905
- 'Donate',
906
- 'FindLocation',
907
- 'InitiateCheckout',
908
- 'Lead',
909
- 'Purchase',
910
- 'Schedule',
911
- 'Search',
912
- 'StartTrial',
913
- 'SubmitApplication',
914
- 'Subscribe',
915
- 'ViewContent',
916
- ];
917
-
918
- // https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
919
- const USER_PROPERTIES_TO_HASH = [
920
- 'email',
921
- 'phone',
922
- 'firstName',
923
- 'lastName',
924
- 'birthdate',
925
- 'gender',
926
- 'city',
927
- 'state',
928
- 'zip',
929
- 'country',
930
- 'externalID',
931
- ];
932
-
933
- // Other optional FB Stuff — doesn't seem very useful
934
- const USER_PROPERTIES_NOT_TO_HASH = [
935
- 'subscription_id',
936
- 'fb_login_id',
937
- 'lead_id',
938
- 'anon_id',
939
- 'madid',
940
- 'page_id',
941
- 'page_scoped_user_id',
942
- 'ctwa_clid',
943
- 'ig_account_id',
944
- 'ig_sid',
945
- ];
946
-
947
- return FB;
948
-
949
- }));