saasco-sdk 0.1.29 → 0.1.31
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/index.cjs.js +144 -70
- package/index.esm.js +145 -69
- package/package.json +1 -1
- package/src/index.d.ts +0 -1
- package/src/lib/tracking/types.d.ts +37 -20
- package/src/lib/getUTMContext.d.ts +0 -2
package/index.cjs.js
CHANGED
|
@@ -7,7 +7,7 @@ var uuid = require('@lukeed/uuid');
|
|
|
7
7
|
var psl = require('psl');
|
|
8
8
|
var zod = require('zod');
|
|
9
9
|
|
|
10
|
-
var version = "0.1.
|
|
10
|
+
var version = "0.1.31";
|
|
11
11
|
|
|
12
12
|
const timezones = {
|
|
13
13
|
'Asia/Barnaul': 'RU',
|
|
@@ -455,6 +455,79 @@ function getBrowserContext() {
|
|
|
455
455
|
const $screenWidth = screen.width;
|
|
456
456
|
const $title = document.title;
|
|
457
457
|
const $userAgent = window.navigator.userAgent;
|
|
458
|
+
const params = new URLSearchParams(window.location.search);
|
|
459
|
+
const $utmSource = params.get('utm_source');
|
|
460
|
+
const $utmMedium = params.get('utm_medium');
|
|
461
|
+
const $utmCampaign = params.get('utm_campaign');
|
|
462
|
+
const $utmTerm = params.get('utm_term');
|
|
463
|
+
const $utmContent = params.get('utm_content');
|
|
464
|
+
const $utmId = params.get('utm_id');
|
|
465
|
+
const $utmSourcePlatform = params.get('utm_source_platform');
|
|
466
|
+
const $utmCampaignId = params.get('utm_campaign_id');
|
|
467
|
+
const $utmCreativeFormat = params.get('utm_creative_format');
|
|
468
|
+
const $utmMarketingTactic = params.get('utm_marketing_tactic');
|
|
469
|
+
let $utmAdSource = params.get('utm_ad_source');
|
|
470
|
+
let $utmAdId = params.get('utm_ad_id');
|
|
471
|
+
// If the adId is not set directly attempt to get it from each ad network
|
|
472
|
+
// Also set the ad source to the ad network if it's not set
|
|
473
|
+
if (!$utmAdId) {
|
|
474
|
+
const fbAdId = params.get('fbadid');
|
|
475
|
+
if (fbAdId) {
|
|
476
|
+
$utmAdId = fbAdId;
|
|
477
|
+
if (!$utmAdSource) {
|
|
478
|
+
$utmAdSource = 'facebook';
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const googleAdId = params.get('gadid');
|
|
482
|
+
if (googleAdId) {
|
|
483
|
+
$utmAdId = googleAdId;
|
|
484
|
+
if (!$utmAdSource) {
|
|
485
|
+
$utmAdSource = 'google';
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const xAdId = params.get('xadid');
|
|
489
|
+
if (xAdId) {
|
|
490
|
+
$utmAdId = xAdId;
|
|
491
|
+
if (!$utmAdSource) {
|
|
492
|
+
$utmAdSource = 'x';
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const pinterestAdId = params.get('padid');
|
|
496
|
+
if (pinterestAdId) {
|
|
497
|
+
$utmAdId = pinterestAdId;
|
|
498
|
+
if (!$utmAdSource) {
|
|
499
|
+
$utmAdSource = 'pinterest';
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
const tiktokAdId = params.get('ttadid');
|
|
503
|
+
if (tiktokAdId) {
|
|
504
|
+
$utmAdId = tiktokAdId;
|
|
505
|
+
if (!$utmAdSource) {
|
|
506
|
+
$utmAdSource = 'tiktok';
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const snapchatAdId = params.get('scadid');
|
|
510
|
+
if (snapchatAdId) {
|
|
511
|
+
$utmAdId = snapchatAdId;
|
|
512
|
+
if (!$utmAdSource) {
|
|
513
|
+
$utmAdSource = 'snapchat';
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
const redditAdId = params.get('radid');
|
|
517
|
+
if (redditAdId) {
|
|
518
|
+
$utmAdId = redditAdId;
|
|
519
|
+
if (!$utmAdSource) {
|
|
520
|
+
$utmAdSource = 'reddit';
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
const linkedinAdId = params.get('liadid');
|
|
524
|
+
if (linkedinAdId) {
|
|
525
|
+
$utmAdId = linkedinAdId;
|
|
526
|
+
if (!$utmAdSource) {
|
|
527
|
+
$utmAdSource = 'linkedin';
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
458
531
|
return {
|
|
459
532
|
$locale,
|
|
460
533
|
$location,
|
|
@@ -465,55 +538,45 @@ function getBrowserContext() {
|
|
|
465
538
|
$screenHeight,
|
|
466
539
|
$screenWidth,
|
|
467
540
|
$title,
|
|
468
|
-
$userAgent
|
|
541
|
+
$userAgent,
|
|
542
|
+
$utmSource,
|
|
543
|
+
$utmMedium,
|
|
544
|
+
$utmCampaign,
|
|
545
|
+
$utmTerm,
|
|
546
|
+
$utmContent,
|
|
547
|
+
$utmId,
|
|
548
|
+
$utmSourcePlatform,
|
|
549
|
+
$utmCampaignId,
|
|
550
|
+
$utmCreativeFormat,
|
|
551
|
+
$utmMarketingTactic,
|
|
552
|
+
$utmAdSource,
|
|
553
|
+
$utmAdId
|
|
469
554
|
};
|
|
470
555
|
}
|
|
471
556
|
|
|
472
|
-
function getUTMContext() {
|
|
473
|
-
const isBrowser = typeof window !== 'undefined';
|
|
474
|
-
if (!isBrowser) throw new Error('getUTMContext can only be called in browser');
|
|
475
|
-
const params = new URLSearchParams(window.location.search);
|
|
476
|
-
const $utmSource = params.get('utm_source');
|
|
477
|
-
const $utmMedium = params.get('utm_medium');
|
|
478
|
-
const $utmCampaign = params.get('utm_campaign');
|
|
479
|
-
const $utmTerm = params.get('utm_term');
|
|
480
|
-
const $utmContent = params.get('utm_content');
|
|
481
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, $utmSource ? {
|
|
482
|
-
$utmSource
|
|
483
|
-
} : {}), $utmMedium ? {
|
|
484
|
-
$utmMedium
|
|
485
|
-
} : {}), $utmCampaign ? {
|
|
486
|
-
$utmCampaign
|
|
487
|
-
} : {}), $utmTerm ? {
|
|
488
|
-
$utmTerm
|
|
489
|
-
} : {}), $utmContent ? {
|
|
490
|
-
$utmContent
|
|
491
|
-
} : {});
|
|
492
|
-
}
|
|
493
|
-
|
|
494
557
|
const isBrowser = typeof window !== 'undefined';
|
|
495
558
|
const isServer = !isBrowser;
|
|
496
559
|
const PREF = 'saasco-sdk';
|
|
497
560
|
const SESSION_DURATION = 1000 * 60 * 30;
|
|
498
561
|
const USER_DURATION = 1000 * 60 * 60 * 24 * 365;
|
|
499
562
|
const data = {};
|
|
500
|
-
function getRootDomain() {
|
|
563
|
+
function getRootDomain(url) {
|
|
501
564
|
if (isServer) return;
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
return
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
565
|
+
if (!url) return;
|
|
566
|
+
try {
|
|
567
|
+
const hostname = new URL(url).hostname;
|
|
568
|
+
if (!psl.isValid(hostname)) return;
|
|
569
|
+
const parsed = psl.parse(hostname);
|
|
570
|
+
if ('domain' in parsed && parsed.domain) return parsed.domain;
|
|
571
|
+
} catch (error) {
|
|
572
|
+
// invalid url
|
|
510
573
|
}
|
|
511
|
-
return
|
|
574
|
+
return;
|
|
512
575
|
}
|
|
513
576
|
function setCookie(name, value, ttl) {
|
|
514
577
|
if (isServer) return;
|
|
515
578
|
const expires = new Date(Date.now() + ttl).toUTCString();
|
|
516
|
-
const domain = getRootDomain();
|
|
579
|
+
const domain = getRootDomain(window.location.href);
|
|
517
580
|
const cookieString = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/${domain ? `; domain=.${domain}` : ''}`;
|
|
518
581
|
document.cookie = cookieString;
|
|
519
582
|
}
|
|
@@ -532,13 +595,13 @@ function getCookie(name) {
|
|
|
532
595
|
}
|
|
533
596
|
function deleteCookie(name) {
|
|
534
597
|
if (isServer) return;
|
|
535
|
-
const domain = getRootDomain();
|
|
598
|
+
const domain = getRootDomain(window.location.href);
|
|
536
599
|
const cookieString = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/${domain ? `; domain=.${domain}` : ''}`;
|
|
537
600
|
document.cookie = cookieString;
|
|
538
601
|
}
|
|
539
602
|
function migrateFromLocalStorage() {
|
|
540
603
|
if (isServer) return;
|
|
541
|
-
const keysToMigrate = [`${PREF}-session-id`, `${PREF}-anonymous-id`, `${PREF}-user-id`, `${PREF}-session-utm-context`];
|
|
604
|
+
const keysToMigrate = [`${PREF}-session-id`, `${PREF}-anonymous-id`, `${PREF}-user-id`, `${PREF}-session-utm-context`, `${PREF}-super-context`];
|
|
542
605
|
keysToMigrate.forEach(key => {
|
|
543
606
|
try {
|
|
544
607
|
const value = localStorage.getItem(key);
|
|
@@ -646,22 +709,31 @@ function getUserId() {
|
|
|
646
709
|
function setUserId(userId) {
|
|
647
710
|
storeData(`user-id`, userId, USER_DURATION);
|
|
648
711
|
}
|
|
649
|
-
function
|
|
650
|
-
return retrieveData(
|
|
712
|
+
function getSuperContext() {
|
|
713
|
+
return retrieveData('super-context') || {};
|
|
651
714
|
}
|
|
652
|
-
function
|
|
653
|
-
storeData(
|
|
715
|
+
function setSuperContext(superContext) {
|
|
716
|
+
storeData('super-context', superContext, SESSION_DURATION);
|
|
654
717
|
}
|
|
655
|
-
function
|
|
656
|
-
|
|
657
|
-
const
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
718
|
+
function updateSuperContext(browserContext) {
|
|
719
|
+
const existingSuperContext = getSuperContext();
|
|
720
|
+
const defaultSuperContextKeys = ['$utmSource', '$utmMedium', '$utmCampaign', '$utmTerm', '$utmContent', '$utmId', '$utmSourcePlatform', '$utmCampaignId', '$utmCreativeFormat', '$utmMarketingTactic', '$utmAdSource', '$utmAdId'];
|
|
721
|
+
const superContext = defaultSuperContextKeys.reduce((acc, key) => {
|
|
722
|
+
const value = Object.assign({}, browserContext)[key];
|
|
723
|
+
if (value) acc[key] = value;
|
|
724
|
+
return acc;
|
|
725
|
+
}, existingSuperContext);
|
|
726
|
+
// Only set referrer if it's from a different root domain
|
|
727
|
+
// Prevents setting referrer when going between subdomains of the same root domain
|
|
728
|
+
if (browserContext.$referrer) {
|
|
729
|
+
const referrerRootDomain = getRootDomain(browserContext.$referrer);
|
|
730
|
+
const currentRootDomain = getRootDomain(browserContext.$href);
|
|
731
|
+
if (referrerRootDomain && currentRootDomain && referrerRootDomain !== currentRootDomain) {
|
|
732
|
+
superContext['$referrer'] = browserContext.$referrer;
|
|
733
|
+
}
|
|
662
734
|
}
|
|
663
|
-
|
|
664
|
-
return
|
|
735
|
+
setSuperContext(superContext);
|
|
736
|
+
return superContext;
|
|
665
737
|
}
|
|
666
738
|
class Saasco {
|
|
667
739
|
/**
|
|
@@ -742,15 +814,16 @@ class Saasco {
|
|
|
742
814
|
const sessionId = (hasAction ? undefined : actionOrPayload.sessionId) || getSessionId();
|
|
743
815
|
const anonymousId = (hasAction ? undefined : actionOrPayload.anonymousId) || getAnonymousId();
|
|
744
816
|
const distinctId = (hasAction ? undefined : actionOrPayload.userId) || getUserId();
|
|
745
|
-
// Only gets browser and
|
|
817
|
+
// Only gets browser and super context if in the browser
|
|
746
818
|
let browserContext;
|
|
747
|
-
let
|
|
819
|
+
let superContext;
|
|
748
820
|
if (isBrowser) {
|
|
749
821
|
browserContext = getBrowserContext();
|
|
750
|
-
|
|
751
|
-
const sessionUTMContext = handleSessionUTMContext();
|
|
752
|
-
if (sessionUTMContext) utmContext = sessionUTMContext;
|
|
822
|
+
superContext = updateSuperContext(browserContext);
|
|
753
823
|
}
|
|
824
|
+
const payloadJSON = Object.assign(Object.assign(Object.assign({}, browserContext), superContext), {
|
|
825
|
+
properties: properties || {}
|
|
826
|
+
});
|
|
754
827
|
const data = {
|
|
755
828
|
id: uuid.v4(),
|
|
756
829
|
timestamp: new Date().toISOString(),
|
|
@@ -760,9 +833,7 @@ class Saasco {
|
|
|
760
833
|
anonymousId,
|
|
761
834
|
distinctId,
|
|
762
835
|
projectId: this.config.projectId,
|
|
763
|
-
payload: JSON.stringify(
|
|
764
|
-
properties: properties || {}
|
|
765
|
-
})),
|
|
836
|
+
payload: JSON.stringify(payloadJSON),
|
|
766
837
|
source: isBrowser ? 'client' : 'server',
|
|
767
838
|
context: JSON.stringify(context || {})
|
|
768
839
|
};
|
|
@@ -843,8 +914,8 @@ class Saasco {
|
|
|
843
914
|
*
|
|
844
915
|
*/
|
|
845
916
|
logout() {
|
|
846
|
-
// Clear
|
|
847
|
-
|
|
917
|
+
// Clear super context data on logout
|
|
918
|
+
setSuperContext(null);
|
|
848
919
|
this.identify(null);
|
|
849
920
|
}
|
|
850
921
|
/**
|
|
@@ -968,19 +1039,22 @@ const browserContextSchema = zod.z.object({
|
|
|
968
1039
|
$screenHeight: zod.z.number(),
|
|
969
1040
|
$screenWidth: zod.z.number(),
|
|
970
1041
|
$title: zod.z.string(),
|
|
971
|
-
$userAgent: zod.z.string()
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
$
|
|
975
|
-
$
|
|
976
|
-
$
|
|
977
|
-
$
|
|
978
|
-
$
|
|
1042
|
+
$userAgent: zod.z.string(),
|
|
1043
|
+
$utmSource: zod.z.string().nullable(),
|
|
1044
|
+
$utmMedium: zod.z.string().nullable(),
|
|
1045
|
+
$utmCampaign: zod.z.string().nullable(),
|
|
1046
|
+
$utmTerm: zod.z.string().nullable(),
|
|
1047
|
+
$utmContent: zod.z.string().nullable(),
|
|
1048
|
+
$utmId: zod.z.string().nullable(),
|
|
1049
|
+
$utmSourcePlatform: zod.z.string().nullable(),
|
|
1050
|
+
$utmCampaignId: zod.z.string().nullable(),
|
|
1051
|
+
$utmCreativeFormat: zod.z.string().nullable(),
|
|
1052
|
+
$utmMarketingTactic: zod.z.string().nullable(),
|
|
1053
|
+
$utmAdSource: zod.z.string().nullable(),
|
|
1054
|
+
$utmAdId: zod.z.string().nullable()
|
|
979
1055
|
});
|
|
980
1056
|
|
|
981
1057
|
exports.Saasco = Saasco;
|
|
982
1058
|
exports.browserContextSchema = browserContextSchema;
|
|
983
1059
|
exports.getBrowserContext = getBrowserContext;
|
|
984
|
-
exports.getUTMContext = getUTMContext;
|
|
985
1060
|
exports.timezones = timezones;
|
|
986
|
-
exports.utmContextSchema = utmContextSchema;
|
package/index.esm.js
CHANGED
|
@@ -3,7 +3,7 @@ import { v4 } from '@lukeed/uuid';
|
|
|
3
3
|
import { isValid, parse } from 'psl';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
|
|
6
|
-
var version = "0.1.
|
|
6
|
+
var version = "0.1.31";
|
|
7
7
|
|
|
8
8
|
const timezones = {
|
|
9
9
|
'Asia/Barnaul': 'RU',
|
|
@@ -451,6 +451,79 @@ function getBrowserContext() {
|
|
|
451
451
|
const $screenWidth = screen.width;
|
|
452
452
|
const $title = document.title;
|
|
453
453
|
const $userAgent = window.navigator.userAgent;
|
|
454
|
+
const params = new URLSearchParams(window.location.search);
|
|
455
|
+
const $utmSource = params.get('utm_source');
|
|
456
|
+
const $utmMedium = params.get('utm_medium');
|
|
457
|
+
const $utmCampaign = params.get('utm_campaign');
|
|
458
|
+
const $utmTerm = params.get('utm_term');
|
|
459
|
+
const $utmContent = params.get('utm_content');
|
|
460
|
+
const $utmId = params.get('utm_id');
|
|
461
|
+
const $utmSourcePlatform = params.get('utm_source_platform');
|
|
462
|
+
const $utmCampaignId = params.get('utm_campaign_id');
|
|
463
|
+
const $utmCreativeFormat = params.get('utm_creative_format');
|
|
464
|
+
const $utmMarketingTactic = params.get('utm_marketing_tactic');
|
|
465
|
+
let $utmAdSource = params.get('utm_ad_source');
|
|
466
|
+
let $utmAdId = params.get('utm_ad_id');
|
|
467
|
+
// If the adId is not set directly attempt to get it from each ad network
|
|
468
|
+
// Also set the ad source to the ad network if it's not set
|
|
469
|
+
if (!$utmAdId) {
|
|
470
|
+
const fbAdId = params.get('fbadid');
|
|
471
|
+
if (fbAdId) {
|
|
472
|
+
$utmAdId = fbAdId;
|
|
473
|
+
if (!$utmAdSource) {
|
|
474
|
+
$utmAdSource = 'facebook';
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const googleAdId = params.get('gadid');
|
|
478
|
+
if (googleAdId) {
|
|
479
|
+
$utmAdId = googleAdId;
|
|
480
|
+
if (!$utmAdSource) {
|
|
481
|
+
$utmAdSource = 'google';
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
const xAdId = params.get('xadid');
|
|
485
|
+
if (xAdId) {
|
|
486
|
+
$utmAdId = xAdId;
|
|
487
|
+
if (!$utmAdSource) {
|
|
488
|
+
$utmAdSource = 'x';
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const pinterestAdId = params.get('padid');
|
|
492
|
+
if (pinterestAdId) {
|
|
493
|
+
$utmAdId = pinterestAdId;
|
|
494
|
+
if (!$utmAdSource) {
|
|
495
|
+
$utmAdSource = 'pinterest';
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const tiktokAdId = params.get('ttadid');
|
|
499
|
+
if (tiktokAdId) {
|
|
500
|
+
$utmAdId = tiktokAdId;
|
|
501
|
+
if (!$utmAdSource) {
|
|
502
|
+
$utmAdSource = 'tiktok';
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const snapchatAdId = params.get('scadid');
|
|
506
|
+
if (snapchatAdId) {
|
|
507
|
+
$utmAdId = snapchatAdId;
|
|
508
|
+
if (!$utmAdSource) {
|
|
509
|
+
$utmAdSource = 'snapchat';
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const redditAdId = params.get('radid');
|
|
513
|
+
if (redditAdId) {
|
|
514
|
+
$utmAdId = redditAdId;
|
|
515
|
+
if (!$utmAdSource) {
|
|
516
|
+
$utmAdSource = 'reddit';
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const linkedinAdId = params.get('liadid');
|
|
520
|
+
if (linkedinAdId) {
|
|
521
|
+
$utmAdId = linkedinAdId;
|
|
522
|
+
if (!$utmAdSource) {
|
|
523
|
+
$utmAdSource = 'linkedin';
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
454
527
|
return {
|
|
455
528
|
$locale,
|
|
456
529
|
$location,
|
|
@@ -461,55 +534,45 @@ function getBrowserContext() {
|
|
|
461
534
|
$screenHeight,
|
|
462
535
|
$screenWidth,
|
|
463
536
|
$title,
|
|
464
|
-
$userAgent
|
|
537
|
+
$userAgent,
|
|
538
|
+
$utmSource,
|
|
539
|
+
$utmMedium,
|
|
540
|
+
$utmCampaign,
|
|
541
|
+
$utmTerm,
|
|
542
|
+
$utmContent,
|
|
543
|
+
$utmId,
|
|
544
|
+
$utmSourcePlatform,
|
|
545
|
+
$utmCampaignId,
|
|
546
|
+
$utmCreativeFormat,
|
|
547
|
+
$utmMarketingTactic,
|
|
548
|
+
$utmAdSource,
|
|
549
|
+
$utmAdId
|
|
465
550
|
};
|
|
466
551
|
}
|
|
467
552
|
|
|
468
|
-
function getUTMContext() {
|
|
469
|
-
const isBrowser = typeof window !== 'undefined';
|
|
470
|
-
if (!isBrowser) throw new Error('getUTMContext can only be called in browser');
|
|
471
|
-
const params = new URLSearchParams(window.location.search);
|
|
472
|
-
const $utmSource = params.get('utm_source');
|
|
473
|
-
const $utmMedium = params.get('utm_medium');
|
|
474
|
-
const $utmCampaign = params.get('utm_campaign');
|
|
475
|
-
const $utmTerm = params.get('utm_term');
|
|
476
|
-
const $utmContent = params.get('utm_content');
|
|
477
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, $utmSource ? {
|
|
478
|
-
$utmSource
|
|
479
|
-
} : {}), $utmMedium ? {
|
|
480
|
-
$utmMedium
|
|
481
|
-
} : {}), $utmCampaign ? {
|
|
482
|
-
$utmCampaign
|
|
483
|
-
} : {}), $utmTerm ? {
|
|
484
|
-
$utmTerm
|
|
485
|
-
} : {}), $utmContent ? {
|
|
486
|
-
$utmContent
|
|
487
|
-
} : {});
|
|
488
|
-
}
|
|
489
|
-
|
|
490
553
|
const isBrowser = typeof window !== 'undefined';
|
|
491
554
|
const isServer = !isBrowser;
|
|
492
555
|
const PREF = 'saasco-sdk';
|
|
493
556
|
const SESSION_DURATION = 1000 * 60 * 30;
|
|
494
557
|
const USER_DURATION = 1000 * 60 * 60 * 24 * 365;
|
|
495
558
|
const data = {};
|
|
496
|
-
function getRootDomain() {
|
|
559
|
+
function getRootDomain(url) {
|
|
497
560
|
if (isServer) return;
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
561
|
+
if (!url) return;
|
|
562
|
+
try {
|
|
563
|
+
const hostname = new URL(url).hostname;
|
|
564
|
+
if (!isValid(hostname)) return;
|
|
565
|
+
const parsed = parse(hostname);
|
|
566
|
+
if ('domain' in parsed && parsed.domain) return parsed.domain;
|
|
567
|
+
} catch (error) {
|
|
568
|
+
// invalid url
|
|
506
569
|
}
|
|
507
|
-
return
|
|
570
|
+
return;
|
|
508
571
|
}
|
|
509
572
|
function setCookie(name, value, ttl) {
|
|
510
573
|
if (isServer) return;
|
|
511
574
|
const expires = new Date(Date.now() + ttl).toUTCString();
|
|
512
|
-
const domain = getRootDomain();
|
|
575
|
+
const domain = getRootDomain(window.location.href);
|
|
513
576
|
const cookieString = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/${domain ? `; domain=.${domain}` : ''}`;
|
|
514
577
|
document.cookie = cookieString;
|
|
515
578
|
}
|
|
@@ -528,13 +591,13 @@ function getCookie(name) {
|
|
|
528
591
|
}
|
|
529
592
|
function deleteCookie(name) {
|
|
530
593
|
if (isServer) return;
|
|
531
|
-
const domain = getRootDomain();
|
|
594
|
+
const domain = getRootDomain(window.location.href);
|
|
532
595
|
const cookieString = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/${domain ? `; domain=.${domain}` : ''}`;
|
|
533
596
|
document.cookie = cookieString;
|
|
534
597
|
}
|
|
535
598
|
function migrateFromLocalStorage() {
|
|
536
599
|
if (isServer) return;
|
|
537
|
-
const keysToMigrate = [`${PREF}-session-id`, `${PREF}-anonymous-id`, `${PREF}-user-id`, `${PREF}-session-utm-context`];
|
|
600
|
+
const keysToMigrate = [`${PREF}-session-id`, `${PREF}-anonymous-id`, `${PREF}-user-id`, `${PREF}-session-utm-context`, `${PREF}-super-context`];
|
|
538
601
|
keysToMigrate.forEach(key => {
|
|
539
602
|
try {
|
|
540
603
|
const value = localStorage.getItem(key);
|
|
@@ -642,22 +705,31 @@ function getUserId() {
|
|
|
642
705
|
function setUserId(userId) {
|
|
643
706
|
storeData(`user-id`, userId, USER_DURATION);
|
|
644
707
|
}
|
|
645
|
-
function
|
|
646
|
-
return retrieveData(
|
|
708
|
+
function getSuperContext() {
|
|
709
|
+
return retrieveData('super-context') || {};
|
|
647
710
|
}
|
|
648
|
-
function
|
|
649
|
-
storeData(
|
|
711
|
+
function setSuperContext(superContext) {
|
|
712
|
+
storeData('super-context', superContext, SESSION_DURATION);
|
|
650
713
|
}
|
|
651
|
-
function
|
|
652
|
-
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
714
|
+
function updateSuperContext(browserContext) {
|
|
715
|
+
const existingSuperContext = getSuperContext();
|
|
716
|
+
const defaultSuperContextKeys = ['$utmSource', '$utmMedium', '$utmCampaign', '$utmTerm', '$utmContent', '$utmId', '$utmSourcePlatform', '$utmCampaignId', '$utmCreativeFormat', '$utmMarketingTactic', '$utmAdSource', '$utmAdId'];
|
|
717
|
+
const superContext = defaultSuperContextKeys.reduce((acc, key) => {
|
|
718
|
+
const value = Object.assign({}, browserContext)[key];
|
|
719
|
+
if (value) acc[key] = value;
|
|
720
|
+
return acc;
|
|
721
|
+
}, existingSuperContext);
|
|
722
|
+
// Only set referrer if it's from a different root domain
|
|
723
|
+
// Prevents setting referrer when going between subdomains of the same root domain
|
|
724
|
+
if (browserContext.$referrer) {
|
|
725
|
+
const referrerRootDomain = getRootDomain(browserContext.$referrer);
|
|
726
|
+
const currentRootDomain = getRootDomain(browserContext.$href);
|
|
727
|
+
if (referrerRootDomain && currentRootDomain && referrerRootDomain !== currentRootDomain) {
|
|
728
|
+
superContext['$referrer'] = browserContext.$referrer;
|
|
729
|
+
}
|
|
658
730
|
}
|
|
659
|
-
|
|
660
|
-
return
|
|
731
|
+
setSuperContext(superContext);
|
|
732
|
+
return superContext;
|
|
661
733
|
}
|
|
662
734
|
class Saasco {
|
|
663
735
|
/**
|
|
@@ -738,15 +810,16 @@ class Saasco {
|
|
|
738
810
|
const sessionId = (hasAction ? undefined : actionOrPayload.sessionId) || getSessionId();
|
|
739
811
|
const anonymousId = (hasAction ? undefined : actionOrPayload.anonymousId) || getAnonymousId();
|
|
740
812
|
const distinctId = (hasAction ? undefined : actionOrPayload.userId) || getUserId();
|
|
741
|
-
// Only gets browser and
|
|
813
|
+
// Only gets browser and super context if in the browser
|
|
742
814
|
let browserContext;
|
|
743
|
-
let
|
|
815
|
+
let superContext;
|
|
744
816
|
if (isBrowser) {
|
|
745
817
|
browserContext = getBrowserContext();
|
|
746
|
-
|
|
747
|
-
const sessionUTMContext = handleSessionUTMContext();
|
|
748
|
-
if (sessionUTMContext) utmContext = sessionUTMContext;
|
|
818
|
+
superContext = updateSuperContext(browserContext);
|
|
749
819
|
}
|
|
820
|
+
const payloadJSON = Object.assign(Object.assign(Object.assign({}, browserContext), superContext), {
|
|
821
|
+
properties: properties || {}
|
|
822
|
+
});
|
|
750
823
|
const data = {
|
|
751
824
|
id: v4(),
|
|
752
825
|
timestamp: new Date().toISOString(),
|
|
@@ -756,9 +829,7 @@ class Saasco {
|
|
|
756
829
|
anonymousId,
|
|
757
830
|
distinctId,
|
|
758
831
|
projectId: this.config.projectId,
|
|
759
|
-
payload: JSON.stringify(
|
|
760
|
-
properties: properties || {}
|
|
761
|
-
})),
|
|
832
|
+
payload: JSON.stringify(payloadJSON),
|
|
762
833
|
source: isBrowser ? 'client' : 'server',
|
|
763
834
|
context: JSON.stringify(context || {})
|
|
764
835
|
};
|
|
@@ -839,8 +910,8 @@ class Saasco {
|
|
|
839
910
|
*
|
|
840
911
|
*/
|
|
841
912
|
logout() {
|
|
842
|
-
// Clear
|
|
843
|
-
|
|
913
|
+
// Clear super context data on logout
|
|
914
|
+
setSuperContext(null);
|
|
844
915
|
this.identify(null);
|
|
845
916
|
}
|
|
846
917
|
/**
|
|
@@ -964,14 +1035,19 @@ const browserContextSchema = z.object({
|
|
|
964
1035
|
$screenHeight: z.number(),
|
|
965
1036
|
$screenWidth: z.number(),
|
|
966
1037
|
$title: z.string(),
|
|
967
|
-
$userAgent: z.string()
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
$
|
|
971
|
-
$
|
|
972
|
-
$
|
|
973
|
-
$
|
|
974
|
-
$
|
|
1038
|
+
$userAgent: z.string(),
|
|
1039
|
+
$utmSource: z.string().nullable(),
|
|
1040
|
+
$utmMedium: z.string().nullable(),
|
|
1041
|
+
$utmCampaign: z.string().nullable(),
|
|
1042
|
+
$utmTerm: z.string().nullable(),
|
|
1043
|
+
$utmContent: z.string().nullable(),
|
|
1044
|
+
$utmId: z.string().nullable(),
|
|
1045
|
+
$utmSourcePlatform: z.string().nullable(),
|
|
1046
|
+
$utmCampaignId: z.string().nullable(),
|
|
1047
|
+
$utmCreativeFormat: z.string().nullable(),
|
|
1048
|
+
$utmMarketingTactic: z.string().nullable(),
|
|
1049
|
+
$utmAdSource: z.string().nullable(),
|
|
1050
|
+
$utmAdId: z.string().nullable()
|
|
975
1051
|
});
|
|
976
1052
|
|
|
977
|
-
export { Saasco, browserContextSchema, getBrowserContext,
|
|
1053
|
+
export { Saasco, browserContextSchema, getBrowserContext, timezones };
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -10,6 +10,18 @@ export declare const browserContextSchema: z.ZodObject<{
|
|
|
10
10
|
$screenWidth: z.ZodNumber;
|
|
11
11
|
$title: z.ZodString;
|
|
12
12
|
$userAgent: z.ZodString;
|
|
13
|
+
$utmSource: z.ZodNullable<z.ZodString>;
|
|
14
|
+
$utmMedium: z.ZodNullable<z.ZodString>;
|
|
15
|
+
$utmCampaign: z.ZodNullable<z.ZodString>;
|
|
16
|
+
$utmTerm: z.ZodNullable<z.ZodString>;
|
|
17
|
+
$utmContent: z.ZodNullable<z.ZodString>;
|
|
18
|
+
$utmId: z.ZodNullable<z.ZodString>;
|
|
19
|
+
$utmSourcePlatform: z.ZodNullable<z.ZodString>;
|
|
20
|
+
$utmCampaignId: z.ZodNullable<z.ZodString>;
|
|
21
|
+
$utmCreativeFormat: z.ZodNullable<z.ZodString>;
|
|
22
|
+
$utmMarketingTactic: z.ZodNullable<z.ZodString>;
|
|
23
|
+
$utmAdSource: z.ZodNullable<z.ZodString>;
|
|
24
|
+
$utmAdId: z.ZodNullable<z.ZodString>;
|
|
13
25
|
}, "strip", z.ZodTypeAny, {
|
|
14
26
|
$locale: string;
|
|
15
27
|
$location: string;
|
|
@@ -21,6 +33,18 @@ export declare const browserContextSchema: z.ZodObject<{
|
|
|
21
33
|
$screenWidth: number;
|
|
22
34
|
$title: string;
|
|
23
35
|
$userAgent: string;
|
|
36
|
+
$utmSource: string | null;
|
|
37
|
+
$utmMedium: string | null;
|
|
38
|
+
$utmCampaign: string | null;
|
|
39
|
+
$utmTerm: string | null;
|
|
40
|
+
$utmContent: string | null;
|
|
41
|
+
$utmId: string | null;
|
|
42
|
+
$utmSourcePlatform: string | null;
|
|
43
|
+
$utmCampaignId: string | null;
|
|
44
|
+
$utmCreativeFormat: string | null;
|
|
45
|
+
$utmMarketingTactic: string | null;
|
|
46
|
+
$utmAdSource: string | null;
|
|
47
|
+
$utmAdId: string | null;
|
|
24
48
|
}, {
|
|
25
49
|
$locale: string;
|
|
26
50
|
$location: string;
|
|
@@ -32,25 +56,18 @@ export declare const browserContextSchema: z.ZodObject<{
|
|
|
32
56
|
$screenWidth: number;
|
|
33
57
|
$title: string;
|
|
34
58
|
$userAgent: string;
|
|
59
|
+
$utmSource: string | null;
|
|
60
|
+
$utmMedium: string | null;
|
|
61
|
+
$utmCampaign: string | null;
|
|
62
|
+
$utmTerm: string | null;
|
|
63
|
+
$utmContent: string | null;
|
|
64
|
+
$utmId: string | null;
|
|
65
|
+
$utmSourcePlatform: string | null;
|
|
66
|
+
$utmCampaignId: string | null;
|
|
67
|
+
$utmCreativeFormat: string | null;
|
|
68
|
+
$utmMarketingTactic: string | null;
|
|
69
|
+
$utmAdSource: string | null;
|
|
70
|
+
$utmAdId: string | null;
|
|
35
71
|
}>;
|
|
36
72
|
export type BrowserContext = z.infer<typeof browserContextSchema>;
|
|
37
|
-
export
|
|
38
|
-
$utmSource: z.ZodOptional<z.ZodString>;
|
|
39
|
-
$utmMedium: z.ZodOptional<z.ZodString>;
|
|
40
|
-
$utmCampaign: z.ZodOptional<z.ZodString>;
|
|
41
|
-
$utmTerm: z.ZodOptional<z.ZodString>;
|
|
42
|
-
$utmContent: z.ZodOptional<z.ZodString>;
|
|
43
|
-
}, "strip", z.ZodTypeAny, {
|
|
44
|
-
$utmSource?: string | undefined;
|
|
45
|
-
$utmMedium?: string | undefined;
|
|
46
|
-
$utmCampaign?: string | undefined;
|
|
47
|
-
$utmTerm?: string | undefined;
|
|
48
|
-
$utmContent?: string | undefined;
|
|
49
|
-
}, {
|
|
50
|
-
$utmSource?: string | undefined;
|
|
51
|
-
$utmMedium?: string | undefined;
|
|
52
|
-
$utmCampaign?: string | undefined;
|
|
53
|
-
$utmTerm?: string | undefined;
|
|
54
|
-
$utmContent?: string | undefined;
|
|
55
|
-
}>;
|
|
56
|
-
export type UTMContext = z.infer<typeof utmContextSchema>;
|
|
73
|
+
export type SuperContext = Record<string, any>;
|