@blotoutio/edgetag-sdk-browser 1.60.0 → 1.61.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 +34 -20
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1471,7 +1471,7 @@
1471
1471
  referrer: getReferrer(destination),
1472
1472
  search: getSearch(destination),
1473
1473
  locale: getLocale(),
1474
- sdkVersion: "1.60.0" ,
1474
+ sdkVersion: "1.61.1" ,
1475
1475
  ...(payload || {}),
1476
1476
  };
1477
1477
  let storage = {};
@@ -1663,16 +1663,26 @@
1663
1663
  // by the plugin's identity `${providerId}||${name}` (which is carried in the
1664
1664
  // plugin object's `name`). A missing scope means the plugin is global.
1665
1665
  //
1666
- // Mirrors the edge getAllowedPlugins per-item logic: at instance level the
1667
- // scripts allow-list wins, otherwise fall back to the providers allow-list.
1666
+ // Mirrors the edge getAllowedPlugins: an instance-scoped plugin runs only for
1667
+ // its exact instance (instance stage) or the channel its scripts imply (channel
1668
+ // stage); a plugin counts as global only when it has NEITHER providers NOR
1669
+ // scripts — an empty providers list alone does not make it global.
1668
1670
  const isPluginAllowed = (scope, providerId, instanceName) => {
1669
1671
  if (!scope) {
1670
1672
  return true;
1671
1673
  }
1672
- if (instanceName && scope.scripts.length > 0) {
1674
+ const isInstanceScoped = scope.scripts.length > 0;
1675
+ // Instance stage for an instance-scoped plugin: only its exact instance.
1676
+ if (instanceName && isInstanceScoped) {
1673
1677
  return scope.scripts.includes(`${providerId}||${instanceName}`);
1674
1678
  }
1675
- return scope.providers.length === 0 || scope.providers.includes(providerId);
1679
+ // Channel stage (or instance stage for a global/channel-scoped plugin).
1680
+ // A plugin is global only when it has NEITHER providers NOR scripts; an
1681
+ // instance-scoped plugin still runs for the channel its scripts imply — it
1682
+ // is NOT global just because its providers list is empty.
1683
+ const isGlobal = scope.providers.length === 0 && !isInstanceScoped;
1684
+ const impliesChannel = scope.scripts.some((script) => script.split('||')[0] === providerId);
1685
+ return isGlobal || scope.providers.includes(providerId) || impliesChannel;
1676
1686
  };
1677
1687
  // Mirrors the edge processPluginsRoot skip scope: a global plugin (no scope)
1678
1688
  // skips every browser instance (null), a scoped plugin skips only the instances
@@ -1968,30 +1978,34 @@
1968
1978
  skipped: rootSkippedInstances.has(`${providerId}||${variable.tagName}`),
1969
1979
  });
1970
1980
  }
1971
- // Channel phase (processPluginsChannel): tagChannel runs once per
1972
- // instance, regardless of skip/consent/geo, so its side effects and
1973
- // additional events still fire on skipped instances.
1981
+ // Channel phase (processPluginsChannel): tagChannel runs ONCE per
1982
+ // channel and the result fans out to every instance, mirroring the
1983
+ // edge. It runs regardless of skip/consent/geo so its additional
1984
+ // events still fire even when instances are skipped. All instances
1985
+ // share the same channel-level input (eventName/data), so a single
1986
+ // invocation is equivalent to running it per instance.
1974
1987
  const channelPlugins = plugins.filter((plugin) => plugin.name !== pluginSource &&
1975
1988
  isPluginAllowed(pluginScopes === null || pluginScopes === void 0 ? void 0 : pluginScopes[plugin.name], providerId, null));
1976
1989
  if (channelPlugins.length > 0) {
1990
+ const channelResult = await runPluginHook(channelPlugins, 'tagChannel', pluginScopes, {
1991
+ payload: {
1992
+ eventName: currentEventName,
1993
+ data,
1994
+ eventId,
1995
+ },
1996
+ context: pluginContext,
1997
+ settings: pluginSettings,
1998
+ providerId,
1999
+ utilities: pluginUtilities,
2000
+ });
1977
2001
  for (const variable of variables) {
1978
2002
  const state = instanceStates.get(variable.tagName);
1979
- const channelResult = await runPluginHook(channelPlugins, 'tagChannel', pluginScopes, {
1980
- payload: {
1981
- eventName: state.eventName,
1982
- data: state.data,
1983
- eventId,
1984
- },
1985
- context: pluginContext,
1986
- settings: pluginSettings,
1987
- providerId,
1988
- utilities: pluginUtilities,
1989
- });
1990
2003
  if (channelResult.skip) {
1991
2004
  state.skipped = true;
1992
2005
  }
1993
2006
  state.eventName = channelResult.eventName;
1994
- state.data = channelResult.data;
2007
+ // Clone per instance so later per-instance mutation stays isolated
2008
+ state.data = jsonClone(channelResult.data);
1995
2009
  }
1996
2010
  }
1997
2011
  // Instance phase (processPluginsInstance + tag send): consent/geo gate,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/edgetag-sdk-browser",
3
- "version": "1.60.0",
3
+ "version": "1.61.1",
4
4
  "description": "Browser SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",