fix(iframe): [PKG-IFRAME-03] release failed setup and bind message peers

This commit is contained in:
Harvey Zhao committed 2026-09-13 00:03:37 +08:00
1 parent b8d03e7366
commit b8cdafedd1
23 files changed
+7940 -32

No files matched your search

+1 -1
View File
@@ -4,4 +4,4 @@
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";const e=new WeakMap;let t=0;class s{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:o=0}){if(!s.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');window.parent.postMessage({type:e,data:t,id:o},"*")}static async onMessage(e){if(!s.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');const{type:t,data:o,id:i}=e.data;if("commit"===t)try{if(o.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${o}\n})`,t=await new Function(e)();s.postMessage({type:"response",data:t,id:i})}else{const e=new Function(o)();s.postMessage({type:"response",data:e,id:i})}}catch(r){throw s.postMessage({type:"error",data:r.message,id:i}),r}}static inject(){if(!s.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');s.postMessage({type:"inject"}),window.addEventListener("message",s.onMessage)}constructor({iframe:e,url:t}){if(e instanceof HTMLIFrameElement===!1)throw new TypeError('"option.iframe" needs to be a HTMLIFrameElement');if("string"!==typeof t)throw new TypeError('"option.url" needs to be a string');this.url=t,this.$iframe=e,this.promises={},this.injected=!1,this.destroyed=!1,this.messageCallback=()=>null,this.onMessage=this.onMessage.bind(this),window.addEventListener("message",this.onMessage),this.$iframe.src=this.url}onMessage(e){if(this.destroyed)return;const{type:t,data:s,id:o}=e.data;if("inject"===t)this.injected=!0;void 0!==o&&Object.prototype.hasOwnProperty.call(this.promises,o)&&this.promises[o]&&("error"===t?this.promises[o].reject(new Error(s)):this.promises[o].resove(s),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:s})}postMessage(s){return function(s,{type:o,data:i}){return new Promise((r,n)=>{if(s.destroyed)return void n(new Error("The instance has been destroyed"));const a=e.get(s)||new Set;e.set(s,a);const d=t=>!!a.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete s.promises[t.id],a.size||e.delete(s),!0),c={callbacks:{resove(e){d(c)&&r(e)},reject(e){d(c)&&n(e)}}};a.add(c);const l=()=>{if(c.timer=void 0,a.has(c))if(s.destroyed)c.callbacks.reject(new Error("The instance has been destroyed"));else try{if(s.injected){const e=Math.max(Date.now(),t+1);t=e,c.id=e,s.promises[e]=c.callbacks,s.$iframe.contentWindow.postMessage({type:o,data:i,id:e},"*")}else c.timer=setTimeout(l,200)}catch(e){c.callbacks.reject(e)}};l()})}(this,s)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),s=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:s})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,window.removeEventListener("message",this.onMessage),function(t){const s=e.get(t);if(s)for(const e of[...s])e.callbacks.reject(new Error("The instance has been destroyed"))}(this)}}return s});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";const e=new WeakMap;let t=0;const s=new WeakMap;function o(t){const o=s.get(t);s.delete(t);try{o?.()}finally{!function(t){const s=e.get(t);if(s)for(const e of[...s])e.callbacks.reject(new Error("The instance has been destroyed"))}(t)}}function r(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const s=e.data;return"object"===typeof s&&null!==s&&"type"in s&&"string"===typeof s.type}class n{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:s=0}){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');window.parent.postMessage({type:e,data:t,id:s},"*")}static async onMessage(e){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!r(e,window.parent))return;const{type:t,data:s,id:o}=e.data;if("commit"===t)try{if(s.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${s}\n})`,t=await new Function(e)();n.postMessage({type:"response",data:t,id:o})}else{const e=new Function(s)();n.postMessage({type:"response",data:e,id:o})}}catch(i){throw n.postMessage({type:"error",data:i.message,id:o}),i}}static inject(){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');n.postMessage({type:"inject"}),window.addEventListener("message",n.onMessage)}constructor({iframe:e,url:t}){if(e instanceof HTMLIFrameElement===!1)throw new TypeError('"option.iframe" needs to be a HTMLIFrameElement');if("string"!==typeof t)throw new TypeError('"option.url" needs to be a string');this.url=t,this.$iframe=e,this.promises={},this.injected=!1,this.destroyed=!1,this.messageCallback=()=>null,this.onMessage=this.onMessage.bind(this);try{!function(e){const t=window,o=e.onMessage;s.set(e,()=>t.removeEventListener("message",o)),t.addEventListener("message",o),e.$iframe.src=e.url}(this)}catch(r){this.destroyed=!0;try{o(this)}catch{}throw r}}onMessage(e){if(this.destroyed||!r(e,this.$iframe.contentWindow))return;const{type:t,data:s,id:o}=e.data;if("inject"===t)this.injected=!0;void 0!==o&&Object.prototype.hasOwnProperty.call(this.promises,o)&&this.promises[o]&&("error"===t?this.promises[o].reject(new Error(s)):this.promises[o].resove(s),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:s})}postMessage(s){return function(s,{type:o,data:r}){return new Promise((n,i)=>{if(s.destroyed)return void i(new Error("The instance has been destroyed"));const a=e.get(s)||new Set;e.set(s,a);const c=t=>!!a.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete s.promises[t.id],a.size||e.delete(s),!0),d={callbacks:{resove(e){c(d)&&n(e)},reject(e){c(d)&&i(e)}}};a.add(d);const l=()=>{if(d.timer=void 0,a.has(d))if(s.destroyed)d.callbacks.reject(new Error("The instance has been destroyed"));else try{if(s.injected){const e=Math.max(Date.now(),t+1);t=e,d.id=e,s.promises[e]=d.callbacks,s.$iframe.contentWindow.postMessage({type:o,data:r,id:e},"*")}else d.timer=setTimeout(l,200)}catch(e){d.callbacks.reject(e)}};l()})}(this,s)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),s=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:s})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,o(this)}}return n});
@@ -4,4 +4,4 @@
* (c) 2017-2026 Harvey Zhao
* Released under the MIT License.
*/
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";const e=new WeakMap;let t=0;class s{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:o=0}){if(!s.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');window.parent.postMessage({type:e,data:t,id:o},"*")}static onMessage(e){return t=this,o=null,r=function*(){if(!s.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');const{type:t,data:o,id:r}=e.data;if("commit"===t)try{if(o.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${o}\n})`,t=yield new Function(e)();s.postMessage({type:"response",data:t,id:r})}else{const e=new Function(o)();s.postMessage({type:"response",data:e,id:r})}}catch(i){throw s.postMessage({type:"error",data:i.message,id:r}),i}},new Promise((e,s)=>{var i=e=>{try{a(r.next(e))}catch(t){s(t)}},n=e=>{try{a(r.throw(e))}catch(t){s(t)}},a=t=>t.done?e(t.value):Promise.resolve(t.value).then(i,n);a((r=r.apply(t,o)).next())});var t,o,r}static inject(){if(!s.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');s.postMessage({type:"inject"}),window.addEventListener("message",s.onMessage)}constructor({iframe:e,url:t}){if(e instanceof HTMLIFrameElement===!1)throw new TypeError('"option.iframe" needs to be a HTMLIFrameElement');if("string"!==typeof t)throw new TypeError('"option.url" needs to be a string');this.url=t,this.$iframe=e,this.promises={},this.injected=!1,this.destroyed=!1,this.messageCallback=()=>null,this.onMessage=this.onMessage.bind(this),window.addEventListener("message",this.onMessage),this.$iframe.src=this.url}onMessage(e){if(this.destroyed)return;const{type:t,data:s,id:o}=e.data;if("inject"===t)this.injected=!0;void 0!==o&&Object.prototype.hasOwnProperty.call(this.promises,o)&&this.promises[o]&&("error"===t?this.promises[o].reject(new Error(s)):this.promises[o].resove(s),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:s})}postMessage(s){return function(s,{type:o,data:r}){return new Promise((i,n)=>{if(s.destroyed)return void n(new Error("The instance has been destroyed"));const a=e.get(s)||new Set;e.set(s,a);const d=t=>!!a.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete s.promises[t.id],a.size||e.delete(s),!0),c={callbacks:{resove(e){d(c)&&i(e)},reject(e){d(c)&&n(e)}}};a.add(c);const l=()=>{if(c.timer=void 0,a.has(c))if(s.destroyed)c.callbacks.reject(new Error("The instance has been destroyed"));else try{if(s.injected){const e=Math.max(Date.now(),t+1);t=e,c.id=e,s.promises[e]=c.callbacks,s.$iframe.contentWindow.postMessage({type:o,data:r,id:e},"*")}else c.timer=setTimeout(l,200)}catch(e){c.callbacks.reject(e)}};l()})}(this,s)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),s=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:s})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,window.removeEventListener("message",this.onMessage),function(t){const s=e.get(t);if(s)for(const e of[...s])e.callbacks.reject(new Error("The instance has been destroyed"))}(this)}}return s});
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";const e=new WeakMap;let t=0;const s=new WeakMap;function o(t){const o=s.get(t);s.delete(t);try{null==o||o()}finally{!function(t){const s=e.get(t);if(s)for(const e of[...s])e.callbacks.reject(new Error("The instance has been destroyed"))}(t)}}function r(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const s=e.data;return"object"===typeof s&&null!==s&&"type"in s&&"string"===typeof s.type}class n{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:s=0}){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');window.parent.postMessage({type:e,data:t,id:s},"*")}static onMessage(e){return t=this,s=null,o=function*(){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!r(e,window.parent))return;const{type:t,data:s,id:o}=e.data;if("commit"===t)try{if(s.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${s}\n})`,t=yield new Function(e)();n.postMessage({type:"response",data:t,id:o})}else{const e=new Function(s)();n.postMessage({type:"response",data:e,id:o})}}catch(i){throw n.postMessage({type:"error",data:i.message,id:o}),i}},new Promise((e,r)=>{var n=e=>{try{a(o.next(e))}catch(t){r(t)}},i=e=>{try{a(o.throw(e))}catch(t){r(t)}},a=t=>t.done?e(t.value):Promise.resolve(t.value).then(n,i);a((o=o.apply(t,s)).next())});var t,s,o}static inject(){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');n.postMessage({type:"inject"}),window.addEventListener("message",n.onMessage)}constructor({iframe:e,url:t}){if(e instanceof HTMLIFrameElement===!1)throw new TypeError('"option.iframe" needs to be a HTMLIFrameElement');if("string"!==typeof t)throw new TypeError('"option.url" needs to be a string');this.url=t,this.$iframe=e,this.promises={},this.injected=!1,this.destroyed=!1,this.messageCallback=()=>null,this.onMessage=this.onMessage.bind(this);try{!function(e){const t=window,o=e.onMessage;s.set(e,()=>t.removeEventListener("message",o)),t.addEventListener("message",o),e.$iframe.src=e.url}(this)}catch(r){this.destroyed=!0;try{o(this)}catch(n){}throw r}}onMessage(e){if(this.destroyed||!r(e,this.$iframe.contentWindow))return;const{type:t,data:s,id:o}=e.data;if("inject"===t)this.injected=!0;void 0!==o&&Object.prototype.hasOwnProperty.call(this.promises,o)&&this.promises[o]&&("error"===t?this.promises[o].reject(new Error(s)):this.promises[o].resove(s),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:s})}postMessage(s){return function(s,{type:o,data:r}){return new Promise((n,i)=>{if(s.destroyed)return void i(new Error("The instance has been destroyed"));const a=e.get(s)||new Set;e.set(s,a);const c=t=>!!a.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete s.promises[t.id],a.size||e.delete(s),!0),d={callbacks:{resove(e){c(d)&&n(e)},reject(e){c(d)&&i(e)}}};a.add(d);const l=()=>{if(d.timer=void 0,a.has(d))if(s.destroyed)d.callbacks.reject(new Error("The instance has been destroyed"));else try{if(s.injected){const e=Math.max(Date.now(),t+1);t=e,d.id=e,s.promises[e]=d.callbacks,s.$iframe.contentWindow.postMessage({type:o,data:r,id:e},"*")}else d.timer=setTimeout(l,200)}catch(e){d.callbacks.reject(e)}};l()})}(this,s)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),s=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:s})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,o(this)}}return n});
+37 -5
View File
@@ -70,6 +70,29 @@ function cancelRequests(host) {
for (const request of [...pending])
request.callbacks.reject(new Error("The instance has been destroyed"));
}
const connections = /* @__PURE__ */ new WeakMap();
function connect(host) {
const owner = window;
const receiver = host.onMessage;
connections.set(host, () => owner.removeEventListener("message", receiver));
owner.addEventListener("message", receiver);
host.$iframe.src = host.url;
}
function releaseConnection(host) {
const disconnect = connections.get(host);
connections.delete(host);
try {
disconnect?.();
} finally {
cancelRequests(host);
}
}
function acceptsMessage(event, peer) {
if (event.source !== void 0 && event.source !== null && event.source !== peer)
return false;
const data = event.data;
return typeof data === "object" && data !== null && "type" in data && typeof data.type === "string";
}
class ArtplayerToolIframe {
static get iframe() {
return window.top !== window;
@@ -91,6 +114,8 @@ class ArtplayerToolIframe {
if (!ArtplayerToolIframe.iframe) {
throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');
}
if (!acceptsMessage(event, window.parent))
return;
const { type, data, id } = event.data;
switch (type) {
case "commit":
@@ -133,11 +158,19 @@ ${data}
this.destroyed = false;
this.messageCallback = () => null;
this.onMessage = this.onMessage.bind(this);
window.addEventListener("message", this.onMessage);
this.$iframe.src = this.url;
try {
connect(this);
} catch (error) {
this.destroyed = true;
try {
releaseConnection(this);
} catch {
}
throw error;
}
}
onMessage(event) {
if (this.destroyed)
if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow))
return;
const { type, data, id } = event.data;
switch (type) {
@@ -176,8 +209,7 @@ ${data}
}
destroy() {
this.destroyed = true;
window.removeEventListener("message", this.onMessage);
cancelRequests(this);
releaseConnection(this);
}
}
export {