@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/cli.cjs CHANGED
@@ -1784,8 +1784,8 @@ function generateLrsBridgeCode(options) {
1784
1784
  ', bravaisUserId=' + employeeData.bravaisUserId + ', tenantUrl=' + employeeData.tenantUrl
1785
1785
  : 'NO DATA'));
1786
1786
  if (employeeData && employeeData.email) {
1787
- actor.mbox = 'mailto:' + employeeData.email;
1788
- log('Enhanced actor with email:', employeeData.email);
1787
+ actor.mbox = 'mailto:' + employeeData.email.toLowerCase();
1788
+ log('Enhanced actor with email:', employeeData.email.toLowerCase());
1789
1789
 
1790
1790
  // Also update name if we got a better one
1791
1791
  if (employeeData.name && (!actor.name || actor.name === 'Unknown Learner')) {
@@ -1950,6 +1950,18 @@ function generateLrsBridgeCode(options) {
1950
1950
  return n === 'anonymous learner' || n === 'unknown learner' || n === 'anonymous' || n === 'unknown';
1951
1951
  }
1952
1952
 
1953
+ /**
1954
+ * Normalize actor IFI fields for consistent matching in Bravais Analytics.
1955
+ * Lowercases mbox email (RFC 5321: local-part is case-insensitive in practice).
1956
+ */
1957
+ function normalizeActor(actor) {
1958
+ if (!actor) return actor;
1959
+ if (actor.mbox && actor.mbox.indexOf('mailto:') === 0) {
1960
+ actor.mbox = 'mailto:' + actor.mbox.substring(7).toLowerCase();
1961
+ }
1962
+ return actor;
1963
+ }
1964
+
1953
1965
  /**
1954
1966
  * Persist actor to localStorage for cross-frame sharing.
1955
1967
  * Only stores non-anonymous actors.
@@ -1981,23 +1993,29 @@ function generateLrsBridgeCode(options) {
1981
1993
 
1982
1994
  /**
1983
1995
  * Get the best available actor for statement building.
1984
- * Priority: LRS.actor (if non-anonymous) > localStorage shared actor > LRS.actor > extractActor()
1996
+ * ALWAYS checks localStorage because the skin overlay in another frame
1997
+ * may have updated the actor AFTER this bridge instance initialized.
1998
+ * (e.g., user enters email in skin overlay \u2192 actor persisted to localStorage,
1999
+ * but the bridge in scormcontent/index.html already loaded a stale actor at init)
1985
2000
  */
1986
2001
  function getActor() {
1987
- // If current actor is non-anonymous, use it
1988
- if (LRS.actor && !isAnonymousActor(LRS.actor)) {
1989
- return LRS.actor;
1990
- }
1991
- // Check localStorage for actor set by another frame (e.g., skin overlay)
2002
+ // Always check localStorage for the freshest actor \u2014 it may have been
2003
+ // updated by the skin overlay in another frame since our init
1992
2004
  var shared = loadSharedActor();
1993
2005
  if (shared) {
1994
- // Update local actor so future calls are fast
1995
- LRS.actor = shared;
1996
- log('Actor loaded from cross-frame storage:', shared.name);
1997
- return shared;
2006
+ // Only update if different from current (avoid unnecessary log spam)
2007
+ if (!LRS.actor || LRS.actor.name !== shared.name ||
2008
+ (LRS.actor.account && shared.account && LRS.actor.account.name !== shared.account.name)) {
2009
+ log('Actor updated from cross-frame storage:', shared.name);
2010
+ }
2011
+ LRS.actor = normalizeActor(shared);
2012
+ return LRS.actor;
1998
2013
  }
1999
2014
  // Fallback to current actor or re-extract
2000
- return LRS.actor || extractActor();
2015
+ if (LRS.actor && !isAnonymousActor(LRS.actor)) {
2016
+ return normalizeActor(LRS.actor);
2017
+ }
2018
+ return normalizeActor(LRS.actor || extractActor());
2001
2019
  }
2002
2020
 
2003
2021
  /**
@@ -2007,7 +2025,9 @@ function generateLrsBridgeCode(options) {
2007
2025
  LRS.setActor = function(actor) {
2008
2026
  LRS.actor = actor;
2009
2027
  persistActor(actor);
2010
- // Also try to propagate to other frames in the hierarchy
2028
+
2029
+ // Propagate to ALL frames: walk UP parent chain AND DOWN into child iframes
2030
+ // UP: parent frames (e.g., if skin is in a child iframe)
2011
2031
  try {
2012
2032
  var w = window;
2013
2033
  for (var i = 0; i < 10; i++) {
@@ -2020,9 +2040,29 @@ function generateLrsBridgeCode(options) {
2020
2040
  w = w.parent;
2021
2041
  }
2022
2042
  } catch (e) {}
2043
+
2044
+ // DOWN: child iframes (e.g., scormcontent/index.html has its own bridge)
2045
+ function setActorInChildren(win) {
2046
+ try {
2047
+ var frames = win.frames;
2048
+ for (var j = 0; j < frames.length; j++) {
2049
+ try {
2050
+ if (frames[j].pa_patcher && frames[j].pa_patcher.lrs) {
2051
+ frames[j].pa_patcher.lrs.actor = actor;
2052
+ log('Actor propagated to child frame', j);
2053
+ }
2054
+ // Recurse into nested iframes
2055
+ setActorInChildren(frames[j]);
2056
+ } catch (e) { /* cross-origin child */ }
2057
+ }
2058
+ } catch (e) {}
2059
+ }
2060
+ setActorInChildren(window);
2061
+
2023
2062
  if (window.console && window.console.info) {
2024
2063
  console.info('[PA-LRS] Actor set:', actor.name,
2025
2064
  actor.mbox ? '(' + actor.mbox + ')' : '',
2065
+ actor.account ? '(account: ' + actor.account.name + ')' : '',
2026
2066
  '\u2014 shared across frames');
2027
2067
  }
2028
2068
  };
@@ -2037,9 +2077,9 @@ function generateLrsBridgeCode(options) {
2037
2077
  function finalizeActor(actor) {
2038
2078
  // Try to enhance actor with email if missing
2039
2079
  enhanceActorWithEmail(actor, function(enhancedActor) {
2040
- LRS.actor = enhancedActor;
2041
- persistActor(enhancedActor);
2042
- callback(enhancedActor);
2080
+ LRS.actor = normalizeActor(enhancedActor);
2081
+ persistActor(LRS.actor);
2082
+ callback(LRS.actor);
2043
2083
  });
2044
2084
  }
2045
2085