@blotoutio/edgetag-sdk-browser 1.72.0 → 1.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +217 -167
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1498,7 +1498,7 @@
1498
1498
  referrer: getReferrer(destination),
1499
1499
  search: getSearch(destination),
1500
1500
  locale: getLocale(),
1501
- sdkVersion: "1.72.0" ,
1501
+ sdkVersion: "1.74.0" ,
1502
1502
  ...(payload || {}),
1503
1503
  };
1504
1504
  let storage = {};
@@ -1620,6 +1620,216 @@
1620
1620
  });
1621
1621
  };
1622
1622
 
1623
+ const processData = (destination, data, providers, options) => {
1624
+ saveKV(destination, data);
1625
+ updateUserProperties(destination, data);
1626
+ const providerPackages = getSetting(destination, 'browserPackages');
1627
+ const configuredTags = getSetting(destination, 'channels');
1628
+ const userId = getUserId$1(destination);
1629
+ const requestCountry = getSetting(destination, 'geoCountry') || null;
1630
+ const requestRegion = getSetting(destination, 'geoRegion') || null;
1631
+ const isEURequest = getSetting(destination, 'isEURequest') || false;
1632
+ const consentChannel = getConsent$1(destination);
1633
+ const consentCategory = getConsentCategories(destination);
1634
+ const consentSettings = getSetting(destination, 'consentSetting');
1635
+ const userConsent = { consentChannel, consentCategory, consentSettings };
1636
+ for (const pkg of providerPackages) {
1637
+ if (!pkg || !pkg.user || !pkg.name) {
1638
+ continue;
1639
+ }
1640
+ if (!configuredTags.has(pkg.name)) {
1641
+ logger.log(`Provider ${pkg.name} is not in allow list`);
1642
+ continue;
1643
+ }
1644
+ const variables = getProviderVariables(destination, pkg.name);
1645
+ for (const variable of variables) {
1646
+ if (!isProviderInstanceAllowed(providers, pkg.name, variable.tagName)) {
1647
+ logger.log(`Data not allowed for ${pkg.name} (${variable.tagName})`);
1648
+ continue;
1649
+ }
1650
+ if (!hasUserConsent(userConsent, pkg.name, variable.tagName)) {
1651
+ logger.log(`Consent is missing for ${pkg.name} (${variable.tagName})`);
1652
+ continue;
1653
+ }
1654
+ if (!doesGeoRequestMatchList(requestCountry, requestRegion, isEURequest, variable.geoRegions)) {
1655
+ logger.log(`GEO request region does not match list, skipping`);
1656
+ continue;
1657
+ }
1658
+ pkg.user({
1659
+ userId,
1660
+ data,
1661
+ manifestVariables: variable.variableSet,
1662
+ destination,
1663
+ });
1664
+ }
1665
+ }
1666
+ postRequest(getDataURL(destination), { data, providers }, options).catch(logger.error);
1667
+ };
1668
+ const handleData = (data, providers, options) => {
1669
+ if (!data || Object.keys(data).length === 0) {
1670
+ logger.error('Provide data for data API.');
1671
+ return;
1672
+ }
1673
+ if (options === null || options === void 0 ? void 0 : options.destination) {
1674
+ processData(options.destination, data, providers, options);
1675
+ return;
1676
+ }
1677
+ getInstances().forEach((destination) => {
1678
+ processData(destination, data, providers, options);
1679
+ });
1680
+ };
1681
+
1682
+ const cacheKey = `${keyPrefix}Cache`;
1683
+ const identity = (v) => v;
1684
+ const saveDataToEdge = (destination, key, value, provider) => {
1685
+ if (!value) {
1686
+ return;
1687
+ }
1688
+ let updatedValue = value;
1689
+ if (typeof value !== 'string') {
1690
+ try {
1691
+ updatedValue = JSON.stringify(value);
1692
+ }
1693
+ catch {
1694
+ logger.log('Error stringify value.');
1695
+ return;
1696
+ }
1697
+ }
1698
+ handleData({ [`${provider}::${key}`]: updatedValue }, undefined, {
1699
+ destination,
1700
+ });
1701
+ };
1702
+ const handleCaptureQuery = (destination, provider, key, persistType, map) => {
1703
+ try {
1704
+ if (!window) {
1705
+ return;
1706
+ }
1707
+ }
1708
+ catch {
1709
+ return;
1710
+ }
1711
+ const params = new URLSearchParams(getSearch(destination));
1712
+ if (!params || !params.get(key)) {
1713
+ return;
1714
+ }
1715
+ const data = (map !== null && map !== void 0 ? map : identity)(params.get(key));
1716
+ if (!data) {
1717
+ return;
1718
+ }
1719
+ if (persistType === 'edge') {
1720
+ saveDataToEdge(destination, key, data, provider);
1721
+ return;
1722
+ }
1723
+ saveDataPerKey(destination, persistType, provider, data, key);
1724
+ };
1725
+ const getFromCache = (destination, persistType, provider, key) => {
1726
+ var _a;
1727
+ const type = persistType === 'edge' ? 'local' : persistType;
1728
+ const cache = getData$1(destination, type, cacheKey);
1729
+ return (_a = cache[provider]) === null || _a === void 0 ? void 0 : _a[key];
1730
+ };
1731
+ const saveToCache = (destination, persistType, provider, key, value) => {
1732
+ const type = persistType === 'edge' ? 'local' : persistType;
1733
+ const cache = getData$1(destination, type, cacheKey);
1734
+ if (!cache[provider]) {
1735
+ cache[provider] = { [key]: value };
1736
+ }
1737
+ else {
1738
+ cache[provider][key] = value;
1739
+ }
1740
+ saveData(destination, type, cache, cacheKey);
1741
+ };
1742
+ const handleCaptureStorage = (destination, provider, key, persistType, location, map, replay = false) => {
1743
+ let data;
1744
+ try {
1745
+ switch (location) {
1746
+ case 'cookie': {
1747
+ data = (map !== null && map !== void 0 ? map : identity)(getCookieValue(key));
1748
+ break;
1749
+ }
1750
+ case 'local': {
1751
+ data = (map !== null && map !== void 0 ? map : identity)(localStorage.getItem(key));
1752
+ break;
1753
+ }
1754
+ case 'session': {
1755
+ data = (map !== null && map !== void 0 ? map : identity)(sessionStorage.getItem(key));
1756
+ }
1757
+ }
1758
+ }
1759
+ catch {
1760
+ return;
1761
+ }
1762
+ if (!data) {
1763
+ return;
1764
+ }
1765
+ const cachedKey = `${getUserId$1(destination)}/${key}`;
1766
+ const cachedValue = getFromCache(destination, persistType, provider, cachedKey);
1767
+ if (persistType === 'edge' && cachedValue !== data) {
1768
+ saveDataToEdge(destination, key, data, provider);
1769
+ saveToCache(destination, persistType, provider, cachedKey, data);
1770
+ return;
1771
+ }
1772
+ // A cache hit means this rule's value has not moved since it was last
1773
+ // written, so a replay has nothing left to do: saveDataPerKey is a getItem +
1774
+ // JSON.parse + JSON.stringify + setItem, per storage rule, per event, on
1775
+ // every tag in the fleet that has one. The boot path always falls through, so
1776
+ // the value is written at least once per page.
1777
+ if (replay && cachedValue === data) {
1778
+ return;
1779
+ }
1780
+ saveDataPerKey(destination, persistType, provider, data, key);
1781
+ // Cached for every persist type, not just 'edge' — the guard above is what
1782
+ // keeps a non-edge rule (trade-desk's uc_tcf) off the read/parse/write cycle
1783
+ // on every event of the visit.
1784
+ saveToCache(destination, persistType, provider, cachedKey, data);
1785
+ };
1786
+ const registry = new Map();
1787
+ // A manifest pass is the authoritative provider set for the destination, and
1788
+ // handleCapture only replaces the entry for the provider it is called with.
1789
+ // Without this, a channel dropped from a later pass (SPA re-init, manifest
1790
+ // refresh, channel removed) keeps replaying its storage rules for the rest of
1791
+ // the page lifetime. handleManifest calls this once, before its provider loop.
1792
+ const resetCaptures = (destination) => {
1793
+ registry.delete(destination);
1794
+ };
1795
+ const handleCapture = (destination, provider, params, capture) => {
1796
+ var _a;
1797
+ const existing = ((_a = registry.get(destination)) !== null && _a !== void 0 ? _a : []).filter((registration) => registration.provider !== provider);
1798
+ registry.set(destination, [...existing, { provider, params, capture }]);
1799
+ params.forEach((param) => {
1800
+ switch (param.type) {
1801
+ case 'query': {
1802
+ handleCaptureQuery(destination, provider, param.key, param.persist, capture === null || capture === void 0 ? void 0 : capture.bind(null, param));
1803
+ break;
1804
+ }
1805
+ case 'storage': {
1806
+ handleCaptureStorage(destination, provider, param.key, param.persist, param.location, capture === null || capture === void 0 ? void 0 : capture.bind(null, param));
1807
+ break;
1808
+ }
1809
+ }
1810
+ });
1811
+ };
1812
+ // A storage capture rule reads a slot the provider's own pixel may not have
1813
+ // written yet: handleManifest calls handleCapture before pkg.init(), and
1814
+ // Customers.ai's pixel is injected async, so on a first visit the read always
1815
+ // loses. Re-read per event so a value that appears later is still captured for
1816
+ // that pageview.
1817
+ //
1818
+ // Opt-in per rule (`replay: true`) and storage rules only, so a provider pays
1819
+ // the per-event read only where a late-writing pixel makes the boot read
1820
+ // unreliable.
1821
+ const replayStorageCaptures = (destination) => {
1822
+ var _a;
1823
+ (_a = registry.get(destination)) === null || _a === void 0 ? void 0 : _a.forEach(({ provider, params, capture }) => {
1824
+ params.forEach((param) => {
1825
+ if (param.type !== 'storage' || !param.replay) {
1826
+ return;
1827
+ }
1828
+ handleCaptureStorage(destination, provider, param.key, param.persist, param.location, capture === null || capture === void 0 ? void 0 : capture.bind(null, param), true);
1829
+ });
1830
+ });
1831
+ };
1832
+
1623
1833
  const preparePayloadWithConversion = (payloadData, currencySettings) => {
1624
1834
  const currency = payloadData['currency'];
1625
1835
  if (!currency || !currencySettings) {
@@ -1943,6 +2153,9 @@
1943
2153
  });
1944
2154
  return;
1945
2155
  }
2156
+ // Capture rules run once at boot, before the providers' own pixels load —
2157
+ // see replayStorageCaptures.
2158
+ replayStorageCaptures(destination);
1946
2159
  let eventId = data['eventId'];
1947
2160
  if (!eventId) {
1948
2161
  eventId = generateEventId(currentEventName);
@@ -2177,65 +2390,6 @@
2177
2390
  });
2178
2391
  };
2179
2392
 
2180
- const processData = (destination, data, providers, options) => {
2181
- saveKV(destination, data);
2182
- updateUserProperties(destination, data);
2183
- const providerPackages = getSetting(destination, 'browserPackages');
2184
- const configuredTags = getSetting(destination, 'channels');
2185
- const userId = getUserId$1(destination);
2186
- const requestCountry = getSetting(destination, 'geoCountry') || null;
2187
- const requestRegion = getSetting(destination, 'geoRegion') || null;
2188
- const isEURequest = getSetting(destination, 'isEURequest') || false;
2189
- const consentChannel = getConsent$1(destination);
2190
- const consentCategory = getConsentCategories(destination);
2191
- const consentSettings = getSetting(destination, 'consentSetting');
2192
- const userConsent = { consentChannel, consentCategory, consentSettings };
2193
- for (const pkg of providerPackages) {
2194
- if (!pkg || !pkg.user || !pkg.name) {
2195
- continue;
2196
- }
2197
- if (!configuredTags.has(pkg.name)) {
2198
- logger.log(`Provider ${pkg.name} is not in allow list`);
2199
- continue;
2200
- }
2201
- const variables = getProviderVariables(destination, pkg.name);
2202
- for (const variable of variables) {
2203
- if (!isProviderInstanceAllowed(providers, pkg.name, variable.tagName)) {
2204
- logger.log(`Data not allowed for ${pkg.name} (${variable.tagName})`);
2205
- continue;
2206
- }
2207
- if (!hasUserConsent(userConsent, pkg.name, variable.tagName)) {
2208
- logger.log(`Consent is missing for ${pkg.name} (${variable.tagName})`);
2209
- continue;
2210
- }
2211
- if (!doesGeoRequestMatchList(requestCountry, requestRegion, isEURequest, variable.geoRegions)) {
2212
- logger.log(`GEO request region does not match list, skipping`);
2213
- continue;
2214
- }
2215
- pkg.user({
2216
- userId,
2217
- data,
2218
- manifestVariables: variable.variableSet,
2219
- destination,
2220
- });
2221
- }
2222
- }
2223
- postRequest(getDataURL(destination), { data, providers }, options).catch(logger.error);
2224
- };
2225
- const handleData = (data, providers, options) => {
2226
- if (!data || Object.keys(data).length === 0) {
2227
- logger.error('Provide data for data API.');
2228
- return;
2229
- }
2230
- if (options === null || options === void 0 ? void 0 : options.destination) {
2231
- processData(options.destination, data, providers, options);
2232
- return;
2233
- }
2234
- getInstances().forEach((destination) => {
2235
- processData(destination, data, providers, options);
2236
- });
2237
- };
2238
-
2239
2393
  const handleConsent = (consent, consentCategories, options) => {
2240
2394
  if (options === null || options === void 0 ? void 0 : options.destination) {
2241
2395
  processConsent(options.destination, consent, consentCategories, options);
@@ -2400,113 +2554,6 @@
2400
2554
  return providersPackages;
2401
2555
  };
2402
2556
 
2403
- const cacheKey = `${keyPrefix}Cache`;
2404
- const identity = (v) => v;
2405
- const saveDataToEdge = (destination, key, value, provider) => {
2406
- if (!value) {
2407
- return;
2408
- }
2409
- let updatedValue = value;
2410
- if (typeof value !== 'string') {
2411
- try {
2412
- updatedValue = JSON.stringify(value);
2413
- }
2414
- catch {
2415
- logger.log('Error stringify value.');
2416
- return;
2417
- }
2418
- }
2419
- handleData({ [`${provider}::${key}`]: updatedValue }, undefined, {
2420
- destination,
2421
- });
2422
- };
2423
- const handleCaptureQuery = (destination, provider, key, persistType, map) => {
2424
- try {
2425
- if (!window) {
2426
- return;
2427
- }
2428
- }
2429
- catch {
2430
- return;
2431
- }
2432
- const params = new URLSearchParams(getSearch(destination));
2433
- if (!params || !params.get(key)) {
2434
- return;
2435
- }
2436
- const data = (map !== null && map !== void 0 ? map : identity)(params.get(key));
2437
- if (!data) {
2438
- return;
2439
- }
2440
- if (persistType === 'edge') {
2441
- saveDataToEdge(destination, key, data, provider);
2442
- return;
2443
- }
2444
- saveDataPerKey(destination, persistType, provider, data, key);
2445
- };
2446
- const getFromCache = (destination, persistType, provider, key) => {
2447
- var _a;
2448
- const type = persistType === 'edge' ? 'local' : persistType;
2449
- const cache = getData$1(destination, type, cacheKey);
2450
- return (_a = cache[provider]) === null || _a === void 0 ? void 0 : _a[key];
2451
- };
2452
- const saveToCache = (destination, persistType, provider, key, value) => {
2453
- const type = persistType === 'edge' ? 'local' : persistType;
2454
- const cache = getData$1(destination, type, cacheKey);
2455
- if (!cache[provider]) {
2456
- cache[provider] = { [key]: value };
2457
- }
2458
- else {
2459
- cache[provider][key] = value;
2460
- }
2461
- saveData(destination, type, cache, cacheKey);
2462
- };
2463
- const handleCaptureStorage = (destination, provider, key, persistType, location, map) => {
2464
- let data;
2465
- try {
2466
- switch (location) {
2467
- case 'cookie': {
2468
- data = (map !== null && map !== void 0 ? map : identity)(getCookieValue(key));
2469
- break;
2470
- }
2471
- case 'local': {
2472
- data = (map !== null && map !== void 0 ? map : identity)(localStorage.getItem(key));
2473
- break;
2474
- }
2475
- case 'session': {
2476
- data = (map !== null && map !== void 0 ? map : identity)(sessionStorage.getItem(key));
2477
- }
2478
- }
2479
- }
2480
- catch {
2481
- return;
2482
- }
2483
- if (!data) {
2484
- return;
2485
- }
2486
- const cachedKey = `${getUserId$1(destination)}/${key}`;
2487
- const cachedValue = getFromCache(destination, persistType, provider, cachedKey);
2488
- if (persistType === 'edge' && cachedValue !== data) {
2489
- saveDataToEdge(destination, key, data, provider);
2490
- saveToCache(destination, persistType, provider, cachedKey, data);
2491
- return;
2492
- }
2493
- saveDataPerKey(destination, persistType, provider, data, key);
2494
- };
2495
- const handleCapture = (destination, provider, params, capture) => {
2496
- params.forEach((param) => {
2497
- switch (param.type) {
2498
- case 'query': {
2499
- handleCaptureQuery(destination, provider, param.key, param.persist, capture === null || capture === void 0 ? void 0 : capture.bind(null, param));
2500
- break;
2501
- }
2502
- case 'storage': {
2503
- handleCaptureStorage(destination, provider, param.key, param.persist, param.location, capture === null || capture === void 0 ? void 0 : capture.bind(null, param));
2504
- break;
2505
- }
2506
- }
2507
- });
2508
- };
2509
-
2510
2557
  const keyName = `${keyPrefix}Store`;
2511
2558
  const handleManifest = (destination, response) => {
2512
2559
  const providerPackages = getSetting(destination, 'browserPackages');
@@ -2517,6 +2564,9 @@
2517
2564
  const consentCategory = getConsentCategories(destination);
2518
2565
  const consentSettings = getSetting(destination, 'consentSetting');
2519
2566
  const userConsent = { consentChannel, consentCategory, consentSettings };
2567
+ // This manifest is the full provider set: drop the previous pass's capture
2568
+ // registrations so a channel that is no longer in it stops replaying.
2569
+ resetCaptures(destination);
2520
2570
  manifest.forEach((provider) => {
2521
2571
  addChannel(destination, provider.package, provider.tagName);
2522
2572
  const pkg = providerPackages.find((pkg) => pkg.name === provider.package);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/edgetag-sdk-browser",
3
- "version": "1.72.0",
3
+ "version": "1.74.0",
4
4
  "description": "Browser SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",