@patch-adams/core 1.5.20 → 1.5.22

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/dist/index.js CHANGED
@@ -1443,8 +1443,8 @@ function generateLrsBridgeCode(options) {
1443
1443
  ', bravaisUserId=' + employeeData.bravaisUserId + ', tenantUrl=' + employeeData.tenantUrl
1444
1444
  : 'NO DATA'));
1445
1445
  if (employeeData && employeeData.email) {
1446
- actor.mbox = 'mailto:' + employeeData.email;
1447
- log('Enhanced actor with email:', employeeData.email);
1446
+ actor.mbox = 'mailto:' + employeeData.email.toLowerCase();
1447
+ log('Enhanced actor with email:', employeeData.email.toLowerCase());
1448
1448
 
1449
1449
  // Also update name if we got a better one
1450
1450
  if (employeeData.name && (!actor.name || actor.name === 'Unknown Learner')) {
@@ -1609,6 +1609,18 @@ function generateLrsBridgeCode(options) {
1609
1609
  return n === 'anonymous learner' || n === 'unknown learner' || n === 'anonymous' || n === 'unknown';
1610
1610
  }
1611
1611
 
1612
+ /**
1613
+ * Normalize actor IFI fields for consistent matching in Bravais Analytics.
1614
+ * Lowercases mbox email (RFC 5321: local-part is case-insensitive in practice).
1615
+ */
1616
+ function normalizeActor(actor) {
1617
+ if (!actor) return actor;
1618
+ if (actor.mbox && actor.mbox.indexOf('mailto:') === 0) {
1619
+ actor.mbox = 'mailto:' + actor.mbox.substring(7).toLowerCase();
1620
+ }
1621
+ return actor;
1622
+ }
1623
+
1612
1624
  /**
1613
1625
  * Persist actor to localStorage for cross-frame sharing.
1614
1626
  * Only stores non-anonymous actors.
@@ -1640,23 +1652,29 @@ function generateLrsBridgeCode(options) {
1640
1652
 
1641
1653
  /**
1642
1654
  * Get the best available actor for statement building.
1643
- * Priority: LRS.actor (if non-anonymous) > localStorage shared actor > LRS.actor > extractActor()
1655
+ * ALWAYS checks localStorage because the skin overlay in another frame
1656
+ * may have updated the actor AFTER this bridge instance initialized.
1657
+ * (e.g., user enters email in skin overlay \u2192 actor persisted to localStorage,
1658
+ * but the bridge in scormcontent/index.html already loaded a stale actor at init)
1644
1659
  */
1645
1660
  function getActor() {
1646
- // If current actor is non-anonymous, use it
1647
- if (LRS.actor && !isAnonymousActor(LRS.actor)) {
1648
- return LRS.actor;
1649
- }
1650
- // Check localStorage for actor set by another frame (e.g., skin overlay)
1661
+ // Always check localStorage for the freshest actor \u2014 it may have been
1662
+ // updated by the skin overlay in another frame since our init
1651
1663
  var shared = loadSharedActor();
1652
1664
  if (shared) {
1653
- // Update local actor so future calls are fast
1654
- LRS.actor = shared;
1655
- log('Actor loaded from cross-frame storage:', shared.name);
1656
- return shared;
1665
+ // Only update if different from current (avoid unnecessary log spam)
1666
+ if (!LRS.actor || LRS.actor.name !== shared.name ||
1667
+ (LRS.actor.account && shared.account && LRS.actor.account.name !== shared.account.name)) {
1668
+ log('Actor updated from cross-frame storage:', shared.name);
1669
+ }
1670
+ LRS.actor = normalizeActor(shared);
1671
+ return LRS.actor;
1657
1672
  }
1658
1673
  // Fallback to current actor or re-extract
1659
- return LRS.actor || extractActor();
1674
+ if (LRS.actor && !isAnonymousActor(LRS.actor)) {
1675
+ return normalizeActor(LRS.actor);
1676
+ }
1677
+ return normalizeActor(LRS.actor || extractActor());
1660
1678
  }
1661
1679
 
1662
1680
  /**
@@ -1666,7 +1684,9 @@ function generateLrsBridgeCode(options) {
1666
1684
  LRS.setActor = function(actor) {
1667
1685
  LRS.actor = actor;
1668
1686
  persistActor(actor);
1669
- // Also try to propagate to other frames in the hierarchy
1687
+
1688
+ // Propagate to ALL frames: walk UP parent chain AND DOWN into child iframes
1689
+ // UP: parent frames (e.g., if skin is in a child iframe)
1670
1690
  try {
1671
1691
  var w = window;
1672
1692
  for (var i = 0; i < 10; i++) {
@@ -1679,9 +1699,29 @@ function generateLrsBridgeCode(options) {
1679
1699
  w = w.parent;
1680
1700
  }
1681
1701
  } catch (e) {}
1702
+
1703
+ // DOWN: child iframes (e.g., scormcontent/index.html has its own bridge)
1704
+ function setActorInChildren(win) {
1705
+ try {
1706
+ var frames = win.frames;
1707
+ for (var j = 0; j < frames.length; j++) {
1708
+ try {
1709
+ if (frames[j].pa_patcher && frames[j].pa_patcher.lrs) {
1710
+ frames[j].pa_patcher.lrs.actor = actor;
1711
+ log('Actor propagated to child frame', j);
1712
+ }
1713
+ // Recurse into nested iframes
1714
+ setActorInChildren(frames[j]);
1715
+ } catch (e) { /* cross-origin child */ }
1716
+ }
1717
+ } catch (e) {}
1718
+ }
1719
+ setActorInChildren(window);
1720
+
1682
1721
  if (window.console && window.console.info) {
1683
1722
  console.info('[PA-LRS] Actor set:', actor.name,
1684
1723
  actor.mbox ? '(' + actor.mbox + ')' : '',
1724
+ actor.account ? '(account: ' + actor.account.name + ')' : '',
1685
1725
  '\u2014 shared across frames');
1686
1726
  }
1687
1727
  };
@@ -1696,9 +1736,9 @@ function generateLrsBridgeCode(options) {
1696
1736
  function finalizeActor(actor) {
1697
1737
  // Try to enhance actor with email if missing
1698
1738
  enhanceActorWithEmail(actor, function(enhancedActor) {
1699
- LRS.actor = enhancedActor;
1700
- persistActor(enhancedActor);
1701
- callback(enhancedActor);
1739
+ LRS.actor = normalizeActor(enhancedActor);
1740
+ persistActor(LRS.actor);
1741
+ callback(LRS.actor);
1702
1742
  });
1703
1743
  }
1704
1744