saasco-sdk 0.1.43 → 0.1.44
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 +406 -116
- package/index.esm.js +405 -116
- package/package.json +1 -1
- package/src/lib/analytics.d.ts +17 -1
- package/src/lib/integrations/facebook-pixel.d.ts +1 -1
- package/src/lib/integrations/index.d.ts +1 -0
- package/src/lib/integrations/integration-manager.d.ts +5 -11
- package/src/lib/integrations/pinterest-tag.d.ts +37 -0
- package/src/lib/integrations/tiktok-pixel.d.ts +1 -1
- package/src/lib/utils/getIntegrationLoggerLevel.d.ts +8 -0
- package/src/lib/utils/index.d.ts +1 -0
- package/src/lib/utils/logger.d.ts +9 -2
package/index.esm.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import { isValid, parse } from 'psl';
|
|
3
|
-
import { sha256 } from 'js-sha256';
|
|
4
3
|
import { v4 } from '@lukeed/uuid';
|
|
4
|
+
import { sha256 } from 'js-sha256';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
7
|
-
var version = "0.1.
|
|
7
|
+
var version = "0.1.44";
|
|
8
8
|
|
|
9
9
|
const timezones = {
|
|
10
10
|
'Asia/Barnaul': 'RU',
|
|
@@ -551,26 +551,117 @@ function getBrowserContext() {
|
|
|
551
551
|
};
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
|
|
555
|
-
|
|
554
|
+
var LogLevel;
|
|
555
|
+
(function (LogLevel) {
|
|
556
|
+
LogLevel[LogLevel["ERROR"] = 0] = "ERROR";
|
|
557
|
+
LogLevel[LogLevel["WARN"] = 1] = "WARN";
|
|
558
|
+
LogLevel[LogLevel["INFO"] = 2] = "INFO";
|
|
559
|
+
LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG";
|
|
560
|
+
})(LogLevel || (LogLevel = {}));
|
|
561
|
+
class AnalyticsLogger {
|
|
562
|
+
constructor(config) {
|
|
563
|
+
this.config = config;
|
|
564
|
+
}
|
|
565
|
+
debug(...args) {
|
|
566
|
+
if (this.config.level < LogLevel.DEBUG) return;
|
|
567
|
+
const icon = '◍';
|
|
568
|
+
const message = `${icon} ${this.config.label}`;
|
|
569
|
+
console.debug(`%c ${message}`, `background: #eee; color: #000; padding-right: 6px; border-radius: 2px;`, ...args);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Log debug information
|
|
573
|
+
*/
|
|
574
|
+
info(...args) {
|
|
575
|
+
if (this.config.level < LogLevel.INFO) return;
|
|
576
|
+
const icon = '◍';
|
|
577
|
+
const message = `${icon} ${this.config.label}`;
|
|
578
|
+
console.info(`%c ${message}`, `background: #eee; color: #000; padding-right: 6px; border-radius: 2px;`, ...args);
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Log warning information
|
|
582
|
+
*/
|
|
583
|
+
warn(...args) {
|
|
584
|
+
if (this.config.level < LogLevel.WARN) return;
|
|
585
|
+
const icon = '◍';
|
|
586
|
+
const message = `${icon} ${this.config.label}`;
|
|
587
|
+
console.warn(`%c ${message}`, `background: #ffa500; color: #000; padding-right: 6px; border-radius: 2px;`, ...args);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Log error information
|
|
591
|
+
*/
|
|
592
|
+
error(...args) {
|
|
593
|
+
const icon = '◍';
|
|
594
|
+
const message = `${icon} ${this.config.label} Error`;
|
|
595
|
+
console.error(`%c ${message}`, 'background: red; color: white; padding-right: 6px; border-radius: 2px;', ...args);
|
|
596
|
+
return {
|
|
597
|
+
success: false,
|
|
598
|
+
message: args.join(' ')
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const isBrowser$4 = typeof window !== 'undefined';
|
|
604
|
+
const isServer$4 = !isBrowser$4;
|
|
605
|
+
/**
|
|
606
|
+
* Get the logger level for a specific integration
|
|
607
|
+
* Supports URL parameters like saasco-debug-{integration-type}=true
|
|
608
|
+
* If debug is true or URL param is true, sets level to DEBUG (3), otherwise WARN
|
|
609
|
+
*/
|
|
610
|
+
function getIntegrationLoggerLevel(integrationName, debug) {
|
|
611
|
+
// Check URL parameters for debug overrides (browser only)
|
|
612
|
+
let urlDebug = false;
|
|
613
|
+
if (!isServer$4) {
|
|
614
|
+
try {
|
|
615
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
616
|
+
const paramName = `saasco-debug-${integrationName}`;
|
|
617
|
+
const paramValue = urlParams.get(paramName);
|
|
618
|
+
if (paramValue === 'true') {
|
|
619
|
+
urlDebug = true;
|
|
620
|
+
}
|
|
621
|
+
} catch (error) {
|
|
622
|
+
// Ignore URL parsing errors
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
// URL parameters override config, config overrides default (WARN)
|
|
626
|
+
return urlDebug || debug ? LogLevel.DEBUG : LogLevel.WARN;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Generate a collision-resistant UUID
|
|
631
|
+
* Uses lukeed's UUID v4 implementation for consistent, fast UUID generation
|
|
632
|
+
*/
|
|
633
|
+
function uuid() {
|
|
634
|
+
return v4();
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const isBrowser$3 = typeof window !== 'undefined';
|
|
638
|
+
const isServer$3 = !isBrowser$3;
|
|
556
639
|
const standardFacebookEvents = ['AddPaymentInfo', 'AddToCart', 'AddToWishlist', 'CompleteRegistration', 'Contact', 'CustomizeProduct', 'Donate', 'FindLocation', 'InitiateCheckout', 'Lead', 'Purchase', 'Schedule', 'Search', 'StartTrial', 'SubmitApplication', 'Subscribe', 'ViewContent', 'PageView'];
|
|
557
640
|
/**
|
|
558
641
|
* Create a Facebook Pixel integration instance
|
|
559
642
|
*/
|
|
560
|
-
function createFacebookPixelIntegration(config) {
|
|
643
|
+
function createFacebookPixelIntegration(config, debug) {
|
|
561
644
|
let isPixelReady = false;
|
|
645
|
+
// Create integration logger
|
|
646
|
+
const integrationLoggerLevel = getIntegrationLoggerLevel('facebook-pixel', debug);
|
|
647
|
+
const logger = new AnalyticsLogger({
|
|
648
|
+
level: integrationLoggerLevel,
|
|
649
|
+
label: 'Saasco facebook-pixel'
|
|
650
|
+
});
|
|
562
651
|
return {
|
|
563
652
|
name: 'facebook-pixel',
|
|
564
653
|
environments: ['client'],
|
|
565
654
|
init: () => __awaiter(this, void 0, void 0, function* () {
|
|
566
|
-
if (isServer$
|
|
567
|
-
|
|
568
|
-
// This allows the integration to be registered but remain inactive
|
|
655
|
+
if (isServer$3) {
|
|
656
|
+
logger.debug('Facebook Pixel init skipped on server');
|
|
569
657
|
return;
|
|
570
658
|
}
|
|
659
|
+
logger.info('Initializing Facebook Pixel', {
|
|
660
|
+
pixelId: config.pixelId
|
|
661
|
+
});
|
|
571
662
|
// Check if Facebook Pixel is already loaded
|
|
572
663
|
if (window.fbq || window._fbq) {
|
|
573
|
-
|
|
664
|
+
logger.warn('Facebook Pixel is already initialized');
|
|
574
665
|
isPixelReady = true;
|
|
575
666
|
return;
|
|
576
667
|
}
|
|
@@ -593,9 +684,11 @@ function createFacebookPixelIntegration(config) {
|
|
|
593
684
|
// Add load event listener
|
|
594
685
|
t.onload = () => {
|
|
595
686
|
isPixelReady = true;
|
|
687
|
+
logger.info('Facebook Pixel script loaded successfully');
|
|
596
688
|
resolve();
|
|
597
689
|
};
|
|
598
690
|
t.onerror = () => {
|
|
691
|
+
logger.error('Failed to load Facebook Pixel script');
|
|
599
692
|
reject(new Error('Failed to load Facebook Pixel script'));
|
|
600
693
|
};
|
|
601
694
|
s = b.getElementsByTagName(e)[0];
|
|
@@ -606,33 +699,56 @@ function createFacebookPixelIntegration(config) {
|
|
|
606
699
|
// Allow duplicate PageView events
|
|
607
700
|
window.fbq.allowDuplicatePageViews = true;
|
|
608
701
|
if (config.automaticConfiguration === false) {
|
|
702
|
+
logger.debug('Disabling automatic configuration');
|
|
609
703
|
window.fbq('set', 'autoConfig', false, config.pixelId);
|
|
610
704
|
}
|
|
611
705
|
// Initialize pixel
|
|
706
|
+
logger.debug('Initializing Facebook Pixel with ID', config.pixelId);
|
|
612
707
|
window.fbq('init', config.pixelId);
|
|
613
708
|
// If script loads synchronously, mark as ready
|
|
614
709
|
if (window.fbq && typeof window.fbq === 'function') {
|
|
615
710
|
isPixelReady = true;
|
|
711
|
+
logger.info('Facebook Pixel initialized synchronously');
|
|
616
712
|
resolve();
|
|
617
713
|
}
|
|
618
714
|
} catch (error) {
|
|
715
|
+
logger.error('Error during Facebook Pixel initialization', error);
|
|
619
716
|
reject(error);
|
|
620
717
|
}
|
|
621
718
|
});
|
|
622
719
|
}),
|
|
623
720
|
track: (eventName, properties, context) => {
|
|
624
|
-
if (!isPixelReady || !window.fbq)
|
|
721
|
+
if (!isPixelReady || !window.fbq) {
|
|
722
|
+
logger.warn('Facebook Pixel not ready, skipping track event', {
|
|
723
|
+
eventName
|
|
724
|
+
});
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
625
727
|
const fbEventName = getFacebookEventName(eventName, config.eventMapping);
|
|
626
728
|
const eventsWithParams = ['Purchase', 'StartTrial', 'Subscribe'];
|
|
627
729
|
const isStandardEvent = standardFacebookEvents.includes(fbEventName);
|
|
628
730
|
const trackType = isStandardEvent ? 'track' : 'trackCustom';
|
|
731
|
+
logger.debug('Tracking Facebook Pixel event', {
|
|
732
|
+
originalEvent: eventName,
|
|
733
|
+
fbEventName,
|
|
734
|
+
trackType,
|
|
735
|
+
isStandardEvent,
|
|
736
|
+
properties
|
|
737
|
+
});
|
|
629
738
|
if (eventsWithParams.includes(fbEventName) && properties) {
|
|
630
739
|
const fbParams = {};
|
|
631
740
|
if (properties['value'] !== undefined) fbParams['value'] = properties['value'];
|
|
632
741
|
if (properties['currency'] !== undefined) fbParams['currency'] = properties['currency'];
|
|
633
742
|
if (properties['predicted_ltv'] !== undefined) fbParams['predicted_ltv'] = properties['predicted_ltv'];
|
|
743
|
+
logger.info('Tracking Facebook Pixel event with parameters', {
|
|
744
|
+
event: fbEventName,
|
|
745
|
+
params: fbParams
|
|
746
|
+
});
|
|
634
747
|
window.fbq(trackType, fbEventName, fbParams);
|
|
635
748
|
} else {
|
|
749
|
+
logger.info('Tracking Facebook Pixel event', {
|
|
750
|
+
event: fbEventName
|
|
751
|
+
});
|
|
636
752
|
window.fbq(trackType, fbEventName);
|
|
637
753
|
}
|
|
638
754
|
},
|
|
@@ -798,7 +914,7 @@ function coerceMetaConversionsAmValues(properties) {
|
|
|
798
914
|
coerceFrom,
|
|
799
915
|
transform
|
|
800
916
|
} of coerce) {
|
|
801
|
-
const foundValue = findFirstProperty$
|
|
917
|
+
const foundValue = findFirstProperty$2(properties, coerceFrom);
|
|
802
918
|
if (foundValue !== null && transform) {
|
|
803
919
|
const transformedValue = transform(foundValue);
|
|
804
920
|
if (transformedValue) {
|
|
@@ -810,6 +926,183 @@ function coerceMetaConversionsAmValues(properties) {
|
|
|
810
926
|
}
|
|
811
927
|
return result;
|
|
812
928
|
}
|
|
929
|
+
function findFirstProperty$2(properties, keys) {
|
|
930
|
+
for (const key of keys) {
|
|
931
|
+
if (properties[key] !== undefined) {
|
|
932
|
+
return properties[key];
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
const isBrowser$2 = typeof window !== 'undefined';
|
|
939
|
+
const isServer$2 = !isBrowser$2;
|
|
940
|
+
/**
|
|
941
|
+
* Standard Pinterest events
|
|
942
|
+
* Reference: https://www.pinterest.com/_/_/help/business/article/event-code
|
|
943
|
+
*/
|
|
944
|
+
const standardPinterestEvents = ['checkout', 'addtocart', 'pagevisit', 'signup', 'watchvideo', 'lead', 'search', 'viewcategory', 'custom', 'addpaymentinfo', 'addtowishlist', 'initiatecheckout', 'subscribe', 'viewcontent'];
|
|
945
|
+
/**
|
|
946
|
+
* Create a Pinterest Tag integration instance
|
|
947
|
+
* Documentation: https://help.pinterest.com/en/business/article/install-the-pinterest-tag
|
|
948
|
+
*/
|
|
949
|
+
function createPinterestTagIntegration(config, debug) {
|
|
950
|
+
let isTagReady = false;
|
|
951
|
+
// Create integration logger
|
|
952
|
+
const integrationLoggerLevel = getIntegrationLoggerLevel('pinterest-tag', debug);
|
|
953
|
+
const logger = new AnalyticsLogger({
|
|
954
|
+
level: integrationLoggerLevel,
|
|
955
|
+
label: 'Saasco Pinterest Tag'
|
|
956
|
+
});
|
|
957
|
+
return {
|
|
958
|
+
name: 'pinterest-tag',
|
|
959
|
+
environments: ['client'],
|
|
960
|
+
init: context => __awaiter(this, void 0, void 0, function* () {
|
|
961
|
+
if (isServer$2) {
|
|
962
|
+
logger.debug('Pinterest Tag init skipped on server');
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
logger.info('Initializing Pinterest Tag', {
|
|
966
|
+
tagId: config.tagId
|
|
967
|
+
});
|
|
968
|
+
// Check if Pinterest Tag is already loaded
|
|
969
|
+
if (window.pintrk || window._pintrk) {
|
|
970
|
+
logger.warn('Pinterest Tag is already initialized');
|
|
971
|
+
isTagReady = true;
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
// Initialize Pinterest Tag
|
|
975
|
+
return new Promise((resolve, reject) => {
|
|
976
|
+
try {
|
|
977
|
+
// Pinterest Tag initialization script
|
|
978
|
+
// Reference: https://help.pinterest.com/en/business/article/install-the-base-code
|
|
979
|
+
(function (e) {
|
|
980
|
+
if (!window.pintrk) {
|
|
981
|
+
window.pintrk = function () {
|
|
982
|
+
window.pintrk.queue.push(Array.prototype.slice.call(arguments));
|
|
983
|
+
};
|
|
984
|
+
const n = window.pintrk;
|
|
985
|
+
n.queue = [];
|
|
986
|
+
n.version = '3.0';
|
|
987
|
+
const t = document.createElement('script');
|
|
988
|
+
t.async = true;
|
|
989
|
+
t.src = e;
|
|
990
|
+
// Add load event listener
|
|
991
|
+
t.onload = () => {
|
|
992
|
+
// base script is loaded; now (re)load tag + fire page via runtime
|
|
993
|
+
window.pintrk('load', config.tagId);
|
|
994
|
+
// initialize the tag
|
|
995
|
+
window.pintrk('page');
|
|
996
|
+
// delay isTagReady to ensure the tag is loaded before sending events
|
|
997
|
+
setTimeout(() => {
|
|
998
|
+
logger.debug('Pinterest Tag initialized');
|
|
999
|
+
isTagReady = true;
|
|
1000
|
+
resolve();
|
|
1001
|
+
}, 500);
|
|
1002
|
+
};
|
|
1003
|
+
t.onerror = () => {
|
|
1004
|
+
logger.error('Failed to load Pinterest Tag script');
|
|
1005
|
+
reject(new Error('Failed to load Pinterest Tag script'));
|
|
1006
|
+
};
|
|
1007
|
+
const r = document.getElementsByTagName('script')[0];
|
|
1008
|
+
r.parentNode.insertBefore(t, r);
|
|
1009
|
+
}
|
|
1010
|
+
})('https://s.pinimg.com/ct/core.js');
|
|
1011
|
+
} catch (error) {
|
|
1012
|
+
logger.error('Failed to initialize Pinterest Tag', error);
|
|
1013
|
+
reject(error);
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
}),
|
|
1017
|
+
track: (eventName, properties, context) => {
|
|
1018
|
+
if (!isTagReady || !window.pintrk) return;
|
|
1019
|
+
const pinterestEventName = getPinterestEventName(eventName, config.eventMapping);
|
|
1020
|
+
const eventData = buildEventData(properties);
|
|
1021
|
+
// Get enhanced matching data from properties
|
|
1022
|
+
const enhancedMatchData = getPinterestEnhancedMatchData(context || {});
|
|
1023
|
+
logger.debug('Tracking event', {
|
|
1024
|
+
eventName,
|
|
1025
|
+
pinterestEventName,
|
|
1026
|
+
eventData,
|
|
1027
|
+
enhancedMatchData
|
|
1028
|
+
});
|
|
1029
|
+
// Combine event data with enhanced matching data
|
|
1030
|
+
const finalEventData = Object.assign(Object.assign({}, eventData), enhancedMatchData);
|
|
1031
|
+
// Track the event
|
|
1032
|
+
window.pintrk('track', pinterestEventName, finalEventData);
|
|
1033
|
+
},
|
|
1034
|
+
identify: (userId, properties, context) => {
|
|
1035
|
+
// Identify not supported with pinterest tag
|
|
1036
|
+
logger.debug('Identify not supported with pinterest tag', {
|
|
1037
|
+
userId,
|
|
1038
|
+
properties,
|
|
1039
|
+
context
|
|
1040
|
+
});
|
|
1041
|
+
window.pintrk('set', {
|
|
1042
|
+
external_id: userId
|
|
1043
|
+
});
|
|
1044
|
+
window.pintrk('set', {
|
|
1045
|
+
em: properties === null || properties === void 0 ? void 0 : properties['email']
|
|
1046
|
+
});
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
function getPinterestEventName(eventName, eventMapping) {
|
|
1052
|
+
// Convert default saasco Page View event by default
|
|
1053
|
+
if (eventName === 'Page View') return 'pagevisit';
|
|
1054
|
+
if (!eventMapping) return eventName.toLowerCase();
|
|
1055
|
+
return eventMapping[eventName] || eventName.toLowerCase();
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Build event data for Pinterest tracking
|
|
1059
|
+
* Reference: https://www.pinterest.com/_/_/help/business/article/event-code
|
|
1060
|
+
*/
|
|
1061
|
+
function buildEventData(properties) {
|
|
1062
|
+
if (!properties) return {};
|
|
1063
|
+
const eventData = {};
|
|
1064
|
+
// Map common properties to Pinterest event data
|
|
1065
|
+
if (properties['event_id']) eventData['event_id'] = properties['event_id'];
|
|
1066
|
+
if (properties['value']) eventData['value'] = properties['value'];
|
|
1067
|
+
if (properties['currency']) eventData['currency'] = properties['currency'];
|
|
1068
|
+
if (properties['order_quantity']) eventData['order_quantity'] = properties['order_quantity'];
|
|
1069
|
+
if (properties['order_id']) eventData['order_id'] = properties['order_id'];
|
|
1070
|
+
if (properties['promo_code']) eventData['promo_code'] = properties['promo_code'];
|
|
1071
|
+
if (properties['property']) eventData['property'] = properties['property'];
|
|
1072
|
+
if (properties['search_query']) eventData['search_query'] = properties['search_query'];
|
|
1073
|
+
if (properties['video_title']) eventData['video_title'] = properties['video_title'];
|
|
1074
|
+
if (properties['lead_type']) eventData['lead_type'] = properties['lead_type'];
|
|
1075
|
+
if (properties['product_category']) eventData['product_category'] = properties['product_category'];
|
|
1076
|
+
// Handle line items for e-commerce tracking
|
|
1077
|
+
if (properties['line_items'] && Array.isArray(properties['line_items'])) {
|
|
1078
|
+
eventData['line_items'] = properties['line_items'];
|
|
1079
|
+
}
|
|
1080
|
+
// Generate event_id if not provided
|
|
1081
|
+
if (!eventData['event_id']) {
|
|
1082
|
+
eventData['event_id'] = uuid();
|
|
1083
|
+
}
|
|
1084
|
+
return eventData;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Get Pinterest Enhanced Matching values from properties
|
|
1088
|
+
* Reference: https://help.pinterest.com/en/business/article/enhanced-match
|
|
1089
|
+
*/
|
|
1090
|
+
function getPinterestEnhancedMatchData(properties) {
|
|
1091
|
+
const enhancedMatch = {};
|
|
1092
|
+
// Email
|
|
1093
|
+
const email = findFirstProperty$1(properties, ['email', 'user_email', 'userEmail', 'email_address', 'emailAddress', 'e_mail', 'E_Mail', 'mail', 'Mail', 'contact_email', 'contactEmail', 'primary_email', 'primaryEmail']);
|
|
1094
|
+
if (email && typeof email === 'string') {
|
|
1095
|
+
// Pinterest expects hashed email for enhanced matching
|
|
1096
|
+
const normalizedEmail = email.trim().toLowerCase();
|
|
1097
|
+
enhancedMatch.em = normalizedEmail;
|
|
1098
|
+
}
|
|
1099
|
+
// External ID (User ID)
|
|
1100
|
+
const externalId = findFirstProperty$1(properties, ['external_id', 'externalId', 'user_id', 'userId', 'id', 'distinctId', 'distinct_id', 'customer_id', 'customerId', 'member_id', 'memberId']);
|
|
1101
|
+
if (externalId) {
|
|
1102
|
+
enhancedMatch.external_id = String(externalId);
|
|
1103
|
+
}
|
|
1104
|
+
return enhancedMatch;
|
|
1105
|
+
}
|
|
813
1106
|
function findFirstProperty$1(properties, keys) {
|
|
814
1107
|
for (const key of keys) {
|
|
815
1108
|
if (properties[key] !== undefined) {
|
|
@@ -845,20 +1138,28 @@ const standardTikTokEvents = ['AddPaymentInfo', 'AddToCart', 'AddToWishlist', 'A
|
|
|
845
1138
|
/**
|
|
846
1139
|
* Create a TikTok Pixel integration instance
|
|
847
1140
|
*/
|
|
848
|
-
function createTikTokPixelIntegration(config) {
|
|
1141
|
+
function createTikTokPixelIntegration(config, debug) {
|
|
849
1142
|
let isPixelReady = false;
|
|
1143
|
+
// Create integration logger
|
|
1144
|
+
const integrationLoggerLevel = getIntegrationLoggerLevel('tiktok-pixel', debug);
|
|
1145
|
+
const logger = new AnalyticsLogger({
|
|
1146
|
+
level: integrationLoggerLevel,
|
|
1147
|
+
label: 'Saasco tiktok-pixel'
|
|
1148
|
+
});
|
|
850
1149
|
return {
|
|
851
1150
|
name: 'tiktok-pixel',
|
|
852
1151
|
environments: ['client'],
|
|
853
1152
|
init: () => __awaiter(this, void 0, void 0, function* () {
|
|
854
1153
|
if (isServer$1) {
|
|
855
|
-
|
|
856
|
-
// This allows the integration to be registered but remain inactive
|
|
1154
|
+
logger.debug('TikTok Pixel init skipped on server');
|
|
857
1155
|
return;
|
|
858
1156
|
}
|
|
1157
|
+
logger.info('Initializing TikTok Pixel', {
|
|
1158
|
+
pixelId: config.pixelId
|
|
1159
|
+
});
|
|
859
1160
|
// Check if TikTok Pixel is already loaded
|
|
860
1161
|
if (window.ttq) {
|
|
861
|
-
|
|
1162
|
+
logger.warn('TikTok Pixel is already initialized');
|
|
862
1163
|
isPixelReady = true;
|
|
863
1164
|
return;
|
|
864
1165
|
}
|
|
@@ -909,7 +1210,6 @@ function createTikTokPixelIntegration(config) {
|
|
|
909
1210
|
ttq.load(config.pixelId, config.testMode ? {
|
|
910
1211
|
test_mode: true
|
|
911
1212
|
} : undefined);
|
|
912
|
-
ttq.page();
|
|
913
1213
|
// If script loads synchronously, mark as ready
|
|
914
1214
|
if (window.ttq && typeof window.ttq === 'function') {
|
|
915
1215
|
isPixelReady = true;
|
|
@@ -1084,69 +1384,9 @@ function mapTikTokEventParameters(eventName, properties) {
|
|
|
1084
1384
|
return Object.keys(params).length > 0 ? params : null;
|
|
1085
1385
|
}
|
|
1086
1386
|
|
|
1087
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1088
|
-
class AnalyticsLogger {
|
|
1089
|
-
constructor(config) {
|
|
1090
|
-
this.config = config;
|
|
1091
|
-
}
|
|
1092
|
-
/**
|
|
1093
|
-
* Log debug information
|
|
1094
|
-
*/
|
|
1095
|
-
log(...args) {
|
|
1096
|
-
if (!this.config.debug) return;
|
|
1097
|
-
const icon = '◍';
|
|
1098
|
-
const message = `${icon} ${this.config.label}`;
|
|
1099
|
-
console.info(`%c ${message}`, `background: #eee; color: #000; padding-right: 6px; border-radius: 2px;`, ...args);
|
|
1100
|
-
}
|
|
1101
|
-
/**
|
|
1102
|
-
* Log warning information
|
|
1103
|
-
*/
|
|
1104
|
-
warn(...args) {
|
|
1105
|
-
if (!this.config.debug) return;
|
|
1106
|
-
const icon = '◍';
|
|
1107
|
-
const message = `${icon} ${this.config.label}`;
|
|
1108
|
-
console.warn(`%c ${message}`, `background: #ffa500; color: #000; padding-right: 6px; border-radius: 2px;`, ...args);
|
|
1109
|
-
}
|
|
1110
|
-
/**
|
|
1111
|
-
* Log error information
|
|
1112
|
-
*/
|
|
1113
|
-
error(...args) {
|
|
1114
|
-
const icon = '◍';
|
|
1115
|
-
const message = `${icon} ${this.config.label} Error`;
|
|
1116
|
-
console.error(`%c ${message}`, 'background: red; color: white; padding-right: 6px; border-radius: 2px;', ...args);
|
|
1117
|
-
return {
|
|
1118
|
-
success: false,
|
|
1119
|
-
message: args.join(' ')
|
|
1120
|
-
};
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
/**
|
|
1125
|
-
* Generate a collision-resistant UUID
|
|
1126
|
-
* Uses lukeed's UUID v4 implementation for consistent, fast UUID generation
|
|
1127
|
-
*/
|
|
1128
|
-
function uuid() {
|
|
1129
|
-
return v4();
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
1387
|
/*
|
|
1133
1388
|
Minimal analytics integration manager (v0)
|
|
1134
1389
|
*/
|
|
1135
|
-
class Logger {
|
|
1136
|
-
constructor(label = 'Analytics', debug = false) {
|
|
1137
|
-
this.label = label;
|
|
1138
|
-
this.debug = debug;
|
|
1139
|
-
}
|
|
1140
|
-
log(...args) {
|
|
1141
|
-
if (this.debug) console.log(`[${this.label}]`, ...args);
|
|
1142
|
-
}
|
|
1143
|
-
warn(...args) {
|
|
1144
|
-
console.warn(`[${this.label}]`, ...args);
|
|
1145
|
-
}
|
|
1146
|
-
error(...args) {
|
|
1147
|
-
console.error(`[${this.label}]`, ...args);
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
1390
|
class IntegrationManager {
|
|
1151
1391
|
constructor(config = {}) {
|
|
1152
1392
|
var _a, _b, _c, _d;
|
|
@@ -1154,14 +1394,14 @@ class IntegrationManager {
|
|
|
1154
1394
|
this.integrations = new Map();
|
|
1155
1395
|
this.globalQueue = [];
|
|
1156
1396
|
this.config = {
|
|
1157
|
-
|
|
1397
|
+
loggerLevel: (_a = config.loggerLevel) !== null && _a !== void 0 ? _a : LogLevel.ERROR,
|
|
1158
1398
|
maxQueueSize: (_b = config.maxQueueSize) !== null && _b !== void 0 ? _b : 200,
|
|
1159
1399
|
maxIntegrationWaitTime: (_c = config.maxIntegrationWaitTime) !== null && _c !== void 0 ? _c : 10000,
|
|
1160
1400
|
flushInterval: (_d = config.flushInterval) !== null && _d !== void 0 ? _d : 5000
|
|
1161
1401
|
};
|
|
1162
1402
|
this.logger = new AnalyticsLogger({
|
|
1163
1403
|
label: 'Saasco Integrations Debug',
|
|
1164
|
-
|
|
1404
|
+
level: this.config.loggerLevel
|
|
1165
1405
|
});
|
|
1166
1406
|
this.initTime = Date.now();
|
|
1167
1407
|
this.currentEnvironment = typeof window !== 'undefined' ? 'client' : 'server';
|
|
@@ -1174,7 +1414,7 @@ class IntegrationManager {
|
|
|
1174
1414
|
setContext(next) {
|
|
1175
1415
|
this.context = Object.assign(Object.assign({}, this.context), next);
|
|
1176
1416
|
// Only log if we are setting something
|
|
1177
|
-
if (Object.keys(this.context).length > 0) this.logger.
|
|
1417
|
+
if (Object.keys(this.context).length > 0) this.logger.info('setContext', this.context);
|
|
1178
1418
|
}
|
|
1179
1419
|
/**
|
|
1180
1420
|
* Register and init an integration. When init resolves, we mark it ready and
|
|
@@ -1182,17 +1422,18 @@ class IntegrationManager {
|
|
|
1182
1422
|
*/
|
|
1183
1423
|
registerIntegration(integration) {
|
|
1184
1424
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1425
|
+
this.logger.debug('Register integrations', this.integrations);
|
|
1185
1426
|
if (this.integrations.has(integration.name)) {
|
|
1186
|
-
this.logger.warn(`
|
|
1427
|
+
this.logger.warn(`Integration already registered: ${integration.name}`);
|
|
1187
1428
|
return;
|
|
1188
1429
|
}
|
|
1189
1430
|
// Check environment compatibility
|
|
1190
1431
|
const isCompatible = integration.environments.includes(this.currentEnvironment);
|
|
1191
1432
|
if (!isCompatible) {
|
|
1192
|
-
this.logger.warn(`
|
|
1433
|
+
this.logger.warn(`Skipping ${integration.name}: requires ${integration.environments.join(' or ')} but running in ${this.currentEnvironment}`);
|
|
1193
1434
|
return;
|
|
1194
1435
|
}
|
|
1195
|
-
this.logger.
|
|
1436
|
+
this.logger.debug(`Registering ${integration.name}`);
|
|
1196
1437
|
const state = {
|
|
1197
1438
|
integration,
|
|
1198
1439
|
status: 'idle'
|
|
@@ -1201,17 +1442,21 @@ class IntegrationManager {
|
|
|
1201
1442
|
if (integration.init) {
|
|
1202
1443
|
try {
|
|
1203
1444
|
state.status = 'loading';
|
|
1204
|
-
|
|
1445
|
+
const startTime = Date.now();
|
|
1446
|
+
this.logger.debug(`Initializing ${integration.name}`);
|
|
1447
|
+
yield integration.init(this.context);
|
|
1205
1448
|
state.status = 'ready';
|
|
1206
|
-
|
|
1449
|
+
const endTime = Date.now();
|
|
1450
|
+
const duration = endTime - startTime;
|
|
1451
|
+
this.logger.debug(`Integration ${integration.name} ready in ${duration}ms`);
|
|
1207
1452
|
this.flush();
|
|
1208
1453
|
} catch (e) {
|
|
1209
1454
|
state.status = 'error';
|
|
1210
|
-
this.logger.error(`
|
|
1455
|
+
this.logger.error(`Failed to init ${integration.name}`, e);
|
|
1211
1456
|
}
|
|
1212
1457
|
} else {
|
|
1213
1458
|
state.status = 'ready';
|
|
1214
|
-
this.logger.
|
|
1459
|
+
this.logger.info(`Integration ${integration.name} ready (no init)`);
|
|
1215
1460
|
this.flush();
|
|
1216
1461
|
}
|
|
1217
1462
|
});
|
|
@@ -1252,10 +1497,10 @@ class IntegrationManager {
|
|
|
1252
1497
|
if (this.globalQueue.length >= this.config.maxQueueSize) {
|
|
1253
1498
|
// drop oldest
|
|
1254
1499
|
this.globalQueue.shift();
|
|
1255
|
-
this.logger.warn('
|
|
1500
|
+
this.logger.warn('Queue full → dropped oldest');
|
|
1256
1501
|
}
|
|
1257
1502
|
this.globalQueue.push(envelope);
|
|
1258
|
-
this.logger.
|
|
1503
|
+
this.logger.debug(`Queued (${this.globalQueue.length})`, envelope);
|
|
1259
1504
|
return;
|
|
1260
1505
|
}
|
|
1261
1506
|
this.deliver(envelope);
|
|
@@ -1269,8 +1514,17 @@ class IntegrationManager {
|
|
|
1269
1514
|
if (status !== 'ready') continue;
|
|
1270
1515
|
try {
|
|
1271
1516
|
if (evt.type === 'track' && integration.track && evt.name) {
|
|
1517
|
+
this.logger.debug(`Track (${integration.name}) ${evt.name}`, {
|
|
1518
|
+
properties: evt.properties,
|
|
1519
|
+
context: evt.context
|
|
1520
|
+
});
|
|
1272
1521
|
yield integration.track(evt.name, evt.properties, evt.context);
|
|
1273
1522
|
} else if (evt.type === 'identify' && integration.identify) {
|
|
1523
|
+
this.logger.debug(`Identify (${integration.name})`, {
|
|
1524
|
+
userId: evt.context.distinctId,
|
|
1525
|
+
properties: evt.properties,
|
|
1526
|
+
context: evt.context
|
|
1527
|
+
});
|
|
1274
1528
|
yield integration.identify(evt.context.distinctId, evt.properties, evt.context);
|
|
1275
1529
|
}
|
|
1276
1530
|
} catch (e) {
|
|
@@ -1287,7 +1541,7 @@ class IntegrationManager {
|
|
|
1287
1541
|
if (this.globalQueue.length === 0) return;
|
|
1288
1542
|
// If we're not ready don't flush
|
|
1289
1543
|
if (!this.isReady()) return;
|
|
1290
|
-
this.logger.
|
|
1544
|
+
this.logger.debug(`flushing ${this.globalQueue.length} queued events`);
|
|
1291
1545
|
const toSend = this.globalQueue;
|
|
1292
1546
|
this.globalQueue = [];
|
|
1293
1547
|
// deliver all events
|
|
@@ -1299,8 +1553,14 @@ class IntegrationManager {
|
|
|
1299
1553
|
return n;
|
|
1300
1554
|
}
|
|
1301
1555
|
isReady() {
|
|
1556
|
+
const timeElapsed = Date.now() - this.initTime;
|
|
1302
1557
|
// Return if integrations are not ready, or if we haven't waited the max integration wait time
|
|
1303
|
-
if (this.readyCount() < this.integrations.size &&
|
|
1558
|
+
if (this.readyCount() < this.integrations.size && timeElapsed < this.config.maxIntegrationWaitTime) {
|
|
1559
|
+
return false;
|
|
1560
|
+
}
|
|
1561
|
+
if (this.readyCount() < this.integrations.size) {
|
|
1562
|
+
this.logger.info(`proceeding with ${this.readyCount()}/${this.integrations.size} integrations ready after ${timeElapsed}ms wait`);
|
|
1563
|
+
}
|
|
1304
1564
|
return true;
|
|
1305
1565
|
}
|
|
1306
1566
|
/**
|
|
@@ -1322,7 +1582,7 @@ class IntegrationManager {
|
|
|
1322
1582
|
return;
|
|
1323
1583
|
}
|
|
1324
1584
|
this.unloadHandler = () => {
|
|
1325
|
-
this.logger.
|
|
1585
|
+
this.logger.info('page unloading, flushing remaining events');
|
|
1326
1586
|
this.flush();
|
|
1327
1587
|
};
|
|
1328
1588
|
// Use both beforeunload and pagehide for better coverage
|
|
@@ -1341,7 +1601,8 @@ class IntegrationManager {
|
|
|
1341
1601
|
queueLength: this.globalQueue.length,
|
|
1342
1602
|
readyCount: this.readyCount(),
|
|
1343
1603
|
periodicFlushEnabled: this.config.flushInterval > 0,
|
|
1344
|
-
flushInterval: this.config.flushInterval
|
|
1604
|
+
flushInterval: this.config.flushInterval,
|
|
1605
|
+
context: this.context
|
|
1345
1606
|
};
|
|
1346
1607
|
}
|
|
1347
1608
|
}
|
|
@@ -1545,11 +1806,13 @@ class Saasco {
|
|
|
1545
1806
|
this.config = config;
|
|
1546
1807
|
this.lastPageViewPath = '';
|
|
1547
1808
|
this.isInitialized = false;
|
|
1809
|
+
const loggerLevel = getLoggerLevel(this.config);
|
|
1548
1810
|
// Initialize logger
|
|
1549
1811
|
this.logger = new AnalyticsLogger({
|
|
1550
|
-
|
|
1812
|
+
level: loggerLevel,
|
|
1551
1813
|
label: 'Saasco Debug'
|
|
1552
1814
|
});
|
|
1815
|
+
this.logger.info('Saasco started');
|
|
1553
1816
|
if (!config.projectId) {
|
|
1554
1817
|
this.logger.error("Project ID is required but has not been provided. If you are using an env variable make sure it's set correctly.");
|
|
1555
1818
|
return;
|
|
@@ -1564,19 +1827,19 @@ class Saasco {
|
|
|
1564
1827
|
}, this.config.autoPageTracking);
|
|
1565
1828
|
// Initialize integration manager
|
|
1566
1829
|
this.integrationManager = new IntegrationManager({
|
|
1567
|
-
|
|
1830
|
+
loggerLevel,
|
|
1568
1831
|
maxQueueSize: 1000
|
|
1569
1832
|
});
|
|
1570
1833
|
// Set initial context
|
|
1571
1834
|
this.integrationManager.setContext({});
|
|
1572
1835
|
// Initialize integrations immediately (works on both client and server)
|
|
1573
1836
|
this.initIntegrations().catch(error => {
|
|
1574
|
-
this.logger.
|
|
1837
|
+
this.logger.info('Error initializing integrations:', error);
|
|
1575
1838
|
});
|
|
1576
1839
|
}
|
|
1577
1840
|
init() {
|
|
1578
1841
|
if (this.isInitialized) {
|
|
1579
|
-
this.logger.
|
|
1842
|
+
this.logger.info('Saasco is already initialized. Please check your code to ensure that init() is not being called multiple times.');
|
|
1580
1843
|
return;
|
|
1581
1844
|
}
|
|
1582
1845
|
// Export Saasco to the window object for easy access and debugging
|
|
@@ -1585,43 +1848,48 @@ class Saasco {
|
|
|
1585
1848
|
}
|
|
1586
1849
|
// Migrate existing localStorage data to cookies for cross-subdomain support
|
|
1587
1850
|
migrateFromLocalStorage();
|
|
1588
|
-
this.logger.
|
|
1589
|
-
if (this.config.debug) this.logger.
|
|
1590
|
-
if (!this.config.enabled) this.logger.
|
|
1851
|
+
this.logger.info('Saasco initialized', this.config);
|
|
1852
|
+
if (this.config.debug) this.logger.info('Debug mode active. This will log all events to the console.');
|
|
1853
|
+
if (!this.config.enabled) this.logger.info(`Analytics is disabled. No requests will be sent to the server and no integrations will be initialized. ${this.config.debug ? 'Debug mode is active and will still log information.' : ''}`);
|
|
1591
1854
|
this.initAutoPageTracking();
|
|
1592
1855
|
this.isInitialized = true;
|
|
1593
1856
|
}
|
|
1594
1857
|
disableDebug() {
|
|
1595
|
-
this.logger.
|
|
1858
|
+
this.logger.info('Debug mode deactivated.');
|
|
1596
1859
|
this.config.debug = false;
|
|
1597
1860
|
}
|
|
1598
1861
|
enableDebug() {
|
|
1599
1862
|
this.config.debug = true;
|
|
1600
|
-
this.logger.
|
|
1863
|
+
this.logger.info('Debug mode activated.');
|
|
1601
1864
|
}
|
|
1602
1865
|
/**
|
|
1603
1866
|
* Initialize third-party integrations
|
|
1604
1867
|
*/
|
|
1605
1868
|
initIntegrations() {
|
|
1606
1869
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1870
|
+
this.logger.info('Initialize integrations');
|
|
1607
1871
|
if (!this.config.integrations || this.config.integrations.length === 0) return;
|
|
1608
1872
|
if (!this.config.enabled) {
|
|
1609
|
-
this.logger.
|
|
1873
|
+
this.logger.info('Analytics is disabled. Skipping integration initialization.');
|
|
1610
1874
|
return;
|
|
1611
1875
|
}
|
|
1612
1876
|
for (const integrationConfig of this.config.integrations) {
|
|
1613
1877
|
try {
|
|
1614
1878
|
if (integrationConfig.type === 'facebook-pixel') {
|
|
1615
|
-
this.logger.
|
|
1616
|
-
const fbIntegration = createFacebookPixelIntegration(integrationConfig.config);
|
|
1879
|
+
this.logger.info('Registering Facebook Pixel integration with ID:', integrationConfig.config.pixelId);
|
|
1880
|
+
const fbIntegration = createFacebookPixelIntegration(integrationConfig.config, integrationConfig.debug);
|
|
1617
1881
|
yield this.integrationManager.registerIntegration(fbIntegration);
|
|
1882
|
+
} else if (integrationConfig.type === 'pinterest-tag') {
|
|
1883
|
+
this.logger.info('Registering Pinterest Tag integration with ID:', integrationConfig.config.tagId);
|
|
1884
|
+
const pinterestIntegration = createPinterestTagIntegration(integrationConfig.config, integrationConfig.debug);
|
|
1885
|
+
yield this.integrationManager.registerIntegration(pinterestIntegration);
|
|
1618
1886
|
} else if (integrationConfig.type === 'tiktok-pixel') {
|
|
1619
|
-
this.logger.
|
|
1620
|
-
const tiktokIntegration = createTikTokPixelIntegration(integrationConfig.config);
|
|
1887
|
+
this.logger.info('Registering TikTok Pixel integration with ID:', integrationConfig.config.pixelId);
|
|
1888
|
+
const tiktokIntegration = createTikTokPixelIntegration(integrationConfig.config, integrationConfig.debug);
|
|
1621
1889
|
yield this.integrationManager.registerIntegration(tiktokIntegration);
|
|
1622
1890
|
}
|
|
1623
1891
|
} catch (error) {
|
|
1624
|
-
this.logger.
|
|
1892
|
+
this.logger.info(`Failed to register ${integrationConfig.type} integration:`, error);
|
|
1625
1893
|
}
|
|
1626
1894
|
}
|
|
1627
1895
|
});
|
|
@@ -1675,9 +1943,9 @@ class Saasco {
|
|
|
1675
1943
|
context: JSON.stringify(context || {})
|
|
1676
1944
|
};
|
|
1677
1945
|
if (data.action === 'Page View') {
|
|
1678
|
-
this.logger.
|
|
1946
|
+
this.logger.info('Page View', window.location.href, data);
|
|
1679
1947
|
} else {
|
|
1680
|
-
this.logger.
|
|
1948
|
+
this.logger.info('track', data);
|
|
1681
1949
|
}
|
|
1682
1950
|
if (!this.config.enabled) {
|
|
1683
1951
|
return Promise.resolve({
|
|
@@ -1730,7 +1998,7 @@ class Saasco {
|
|
|
1730
1998
|
// This should only be called when distinctId is null and there is an existing userId.
|
|
1731
1999
|
// This means the user has logged out and we should reset the session and anonymous IDs
|
|
1732
2000
|
const userIdChangedToNull = distinctId === null && !!getUserId();
|
|
1733
|
-
if (userIdChangedToNull) this.logger.
|
|
2001
|
+
if (userIdChangedToNull) this.logger.info('User logged out');
|
|
1734
2002
|
const reset = userIdChangedToNull;
|
|
1735
2003
|
const sessionId = setSessionId({
|
|
1736
2004
|
reset
|
|
@@ -1741,11 +2009,11 @@ class Saasco {
|
|
|
1741
2009
|
// set the distinct Id to the userId
|
|
1742
2010
|
setUserId(distinctId);
|
|
1743
2011
|
// Update integration manager context and send identify (IntegrationManager will filter by environment)
|
|
1744
|
-
this.integrationManager.setContext({
|
|
2012
|
+
this.integrationManager.setContext(Object.assign({
|
|
1745
2013
|
distinctId,
|
|
1746
2014
|
anonymousId,
|
|
1747
2015
|
sessionId
|
|
1748
|
-
});
|
|
2016
|
+
}, properties));
|
|
1749
2017
|
// No distinctId provided so we don't track the user
|
|
1750
2018
|
if (!distinctId) return Promise.resolve({
|
|
1751
2019
|
success: true,
|
|
@@ -1762,7 +2030,7 @@ class Saasco {
|
|
|
1762
2030
|
payload: properties || {},
|
|
1763
2031
|
context: context || {}
|
|
1764
2032
|
};
|
|
1765
|
-
this.logger.
|
|
2033
|
+
this.logger.info('identify', data);
|
|
1766
2034
|
// Only send identify to integrations if analytics is enabled
|
|
1767
2035
|
if (!this.config.enabled) {
|
|
1768
2036
|
return Promise.resolve({
|
|
@@ -1838,11 +2106,11 @@ class Saasco {
|
|
|
1838
2106
|
if (isServer) return console.warn('Saasco auto page tracking is only available in the browser');
|
|
1839
2107
|
// Prevent intitializing auto page tracking more than once
|
|
1840
2108
|
if (window.saascoAutoPageTrackingActive) {
|
|
1841
|
-
this.logger.
|
|
2109
|
+
this.logger.info('Auto Page Tracking already enabled');
|
|
1842
2110
|
return;
|
|
1843
2111
|
}
|
|
1844
2112
|
window.saascoAutoPageTrackingActive = true;
|
|
1845
|
-
this.logger.
|
|
2113
|
+
this.logger.info('Auto Page Tracking enabled');
|
|
1846
2114
|
// Track initial page load
|
|
1847
2115
|
this.page();
|
|
1848
2116
|
// Listen for hash changes if hash tracking is enabled
|
|
@@ -1866,6 +2134,27 @@ class Saasco {
|
|
|
1866
2134
|
return returnValue;
|
|
1867
2135
|
};
|
|
1868
2136
|
}
|
|
2137
|
+
getIntegrationsStats() {
|
|
2138
|
+
return this.integrationManager.getStats();
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
function getLoggerLevel(config) {
|
|
2142
|
+
// Check URL parameters for debug overrides (browser only)
|
|
2143
|
+
let urlDebug = false;
|
|
2144
|
+
let urlDebugVerbose = false;
|
|
2145
|
+
if (!isServer) {
|
|
2146
|
+
try {
|
|
2147
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
2148
|
+
urlDebug = urlParams.get('saasco-debug') === 'true';
|
|
2149
|
+
urlDebugVerbose = urlParams.get('saasco-debug-verbose') === 'true';
|
|
2150
|
+
} catch (error) {
|
|
2151
|
+
// Ignore URL parsing errors
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
// URL parameters override config
|
|
2155
|
+
const effectiveDebug = urlDebug || config.debug;
|
|
2156
|
+
const effectiveDebugVerbose = urlDebugVerbose || config.debugVerbose;
|
|
2157
|
+
return !!effectiveDebugVerbose ? LogLevel.DEBUG : !!effectiveDebug ? LogLevel.INFO : LogLevel.ERROR;
|
|
1869
2158
|
}
|
|
1870
2159
|
|
|
1871
2160
|
const browserContextSchema = z.object({
|
|
@@ -1893,4 +2182,4 @@ const browserContextSchema = z.object({
|
|
|
1893
2182
|
$utmAdId: z.string().nullable()
|
|
1894
2183
|
});
|
|
1895
2184
|
|
|
1896
|
-
export { IntegrationManager,
|
|
2185
|
+
export { IntegrationManager, Saasco, browserContextSchema, createFacebookPixelIntegration, createPinterestTagIntegration, createTikTokPixelIntegration, getBrowserContext, standardFacebookEvents, standardPinterestEvents, standardTikTokEvents, timezones };
|