@blotoutio/edgetag-sdk-browser 1.56.1 → 1.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +123 -39
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -508,6 +508,74 @@
508
508
  ['US-VI', 'Virgin Islands, U.S.'],
509
509
  ]);
510
510
  new Set([...isoCountries.keys(), ...usStates.keys()]);
511
+ /**
512
+ * ISO 3166-1 alpha-2 codes for EU member states (as of 2024)
513
+ */
514
+ const EU_COUNTRY_CODES = new Set([
515
+ 'AT', // Austria
516
+ 'BE', // Belgium
517
+ 'BG', // Bulgaria
518
+ 'CY', // Cyprus
519
+ 'CZ', // Czech Republic
520
+ 'DE', // Germany
521
+ 'DK', // Denmark
522
+ 'EE', // Estonia
523
+ 'ES', // Spain
524
+ 'FI', // Finland
525
+ 'FR', // France
526
+ 'GR', // Greece
527
+ 'HR', // Croatia
528
+ 'HU', // Hungary
529
+ 'IE', // Ireland
530
+ 'IT', // Italy
531
+ 'LT', // Lithuania
532
+ 'LU', // Luxembourg
533
+ 'LV', // Latvia
534
+ 'MT', // Malta
535
+ 'NL', // Netherlands
536
+ 'PL', // Poland
537
+ 'PT', // Portugal
538
+ 'RO', // Romania
539
+ 'SE', // Sweden
540
+ 'SI', // Slovenia
541
+ 'SK', // Slovakia
542
+ ]);
543
+ /**
544
+ * Returns true if the request originates from the EU or the UK (GB).
545
+ * Cloudflare's isEUCountry flag excludes the UK post-Brexit, so GB is
546
+ * checked explicitly alongside the EU member set.
547
+ *
548
+ * Fails closed: when the country cannot be resolved, the request is treated
549
+ * as EU/UK. This is the safe default for the compliance-sensitive Grey Switch
550
+ * (an unknown visitor may be in the EU/UK, so it must not slip through when
551
+ * the EU/UK toggle is off).
552
+ */
553
+ const isEuUkRegion = (country, isEURequest) => {
554
+ if (isEURequest) {
555
+ return true;
556
+ }
557
+ if (!country) {
558
+ return true;
559
+ }
560
+ const upper = country.toUpperCase();
561
+ return upper === 'GB' || EU_COUNTRY_CODES.has(upper);
562
+ };
563
+ /**
564
+ * Grey Switch fire rule, shared by the SDK and the CDN worker so both stay in
565
+ * sync. When Grey Switch is on, EdgeTag fires server-side events for
566
+ * non-consented users. The EU/UK toggle is off by default, which keeps EU/UK
567
+ * visitors on normal consent unless the merchant explicitly opts those regions
568
+ * in. Returns whether a server-side event should fire for a non-consented user.
569
+ */
570
+ const greySwitchAllowsServerEvent = ({ greySwitch, greySwitchEuUk, country, isEURequest, }) => {
571
+ if (!greySwitch) {
572
+ return false;
573
+ }
574
+ if (greySwitchEuUk) {
575
+ return true;
576
+ }
577
+ return !isEuUkRegion(country, isEURequest);
578
+ };
511
579
  const parseCache = new Map();
512
580
  const parseRegions = (regionString) => {
513
581
  const include = new Set();
@@ -1225,7 +1293,7 @@
1225
1293
  time = perf.toFixed(4);
1226
1294
  }
1227
1295
  }
1228
- return `${encodeString(name)}-${generateUUID()}-${time}`;
1296
+ return `${encodeString(name).replace(/[^a-zA-Z0-9]/g, '')}-${generateUUID()}-${time}`;
1229
1297
  };
1230
1298
 
1231
1299
  const getCookieValue = (key) => {
@@ -1408,6 +1476,11 @@
1408
1476
  }
1409
1477
  };
1410
1478
 
1479
+ const getIsNewCustomerFlag = async (getData) => {
1480
+ const { isNewCustomer } = await new Promise((resolve) => getData(['isNewCustomer'], resolve));
1481
+ return isNewCustomer ? isNewCustomer === 'true' : undefined;
1482
+ };
1483
+
1411
1484
  const getUserId$1 = (destination) => {
1412
1485
  const userId = getSetting(destination, 'userId');
1413
1486
  if (userId) {
@@ -1466,7 +1539,7 @@
1466
1539
  referrer: getReferrer(destination),
1467
1540
  search: getSearch(destination),
1468
1541
  locale: getLocale(),
1469
- sdkVersion: "1.56.1" ,
1542
+ sdkVersion: "1.57.1" ,
1470
1543
  ...(payload || {}),
1471
1544
  };
1472
1545
  let storage = {};
@@ -1669,6 +1742,7 @@
1669
1742
  const payload = baseParams['payload'];
1670
1743
  let currentEventName = payload['eventName'];
1671
1744
  let currentData = payload['data'];
1745
+ let currentProviders = baseParams['providers'];
1672
1746
  let skip = false;
1673
1747
  for (const plugin of plugins) {
1674
1748
  const hook = plugin.rules[hookName];
@@ -1694,6 +1768,9 @@
1694
1768
  if ((_b = result === null || result === void 0 ? void 0 : result.payload) === null || _b === void 0 ? void 0 : _b.data) {
1695
1769
  currentData = result.payload.data;
1696
1770
  }
1771
+ if ((result === null || result === void 0 ? void 0 : result.providers) !== undefined) {
1772
+ currentProviders = result.providers;
1773
+ }
1697
1774
  if (result === null || result === void 0 ? void 0 : result.additionalEvents) {
1698
1775
  for (const evt of result.additionalEvents) {
1699
1776
  handleTag(evt.eventName, evt.data, undefined, undefined);
@@ -1707,6 +1784,7 @@
1707
1784
  return {
1708
1785
  eventName: currentEventName,
1709
1786
  data: currentData,
1787
+ providers: currentProviders,
1710
1788
  skip,
1711
1789
  };
1712
1790
  };
@@ -1737,6 +1815,15 @@
1737
1815
  const consentCategory = getConsentCategories(destination);
1738
1816
  const consentSettings = getSetting(destination, 'consentSetting');
1739
1817
  const userConsent = { consentChannel, consentCategory, consentSettings };
1818
+ // Grey Switch: when enabled, still send the event to the server for
1819
+ // non-consented users. Browser pixels remain gated by hasUserConsent below,
1820
+ // so nothing fires client-side.
1821
+ const greySwitchAllows = greySwitchAllowsServerEvent({
1822
+ greySwitch: getSetting(destination, 'greySwitch') || false,
1823
+ greySwitchEuUk: getSetting(destination, 'greySwitchEuUk') || false,
1824
+ country: requestCountry,
1825
+ isEURequest,
1826
+ });
1740
1827
  const ip = getSetting(destination, 'ip') || null;
1741
1828
  const userProperties = getSetting(destination, 'userProperties');
1742
1829
  if (skipZeroPurchaseEvent && isZeroPurchaseEvent({ eventName, data })) {
@@ -1757,23 +1844,29 @@
1757
1844
  providers = rulesResult.updatedProviders;
1758
1845
  }
1759
1846
  const plugins = getPlugins(destination);
1847
+ const pluginSettings = {
1848
+ userId,
1849
+ sessionId,
1850
+ geoCountry: requestCountry,
1851
+ geoRegion: requestRegion,
1852
+ isEURequest,
1853
+ ip,
1854
+ consent: consentChannel,
1855
+ consentCategories: consentCategory,
1856
+ userProperties,
1857
+ };
1858
+ const pluginContext = getStandardPayload(destination);
1859
+ const pluginUtilities = {
1860
+ getIsNewCustomerFlag: () => getIsNewCustomerFlag(processGetData.bind(null, destination)),
1861
+ };
1760
1862
  if (plugins.length > 0) {
1761
- const pluginSettings = {
1762
- userId,
1763
- sessionId,
1764
- geoCountry: requestCountry,
1765
- geoRegion: requestRegion,
1766
- isEURequest,
1767
- ip,
1768
- consent: consentChannel,
1769
- consentCategories: consentCategory,
1770
- userProperties,
1771
- };
1772
- const baseParams = {
1863
+ const rootResult = await runPluginHook(plugins, 'tagRoot', {
1773
1864
  payload: { eventName: currentEventName, data, eventId },
1865
+ context: pluginContext,
1866
+ providers,
1774
1867
  settings: pluginSettings,
1775
- };
1776
- const rootResult = await runPluginHook(plugins, 'tagRoot', baseParams);
1868
+ utilities: pluginUtilities,
1869
+ });
1777
1870
  if (rootResult.skip) {
1778
1871
  sendTag(destination, {
1779
1872
  configuratorProcessed: true,
@@ -1786,6 +1879,10 @@
1786
1879
  });
1787
1880
  return;
1788
1881
  }
1882
+ if (rootResult.providers !== undefined) {
1883
+ // eslint-disable-next-line no-param-reassign
1884
+ providers = rootResult.providers;
1885
+ }
1789
1886
  currentEventName = rootResult.eventName;
1790
1887
  // eslint-disable-next-line no-param-reassign
1791
1888
  data = rootResult.data;
@@ -1809,18 +1906,10 @@
1809
1906
  data: channelData,
1810
1907
  eventId,
1811
1908
  },
1812
- settings: {
1813
- userId,
1814
- sessionId,
1815
- geoCountry: requestCountry,
1816
- geoRegion: requestRegion,
1817
- isEURequest,
1818
- ip,
1819
- consent: consentChannel,
1820
- consentCategories: consentCategory,
1821
- userProperties,
1822
- },
1909
+ context: pluginContext,
1910
+ settings: pluginSettings,
1823
1911
  providerId: pkg.name,
1912
+ utilities: pluginUtilities,
1824
1913
  });
1825
1914
  if (channelResult.skip)
1826
1915
  continue;
@@ -1852,18 +1941,10 @@
1852
1941
  data: instanceData,
1853
1942
  eventId,
1854
1943
  },
1855
- settings: {
1856
- userId,
1857
- sessionId,
1858
- geoCountry: requestCountry,
1859
- geoRegion: requestRegion,
1860
- isEURequest,
1861
- ip,
1862
- consent: consentChannel,
1863
- consentCategories: consentCategory,
1864
- userProperties,
1865
- },
1944
+ context: pluginContext,
1945
+ settings: pluginSettings,
1866
1946
  providerId: pkg.name,
1947
+ utilities: pluginUtilities,
1867
1948
  });
1868
1949
  if (instanceResult.skip)
1869
1950
  continue;
@@ -1899,7 +1980,8 @@
1899
1980
  else {
1900
1981
  logger.log('Browser events skipped by event rules, sending tag to server only');
1901
1982
  }
1902
- if (!hasAllowedManifestTags(configuredTags, userConsent, providers)) {
1983
+ if (!hasAllowedManifestTags(configuredTags, userConsent, providers) &&
1984
+ !greySwitchAllows) {
1903
1985
  return;
1904
1986
  }
1905
1987
  sendTag(destination, {
@@ -2470,6 +2552,8 @@
2470
2552
  storageId: result.storageId,
2471
2553
  currency: result.currency,
2472
2554
  skipZeroPurchaseEvent: result.skipZeroPurchaseEvent,
2555
+ greySwitch: result.greySwitch,
2556
+ greySwitchEuUk: result.greySwitchEuUk,
2473
2557
  geoCountry: result.geoCountry,
2474
2558
  geoRegion: result.geoRegion,
2475
2559
  isEURequest: result.isEURequest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/edgetag-sdk-browser",
3
- "version": "1.56.1",
3
+ "version": "1.57.1",
4
4
  "description": "Browser SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",