scorm-again 3.1.5 → 3.2.0
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/README.md +3 -1
- package/dist/cross-frame-api.js +6 -13
- package/dist/cross-frame-api.js.map +1 -1
- package/dist/cross-frame-api.min.js +1 -1
- package/dist/cross-frame-lms.js +2 -6
- package/dist/cross-frame-lms.js.map +1 -1
- package/dist/esm/scorm-again.js +48 -11
- package/dist/esm/scorm-again.js.map +1 -1
- package/dist/esm/scorm-again.min.js +1 -1
- package/dist/esm/scorm-again.min.js.map +1 -1
- package/dist/esm/scorm12.js +46 -10
- package/dist/esm/scorm12.js.map +1 -1
- package/dist/esm/scorm12.min.js +1 -1
- package/dist/esm/scorm12.min.js.map +1 -1
- package/dist/esm/scorm2004.js +48 -11
- package/dist/esm/scorm2004.js.map +1 -1
- package/dist/esm/scorm2004.min.js +1 -1
- package/dist/esm/scorm2004.min.js.map +1 -1
- package/dist/scorm-again.js +697 -1070
- package/dist/scorm-again.js.map +1 -1
- package/dist/scorm-again.min.js +1 -1
- package/dist/scorm12.js +293 -406
- package/dist/scorm12.js.map +1 -1
- package/dist/scorm12.min.js +1 -1
- package/dist/scorm2004.js +597 -911
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +1 -1
- package/dist/types/BaseAPI.d.ts +1 -1
- package/dist/types/interfaces/services.d.ts +1 -1
- package/dist/types/services/AsynchronousHttpService.d.ts +1 -0
- package/dist/types/services/ErrorHandlingService.d.ts +4 -4
- package/dist/types/services/SynchronousHttpService.d.ts +1 -0
- package/dist/types/types/api_types.d.ts +4 -0
- package/dist/types/utilities/core.d.ts +2 -0
- package/package.json +4 -4
package/dist/esm/scorm2004.js
CHANGED
|
@@ -2,6 +2,23 @@ const SECONDS_PER_SECOND = 1;
|
|
|
2
2
|
const SECONDS_PER_MINUTE = 60;
|
|
3
3
|
const SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
|
|
4
4
|
const SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
|
|
5
|
+
const CORS_SAFELISTED_CONTENT_TYPES = [
|
|
6
|
+
"text/plain",
|
|
7
|
+
"application/x-www-form-urlencoded",
|
|
8
|
+
"multipart/form-data"
|
|
9
|
+
];
|
|
10
|
+
function isCorsSafelistedContentType(contentType) {
|
|
11
|
+
const essence = ((contentType || "").split(";")[0] ?? "").trim().toLowerCase();
|
|
12
|
+
return CORS_SAFELISTED_CONTENT_TYPES.includes(essence);
|
|
13
|
+
}
|
|
14
|
+
function isCrossOriginUrl(url) {
|
|
15
|
+
if (typeof location === "undefined" || !location || !location.origin) return false;
|
|
16
|
+
try {
|
|
17
|
+
return new URL(url, location.href).origin !== location.origin;
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
5
22
|
const designations = {
|
|
6
23
|
D: SECONDS_PER_DAY,
|
|
7
24
|
H: SECONDS_PER_HOUR,
|
|
@@ -736,8 +753,10 @@ const DefaultSettings = {
|
|
|
736
753
|
lmsCommitUrl: false,
|
|
737
754
|
dataCommitFormat: "json",
|
|
738
755
|
commitRequestDataType: "application/json;charset=UTF-8",
|
|
756
|
+
terminationCommitContentType: "text/plain;charset=UTF-8",
|
|
739
757
|
autoProgress: false,
|
|
740
758
|
logLevel: LogLevelEnum.ERROR,
|
|
759
|
+
uninitializedGetLogLevel: LogLevelEnum.WARN,
|
|
741
760
|
selfReportSessionTime: false,
|
|
742
761
|
alwaysSendTotalTime: false,
|
|
743
762
|
renderCommonCommitFields: false,
|
|
@@ -5098,7 +5117,9 @@ class AsynchronousHttpService {
|
|
|
5098
5117
|
*/
|
|
5099
5118
|
async performBeacon(url, params) {
|
|
5100
5119
|
const { body, contentType } = this._prepareRequestBody(params);
|
|
5101
|
-
const
|
|
5120
|
+
const beaconContentType = Array.isArray(params) ? contentType : this.settings.terminationCommitContentType;
|
|
5121
|
+
this._warnIfBeaconContentTypeUnsafe(url, beaconContentType);
|
|
5122
|
+
const beaconSuccess = navigator.sendBeacon(url, new Blob([body], { type: beaconContentType }));
|
|
5102
5123
|
return Promise.resolve({
|
|
5103
5124
|
status: beaconSuccess ? 200 : 0,
|
|
5104
5125
|
ok: beaconSuccess,
|
|
@@ -5112,6 +5133,14 @@ class AsynchronousHttpService {
|
|
|
5112
5133
|
})
|
|
5113
5134
|
});
|
|
5114
5135
|
}
|
|
5136
|
+
_warnIfBeaconContentTypeUnsafe(url, contentType) {
|
|
5137
|
+
if (isCrossOriginUrl(url) && !isCorsSafelistedContentType(contentType)) {
|
|
5138
|
+
this.settings.onLogMessage?.(
|
|
5139
|
+
LogLevelEnum.WARN,
|
|
5140
|
+
`sendBeacon to cross-origin URL with non-CORS-safelisted Content-Type "${contentType}" may be silently dropped by the browser (Beacon cannot preflight). Use fetch (useAsynchronousCommits + asyncModeBeaconBehavior:"never") for cross-origin JSON/auth on terminate.`
|
|
5141
|
+
);
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5115
5144
|
/**
|
|
5116
5145
|
* Transforms the response from the LMS to a ResultObject
|
|
5117
5146
|
* @param {Response} response - The response from the LMS
|
|
@@ -5779,14 +5808,14 @@ class ErrorHandlingService {
|
|
|
5779
5808
|
* @param {string} message - The error message
|
|
5780
5809
|
* @throws {ValidationError} - If throwException is true, throws a ValidationError
|
|
5781
5810
|
*/
|
|
5782
|
-
throwSCORMError(CMIElement, errorNumber, message) {
|
|
5811
|
+
throwSCORMError(CMIElement, errorNumber, message, messageLevel = LogLevelEnum.ERROR) {
|
|
5783
5812
|
this._lastDiagnostic = message || "";
|
|
5784
5813
|
if (!message) {
|
|
5785
5814
|
message = this._getLmsErrorMessageDetails(errorNumber, true);
|
|
5786
5815
|
}
|
|
5787
5816
|
const formattedMessage = `SCORM Error ${errorNumber}: ${message}${CMIElement ? ` [Element: ${CMIElement}]` : ""}`;
|
|
5788
|
-
this._apiLog("throwSCORMError", errorNumber + ": " + message,
|
|
5789
|
-
this._loggingService.
|
|
5817
|
+
this._apiLog("throwSCORMError", errorNumber + ": " + message, messageLevel, CMIElement);
|
|
5818
|
+
this._loggingService.log(messageLevel, formattedMessage);
|
|
5790
5819
|
this._lastErrorCode = String(errorNumber);
|
|
5791
5820
|
}
|
|
5792
5821
|
/**
|
|
@@ -15931,15 +15960,22 @@ class SynchronousHttpService {
|
|
|
15931
15960
|
const handledPayload = metadata === void 0 ? this.settings.requestHandler(params) : this.settings.requestHandler(params, metadata);
|
|
15932
15961
|
const requestPayload = handledPayload ?? params;
|
|
15933
15962
|
const { body } = this._prepareRequestBody(requestPayload);
|
|
15934
|
-
const
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
);
|
|
15963
|
+
const beaconContentType = this.settings.terminationCommitContentType;
|
|
15964
|
+
this._warnIfBeaconContentTypeUnsafe(url, beaconContentType);
|
|
15965
|
+
const beaconSuccess = navigator.sendBeacon(url, new Blob([body], { type: beaconContentType }));
|
|
15938
15966
|
return {
|
|
15939
15967
|
result: beaconSuccess ? "true" : "false",
|
|
15940
15968
|
errorCode: beaconSuccess ? 0 : this.error_codes.GENERAL_COMMIT_FAILURE || 391
|
|
15941
15969
|
};
|
|
15942
15970
|
}
|
|
15971
|
+
_warnIfBeaconContentTypeUnsafe(url, contentType) {
|
|
15972
|
+
if (isCrossOriginUrl(url) && !isCorsSafelistedContentType(contentType)) {
|
|
15973
|
+
this.settings.onLogMessage?.(
|
|
15974
|
+
LogLevelEnum.WARN,
|
|
15975
|
+
`sendBeacon to cross-origin URL with non-CORS-safelisted Content-Type "${contentType}" may be silently dropped by the browser (Beacon cannot preflight). Use fetch (useAsynchronousCommits + asyncModeBeaconBehavior:"never") for cross-origin JSON/auth on terminate.`
|
|
15976
|
+
);
|
|
15977
|
+
}
|
|
15978
|
+
}
|
|
15943
15979
|
/**
|
|
15944
15980
|
* Performs a synchronous XMLHttpRequest
|
|
15945
15981
|
* @param {string} url - The URL to send the request to
|
|
@@ -16966,8 +17002,8 @@ class BaseAPI {
|
|
|
16966
17002
|
* // Throw a "not initialized" error
|
|
16967
17003
|
* this.throwSCORMError(301, "The API must be initialized before calling GetValue");
|
|
16968
17004
|
*/
|
|
16969
|
-
throwSCORMError(CMIElement, errorNumber, message) {
|
|
16970
|
-
this._errorHandlingService.throwSCORMError(CMIElement, errorNumber ?? 0, message);
|
|
17005
|
+
throwSCORMError(CMIElement, errorNumber, message, messageLevel) {
|
|
17006
|
+
this._errorHandlingService.throwSCORMError(CMIElement, errorNumber ?? 0, message, messageLevel);
|
|
16971
17007
|
}
|
|
16972
17008
|
/**
|
|
16973
17009
|
* Clears the last SCORM error code when an operation succeeds.
|
|
@@ -23998,7 +24034,8 @@ class Scorm2004API extends BaseAPI {
|
|
|
23998
24034
|
this.throwSCORMError(
|
|
23999
24035
|
CMIElement,
|
|
24000
24036
|
this._error_codes.VALUE_NOT_INITIALIZED ?? 403,
|
|
24001
|
-
`The data model element passed to GetValue (${CMIElement}) has not been initialized
|
|
24037
|
+
`The data model element passed to GetValue (${CMIElement}) has not been initialized.`,
|
|
24038
|
+
this.settings.uninitializedGetLogLevel
|
|
24002
24039
|
);
|
|
24003
24040
|
}
|
|
24004
24041
|
/**
|