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 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
- | `useBeaconInsteadOfFetch` | '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. |
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`. |
@@ -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
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
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.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
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
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -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 beaconSuccess = navigator.sendBeacon(url, new Blob([body], { type: contentType }));
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, LogLevelEnum.ERROR, CMIElement);
6009
- this._loggingService.error(formattedMessage);
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 beaconSuccess = navigator.sendBeacon(
16155
- url,
16156
- new Blob([body], { type: "text/plain;charset=UTF-8" })
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
  /**