@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.js
CHANGED
|
@@ -389,7 +389,9 @@ var LrsBridgeConfigSchema = z.object({
|
|
|
389
389
|
/** Document GUID for xAPI statement aggregation - baked into package at wrap time */
|
|
390
390
|
documentGuid: z.string().optional(),
|
|
391
391
|
/** Version GUID for xAPI statement aggregation - unique per export */
|
|
392
|
-
versionGuid: z.string().optional()
|
|
392
|
+
versionGuid: z.string().optional(),
|
|
393
|
+
/** Original SCORM package filename - baked in at wrap time for LRS searchability */
|
|
394
|
+
packageName: z.string().optional()
|
|
393
395
|
});
|
|
394
396
|
var BlockingAssetConfigSchema = z.object({
|
|
395
397
|
/** Filename for the asset */
|
|
@@ -738,6 +740,7 @@ function generateLrsBridgeCode(options) {
|
|
|
738
740
|
const lrsProxyEndpoint = options.lrsProxyEndpoint || "";
|
|
739
741
|
const documentGuid = options.documentGuid || "";
|
|
740
742
|
const versionGuid = options.versionGuid || "";
|
|
743
|
+
const packageName = options.packageName || "";
|
|
741
744
|
return `
|
|
742
745
|
// ==========================================================================
|
|
743
746
|
// PATCH-ADAMS LRS BRIDGE v2.2.0
|
|
@@ -770,6 +773,7 @@ function generateLrsBridgeCode(options) {
|
|
|
770
773
|
var LRS_PROXY_ENDPOINT = '${lrsProxyEndpoint}';
|
|
771
774
|
var DOCUMENT_GUID = '${documentGuid}';
|
|
772
775
|
var VERSION_GUID = '${versionGuid}';
|
|
776
|
+
var PACKAGE_NAME = '${packageName}';
|
|
773
777
|
|
|
774
778
|
// Bravais LRS endpoint pattern: https://lrs-{tenant}.bravais.com/XAPI/statements
|
|
775
779
|
// Example: core-acme.bravais.com -> lrs-acme.bravais.com
|
|
@@ -2453,7 +2457,9 @@ function generateLrsBridgeCode(options) {
|
|
|
2453
2457
|
sharedLinkName: null,
|
|
2454
2458
|
// Tenant info
|
|
2455
2459
|
homepage: COURSE_HOMEPAGE || window.location.origin,
|
|
2456
|
-
tenantHomepage: null
|
|
2460
|
+
tenantHomepage: null, // https://{tenant}.bravais.com format
|
|
2461
|
+
// Package info
|
|
2462
|
+
packageName: null // Original SCORM zip filename
|
|
2457
2463
|
};
|
|
2458
2464
|
|
|
2459
2465
|
// 0. Use baked-in GUIDs from PA-Patcher config (highest priority - set at wrap time)
|
|
@@ -2466,6 +2472,10 @@ function generateLrsBridgeCode(options) {
|
|
|
2466
2472
|
info.versionGuid = VERSION_GUID;
|
|
2467
2473
|
log('Version GUID from baked-in config:', VERSION_GUID);
|
|
2468
2474
|
}
|
|
2475
|
+
if (PACKAGE_NAME) {
|
|
2476
|
+
info.packageName = PACKAGE_NAME;
|
|
2477
|
+
log('Package name from baked-in config:', PACKAGE_NAME);
|
|
2478
|
+
}
|
|
2469
2479
|
|
|
2470
2480
|
// 1. Extract shared link token and document ID from URL
|
|
2471
2481
|
info.sharedLinkToken = extractSharedLinkToken();
|
|
@@ -2896,6 +2906,11 @@ function generateLrsBridgeCode(options) {
|
|
|
2896
2906
|
// Resource type
|
|
2897
2907
|
obj.definition.extensions['resourceType'] = LRS.courseInfo.resourceType || 'Course';
|
|
2898
2908
|
|
|
2909
|
+
// Package name (original SCORM zip filename)
|
|
2910
|
+
if (LRS.courseInfo.packageName) {
|
|
2911
|
+
obj.definition.extensions['packageName'] = LRS.courseInfo.packageName;
|
|
2912
|
+
}
|
|
2913
|
+
|
|
2899
2914
|
return obj;
|
|
2900
2915
|
}
|
|
2901
2916
|
|
|
@@ -3729,11 +3744,11 @@ function generateLrsBridgeCode(options) {
|
|
|
3729
3744
|
// Send a course completion statement \u2014 called by skin or auto-detected via SCORM
|
|
3730
3745
|
LRS.sendCompletionStatement = function(data) {
|
|
3731
3746
|
data = data || {};
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3747
|
+
// Cancel any pending SCORM auto-detection to avoid double-fire for same attempt
|
|
3748
|
+
if (scormCompletionDebounce) {
|
|
3749
|
+
clearTimeout(scormCompletionDebounce);
|
|
3750
|
+
scormCompletionDebounce = null;
|
|
3735
3751
|
}
|
|
3736
|
-
scormCompletionSent = true;
|
|
3737
3752
|
|
|
3738
3753
|
var status = data.status || 'completed';
|
|
3739
3754
|
var courseTitle = data.courseTitle || (LRS.courseInfo && LRS.courseInfo.title ? decodeEntities(LRS.courseInfo.title) : decodeEntities(document.title) || 'Course');
|
|
@@ -3763,11 +3778,58 @@ function generateLrsBridgeCode(options) {
|
|
|
3763
3778
|
};
|
|
3764
3779
|
if (data.employeeName) activityDetails.employeeName = data.employeeName;
|
|
3765
3780
|
|
|
3766
|
-
|
|
3767
|
-
|
|
3781
|
+
// 1. Always send "completed" statement
|
|
3782
|
+
log('Sending completed statement, score:', result.score, 'title:', courseTitle);
|
|
3783
|
+
var completedStatement = buildStatement('completed', ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
3784
|
+
sendStatement(completedStatement);
|
|
3785
|
+
|
|
3786
|
+
// 2. Send "passed" or "failed" statement (assessment outcome)
|
|
3787
|
+
if (status === 'passed' || status === 'failed') {
|
|
3788
|
+
log('Sending', status, 'statement');
|
|
3789
|
+
var outcomeStatement = buildStatement(status, ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
3790
|
+
sendStatement(outcomeStatement);
|
|
3791
|
+
}
|
|
3792
|
+
};
|
|
3793
|
+
|
|
3794
|
+
// Send a "terminated" statement \u2014 called by skin close button or auto on page unload
|
|
3795
|
+
var exitStatementSent = false;
|
|
3796
|
+
LRS.sendExitStatement = function(data) {
|
|
3797
|
+
if (exitStatementSent) return;
|
|
3798
|
+
exitStatementSent = true;
|
|
3799
|
+
data = data || {};
|
|
3800
|
+
|
|
3801
|
+
var courseTitle = (LRS.courseInfo && LRS.courseInfo.title) ? decodeEntities(LRS.courseInfo.title) : decodeEntities(document.title) || 'Course';
|
|
3802
|
+
var duration = null;
|
|
3803
|
+
if (LRS.launchTime) {
|
|
3804
|
+
var ms = new Date().getTime() - new Date(LRS.launchTime).getTime();
|
|
3805
|
+
var secs = Math.floor(ms / 1000);
|
|
3806
|
+
var mins = Math.floor(secs / 60);
|
|
3807
|
+
var hrs = Math.floor(mins / 60);
|
|
3808
|
+
duration = 'PT' + (hrs > 0 ? hrs + 'H' : '') + (mins % 60) + 'M' + (secs % 60) + 'S';
|
|
3809
|
+
}
|
|
3810
|
+
|
|
3811
|
+
var activityDetails = {
|
|
3812
|
+
courseTitle: courseTitle,
|
|
3813
|
+
exitSource: data.source || 'page-unload',
|
|
3814
|
+
employeeEmail: LRS.actor && LRS.actor.mbox ? LRS.actor.mbox.replace('mailto:', '') : undefined,
|
|
3815
|
+
employeeId: LRS.employeeId || undefined,
|
|
3816
|
+
sessionDuration: duration,
|
|
3817
|
+
statementsSent: LRS.stats.statementsSent
|
|
3818
|
+
};
|
|
3819
|
+
|
|
3820
|
+
var result = duration ? { duration: duration } : null;
|
|
3821
|
+
log('Sending exit statement, duration:', duration);
|
|
3822
|
+
var statement = buildStatement('terminated', ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
3768
3823
|
sendStatement(statement);
|
|
3769
3824
|
};
|
|
3770
3825
|
|
|
3826
|
+
// Auto-send exit statement on page unload
|
|
3827
|
+
window.addEventListener('beforeunload', function() {
|
|
3828
|
+
if (!exitStatementSent && LRS.actor) {
|
|
3829
|
+
LRS.sendExitStatement({ source: 'page-unload' });
|
|
3830
|
+
}
|
|
3831
|
+
});
|
|
3832
|
+
|
|
3771
3833
|
/**
|
|
3772
3834
|
* Re-extract actor from SCORM after LMSInitialize has been called.
|
|
3773
3835
|
* Call this from the SCORM wrapper after scormInit() succeeds,
|
|
@@ -3874,6 +3936,23 @@ function generateLrsBridgeCode(options) {
|
|
|
3874
3936
|
LRS.interacted({ type: 'choice-branch', id: data.id, name: 'Choice Branch Discarded' });
|
|
3875
3937
|
};
|
|
3876
3938
|
|
|
3939
|
+
// ========================================================================
|
|
3940
|
+
// PUBLIC API \u2014 expose core internals for skin scripts
|
|
3941
|
+
// Usage: window.pa_patcher.lrs.api.sendStatement(stmt)
|
|
3942
|
+
// ========================================================================
|
|
3943
|
+
LRS.api = {
|
|
3944
|
+
sendStatement: sendStatement,
|
|
3945
|
+
buildStatement: buildStatement,
|
|
3946
|
+
buildCourseActivityObject: buildCourseActivityObject,
|
|
3947
|
+
buildXylemeContext: buildXylemeContext,
|
|
3948
|
+
generateUUID: generateUUID,
|
|
3949
|
+
decodeEntities: decodeEntities,
|
|
3950
|
+
extractActor: extractActor,
|
|
3951
|
+
getCachedLessonInfo: getCachedLessonInfo,
|
|
3952
|
+
VERBS: VERBS,
|
|
3953
|
+
ACTIVITY_TYPES: ACTIVITY_TYPES
|
|
3954
|
+
};
|
|
3955
|
+
|
|
3877
3956
|
// ========================================================================
|
|
3878
3957
|
// 8. RISE EVENT INTERCEPTORS
|
|
3879
3958
|
// ========================================================================
|
|
@@ -4439,7 +4518,7 @@ function generateLrsBridgeCode(options) {
|
|
|
4439
4518
|
var scormInteractionsSent = {}; // Track which interactions were already sent
|
|
4440
4519
|
var scormTrackerActive = false; // Set true when SCORM tracker wraps SetValue \u2014 KC handler defers
|
|
4441
4520
|
var scormCourseData = {}; // Accumulates course-level SCORM data (score, status)
|
|
4442
|
-
var
|
|
4521
|
+
var scormCompletionDebounce = null; // Debounce timer \u2014 prevents duplicate fires within same completion event
|
|
4443
4522
|
|
|
4444
4523
|
function interceptScormSetValue(key, value) {
|
|
4445
4524
|
if (typeof key !== 'string') return;
|
|
@@ -4459,12 +4538,15 @@ function generateLrsBridgeCode(options) {
|
|
|
4459
4538
|
if (key === 'cmi.success_status') { scormCourseData.successStatus = String(value).toLowerCase(); }
|
|
4460
4539
|
|
|
4461
4540
|
// Fire course completion statement when status indicates pass/fail/complete
|
|
4462
|
-
|
|
4541
|
+
// Uses debounce (not one-time flag) so retries/new attempts are captured
|
|
4542
|
+
if (key === 'cmi.core.lesson_status' || key === 'cmi.success_status' || key === 'cmi.completion_status') {
|
|
4463
4543
|
var status = String(value).toLowerCase();
|
|
4464
4544
|
if (status === 'passed' || status === 'failed' || status === 'completed') {
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4545
|
+
if (scormCompletionDebounce) clearTimeout(scormCompletionDebounce);
|
|
4546
|
+
scormCompletionDebounce = setTimeout(function() {
|
|
4547
|
+
scormCompletionDebounce = null;
|
|
4548
|
+
sendCourseCompletionStatement(status);
|
|
4549
|
+
}, 500);
|
|
4468
4550
|
}
|
|
4469
4551
|
}
|
|
4470
4552
|
|
|
@@ -4575,11 +4657,6 @@ function generateLrsBridgeCode(options) {
|
|
|
4575
4657
|
|
|
4576
4658
|
var courseTitle = (LRS.courseInfo && LRS.courseInfo.title) ? decodeEntities(LRS.courseInfo.title) : decodeEntities(document.title) || 'Course';
|
|
4577
4659
|
|
|
4578
|
-
// Determine verb
|
|
4579
|
-
var verbKey = 'completed';
|
|
4580
|
-
if (status === 'passed') verbKey = 'passed';
|
|
4581
|
-
if (status === 'failed') verbKey = 'failed';
|
|
4582
|
-
|
|
4583
4660
|
// Build result with score
|
|
4584
4661
|
var result = { completion: true };
|
|
4585
4662
|
|
|
@@ -4605,10 +4682,17 @@ function generateLrsBridgeCode(options) {
|
|
|
4605
4682
|
employeeId: LRS.employeeId || undefined
|
|
4606
4683
|
};
|
|
4607
4684
|
|
|
4608
|
-
|
|
4685
|
+
// 1. Send "completed" statement (course was finished)
|
|
4686
|
+
log('Sending completed statement, score:', result.score, 'title:', courseTitle);
|
|
4687
|
+
var completedStatement = buildStatement('completed', ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
4688
|
+
sendStatement(completedStatement);
|
|
4609
4689
|
|
|
4610
|
-
|
|
4611
|
-
|
|
4690
|
+
// 2. Send "passed" or "failed" statement (assessment outcome)
|
|
4691
|
+
if (status === 'passed' || status === 'failed') {
|
|
4692
|
+
log('Sending', status, 'statement');
|
|
4693
|
+
var outcomeStatement = buildStatement(status, ACTIVITY_TYPES.course, activityDetails, result, null);
|
|
4694
|
+
sendStatement(outcomeStatement);
|
|
4695
|
+
}
|
|
4612
4696
|
|
|
4613
4697
|
logGroupEnd();
|
|
4614
4698
|
}
|
|
@@ -5292,7 +5376,8 @@ function buildJsBeforeOptions(config, metadata) {
|
|
|
5292
5376
|
lrsProxyEndpoint: lrsBridgeConfig.lrsProxyEndpoint,
|
|
5293
5377
|
employeeApiEndpoint: lrsBridgeConfig.employeeApiEndpoint,
|
|
5294
5378
|
documentGuid: lrsBridgeConfig.documentGuid,
|
|
5295
|
-
versionGuid: lrsBridgeConfig.versionGuid
|
|
5379
|
+
versionGuid: lrsBridgeConfig.versionGuid,
|
|
5380
|
+
packageName: lrsBridgeConfig.packageName
|
|
5296
5381
|
};
|
|
5297
5382
|
return {
|
|
5298
5383
|
remoteUrl: `${config.remoteDomain}/${config.localFolders.js}/${config.jsBefore.filename}`,
|
|
@@ -6672,6 +6757,11 @@ var Patcher = class {
|
|
|
6672
6757
|
if (effectiveSkin) {
|
|
6673
6758
|
console.log(`[Patcher] Skin: ${effectiveSkin}`);
|
|
6674
6759
|
}
|
|
6760
|
+
if (options.packageName) {
|
|
6761
|
+
this.config.lrsBridge = this.config.lrsBridge ?? {};
|
|
6762
|
+
this.config.lrsBridge.packageName = options.packageName;
|
|
6763
|
+
console.log(`[Patcher] Package name: ${options.packageName}`);
|
|
6764
|
+
}
|
|
6675
6765
|
const htmlInjector = this.getHtmlInjector(toolInfo.tool);
|
|
6676
6766
|
htmlInjector.setMetadata(metadata);
|
|
6677
6767
|
let fetchedFallbacks = {};
|
|
@@ -6965,6 +7055,7 @@ program.command("patch <input>").description("Patch a Rise course ZIP file").opt
|
|
|
6965
7055
|
if (options.jsAfter) {
|
|
6966
7056
|
patchOptions.jsAfterContent = readFileSync(resolve(options.jsAfter), "utf-8");
|
|
6967
7057
|
}
|
|
7058
|
+
patchOptions.packageName = basename(inputPath);
|
|
6968
7059
|
spinner.text = "Patching package...";
|
|
6969
7060
|
const patcher = new Patcher(validatedConfig);
|
|
6970
7061
|
const { buffer, result } = await patcher.patch(inputBuffer, patchOptions);
|