@patch-adams/core 1.5.11 → 1.5.14
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 +113 -22
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +113 -22
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +114 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +114 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -399,7 +399,9 @@ var LrsBridgeConfigSchema = zod.z.object({
|
|
|
399
399
|
/** Document GUID for xAPI statement aggregation - baked into package at wrap time */
|
|
400
400
|
documentGuid: zod.z.string().optional(),
|
|
401
401
|
/** Version GUID for xAPI statement aggregation - unique per export */
|
|
402
|
-
versionGuid: zod.z.string().optional()
|
|
402
|
+
versionGuid: zod.z.string().optional(),
|
|
403
|
+
/** Original SCORM package filename - baked in at wrap time for LRS searchability */
|
|
404
|
+
packageName: zod.z.string().optional()
|
|
403
405
|
});
|
|
404
406
|
var BlockingAssetConfigSchema = zod.z.object({
|
|
405
407
|
/** Filename for the asset */
|
|
@@ -748,6 +750,7 @@ function generateLrsBridgeCode(options) {
|
|
|
748
750
|
const lrsProxyEndpoint = options.lrsProxyEndpoint || "";
|
|
749
751
|
const documentGuid = options.documentGuid || "";
|
|
750
752
|
const versionGuid = options.versionGuid || "";
|
|
753
|
+
const packageName = options.packageName || "";
|
|
751
754
|
return `
|
|
752
755
|
// ==========================================================================
|
|
753
756
|
// PATCH-ADAMS LRS BRIDGE v2.2.0
|
|
@@ -780,6 +783,7 @@ function generateLrsBridgeCode(options) {
|
|
|
780
783
|
var LRS_PROXY_ENDPOINT = '${lrsProxyEndpoint}';
|
|
781
784
|
var DOCUMENT_GUID = '${documentGuid}';
|
|
782
785
|
var VERSION_GUID = '${versionGuid}';
|
|
786
|
+
var PACKAGE_NAME = '${packageName}';
|
|
783
787
|
|
|
784
788
|
// Bravais LRS endpoint pattern: https://lrs-{tenant}.bravais.com/XAPI/statements
|
|
785
789
|
// Example: core-acme.bravais.com -> lrs-acme.bravais.com
|
|
@@ -2463,7 +2467,9 @@ function generateLrsBridgeCode(options) {
|
|
|
2463
2467
|
sharedLinkName: null,
|
|
2464
2468
|
// Tenant info
|
|
2465
2469
|
homepage: COURSE_HOMEPAGE || window.location.origin,
|
|
2466
|
-
tenantHomepage: null
|
|
2470
|
+
tenantHomepage: null, // https://{tenant}.bravais.com format
|
|
2471
|
+
// Package info
|
|
2472
|
+
packageName: null // Original SCORM zip filename
|
|
2467
2473
|
};
|
|
2468
2474
|
|
|
2469
2475
|
// 0. Use baked-in GUIDs from PA-Patcher config (highest priority - set at wrap time)
|
|
@@ -2476,6 +2482,10 @@ function generateLrsBridgeCode(options) {
|
|
|
2476
2482
|
info.versionGuid = VERSION_GUID;
|
|
2477
2483
|
log('Version GUID from baked-in config:', VERSION_GUID);
|
|
2478
2484
|
}
|
|
2485
|
+
if (PACKAGE_NAME) {
|
|
2486
|
+
info.packageName = PACKAGE_NAME;
|
|
2487
|
+
log('Package name from baked-in config:', PACKAGE_NAME);
|
|
2488
|
+
}
|
|
2479
2489
|
|
|
2480
2490
|
// 1. Extract shared link token and document ID from URL
|
|
2481
2491
|
info.sharedLinkToken = extractSharedLinkToken();
|
|
@@ -2906,6 +2916,11 @@ function generateLrsBridgeCode(options) {
|
|
|
2906
2916
|
// Resource type
|
|
2907
2917
|
obj.definition.extensions['resourceType'] = LRS.courseInfo.resourceType || 'Course';
|
|
2908
2918
|
|
|
2919
|
+
// Package name (original SCORM zip filename)
|
|
2920
|
+
if (LRS.courseInfo.packageName) {
|
|
2921
|
+
obj.definition.extensions['packageName'] = LRS.courseInfo.packageName;
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2909
2924
|
return obj;
|
|
2910
2925
|
}
|
|
2911
2926
|
|
|
@@ -3739,11 +3754,11 @@ function generateLrsBridgeCode(options) {
|
|
|
3739
3754
|
// Send a course completion statement \u2014 called by skin or auto-detected via SCORM
|
|
3740
3755
|
LRS.sendCompletionStatement = function(data) {
|
|
3741
3756
|
data = data || {};
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3757
|
+
// Cancel any pending SCORM auto-detection to avoid double-fire for same attempt
|
|
3758
|
+
if (scormCompletionDebounce) {
|
|
3759
|
+
clearTimeout(scormCompletionDebounce);
|
|
3760
|
+
scormCompletionDebounce = null;
|
|
3745
3761
|
}
|
|
3746
|
-
scormCompletionSent = true;
|
|
3747
3762
|
|
|
3748
3763
|
var status = data.status || 'completed';
|
|
3749
3764
|
var courseTitle = data.courseTitle || (LRS.courseInfo && LRS.courseInfo.title ? decodeEntities(LRS.courseInfo.title) : decodeEntities(document.title) || 'Course');
|
|
@@ -3773,11 +3788,58 @@ function generateLrsBridgeCode(options) {
|
|
|
3773
3788
|
};
|
|
3774
3789
|
if (data.employeeName) activityDetails.employeeName = data.employeeName;
|
|
3775
3790
|
|
|
3776
|
-
|
|
3777
|
-
|
|
3791
|
+
// 1. Always send "completed" statement
|
|
3792
|
+
log('Sending completed statement, score:', result.score, 'title:', courseTitle);
|
|
3793
|
+
var completedStatement = buildStatement('completed', ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
3794
|
+
sendStatement(completedStatement);
|
|
3795
|
+
|
|
3796
|
+
// 2. Send "passed" or "failed" statement (assessment outcome)
|
|
3797
|
+
if (status === 'passed' || status === 'failed') {
|
|
3798
|
+
log('Sending', status, 'statement');
|
|
3799
|
+
var outcomeStatement = buildStatement(status, ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
3800
|
+
sendStatement(outcomeStatement);
|
|
3801
|
+
}
|
|
3802
|
+
};
|
|
3803
|
+
|
|
3804
|
+
// Send a "terminated" statement \u2014 called by skin close button or auto on page unload
|
|
3805
|
+
var exitStatementSent = false;
|
|
3806
|
+
LRS.sendExitStatement = function(data) {
|
|
3807
|
+
if (exitStatementSent) return;
|
|
3808
|
+
exitStatementSent = true;
|
|
3809
|
+
data = data || {};
|
|
3810
|
+
|
|
3811
|
+
var courseTitle = (LRS.courseInfo && LRS.courseInfo.title) ? decodeEntities(LRS.courseInfo.title) : decodeEntities(document.title) || 'Course';
|
|
3812
|
+
var duration = null;
|
|
3813
|
+
if (LRS.launchTime) {
|
|
3814
|
+
var ms = new Date().getTime() - new Date(LRS.launchTime).getTime();
|
|
3815
|
+
var secs = Math.floor(ms / 1000);
|
|
3816
|
+
var mins = Math.floor(secs / 60);
|
|
3817
|
+
var hrs = Math.floor(mins / 60);
|
|
3818
|
+
duration = 'PT' + (hrs > 0 ? hrs + 'H' : '') + (mins % 60) + 'M' + (secs % 60) + 'S';
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
var activityDetails = {
|
|
3822
|
+
courseTitle: courseTitle,
|
|
3823
|
+
exitSource: data.source || 'page-unload',
|
|
3824
|
+
employeeEmail: LRS.actor && LRS.actor.mbox ? LRS.actor.mbox.replace('mailto:', '') : undefined,
|
|
3825
|
+
employeeId: LRS.employeeId || undefined,
|
|
3826
|
+
sessionDuration: duration,
|
|
3827
|
+
statementsSent: LRS.stats.statementsSent
|
|
3828
|
+
};
|
|
3829
|
+
|
|
3830
|
+
var result = duration ? { duration: duration } : null;
|
|
3831
|
+
log('Sending exit statement, duration:', duration);
|
|
3832
|
+
var statement = buildStatement('terminated', ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
3778
3833
|
sendStatement(statement);
|
|
3779
3834
|
};
|
|
3780
3835
|
|
|
3836
|
+
// Auto-send exit statement on page unload
|
|
3837
|
+
window.addEventListener('beforeunload', function() {
|
|
3838
|
+
if (!exitStatementSent && LRS.actor) {
|
|
3839
|
+
LRS.sendExitStatement({ source: 'page-unload' });
|
|
3840
|
+
}
|
|
3841
|
+
});
|
|
3842
|
+
|
|
3781
3843
|
/**
|
|
3782
3844
|
* Re-extract actor from SCORM after LMSInitialize has been called.
|
|
3783
3845
|
* Call this from the SCORM wrapper after scormInit() succeeds,
|
|
@@ -3884,6 +3946,23 @@ function generateLrsBridgeCode(options) {
|
|
|
3884
3946
|
LRS.interacted({ type: 'choice-branch', id: data.id, name: 'Choice Branch Discarded' });
|
|
3885
3947
|
};
|
|
3886
3948
|
|
|
3949
|
+
// ========================================================================
|
|
3950
|
+
// PUBLIC API \u2014 expose core internals for skin scripts
|
|
3951
|
+
// Usage: window.pa_patcher.lrs.api.sendStatement(stmt)
|
|
3952
|
+
// ========================================================================
|
|
3953
|
+
LRS.api = {
|
|
3954
|
+
sendStatement: sendStatement,
|
|
3955
|
+
buildStatement: buildStatement,
|
|
3956
|
+
buildCourseActivityObject: buildCourseActivityObject,
|
|
3957
|
+
buildXylemeContext: buildXylemeContext,
|
|
3958
|
+
generateUUID: generateUUID,
|
|
3959
|
+
decodeEntities: decodeEntities,
|
|
3960
|
+
extractActor: extractActor,
|
|
3961
|
+
getCachedLessonInfo: getCachedLessonInfo,
|
|
3962
|
+
VERBS: VERBS,
|
|
3963
|
+
ACTIVITY_TYPES: ACTIVITY_TYPES
|
|
3964
|
+
};
|
|
3965
|
+
|
|
3887
3966
|
// ========================================================================
|
|
3888
3967
|
// 8. RISE EVENT INTERCEPTORS
|
|
3889
3968
|
// ========================================================================
|
|
@@ -4449,7 +4528,7 @@ function generateLrsBridgeCode(options) {
|
|
|
4449
4528
|
var scormInteractionsSent = {}; // Track which interactions were already sent
|
|
4450
4529
|
var scormTrackerActive = false; // Set true when SCORM tracker wraps SetValue \u2014 KC handler defers
|
|
4451
4530
|
var scormCourseData = {}; // Accumulates course-level SCORM data (score, status)
|
|
4452
|
-
var
|
|
4531
|
+
var scormCompletionDebounce = null; // Debounce timer \u2014 prevents duplicate fires within same completion event
|
|
4453
4532
|
|
|
4454
4533
|
function interceptScormSetValue(key, value) {
|
|
4455
4534
|
if (typeof key !== 'string') return;
|
|
@@ -4469,12 +4548,15 @@ function generateLrsBridgeCode(options) {
|
|
|
4469
4548
|
if (key === 'cmi.success_status') { scormCourseData.successStatus = String(value).toLowerCase(); }
|
|
4470
4549
|
|
|
4471
4550
|
// Fire course completion statement when status indicates pass/fail/complete
|
|
4472
|
-
|
|
4551
|
+
// Uses debounce (not one-time flag) so retries/new attempts are captured
|
|
4552
|
+
if (key === 'cmi.core.lesson_status' || key === 'cmi.success_status' || key === 'cmi.completion_status') {
|
|
4473
4553
|
var status = String(value).toLowerCase();
|
|
4474
4554
|
if (status === 'passed' || status === 'failed' || status === 'completed') {
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4555
|
+
if (scormCompletionDebounce) clearTimeout(scormCompletionDebounce);
|
|
4556
|
+
scormCompletionDebounce = setTimeout(function() {
|
|
4557
|
+
scormCompletionDebounce = null;
|
|
4558
|
+
sendCourseCompletionStatement(status);
|
|
4559
|
+
}, 500);
|
|
4478
4560
|
}
|
|
4479
4561
|
}
|
|
4480
4562
|
|
|
@@ -4585,11 +4667,6 @@ function generateLrsBridgeCode(options) {
|
|
|
4585
4667
|
|
|
4586
4668
|
var courseTitle = (LRS.courseInfo && LRS.courseInfo.title) ? decodeEntities(LRS.courseInfo.title) : decodeEntities(document.title) || 'Course';
|
|
4587
4669
|
|
|
4588
|
-
// Determine verb
|
|
4589
|
-
var verbKey = 'completed';
|
|
4590
|
-
if (status === 'passed') verbKey = 'passed';
|
|
4591
|
-
if (status === 'failed') verbKey = 'failed';
|
|
4592
|
-
|
|
4593
4670
|
// Build result with score
|
|
4594
4671
|
var result = { completion: true };
|
|
4595
4672
|
|
|
@@ -4615,10 +4692,17 @@ function generateLrsBridgeCode(options) {
|
|
|
4615
4692
|
employeeId: LRS.employeeId || undefined
|
|
4616
4693
|
};
|
|
4617
4694
|
|
|
4618
|
-
|
|
4695
|
+
// 1. Send "completed" statement (course was finished)
|
|
4696
|
+
log('Sending completed statement, score:', result.score, 'title:', courseTitle);
|
|
4697
|
+
var completedStatement = buildStatement('completed', ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
4698
|
+
sendStatement(completedStatement);
|
|
4619
4699
|
|
|
4620
|
-
|
|
4621
|
-
|
|
4700
|
+
// 2. Send "passed" or "failed" statement (assessment outcome)
|
|
4701
|
+
if (status === 'passed' || status === 'failed') {
|
|
4702
|
+
log('Sending', status, 'statement');
|
|
4703
|
+
var outcomeStatement = buildStatement(status, ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
4704
|
+
sendStatement(outcomeStatement);
|
|
4705
|
+
}
|
|
4622
4706
|
|
|
4623
4707
|
logGroupEnd();
|
|
4624
4708
|
}
|
|
@@ -5302,7 +5386,8 @@ function buildJsBeforeOptions(config, metadata) {
|
|
|
5302
5386
|
lrsProxyEndpoint: lrsBridgeConfig.lrsProxyEndpoint,
|
|
5303
5387
|
employeeApiEndpoint: lrsBridgeConfig.employeeApiEndpoint,
|
|
5304
5388
|
documentGuid: lrsBridgeConfig.documentGuid,
|
|
5305
|
-
versionGuid: lrsBridgeConfig.versionGuid
|
|
5389
|
+
versionGuid: lrsBridgeConfig.versionGuid,
|
|
5390
|
+
packageName: lrsBridgeConfig.packageName
|
|
5306
5391
|
};
|
|
5307
5392
|
return {
|
|
5308
5393
|
remoteUrl: `${config.remoteDomain}/${config.localFolders.js}/${config.jsBefore.filename}`,
|
|
@@ -6682,6 +6767,11 @@ var Patcher = class {
|
|
|
6682
6767
|
if (effectiveSkin) {
|
|
6683
6768
|
console.log(`[Patcher] Skin: ${effectiveSkin}`);
|
|
6684
6769
|
}
|
|
6770
|
+
if (options.packageName) {
|
|
6771
|
+
this.config.lrsBridge = this.config.lrsBridge ?? {};
|
|
6772
|
+
this.config.lrsBridge.packageName = options.packageName;
|
|
6773
|
+
console.log(`[Patcher] Package name: ${options.packageName}`);
|
|
6774
|
+
}
|
|
6685
6775
|
const htmlInjector = this.getHtmlInjector(toolInfo.tool);
|
|
6686
6776
|
htmlInjector.setMetadata(metadata);
|
|
6687
6777
|
let fetchedFallbacks = {};
|
|
@@ -6975,6 +7065,7 @@ program.command("patch <input>").description("Patch a Rise course ZIP file").opt
|
|
|
6975
7065
|
if (options.jsAfter) {
|
|
6976
7066
|
patchOptions.jsAfterContent = fs.readFileSync(path.resolve(options.jsAfter), "utf-8");
|
|
6977
7067
|
}
|
|
7068
|
+
patchOptions.packageName = path.basename(inputPath);
|
|
6978
7069
|
spinner.text = "Patching package...";
|
|
6979
7070
|
const patcher = new Patcher(validatedConfig);
|
|
6980
7071
|
const { buffer, result } = await patcher.patch(inputBuffer, patchOptions);
|