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.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.43";
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
- const isBrowser$2 = typeof window !== 'undefined';
555
- const isServer$2 = !isBrowser$2;
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$2) {
567
- // On server, Facebook Pixel is a no-op but doesn't throw
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
- console.warn('Facebook Pixel is already initialized');
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) return;
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$1(properties, coerceFrom);
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
- // On server, TikTok Pixel is a no-op but doesn't throw
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
- console.warn('TikTok Pixel is already initialized');
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
- debug: (_a = config.debug) !== null && _a !== void 0 ? _a : false,
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
- debug: this.config.debug
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.log('context', this.context);
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(`integration already registered: ${integration.name}`);
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(`skipping ${integration.name}: requires ${integration.environments.join(' or ')} but running in ${this.currentEnvironment}`);
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.log(`registering ${integration.name})`);
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
- yield integration.init();
1445
+ const startTime = Date.now();
1446
+ this.logger.debug(`Initializing ${integration.name}`);
1447
+ yield integration.init(this.context);
1205
1448
  state.status = 'ready';
1206
- this.logger.log(`${integration.name} integration ready`);
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(`failed to init ${integration.name}`, e);
1455
+ this.logger.error(`Failed to init ${integration.name}`, e);
1211
1456
  }
1212
1457
  } else {
1213
1458
  state.status = 'ready';
1214
- this.logger.log(`ready (no init) ${integration.name}`);
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('queue full → dropped oldest');
1500
+ this.logger.warn('Queue full → dropped oldest');
1256
1501
  }
1257
1502
  this.globalQueue.push(envelope);
1258
- this.logger.log(`queued (${this.globalQueue.length})`, envelope);
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.log(`flushing ${this.globalQueue.length} queued events`);
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 && Date.now() - this.initTime < this.config.maxIntegrationWaitTime) return false;
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.log('page unloading, flushing remaining events');
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
- debug: !!this.config.debug,
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
- debug: this.config.debug,
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.log('Error initializing integrations:', error);
1837
+ this.logger.info('Error initializing integrations:', error);
1575
1838
  });
1576
1839
  }
1577
1840
  init() {
1578
1841
  if (this.isInitialized) {
1579
- this.logger.log('Saasco is already initialized. Please check your code to ensure that init() is not being called multiple times.');
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.log('Saasco initialized', this.config);
1589
- if (this.config.debug) this.logger.log('Debug mode active. This will log all events to the console.');
1590
- if (!this.config.enabled) this.logger.log(`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.' : ''}`);
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.log('Debug mode deactivated.');
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.log('Debug mode activated.');
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.log('Analytics is disabled. Skipping integration initialization.');
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.log('Registering Facebook Pixel integration with ID:', integrationConfig.config.pixelId);
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.log('Registering TikTok Pixel integration with ID:', integrationConfig.config.pixelId);
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.log(`Failed to register ${integrationConfig.type} integration:`, error);
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.log('Page View', window.location.href, data);
1946
+ this.logger.info('Page View', window.location.href, data);
1679
1947
  } else {
1680
- this.logger.log('track', data);
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.log('User logged out');
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.log('identify', data);
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.log('Auto Page Tracking already enabled');
2109
+ this.logger.info('Auto Page Tracking already enabled');
1842
2110
  return;
1843
2111
  }
1844
2112
  window.saascoAutoPageTrackingActive = true;
1845
- this.logger.log('Auto Page Tracking enabled');
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, Logger, Saasco, browserContextSchema, createFacebookPixelIntegration, createTikTokPixelIntegration, getBrowserContext, standardFacebookEvents, standardTikTokEvents, timezones };
2185
+ export { IntegrationManager, Saasco, browserContextSchema, createFacebookPixelIntegration, createPinterestTagIntegration, createTikTokPixelIntegration, getBrowserContext, standardFacebookEvents, standardPinterestEvents, standardTikTokEvents, timezones };