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/README.md
CHANGED
|
@@ -376,6 +376,7 @@ The APIs include several settings to customize the functionality of each API:
|
|
|
376
376
|
| `lmsCommitUrl` | false | url | The URL endpoint of the LMS where data should be sent upon commit. If no value is provided, modules will run as usual, but all method calls will be logged to the console. |
|
|
377
377
|
| `dataCommitFormat` | `json` | `json`, `flattened`, `params` | `json` will send a JSON object to the lmsCommitUrl in the format of <br>`{'cmi': {'core': {...}}`<br><br> `flattened` will send the data in the format <br>`{'cmi.core.exit': 'suspend', 'cmi.core.mode': 'normal'...}`<br><br> `params` will send the data as <br>`?cmi.core.exit=suspend&cmi.core.mode=normal...` |
|
|
378
378
|
| `commitRequestDataType` | 'application/json;charset=UTF-8' | string | This setting is provided in case your LMS expects a different content type or character set. |
|
|
379
|
+
| `terminationCommitContentType` | 'text/plain;charset=UTF-8' | string | Content-Type used for sendBeacon commits. A non-CORS-safelisted value on a cross-origin commit URL may be silently dropped because Beacon cannot preflight; use fetch via `useAsynchronousCommits` with `asyncModeBeaconBehavior: "never"` for cross-origin JSON or custom auth headers. |
|
|
379
380
|
| `renderCommonCommitFields` | false | true/false | Determines whether the API should render the common fields in the commit object. Common fields are `successStatus`, `completionStatus`, `totalTimeSeconds`, `score`, and `runtimeData`. The `runtimeData` field contains the render CMI object. This allows for easier processing on the LMS. |
|
|
380
381
|
| `autoCompleteLessonStatus` | false | true/false | Controls termination behaviour for SCOs that never set `cmi.core.lesson_status`. When false (default), the API leaves the status as `incomplete`; when true, it restores the legacy behaviour of auto-upgrading to `completed`. |
|
|
381
382
|
| `terminateCommitParam` | undefined | string | When set, the terminate-time commit's URL gets `?<name>=true` appended (or `&<name>=true` if `lmsCommitUrl` already has a query string), letting the server distinguish the final commit from heartbeat commits. Applies to normal terminate commits, sendBeacon terminate commits, and offline replays of a terminate commit. |
|
|
@@ -383,11 +384,12 @@ The APIs include several settings to customize the functionality of each API:
|
|
|
383
384
|
| `includeCommitSequence` | false | true/false | When enabled, every commit payload includes a `commitSequence` field with a monotonically increasing number assigned when the commit is captured. Offline-replayed commits keep their original sequence, so servers can reject stale, out-of-order commits. |
|
|
384
385
|
| `autoProgress` | false | true/false | In case Sequencing is being used, you can tell the API to automatically throw the `SequenceNext` event. |
|
|
385
386
|
| `logLevel` | 4 | number \| string \| LogLevelEnum<br><br>`1` => DEBUG<br>`2` => INFO<br>`3` => WARN<br>`4` => ERROR<br>`5` => NONE | By default, the APIs only log error messages. |
|
|
387
|
+
| `uninitializedGetLogLevel` | 3 | number \| string \| LogLevelEnum | (SCORM 2004) Log level for the spec-conforming 'GetValue on an uninitialized element' 403 — e.g. reading `cmi.suspend_data`/`cmi.location` before they are set, which SCOs do to detect a resumed session. Defaults to WARN, so it is hidden under the default `logLevel` of ERROR. Set to `4`/`ERROR` to restore logging these as errors. Does not change the error returned to the SCO. |
|
|
386
388
|
| `mastery_override` | false | true/false | (SCORM 1.2) Used to override a module's `cmi.core.lesson_status` so that a pass/fail is determined based on a mastery score and the user's raw score, rather than using whatever status is provided by the module. An example of this would be if a module is published using a `Complete/Incomplete` final status, but the LMS always wants to receive a `Passed/Failed` for quizzes, then we can use this setting to override the given final status. |
|
|
387
389
|
| `selfReportSessionTime` | false | true/false | Should the API override the default `session_time` reported by the module? Useful when modules don't properly report time. |
|
|
388
390
|
| `alwaysSendTotalTime` | false | true/false | Should the API always send `total_time` when committing to the LMS |
|
|
389
391
|
| `fetchMode` | 'cors' | 'cors', 'no-cors', 'same-origin', 'navigate' | The fetch mode to use when sending requests to the LMS. |
|
|
390
|
-
| `
|
|
392
|
+
| `asyncModeBeaconBehavior` | 'never' | 'always', 'on-terminate', 'never' | Controls when to use the Beacon API instead of fetch for HTTP requests. 'always' uses Beacon for all requests, 'on-terminate' uses Beacon only for final commit during page unload, 'never' always uses fetch. |
|
|
391
393
|
| `xhrWithCredentials` | false | true/false | Sets the withCredentials flag on the request to the LMS |
|
|
392
394
|
| `xhrHeaders` | {} | Object | This allows setting of additional headers on the request to the LMS where the key should be the header name and the value is the value of the header you want to send |
|
|
393
395
|
| `httpService` | null | IHttpService | Advanced: Inject custom HTTP service implementation. Overrides `useAsynchronousCommits`. |
|
package/dist/cross-frame-api.js
CHANGED
|
@@ -9,9 +9,7 @@ this.CrossFrameAPI = (function () {
|
|
|
9
9
|
configurable: true,
|
|
10
10
|
writable: true
|
|
11
11
|
});
|
|
12
|
-
} else
|
|
13
|
-
obj[key] = value;
|
|
14
|
-
}
|
|
12
|
+
} else obj[key] = value;
|
|
15
13
|
return obj;
|
|
16
14
|
}
|
|
17
15
|
function _object_spread(target) {
|
|
@@ -39,9 +37,8 @@ this.CrossFrameAPI = (function () {
|
|
|
39
37
|
}
|
|
40
38
|
function _object_spread_props(target, source) {
|
|
41
39
|
source = source != null ? source : {};
|
|
42
|
-
if (Object.getOwnPropertyDescriptors)
|
|
43
|
-
|
|
44
|
-
} else {
|
|
40
|
+
if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
41
|
+
else {
|
|
45
42
|
ownKeys(Object(source)).forEach(function(key) {
|
|
46
43
|
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
47
44
|
});
|
|
@@ -135,9 +132,7 @@ this.CrossFrameAPI = (function () {
|
|
|
135
132
|
if (Array.isArray(arr)) return arr;
|
|
136
133
|
}
|
|
137
134
|
function _class_call_check(instance, Constructor) {
|
|
138
|
-
if (!(instance instanceof Constructor))
|
|
139
|
-
throw new TypeError("Cannot call a class as a function");
|
|
140
|
-
}
|
|
135
|
+
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
|
|
141
136
|
}
|
|
142
137
|
function _defineProperties(target, props) {
|
|
143
138
|
for(var i = 0; i < props.length; i++){
|
|
@@ -157,9 +152,7 @@ this.CrossFrameAPI = (function () {
|
|
|
157
152
|
"@swc/helpers - instanceof";
|
|
158
153
|
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
159
154
|
return !!right[Symbol.hasInstance](left);
|
|
160
|
-
} else
|
|
161
|
-
return left instanceof right;
|
|
162
|
-
}
|
|
155
|
+
} else return left instanceof right;
|
|
163
156
|
}
|
|
164
157
|
function _iterable_to_array_limit(arr, i) {
|
|
165
158
|
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
@@ -186,7 +179,7 @@ this.CrossFrameAPI = (function () {
|
|
|
186
179
|
return _arr;
|
|
187
180
|
}
|
|
188
181
|
function _non_iterable_rest() {
|
|
189
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance
|
|
182
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
190
183
|
}
|
|
191
184
|
function _sliced_to_array(arr, i) {
|
|
192
185
|
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-frame-api.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cross-frame-api.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
this.CrossFrameAPI=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(t){for(var r=1;arguments.length>r;r++){var n=null!=arguments[r]?arguments[r]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),i.forEach(function(r){e(t,r,n[r])})}return t}function r(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t.push.apply(t,r)}return t}(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}),e}var n={GENERAL:101,INITIALIZATION_FAILED:101,INITIALIZED:101,TERMINATED:101,TERMINATION_FAILURE:101,TERMINATION_BEFORE_INIT:101,MULTIPLE_TERMINATION:101,RETRIEVE_BEFORE_INIT:101,RETRIEVE_AFTER_TERM:101,STORE_BEFORE_INIT:101,STORE_AFTER_TERM:101,COMMIT_BEFORE_INIT:101,COMMIT_AFTER_TERM:101,ARGUMENT_ERROR:101,CHILDREN_ERROR:101,COUNT_ERROR:101,GENERAL_GET_FAILURE:101,GENERAL_SET_FAILURE:101,GENERAL_COMMIT_FAILURE:101,UNDEFINED_DATA_MODEL:101,UNIMPLEMENTED_ELEMENT:101,VALUE_NOT_INITIALIZED:101,INVALID_SET_VALUE:101,READ_ONLY_ELEMENT:101,WRITE_ONLY_ELEMENT:101,TYPE_MISMATCH:101,VALUE_OUT_OF_RANGE:101,DEPENDENCY_NOT_ESTABLISHED:101};function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);t>r;r++)n[r]=e[r];return n}function o(e,t){for(var r=0;t.length>r;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function a(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e}r(t({},n),{RETRIEVE_BEFORE_INIT:301,STORE_BEFORE_INIT:301,COMMIT_BEFORE_INIT:301,ARGUMENT_ERROR:201,CHILDREN_ERROR:202,COUNT_ERROR:203,UNDEFINED_DATA_MODEL:401,UNIMPLEMENTED_ELEMENT:401,VALUE_NOT_INITIALIZED:301,INVALID_SET_VALUE:402,READ_ONLY_ELEMENT:403,WRITE_ONLY_ELEMENT:404,TYPE_MISMATCH:405,VALUE_OUT_OF_RANGE:405,DEPENDENCY_NOT_ESTABLISHED:408}),r(t({},n),{INITIALIZATION_FAILED:102,INITIALIZED:103,TERMINATED:104,TERMINATION_FAILURE:111,TERMINATION_BEFORE_INIT:112,MULTIPLE_TERMINATION:113,MULTIPLE_TERMINATIONS:113,RETRIEVE_BEFORE_INIT:122,RETRIEVE_AFTER_TERM:123,STORE_BEFORE_INIT:132,STORE_AFTER_TERM:133,COMMIT_BEFORE_INIT:142,COMMIT_AFTER_TERM:143,ARGUMENT_ERROR:201,GENERAL_GET_FAILURE:301,GENERAL_SET_FAILURE:351,GENERAL_COMMIT_FAILURE:391,UNDEFINED_DATA_MODEL:401,UNIMPLEMENTED_ELEMENT:402,VALUE_NOT_INITIALIZED:403,READ_ONLY_ELEMENT:404,WRITE_ONLY_ELEMENT:405,TYPE_MISMATCH:406,VALUE_OUT_OF_RANGE:407,DEPENDENCY_NOT_ESTABLISHED:408});var s=Object.defineProperty,c=function(e,t,r){return function(e,t,r){return t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r}(e,"symbol"!==(void 0===t?"undefined":a(t))?t+"":t,r)},_=function(){function e(){var t,r,n,o=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"*",s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:window.parent,_=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),c(this,"_cache",new Map),c(this,"_cacheTimestamps",new Map),c(this,"_lastError","0"),c(this,"_pending",new Map),c(this,"_counter",0),c(this,"_origin"),c(this,"_targetWindow"),c(this,"_timeout"),c(this,"_heartbeatInterval"),c(this,"_heartbeatTimeout"),c(this,"_destroyed",!1),c(this,"_connected",!0),c(this,"_lastHeartbeatResponse",Date.now()),c(this,"_heartbeatTimer"),c(this,"_eventListeners",new Map),c(this,"_boundOnMessage"),c(this,"_handler",{get:function(t,r,n){if("string"!=typeof r||r in t){var o=Reflect.get(t,r,n);return"function"==typeof o?o.bind(t):o}var s=r,c=s.endsWith("GetValue"),_=s.startsWith("LMSSet")||s.endsWith("SetValue"),E="Initialize"===s||"LMSInitialize"===s,l="Terminate"===s||"LMSFinish"===s,u="Commit"===s||"LMSCommit"===s,h="GetErrorString"===s||"LMSGetErrorString"===s,d="GetDiagnostic"===s||"LMSGetDiagnostic"===s;return function(){for(var r=arguments.length,n=Array(r),o=0;r>o;o++)n[o]=arguments[o];if(!e._validateArgs(n))return console.error("CrossFrameAPI: Invalid arguments for ".concat(s)),"";if(_&&n.length>=2){var T=n[0];t._cache.set(T,n[1]+""),t._cacheTimestamps.set(T,Date.now()),t._lastError="0"}var I,f,m,g=Date.now();return t._post(s,n).then(function(e){if(c&&n.length>=1){var r,i=n[0],o=null!==(r=t._cacheTimestamps.get(i))&&void 0!==r?r:0;g>o&&(t._cache.set(i,e+""),t._cacheTimestamps.delete(i)),t._lastError="0"}h&&n.length>=1&&t._cache.set("error_".concat(n[0]+""),e+""),d&&n.length>=1&&t._cache.set("diag_".concat(n[0]+""),e+""),"GetLastError"!==s&&"LMSGetLastError"!==s||(t._lastError=e+"")}).catch(function(e){return t._capture(s,e)}),c&&n.length>=1?null!==(I=t._cache.get(n[0]))&&void 0!==I?I:"":h&&n.length>=1?null!==(f=t._cache.get("error_".concat(n[0]+"")))&&void 0!==f?f:"":d&&n.length>=1?null!==(m=t._cache.get("diag_".concat(n[0]+"")))&&void 0!==m?m:"":E||l||u||_?(t._post("getFlattenedCMI",[]).then(function(e){e&&"object"===(void 0===e?"undefined":a(e))&&Object.entries(e).forEach(function(e){var r,n,o,a=(o=2,function(e){if(Array.isArray(e))return e}(n=e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,i,o=[],a=!0,s=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(o.push(n.value),!t||o.length!==t);a=!0);}catch(e){s=!0,i=e}finally{try{a||null==r.return||r.return()}finally{if(s)throw i}}return o}}(n,o)||function(e,t){if(e){if("string"==typeof e)return i(e,t);var r={}.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(r):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?i(e,t):void 0}}(n,o)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),s=a[0],c=a[1],_=null!==(r=t._cacheTimestamps.get(s))&&void 0!==r?r:0;g>_&&(t._cache.set(s,c),t._cacheTimestamps.delete(s))}),t._lastError="0"}).catch(function(e){return t._capture("getFlattenedCMI",e)}),"true"):"GetLastError"===s||"LMSGetLastError"===s?t._lastError:""}}}),this._origin=o,this._targetWindow=s,this._timeout=null!==(t=_.timeout)&&void 0!==t?t:5e3,this._heartbeatInterval=null!==(r=_.heartbeatInterval)&&void 0!==r?r:3e4,this._heartbeatTimeout=null!==(n=_.heartbeatTimeout)&&void 0!==n?n:6e4,"*"===o&&console.warn("CrossFrameAPI: Using wildcard origin ('*') allows any origin to receive messages. This is insecure for production use. Specify an explicit origin (e.g., 'https://lms.example.com') to restrict message recipients."),this._boundOnMessage=this._onMessage.bind(this),window.addEventListener("message",this._boundOnMessage),this._startHeartbeat(),new Proxy(this,this._handler)}var t,r,s;return t=e,s=[{key:"_isValidMessageResponse",value:function(e){if("object"!==(void 0===e?"undefined":a(e))||null===e)return!1;var t=e;if("string"!=typeof t.messageId||0===t.messageId.length)return!1;if(void 0!==t.error){if("object"!==a(t.error)||null===t.error)return!1;var r=t.error;if("string"!=typeof r.message)return!1;if(void 0!==r.code&&"string"!=typeof r.code)return!1}return void 0===t.isHeartbeat||"boolean"==typeof t.isHeartbeat}},{key:"_validateArgs",value:function(e){return!!Array.isArray(e)}}],(r=[{key:"destroy",value:function(){if(!this._destroyed){this._destroyed=!0,window.removeEventListener("message",this._boundOnMessage),this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._heartbeatTimer=void 0);var e=!0,t=!1,r=void 0;try{for(var n,i=Array.from(this._pending.values())[Symbol.iterator]();!(e=(n=i.next()).done);e=!0){var o=n.value;clearTimeout(o.timer),o.reject(Error("CrossFrameAPI destroyed"))}}catch(e){t=!0,r=e}finally{try{e||null==i.return||i.return()}finally{if(t)throw r}}this._pending.clear(),this._cache.clear(),this._cacheTimestamps.clear(),this._eventListeners.clear()}}},{key:"on",value:function(e,t){var r;this._eventListeners.has(e)||this._eventListeners.set(e,new Set),null===(r=this._eventListeners.get(e))||void 0===r||r.add(t)}},{key:"off",value:function(e,t){var r;null===(r=this._eventListeners.get(e))||void 0===r||r.delete(t)}},{key:"connected",get:function(){return this._connected}},{key:"_emit",value:function(e){var t;null===(t=this._eventListeners.get(e.type))||void 0===t||t.forEach(function(t){return t(e)})}},{key:"_startHeartbeat",value:function(){var e=this;this._heartbeatTimer&&clearInterval(this._heartbeatTimer),this._heartbeatTimer=setInterval(function(){e._destroyed||(Date.now()-e._lastHeartbeatResponse>e._heartbeatTimeout&&e._connected&&(e._connected=!1,e._emit({type:"connectionLost"})),e._sendHeartbeat())},this._heartbeatInterval)}},{key:"_sendHeartbeat",value:function(){var e="hb-".concat(Date.now(),"-").concat(this._counter++);this._targetWindow.postMessage({messageId:e,method:"__heartbeat__",params:[],isHeartbeat:!0},this._origin)}},{key:"_post",value:function(e,t){var r=this;if(this._destroyed)return Promise.reject(Error("CrossFrameAPI destroyed"));var n="cfapi-".concat(Date.now(),"-").concat(this._counter++),i=Date.now(),o=t.map(function(t){if("function"!=typeof t)return t;console.warn("Dropping function param when posting SCORM call:",e)});return new Promise(function(t,a){var s=setTimeout(function(){r._pending.has(n)&&(r._pending.delete(n),a(Error("Timeout calling ".concat(e))))},r._timeout);r._pending.set(n,{resolve:t,reject:a,timer:s,requestTime:i,method:e}),r._targetWindow.postMessage({messageId:n,method:e,params:o},r._origin)})}},{key:"_onMessage",value:function(t){if(!this._destroyed&&("*"===this._origin||t.origin===this._origin)&&(!t.source||t.source===this._targetWindow)&&e._isValidMessageResponse(t.data)){var r=t.data;if(r.isHeartbeat)return this._lastHeartbeatResponse=Date.now(),void(this._connected||(this._connected=!0,this._emit({type:"connectionRestored"})));var n=this._pending.get(r.messageId);n&&(clearTimeout(n.timer),this._pending.delete(r.messageId),r.error?("Rate limit exceeded"===r.error.message&&this._emit({type:"rateLimited",method:n.method}),n.reject(r.error)):n.resolve(r.result))}}},{key:"_capture",value:function(e,t){var r,i,o,s="Unknown error";i=t,(null!=(o=Error)&&"undefined"!=typeof Symbol&&o[Symbol.hasInstance]?o[Symbol.hasInstance](i):i instanceof o)?s=t.message:"object"===(void 0===t?"undefined":a(t))&&null!==t&&"message"in t&&(s=t.message+""),console.error("CrossFrameAPI ".concat(e," error:"),t);var c=/(?:error code|code)?\s*(\d{3})\b/i.exec(s),_=null!==(r=null==c?void 0:c[1])&&void 0!==r?r:n.GENERAL+"";this._lastError=_,this._cache.set("error_".concat(_),s)}}])&&o(t.prototype,r),s&&o(t,s),e}();return _}();
|
|
1
|
+
this.CrossFrameAPI=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(t){for(var r=1;arguments.length>r;r++){var n=null!=arguments[r]?arguments[r]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),i.forEach(function(r){e(t,r,n[r])})}return t}function r(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t.push.apply(t,r)}return t}(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}),e}var n={GENERAL:101,INITIALIZATION_FAILED:101,INITIALIZED:101,TERMINATED:101,TERMINATION_FAILURE:101,TERMINATION_BEFORE_INIT:101,MULTIPLE_TERMINATION:101,RETRIEVE_BEFORE_INIT:101,RETRIEVE_AFTER_TERM:101,STORE_BEFORE_INIT:101,STORE_AFTER_TERM:101,COMMIT_BEFORE_INIT:101,COMMIT_AFTER_TERM:101,ARGUMENT_ERROR:101,CHILDREN_ERROR:101,COUNT_ERROR:101,GENERAL_GET_FAILURE:101,GENERAL_SET_FAILURE:101,GENERAL_COMMIT_FAILURE:101,UNDEFINED_DATA_MODEL:101,UNIMPLEMENTED_ELEMENT:101,VALUE_NOT_INITIALIZED:101,INVALID_SET_VALUE:101,READ_ONLY_ELEMENT:101,WRITE_ONLY_ELEMENT:101,TYPE_MISMATCH:101,VALUE_OUT_OF_RANGE:101,DEPENDENCY_NOT_ESTABLISHED:101};function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);t>r;r++)n[r]=e[r];return n}function o(e,t){for(var r=0;t.length>r;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function a(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e}r(t({},n),{RETRIEVE_BEFORE_INIT:301,STORE_BEFORE_INIT:301,COMMIT_BEFORE_INIT:301,ARGUMENT_ERROR:201,CHILDREN_ERROR:202,COUNT_ERROR:203,UNDEFINED_DATA_MODEL:401,UNIMPLEMENTED_ELEMENT:401,VALUE_NOT_INITIALIZED:301,INVALID_SET_VALUE:402,READ_ONLY_ELEMENT:403,WRITE_ONLY_ELEMENT:404,TYPE_MISMATCH:405,VALUE_OUT_OF_RANGE:405,DEPENDENCY_NOT_ESTABLISHED:408}),r(t({},n),{INITIALIZATION_FAILED:102,INITIALIZED:103,TERMINATED:104,TERMINATION_FAILURE:111,TERMINATION_BEFORE_INIT:112,MULTIPLE_TERMINATION:113,MULTIPLE_TERMINATIONS:113,RETRIEVE_BEFORE_INIT:122,RETRIEVE_AFTER_TERM:123,STORE_BEFORE_INIT:132,STORE_AFTER_TERM:133,COMMIT_BEFORE_INIT:142,COMMIT_AFTER_TERM:143,ARGUMENT_ERROR:201,GENERAL_GET_FAILURE:301,GENERAL_SET_FAILURE:351,GENERAL_COMMIT_FAILURE:391,UNDEFINED_DATA_MODEL:401,UNIMPLEMENTED_ELEMENT:402,VALUE_NOT_INITIALIZED:403,READ_ONLY_ELEMENT:404,WRITE_ONLY_ELEMENT:405,TYPE_MISMATCH:406,VALUE_OUT_OF_RANGE:407,DEPENDENCY_NOT_ESTABLISHED:408});var s=Object.defineProperty,c=function(e,t,r){return function(e,t,r){return t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r}(e,"symbol"!==(void 0===t?"undefined":a(t))?t+"":t,r)},_=function(){function e(){var t,r,n,o=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"*",s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:window.parent,_=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),c(this,"_cache",new Map),c(this,"_cacheTimestamps",new Map),c(this,"_lastError","0"),c(this,"_pending",new Map),c(this,"_counter",0),c(this,"_origin"),c(this,"_targetWindow"),c(this,"_timeout"),c(this,"_heartbeatInterval"),c(this,"_heartbeatTimeout"),c(this,"_destroyed",!1),c(this,"_connected",!0),c(this,"_lastHeartbeatResponse",Date.now()),c(this,"_heartbeatTimer"),c(this,"_eventListeners",new Map),c(this,"_boundOnMessage"),c(this,"_handler",{get:function(t,r,n){if("string"!=typeof r||r in t){var o=Reflect.get(t,r,n);return"function"==typeof o?o.bind(t):o}var s=r,c=s.endsWith("GetValue"),_=s.startsWith("LMSSet")||s.endsWith("SetValue"),E="Initialize"===s||"LMSInitialize"===s,l="Terminate"===s||"LMSFinish"===s,u="Commit"===s||"LMSCommit"===s,h="GetErrorString"===s||"LMSGetErrorString"===s,d="GetDiagnostic"===s||"LMSGetDiagnostic"===s;return function(){for(var r=arguments.length,n=Array(r),o=0;r>o;o++)n[o]=arguments[o];if(!e._validateArgs(n))return console.error("CrossFrameAPI: Invalid arguments for ".concat(s)),"";if(_&&n.length>=2){var T=n[0];t._cache.set(T,n[1]+""),t._cacheTimestamps.set(T,Date.now()),t._lastError="0"}var I,f,m,g=Date.now();return t._post(s,n).then(function(e){if(c&&n.length>=1){var r,i=n[0],o=null!==(r=t._cacheTimestamps.get(i))&&void 0!==r?r:0;g>o&&(t._cache.set(i,e+""),t._cacheTimestamps.delete(i)),t._lastError="0"}h&&n.length>=1&&t._cache.set("error_".concat(n[0]+""),e+""),d&&n.length>=1&&t._cache.set("diag_".concat(n[0]+""),e+""),"GetLastError"!==s&&"LMSGetLastError"!==s||(t._lastError=e+"")}).catch(function(e){return t._capture(s,e)}),c&&n.length>=1?null!==(I=t._cache.get(n[0]))&&void 0!==I?I:"":h&&n.length>=1?null!==(f=t._cache.get("error_".concat(n[0]+"")))&&void 0!==f?f:"":d&&n.length>=1?null!==(m=t._cache.get("diag_".concat(n[0]+"")))&&void 0!==m?m:"":E||l||u||_?(t._post("getFlattenedCMI",[]).then(function(e){e&&"object"===(void 0===e?"undefined":a(e))&&Object.entries(e).forEach(function(e){var r,n,o,a=(o=2,function(e){if(Array.isArray(e))return e}(n=e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,i,o=[],a=!0,s=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(o.push(n.value),!t||o.length!==t);a=!0);}catch(e){s=!0,i=e}finally{try{a||null==r.return||r.return()}finally{if(s)throw i}}return o}}(n,o)||function(e,t){if(e){if("string"==typeof e)return i(e,t);var r={}.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(r):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?i(e,t):void 0}}(n,o)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),s=a[0],c=a[1],_=null!==(r=t._cacheTimestamps.get(s))&&void 0!==r?r:0;g>_&&(t._cache.set(s,c),t._cacheTimestamps.delete(s))}),t._lastError="0"}).catch(function(e){return t._capture("getFlattenedCMI",e)}),"true"):"GetLastError"===s||"LMSGetLastError"===s?t._lastError:""}}}),this._origin=o,this._targetWindow=s,this._timeout=null!==(t=_.timeout)&&void 0!==t?t:5e3,this._heartbeatInterval=null!==(r=_.heartbeatInterval)&&void 0!==r?r:3e4,this._heartbeatTimeout=null!==(n=_.heartbeatTimeout)&&void 0!==n?n:6e4,"*"===o&&console.warn("CrossFrameAPI: Using wildcard origin ('*') allows any origin to receive messages. This is insecure for production use. Specify an explicit origin (e.g., 'https://lms.example.com') to restrict message recipients."),this._boundOnMessage=this._onMessage.bind(this),window.addEventListener("message",this._boundOnMessage),this._startHeartbeat(),new Proxy(this,this._handler)}var t,r,s;return t=e,s=[{key:"_isValidMessageResponse",value:function(e){if("object"!==(void 0===e?"undefined":a(e))||null===e)return!1;var t=e;if("string"!=typeof t.messageId||0===t.messageId.length)return!1;if(void 0!==t.error){if("object"!==a(t.error)||null===t.error)return!1;var r=t.error;if("string"!=typeof r.message)return!1;if(void 0!==r.code&&"string"!=typeof r.code)return!1}return void 0===t.isHeartbeat||"boolean"==typeof t.isHeartbeat}},{key:"_validateArgs",value:function(e){return!!Array.isArray(e)}}],(r=[{key:"destroy",value:function(){if(!this._destroyed){this._destroyed=!0,window.removeEventListener("message",this._boundOnMessage),this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._heartbeatTimer=void 0);var e=!0,t=!1,r=void 0;try{for(var n,i=Array.from(this._pending.values())[Symbol.iterator]();!(e=(n=i.next()).done);e=!0){var o=n.value;clearTimeout(o.timer),o.reject(Error("CrossFrameAPI destroyed"))}}catch(e){t=!0,r=e}finally{try{e||null==i.return||i.return()}finally{if(t)throw r}}this._pending.clear(),this._cache.clear(),this._cacheTimestamps.clear(),this._eventListeners.clear()}}},{key:"on",value:function(e,t){var r;this._eventListeners.has(e)||this._eventListeners.set(e,new Set),null===(r=this._eventListeners.get(e))||void 0===r||r.add(t)}},{key:"off",value:function(e,t){var r;null===(r=this._eventListeners.get(e))||void 0===r||r.delete(t)}},{key:"connected",get:function(){return this._connected}},{key:"_emit",value:function(e){var t;null===(t=this._eventListeners.get(e.type))||void 0===t||t.forEach(function(t){return t(e)})}},{key:"_startHeartbeat",value:function(){var e=this;this._heartbeatTimer&&clearInterval(this._heartbeatTimer),this._heartbeatTimer=setInterval(function(){e._destroyed||(Date.now()-e._lastHeartbeatResponse>e._heartbeatTimeout&&e._connected&&(e._connected=!1,e._emit({type:"connectionLost"})),e._sendHeartbeat())},this._heartbeatInterval)}},{key:"_sendHeartbeat",value:function(){var e="hb-".concat(Date.now(),"-").concat(this._counter++);this._targetWindow.postMessage({messageId:e,method:"__heartbeat__",params:[],isHeartbeat:!0},this._origin)}},{key:"_post",value:function(e,t){var r=this;if(this._destroyed)return Promise.reject(Error("CrossFrameAPI destroyed"));var n="cfapi-".concat(Date.now(),"-").concat(this._counter++),i=Date.now(),o=t.map(function(t){if("function"!=typeof t)return t;console.warn("Dropping function param when posting SCORM call:",e)});return new Promise(function(t,a){var s=setTimeout(function(){r._pending.has(n)&&(r._pending.delete(n),a(Error("Timeout calling ".concat(e))))},r._timeout);r._pending.set(n,{resolve:t,reject:a,timer:s,requestTime:i,method:e}),r._targetWindow.postMessage({messageId:n,method:e,params:o},r._origin)})}},{key:"_onMessage",value:function(t){if(!this._destroyed&&("*"===this._origin||t.origin===this._origin)&&(!t.source||t.source===this._targetWindow)&&e._isValidMessageResponse(t.data)){var r=t.data;if(r.isHeartbeat)return this._lastHeartbeatResponse=Date.now(),void(this._connected||(this._connected=!0,this._emit({type:"connectionRestored"})));var n=this._pending.get(r.messageId);n&&(clearTimeout(n.timer),this._pending.delete(r.messageId),r.error?("Rate limit exceeded"===r.error.message&&this._emit({type:"rateLimited",method:n.method}),n.reject(r.error)):n.resolve(r.result))}}},{key:"_capture",value:function(e,t){var r,i,o,s="Unknown error";i=t,(null!=(o=Error)&&"undefined"!=typeof Symbol&&o[Symbol.hasInstance]?o[Symbol.hasInstance](i):i instanceof o)?s=t.message:"object"===(void 0===t?"undefined":a(t))&&null!==t&&"message"in t&&(s=t.message+""),console.error("CrossFrameAPI ".concat(e," error:"),t);var c=/(?:error code|code)?\s*(\d{3})\b/i.exec(s),_=null!==(r=null==c?void 0:c[1])&&void 0!==r?r:n.GENERAL+"";this._lastError=_,this._cache.set("error_".concat(_),s)}}])&&o(t.prototype,r),s&&o(t,s),e}();return _}();
|
|
2
2
|
//# sourceMappingURL=cross-frame-api.min.js.map
|
package/dist/cross-frame-lms.js
CHANGED
|
@@ -2,9 +2,7 @@ this.CrossFrameLMS = (function () {
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
function _class_call_check(instance, Constructor) {
|
|
5
|
-
if (!(instance instanceof Constructor))
|
|
6
|
-
throw new TypeError("Cannot call a class as a function");
|
|
7
|
-
}
|
|
5
|
+
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
|
|
8
6
|
}
|
|
9
7
|
function _defineProperties(target, props) {
|
|
10
8
|
for(var i = 0; i < props.length; i++){
|
|
@@ -24,9 +22,7 @@ this.CrossFrameLMS = (function () {
|
|
|
24
22
|
"@swc/helpers - instanceof";
|
|
25
23
|
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
26
24
|
return !!right[Symbol.hasInstance](left);
|
|
27
|
-
} else
|
|
28
|
-
return left instanceof right;
|
|
29
|
-
}
|
|
25
|
+
} else return left instanceof right;
|
|
30
26
|
}
|
|
31
27
|
function _type_of(obj) {
|
|
32
28
|
"@swc/helpers - typeof";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-frame-lms.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cross-frame-lms.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/esm/scorm-again.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,
|
|
@@ -814,8 +831,10 @@ const DefaultSettings = {
|
|
|
814
831
|
lmsCommitUrl: false,
|
|
815
832
|
dataCommitFormat: "json",
|
|
816
833
|
commitRequestDataType: "application/json;charset=UTF-8",
|
|
834
|
+
terminationCommitContentType: "text/plain;charset=UTF-8",
|
|
817
835
|
autoProgress: false,
|
|
818
836
|
logLevel: LogLevelEnum.ERROR,
|
|
837
|
+
uninitializedGetLogLevel: LogLevelEnum.WARN,
|
|
819
838
|
selfReportSessionTime: false,
|
|
820
839
|
alwaysSendTotalTime: false,
|
|
821
840
|
renderCommonCommitFields: false,
|
|
@@ -5318,7 +5337,9 @@ class AsynchronousHttpService {
|
|
|
5318
5337
|
*/
|
|
5319
5338
|
async performBeacon(url, params) {
|
|
5320
5339
|
const { body, contentType } = this._prepareRequestBody(params);
|
|
5321
|
-
const
|
|
5340
|
+
const beaconContentType = Array.isArray(params) ? contentType : this.settings.terminationCommitContentType;
|
|
5341
|
+
this._warnIfBeaconContentTypeUnsafe(url, beaconContentType);
|
|
5342
|
+
const beaconSuccess = navigator.sendBeacon(url, new Blob([body], { type: beaconContentType }));
|
|
5322
5343
|
return Promise.resolve({
|
|
5323
5344
|
status: beaconSuccess ? 200 : 0,
|
|
5324
5345
|
ok: beaconSuccess,
|
|
@@ -5332,6 +5353,14 @@ class AsynchronousHttpService {
|
|
|
5332
5353
|
})
|
|
5333
5354
|
});
|
|
5334
5355
|
}
|
|
5356
|
+
_warnIfBeaconContentTypeUnsafe(url, contentType) {
|
|
5357
|
+
if (isCrossOriginUrl(url) && !isCorsSafelistedContentType(contentType)) {
|
|
5358
|
+
this.settings.onLogMessage?.(
|
|
5359
|
+
LogLevelEnum.WARN,
|
|
5360
|
+
`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.`
|
|
5361
|
+
);
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5335
5364
|
/**
|
|
5336
5365
|
* Transforms the response from the LMS to a ResultObject
|
|
5337
5366
|
* @param {Response} response - The response from the LMS
|
|
@@ -5999,14 +6028,14 @@ class ErrorHandlingService {
|
|
|
5999
6028
|
* @param {string} message - The error message
|
|
6000
6029
|
* @throws {ValidationError} - If throwException is true, throws a ValidationError
|
|
6001
6030
|
*/
|
|
6002
|
-
throwSCORMError(CMIElement, errorNumber, message) {
|
|
6031
|
+
throwSCORMError(CMIElement, errorNumber, message, messageLevel = LogLevelEnum.ERROR) {
|
|
6003
6032
|
this._lastDiagnostic = message || "";
|
|
6004
6033
|
if (!message) {
|
|
6005
6034
|
message = this._getLmsErrorMessageDetails(errorNumber, true);
|
|
6006
6035
|
}
|
|
6007
6036
|
const formattedMessage = `SCORM Error ${errorNumber}: ${message}${CMIElement ? ` [Element: ${CMIElement}]` : ""}`;
|
|
6008
|
-
this._apiLog("throwSCORMError", errorNumber + ": " + message,
|
|
6009
|
-
this._loggingService.
|
|
6037
|
+
this._apiLog("throwSCORMError", errorNumber + ": " + message, messageLevel, CMIElement);
|
|
6038
|
+
this._loggingService.log(messageLevel, formattedMessage);
|
|
6010
6039
|
this._lastErrorCode = String(errorNumber);
|
|
6011
6040
|
}
|
|
6012
6041
|
/**
|
|
@@ -16151,15 +16180,22 @@ class SynchronousHttpService {
|
|
|
16151
16180
|
const handledPayload = metadata === void 0 ? this.settings.requestHandler(params) : this.settings.requestHandler(params, metadata);
|
|
16152
16181
|
const requestPayload = handledPayload ?? params;
|
|
16153
16182
|
const { body } = this._prepareRequestBody(requestPayload);
|
|
16154
|
-
const
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
);
|
|
16183
|
+
const beaconContentType = this.settings.terminationCommitContentType;
|
|
16184
|
+
this._warnIfBeaconContentTypeUnsafe(url, beaconContentType);
|
|
16185
|
+
const beaconSuccess = navigator.sendBeacon(url, new Blob([body], { type: beaconContentType }));
|
|
16158
16186
|
return {
|
|
16159
16187
|
result: beaconSuccess ? "true" : "false",
|
|
16160
16188
|
errorCode: beaconSuccess ? 0 : this.error_codes.GENERAL_COMMIT_FAILURE || 391
|
|
16161
16189
|
};
|
|
16162
16190
|
}
|
|
16191
|
+
_warnIfBeaconContentTypeUnsafe(url, contentType) {
|
|
16192
|
+
if (isCrossOriginUrl(url) && !isCorsSafelistedContentType(contentType)) {
|
|
16193
|
+
this.settings.onLogMessage?.(
|
|
16194
|
+
LogLevelEnum.WARN,
|
|
16195
|
+
`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.`
|
|
16196
|
+
);
|
|
16197
|
+
}
|
|
16198
|
+
}
|
|
16163
16199
|
/**
|
|
16164
16200
|
* Performs a synchronous XMLHttpRequest
|
|
16165
16201
|
* @param {string} url - The URL to send the request to
|
|
@@ -17186,8 +17222,8 @@ class BaseAPI {
|
|
|
17186
17222
|
* // Throw a "not initialized" error
|
|
17187
17223
|
* this.throwSCORMError(301, "The API must be initialized before calling GetValue");
|
|
17188
17224
|
*/
|
|
17189
|
-
throwSCORMError(CMIElement, errorNumber, message) {
|
|
17190
|
-
this._errorHandlingService.throwSCORMError(CMIElement, errorNumber ?? 0, message);
|
|
17225
|
+
throwSCORMError(CMIElement, errorNumber, message, messageLevel) {
|
|
17226
|
+
this._errorHandlingService.throwSCORMError(CMIElement, errorNumber ?? 0, message, messageLevel);
|
|
17191
17227
|
}
|
|
17192
17228
|
/**
|
|
17193
17229
|
* Clears the last SCORM error code when an operation succeeds.
|
|
@@ -26189,7 +26225,8 @@ class Scorm2004API extends BaseAPI {
|
|
|
26189
26225
|
this.throwSCORMError(
|
|
26190
26226
|
CMIElement,
|
|
26191
26227
|
this._error_codes.VALUE_NOT_INITIALIZED ?? 403,
|
|
26192
|
-
`The data model element passed to GetValue (${CMIElement}) has not been initialized
|
|
26228
|
+
`The data model element passed to GetValue (${CMIElement}) has not been initialized.`,
|
|
26229
|
+
this.settings.uninitializedGetLogLevel
|
|
26193
26230
|
);
|
|
26194
26231
|
}
|
|
26195
26232
|
/**
|