@patch-adams/core 1.3.3 → 1.3.6

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
@@ -389,10 +389,11 @@ function generateLrsBridgeCode(options) {
389
389
  const employeeApiEndpoint = options.employeeApiEndpoint || "";
390
390
  return `
391
391
  // ==========================================================================
392
- // PATCH-ADAMS LRS BRIDGE v2.1.0
392
+ // PATCH-ADAMS LRS BRIDGE v2.2.0
393
393
  // Full xAPI support with direct LRS communication for Rise courses
394
- // ALL statements use COURSE as main object for Analytics searchability
394
+ // ALL statements use DOCUMENT as main object for Bravais aggregation
395
395
  // Activity type (video, assessment, etc.) stored in object.definition.type
396
+ // Page/lesson info stored in context.extensions for navigation tracking
396
397
  // ==========================================================================
397
398
  (function() {
398
399
  'use strict';
@@ -1561,6 +1562,132 @@ function generateLrsBridgeCode(options) {
1561
1562
  return null;
1562
1563
  }
1563
1564
 
1565
+ // Store for document API data
1566
+ var documentApiData = null;
1567
+ var documentApiFetched = false;
1568
+
1569
+ /**
1570
+ * Fetch document metadata from Bravais API to get GUIDs
1571
+ * Endpoint: /api/v3/documents/{documentId}
1572
+ */
1573
+ function fetchDocumentMetadata(documentId, callback) {
1574
+ if (!documentId) {
1575
+ callback(null);
1576
+ return;
1577
+ }
1578
+
1579
+ if (documentApiFetched) {
1580
+ callback(documentApiData);
1581
+ return;
1582
+ }
1583
+
1584
+ // Detect Bravais core URL
1585
+ var coreUrl = null;
1586
+ var urlsToCheck = [window.location.href, document.referrer];
1587
+
1588
+ try {
1589
+ var win = window;
1590
+ for (var i = 0; i < 10; i++) {
1591
+ if (win.parent && win.parent !== win) {
1592
+ win = win.parent;
1593
+ try {
1594
+ urlsToCheck.push(win.location.href);
1595
+ } catch (e) { break; }
1596
+ } else { break; }
1597
+ }
1598
+ } catch (e) {}
1599
+
1600
+ for (var j = 0; j < urlsToCheck.length; j++) {
1601
+ var match = urlsToCheck[j].match(/(https?:\\/\\/core-[a-zA-Z0-9_-]+\\.bravais\\.com)/);
1602
+ if (match) {
1603
+ coreUrl = match[1];
1604
+ break;
1605
+ }
1606
+ }
1607
+
1608
+ if (!coreUrl) {
1609
+ log('No Bravais core URL detected for document metadata fetch');
1610
+ documentApiFetched = true;
1611
+ callback(null);
1612
+ return;
1613
+ }
1614
+
1615
+ var apiUrl = coreUrl + '/api/v3/documents/' + documentId;
1616
+ log('Fetching document metadata from:', apiUrl);
1617
+
1618
+ var xhr = new XMLHttpRequest();
1619
+ xhr.open('GET', apiUrl, true);
1620
+ xhr.withCredentials = true;
1621
+ xhr.setRequestHeader('Accept', 'application/json');
1622
+
1623
+ xhr.onreadystatechange = function() {
1624
+ if (xhr.readyState === 4) {
1625
+ documentApiFetched = true;
1626
+ log('Document API response status:', xhr.status);
1627
+ if (xhr.status >= 200 && xhr.status < 300) {
1628
+ try {
1629
+ documentApiData = JSON.parse(xhr.responseText);
1630
+ log('Document metadata received:', documentApiData);
1631
+ callback(documentApiData);
1632
+ } catch (e) {
1633
+ warn('Error parsing document metadata:', e);
1634
+ callback(null);
1635
+ }
1636
+ } else {
1637
+ log('Document metadata fetch failed. Status:', xhr.status);
1638
+ callback(null);
1639
+ }
1640
+ }
1641
+ };
1642
+
1643
+ xhr.onerror = function() {
1644
+ documentApiFetched = true;
1645
+ log('Network error fetching document metadata');
1646
+ callback(null);
1647
+ };
1648
+
1649
+ try {
1650
+ xhr.send();
1651
+ } catch (e) {
1652
+ documentApiFetched = true;
1653
+ warn('Error sending document request:', e);
1654
+ callback(null);
1655
+ }
1656
+ }
1657
+
1658
+ /**
1659
+ * Update course info with data from document API
1660
+ */
1661
+ function updateCourseInfoFromApi(docData) {
1662
+ if (!docData || !LRS.courseInfo) return;
1663
+
1664
+ // Document GUID
1665
+ if (docData.guid && !LRS.courseInfo.guid) {
1666
+ LRS.courseInfo.guid = docData.guid;
1667
+ LRS.courseInfo.id = 'http://xyleme.com/bravais/document/' + docData.guid;
1668
+ log('Updated course guid from API:', docData.guid);
1669
+ }
1670
+
1671
+ // Version GUID from latestVersion
1672
+ if (docData.latestVersion && docData.latestVersion.guid && !LRS.courseInfo.versionGuid) {
1673
+ LRS.courseInfo.versionGuid = docData.latestVersion.guid;
1674
+ log('Updated version guid from API:', docData.latestVersion.guid);
1675
+ }
1676
+
1677
+ // Other metadata
1678
+ if (docData.name && LRS.courseInfo.title === 'Rise Course') {
1679
+ LRS.courseInfo.title = docData.name;
1680
+ }
1681
+ if (docData.format) {
1682
+ LRS.courseInfo.format = docData.format;
1683
+ }
1684
+ if (docData.resourceType) {
1685
+ LRS.courseInfo.resourceType = docData.resourceType;
1686
+ }
1687
+
1688
+ log('Course info updated from API:', LRS.courseInfo);
1689
+ }
1690
+
1564
1691
  /**
1565
1692
  * Extract Bravais document ID from URL
1566
1693
  * Pattern: /api/shared/.../files/{documentId}/scormcontent/
@@ -2261,24 +2388,41 @@ function generateLrsBridgeCode(options) {
2261
2388
  sendStatement(statement);
2262
2389
  };
2263
2390
 
2264
- // Content/Page viewed
2391
+ // Content/Page viewed - uses document as object for Bravais aggregation
2265
2392
  LRS.contentOpened = function(data) {
2266
2393
  if (!TRACK_NAVIGATION) return;
2267
2394
 
2268
- // Build page-level activity object for Xyleme format
2269
- var pageObject = buildPageActivityObject({
2270
- pageGuid: data.pageGuid || data.lessonId,
2271
- name: data.title || 'Page',
2272
- type: 'page'
2273
- });
2274
-
2275
2395
  var result = null;
2276
2396
  if (data.duration) {
2277
2397
  result = { duration: data.duration };
2278
2398
  }
2279
2399
 
2280
- // Use 'opened' verb for Xyleme compatibility (ActivityStrea.ms)
2281
- var statement = buildStatementXyleme('opened', pageObject, result);
2400
+ // Extract clean page/lesson ID from Rise hash paths
2401
+ var lessonId = data.pageGuid || data.lessonId || '';
2402
+ if (lessonId.indexOf('#/lessons/') === 0) {
2403
+ lessonId = lessonId.substring(10); // Remove '#/lessons/'
2404
+ } else if (lessonId.indexOf('#/') === 0) {
2405
+ lessonId = lessonId.substring(2); // Remove '#/'
2406
+ }
2407
+
2408
+ // Add page info to context extensions (not as main object)
2409
+ var additionalContext = {
2410
+ extensions: {
2411
+ pageId: lessonId || 'home',
2412
+ pageTitle: data.title || 'Page',
2413
+ pageUrl: data.url || window.location.href
2414
+ }
2415
+ };
2416
+
2417
+ // Use document as main object (required for Bravais aggregation)
2418
+ // Use 'experienced' verb which is standard xAPI for viewing content
2419
+ var statement = buildStatement(
2420
+ 'experienced',
2421
+ 'http://xyleme.com/bravais/activities/document',
2422
+ { event: 'page_viewed', pageId: lessonId },
2423
+ result,
2424
+ additionalContext
2425
+ );
2282
2426
  sendStatement(statement);
2283
2427
  };
2284
2428
 
@@ -2778,7 +2922,7 @@ function generateLrsBridgeCode(options) {
2778
2922
  // ========================================================================
2779
2923
 
2780
2924
  function init() {
2781
- log('Initializing LRS bridge v2.0.0...');
2925
+ log('Initializing LRS bridge v2.2.0...');
2782
2926
 
2783
2927
  // Extract course info early
2784
2928
  extractCourseInfo();
@@ -2812,8 +2956,11 @@ function generateLrsBridgeCode(options) {
2812
2956
  setupQuizInterceptors();
2813
2957
  setupInteractionInterceptors();
2814
2958
 
2815
- // Send course launched event after a short delay to allow actor fetch
2816
- setTimeout(function() {
2959
+ // Fetch document metadata from API to get GUIDs (async)
2960
+ // Then send course launched event
2961
+ var documentId = LRS.courseInfo ? LRS.courseInfo.documentId : null;
2962
+
2963
+ function sendLaunchEvents() {
2817
2964
  if (TRACK_NAVIGATION) {
2818
2965
  LRS.courseLaunched();
2819
2966
  LRS.contentOpened({
@@ -2822,7 +2969,21 @@ function generateLrsBridgeCode(options) {
2822
2969
  action: 'launched'
2823
2970
  });
2824
2971
  }
2825
- }, 500);
2972
+ }
2973
+
2974
+ if (documentId && !LRS.courseInfo.guid) {
2975
+ // Try to fetch GUIDs from API before sending statements
2976
+ fetchDocumentMetadata(documentId, function(docData) {
2977
+ if (docData) {
2978
+ updateCourseInfoFromApi(docData);
2979
+ }
2980
+ // Send launch events after API fetch (success or failure)
2981
+ setTimeout(sendLaunchEvents, 100);
2982
+ });
2983
+ } else {
2984
+ // Already have GUID or no document ID - send after short delay
2985
+ setTimeout(sendLaunchEvents, 500);
2986
+ }
2826
2987
 
2827
2988
  // Setup beforeunload to send terminated
2828
2989
  window.addEventListener('beforeunload', function() {