UNPKG

scorm-again

Version:

A modern SCORM JavaScript run-time library for SCORM 1.2 and SCORM 2004

3 lines (2 loc) 6.1 kB
this.CrossFrameAPI=function(){"use strict";var e=Object.defineProperty,t=(t,r,s)=>((t,r,s)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[r]=s)(t,"symbol"!=typeof r?r+"":r,s);class r{constructor(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"*",s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:window.parent,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return t(this,"_cache",new Map),t(this,"_cacheTimestamps",new Map),t(this,"_lastError","0"),t(this,"_pending",new Map),t(this,"_counter",0),t(this,"_origin"),t(this,"_targetWindow"),t(this,"_timeout"),t(this,"_heartbeatInterval"),t(this,"_heartbeatTimeout"),t(this,"_destroyed",!1),t(this,"_connected",!0),t(this,"_lastHeartbeatResponse",Date.now()),t(this,"_heartbeatTimer"),t(this,"_eventListeners",new Map),t(this,"_boundOnMessage"),t(this,"_handler",{get:(e,t,s)=>{if("string"!=typeof t||t in e){const r=Reflect.get(e,t,s);return"function"==typeof r?r.bind(e):r}const i=t,n=i.endsWith("GetValue"),a=i.startsWith("LMSSet")||i.endsWith("SetValue"),o="Initialize"===i||"LMSInitialize"===i,h="Terminate"===i||"LMSFinish"===i,c="Commit"===i||"LMSCommit"===i,_="GetErrorString"===i||"LMSGetErrorString"===i,d="GetDiagnostic"===i||"LMSGetDiagnostic"===i;return function(){for(var t=arguments.length,s=Array(t),g=0;t>g;g++)s[g]=arguments[g];if(!r._validateArgs(s))return console.error("CrossFrameAPI: Invalid arguments for "+i),"";if(a&&s.length>=2){const t=s[0];e._cache.set(t,s[1]+""),e._cacheTimestamps.set(t,Date.now()),e._lastError="0"}const l=Date.now();if(e._post(i,s).then(t=>{if(n&&s.length>=1){const r=s[0],i=e._cacheTimestamps.get(r)??0;l>i&&(e._cache.set(r,t+""),e._cacheTimestamps.delete(r)),e._lastError="0"}_&&s.length>=1&&e._cache.set("error_"+s[0],t+""),d&&s.length>=1&&e._cache.set("diag_"+s[0],t+""),"GetLastError"!==i&&"LMSGetLastError"!==i||(e._lastError=t+"")}).catch(t=>e._capture(i,t)),n&&s.length>=1)return e._cache.get(s[0])??"";if(_&&s.length>=1)return e._cache.get("error_"+s[0])??"";if(d&&s.length>=1)return e._cache.get("diag_"+s[0])??"";if(o||h||c||a){const result="true";return e._post("getFlattenedCMI",[]).then(t=>{t&&"object"==typeof t&&Object.entries(t).forEach(t=>{let[r,s]=t;const i=e._cacheTimestamps.get(r)??0;l>i&&(e._cache.set(r,s),e._cacheTimestamps.delete(r))}),e._lastError="0"}).catch(t=>e._capture("getFlattenedCMI",t)),result}return"GetLastError"===i||"LMSGetLastError"===i?e._lastError:""}}}),this._origin=e,this._targetWindow=s,this._timeout=i.timeout??5e3,this._heartbeatInterval=i.heartbeatInterval??3e4,this._heartbeatTimeout=i.heartbeatTimeout??6e4,"*"===e&&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)}static _isValidMessageResponse(e){if("object"!=typeof e||null===e)return!1;if("string"!=typeof e.messageId||0===e.messageId.length)return!1;if(void 0!==e.error){if("object"!=typeof e.error||null===e.error)return!1;const e=e.error;if("string"!=typeof e.message)return!1;if(void 0!==e.code&&"string"!=typeof e.code)return!1}return void 0===e.isHeartbeat||"boolean"==typeof e.isHeartbeat}static _validateArgs(e){return!!Array.isArray(e)}destroy(){if(!this._destroyed){this._destroyed=!0,window.removeEventListener("message",this._boundOnMessage),this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._heartbeatTimer=void 0);for(const e of Array.from(this._pending.values()))clearTimeout(e.timer),e.reject(Error("CrossFrameAPI destroyed"));this._pending.clear(),this._cache.clear(),this._cacheTimestamps.clear(),this._eventListeners.clear()}}on(e,t){this._eventListeners.has(e)||this._eventListeners.set(e,new Set),this._eventListeners.get(e)?.add(t)}off(e,t){this._eventListeners.get(e)?.delete(t)}get connected(){return this._connected}_emit(e){this._eventListeners.get(e.type)?.forEach(t=>t(e))}_startHeartbeat(){this._heartbeatTimer&&clearInterval(this._heartbeatTimer),this._heartbeatTimer=setInterval(()=>{this._destroyed||(Date.now()-this._lastHeartbeatResponse>this._heartbeatTimeout&&this._connected&&(this._connected=!1,this._emit({type:"connectionLost"})),this._sendHeartbeat())},this._heartbeatInterval)}_sendHeartbeat(){const e=`hb-${Date.now()}-${this._counter++}`;this._targetWindow.postMessage({messageId:e,method:"__heartbeat__",params:[],isHeartbeat:!0},this._origin)}_post(e,t){if(this._destroyed)return Promise.reject(Error("CrossFrameAPI destroyed"));const r=`cfapi-${Date.now()}-${this._counter++}`,s=Date.now(),i=t.map(t=>{if("function"!=typeof t)return t;console.warn("Dropping function param when posting SCORM call:",e)});return new Promise((t,n)=>{const a=setTimeout(()=>{this._pending.has(r)&&(this._pending.delete(r),n(Error("Timeout calling "+e)))},this._timeout);this._pending.set(r,{resolve:t,reject:n,timer:a,requestTime:s,method:e}),this._targetWindow.postMessage({messageId:r,method:e,params:i},this._origin)})}_onMessage(e){if(this._destroyed)return;if("*"!==this._origin&&e.origin!==this._origin)return;if(e.source&&e.source!==this._targetWindow)return;if(!r._isValidMessageResponse(e.data))return;const t=e.data;if(t.isHeartbeat)return this._lastHeartbeatResponse=Date.now(),void(this._connected||(this._connected=!0,this._emit({type:"connectionRestored"})));const s=this._pending.get(t.messageId);s&&(clearTimeout(s.timer),this._pending.delete(t.messageId),t.error?("Rate limit exceeded"===t.error.message&&this._emit({type:"rateLimited",method:s.method}),s.reject(t.error)):s.resolve(t.result))}_capture(e,t){let r="Unknown error";t instanceof Error?r=t.message:"object"==typeof t&&null!==t&&"message"in t&&(r=t.message+""),console.error(`CrossFrameAPI ${e} error:`,t);const s=/(?:error code|code)?\s*(\d{3})\b/i.exec(r),i=s?.[1]??"101";this._lastError=i,this._cache.set("error_"+i,r)}}return r}(); //# sourceMappingURL=cross-frame-api.min.js.map