diff --git a/docs/compiled/artplayer-tool-iframe.js b/docs/compiled/artplayer-tool-iframe.js index b7b8a537c..58a109a1d 100644 --- a/docs/compiled/artplayer-tool-iframe.js +++ b/docs/compiled/artplayer-tool-iframe.js @@ -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;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}); +!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="artplayer-tool-iframe:session";function t(e){const t=e.__artplayerIframe;if(1===t?.version&&"string"===typeof t.document&&t.document&&["inject","message","ack","leave","resume","fragment"].includes(t.phase))return t}function n(e,t,n){return{...e,__artplayerIframe:{version:1,document:t,phase:n}}}function r(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const n=e.data;return"object"===typeof n&&null!==n&&"type"in n&&"string"===typeof n.type}let o;const s=new WeakMap,i=new WeakMap;let a=0;function c(e,t){t?i.set(e,t):i.delete(e)}function d(e,t=new Error("The instance has been destroyed")){const n=s.get(e);if(n)for(const r of[...n])r.cancel(t)}const u=new WeakMap;function f(e){const t=e.$iframe;return t.hasAttribute?.("srcdoc")?`srcdoc:${t.getAttribute("srcdoc")}`:`src:${n=t.src||"",n.split("#")[0]}`;var n}function m(e){const t=e.$iframe;return t.hasAttribute?.("srcdoc")?`srcdoc:${t.getAttribute("srcdoc")}`:`src:${t.getAttribute?.("src")??t.src??""}`}function h(e,t){t.waiting||(t.documentId?t.cancelPrevious=function(e){const t=[...s.get(e)||[]];return e=>{for(const n of t)n.cancel(e)}}(e):d(e,new Error("The iframe document has changed"))),t.waiting=!0,e.injected=!1}function l(e,t,n){const r=m(e);if(!n.length&&r===t.rawSource)return;const o=function(e,t,n){return f(e)!==t.source||!!t.documentId&&(m(e)!==t.rawSource||n.some(t=>"srcdoc"===t.attributeName||"src"===t.attributeName&&!e.$iframe.hasAttribute?.("srcdoc")))}(e,t,n);t.rawSource=r,t.source=f(e),o&&h(e,t)}function w(e){const t=u.get(e);if(!t||e.destroyed)return;const n=t.observer?.takeRecords()||[];l(e,t,n)}function p(t,r,o){r.hasHandshake&&r.documentId!==o&&(r.cancelPrevious?r.cancelPrevious(new Error("The iframe document has changed")):r.waiting||d(t,new Error("The iframe document has changed"))),r.cancelPrevious=void 0,r.documentId=o,r.hasHandshake=!0,r.waiting=!1,t.injected=!0;try{t.$iframe.contentWindow?.postMessage(n({type:e,data:void 0,id:0},o,"ack"),"*")}catch{}}function g(n,r){const o=u.get(n);if(!o)return!1;w(n);const s=t(r);if(s&&r.type===e)return"resume"===s.phase?p(n,o,s.document):s.document===o.documentId&&("leave"===s.phase?function(e,t){t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||d(e,new Error("The iframe document has changed")),t.cancelPrevious=void 0,t.waiting=!0,e.injected=!1}(n,o):"fragment"===s.phase&&o.cancelPrevious&&!n.$iframe.hasAttribute?.("srcdoc")&&r.data===n.$iframe.src&&p(n,o,s.document)),!0;if("inject"===r.type){if("inject"===s?.phase){if(o.waiting&&s.document===o.documentId)return!0;p(n,o,s.document)}else o.waiting&&(o.cancelPrevious?.(new Error("The iframe document has changed")),o.cancelPrevious=void 0,o.documentId=void 0),o.hasHandshake=!0,o.waiting=!1;return!1}return Boolean(s&&(o.waiting&&!o.cancelPrevious||s.document!==o.documentId))}const y=new WeakMap;function v(e){const t=window,r=e.onMessage,o=[()=>t.removeEventListener("message",r)];y.set(e,()=>{let e,t=!1;for(const r of o)try{r()}catch(n){t||(t=!0,e=n)}if(t)throw e}),t.addEventListener("message",r),e.$iframe.src=e.url;const s=function(e){const t={source:f(e),rawSource:m(e),hasHandshake:!1,waiting:!1};return u.set(e,t),c(e,{prepare:()=>w(e),envelope:e=>t.documentId?n(e,t.documentId,"message"):e}),{start(){"function"===typeof window.MutationObserver&&(t.observer=new window.MutationObserver(n=>{e.destroyed||l(e,t,n)}),t.observer.observe(e.$iframe,{attributes:!0,attributeOldValue:!0,attributeFilter:["src","srcdoc"]}))},dispose(){u.delete(e),c(e,void 0),t.cancelPrevious=void 0,t.observer?.disconnect()}}}(e);o.push(s.dispose),s.start()}function b(e){const t=y.get(e);y.delete(e);try{t?.()}finally{d(e)}}class E{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:r=0}){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');var s;window.parent.postMessage((s={type:e,data:t,id:r},o&&("inject"===s.type||o.acknowledged)?n(s,o.id,"inject"===s.type?"inject":"message"):s),"*")}static async onMessage(n){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!r(n,window.parent)||function(n){const r=t(n);return!!r&&(n.type===e?(o&&r.document===o.id&&"ack"===r.phase&&(o.acknowledged=!0),!0):!o||r.document!==o.id)}(n.data))return;const{type:s,data:i,id:a}=n.data;if("commit"===s)try{if(i.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${i}\n})`,t=await new Function(e)();E.postMessage({type:"response",data:t,id:a})}else{const e=new Function(i)();E.postMessage({type:"response",data:e,id:a})}}catch(c){throw E.postMessage({type:"error",data:c.message,id:a}),c}}static inject(){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');!function(){if(o?.owner===window.document&&o)return;const e=new Uint32Array(4);window.crypto?.getRandomValues?window.crypto.getRandomValues(e):e.forEach((t,n)=>e[n]=Math.floor(4294967296*Math.random())),o={owner:window.document,id:`${Date.now()}-${Array.from(e).join("-")}`,acknowledged:!1,lifecycle:!1,receivers:new Set}}(),E.postMessage({type:"inject"}),function(t){const r=o,s=!r.receivers.has(t),i=!r.lifecycle,a=(t,o)=>{if(r.acknowledged)try{window.parent.postMessage(n({type:e,data:o,id:0},r.id,t),"*")}catch{}},c=()=>a("leave"),d=()=>a("fragment",window.location.href),u=e=>{e.persisted&&a("resume")};try{if(window.addEventListener("message",t),r.receivers.add(t),!i)return;window.addEventListener("pagehide",c),window.addEventListener("pageshow",u),window.addEventListener("hashchange",d),r.lifecycle=!0}catch(f){const e=[];i&&(e.push(()=>window.removeEventListener("pagehide",c)),e.push(()=>window.removeEventListener("pageshow",u)),e.push(()=>window.removeEventListener("hashchange",d))),s&&e.push(()=>window.removeEventListener("message",t));for(const t of e)try{t()}catch{}throw s&&r.receivers.delete(t),f}}(E.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{v(this)}catch(n){this.destroyed=!0;try{b(this)}catch{}throw n}}onMessage(e){if(this.destroyed||!r(e,this.$iframe.contentWindow)||g(this,e.data))return;const{type:t,data:n,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(n)):this.promises[o].resove(n),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:n})}postMessage(e){return w(this),function(e,{type:t,data:n}){return new Promise((r,o)=>{if(e.destroyed)return void o(new Error("The instance has been destroyed"));const c=s.get(e)||new Set;s.set(e,c);const d=t=>!!c.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete e.promises[t.id],c.size||s.delete(e),!0),u={callbacks:{resove(e){d(u)&&r(e)},reject(e){d(u)&&o(e)}},cancel(e){d(u)&&o(e)}};c.add(u);const f=()=>{if(u.timer=void 0,c.has(u))if(e.destroyed)u.cancel(new Error("The instance has been destroyed"));else try{if(i.get(e)?.prepare(),!c.has(u))return;if(e.injected){const r=Math.max(Date.now(),a+1);a=r,u.id=r,e.promises[r]=u.callbacks;const o={type:t,data:n,id:r};e.$iframe.contentWindow.postMessage(i.get(e)?.envelope(o)||o,"*")}else u.timer=setTimeout(f,200)}catch(r){u.cancel(r)}};f()})}(this,e)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),n=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:n})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,b(this)}}return E}); diff --git a/docs/compiled/artplayer-tool-iframe.legacy.js b/docs/compiled/artplayer-tool-iframe.legacy.js index 1d8339ba4..171c31876 100644 --- a/docs/compiled/artplayer-tool-iframe.legacy.js +++ b/docs/compiled/artplayer-tool-iframe.legacy.js @@ -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;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}); +!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";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;const a="artplayer-tool-iframe:session";function c(e){const t=e.__artplayerIframe;if(1===(null==t?void 0:t.version)&&"string"===typeof t.document&&t.document&&["inject","message","ack","leave","resume","fragment"].includes(t.phase))return t}function d(e,a,c){return d=((e,t)=>{for(var n in t||(t={}))o.call(t,n)&&i(e,n,t[n]);if(r)for(var n of r(t))s.call(t,n)&&i(e,n,t[n]);return e})({},e),t(d,n({__artplayerIframe:{version:1,document:a,phase:c}}));var d}function u(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const n=e.data;return"object"===typeof n&&null!==n&&"type"in n&&"string"===typeof n.type}let l;const f=new WeakMap,m=new WeakMap;let h=0;function p(e,t){t?m.set(e,t):m.delete(e)}function w(e,t=new Error("The instance has been destroyed")){const n=f.get(e);if(n)for(const r of[...n])r.cancel(t)}const v=new WeakMap;function y(e){var t;const n=e.$iframe;return(null==(t=n.hasAttribute)?void 0:t.call(n,"srcdoc"))?`srcdoc:${n.getAttribute("srcdoc")}`:`src:${r=n.src||"",r.split("#")[0]}`;var r}function g(e){var t,n,r,o;const s=e.$iframe;return(null==(t=s.hasAttribute)?void 0:t.call(s,"srcdoc"))?`srcdoc:${s.getAttribute("srcdoc")}`:`src:${null!=(o=null!=(r=null==(n=s.getAttribute)?void 0:n.call(s,"src"))?r:s.src)?o:""}`}function b(e,t){t.waiting||(t.documentId?t.cancelPrevious=function(e){const t=[...f.get(e)||[]];return e=>{for(const n of t)n.cancel(e)}}(e):w(e,new Error("The iframe document has changed"))),t.waiting=!0,e.injected=!1}function E(e,t,n){const r=g(e);if(!n.length&&r===t.rawSource)return;const o=function(e,t,n){return y(e)!==t.source||!!t.documentId&&(g(e)!==t.rawSource||n.some(t=>{var n,r;return"srcdoc"===t.attributeName||"src"===t.attributeName&&!(null==(r=(n=e.$iframe).hasAttribute)?void 0:r.call(n,"srcdoc"))}))}(e,t,n);t.rawSource=r,t.source=y(e),o&&b(e,t)}function M(e){var t;const n=v.get(e);if(!n||e.destroyed)return;E(e,n,(null==(t=n.observer)?void 0:t.takeRecords())||[])}function j(e,t,n){var r;t.hasHandshake&&t.documentId!==n&&(t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||w(e,new Error("The iframe document has changed"))),t.cancelPrevious=void 0,t.documentId=n,t.hasHandshake=!0,t.waiting=!1,e.injected=!0;try{null==(r=e.$iframe.contentWindow)||r.postMessage(d({type:a,data:void 0,id:0},n,"ack"),"*")}catch(o){}}function T(e,t){var n,r,o;const s=v.get(e);if(!s)return!1;M(e);const i=c(t);if(i&&t.type===a)return"resume"===i.phase?j(e,s,i.document):i.document===s.documentId&&("leave"===i.phase?function(e,t){t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||w(e,new Error("The iframe document has changed")),t.cancelPrevious=void 0,t.waiting=!0,e.injected=!1}(e,s):"fragment"===i.phase&&s.cancelPrevious&&!(null==(r=(n=e.$iframe).hasAttribute)?void 0:r.call(n,"srcdoc"))&&t.data===e.$iframe.src&&j(e,s,i.document)),!0;if("inject"===t.type){if("inject"===(null==i?void 0:i.phase)){if(s.waiting&&i.document===s.documentId)return!0;j(e,s,i.document)}else s.waiting&&(null==(o=s.cancelPrevious)||o.call(s,new Error("The iframe document has changed")),s.cancelPrevious=void 0,s.documentId=void 0),s.hasHandshake=!0,s.waiting=!1;return!1}return Boolean(i&&(s.waiting&&!s.cancelPrevious||i.document!==s.documentId))}const k=new WeakMap;function P(e){const t=window,n=e.onMessage,r=[()=>t.removeEventListener("message",n)];k.set(e,()=>{let e,t=!1;for(const o of r)try{o()}catch(n){t||(t=!0,e=n)}if(t)throw e}),t.addEventListener("message",n),e.$iframe.src=e.url;const o=function(e){const t={source:y(e),rawSource:g(e),hasHandshake:!1,waiting:!1};return v.set(e,t),p(e,{prepare:()=>M(e),envelope:e=>t.documentId?d(e,t.documentId,"message"):e}),{start(){"function"===typeof window.MutationObserver&&(t.observer=new window.MutationObserver(n=>{e.destroyed||E(e,t,n)}),t.observer.observe(e.$iframe,{attributes:!0,attributeOldValue:!0,attributeFilter:["src","srcdoc"]}))},dispose(){var n;v.delete(e),p(e,void 0),t.cancelPrevious=void 0,null==(n=t.observer)||n.disconnect()}}}(e);r.push(o.dispose),o.start()}function I(e){const t=k.get(e);k.delete(e);try{null==t||t()}finally{w(e)}}class ${static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:n=0}){if(!$.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');var r;window.parent.postMessage((r={type:e,data:t,id:n},l&&("inject"===r.type||l.acknowledged)?d(r,l.id,"inject"===r.type?"inject":"message"):r),"*")}static onMessage(e){return t=this,n=null,r=function*(){if(!$.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!u(e,window.parent)||function(e){const t=c(e);return!!t&&(e.type===a?(l&&t.document===l.id&&"ack"===t.phase&&(l.acknowledged=!0),!0):!l||t.document!==l.id)}(e.data))return;const{type:t,data:n,id:r}=e.data;if("commit"===t)try{if(n.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${n}\n})`,t=yield new Function(e)();$.postMessage({type:"response",data:t,id:r})}else{const e=new Function(n)();$.postMessage({type:"response",data:e,id:r})}}catch(o){throw $.postMessage({type:"error",data:o.message,id:r}),o}},new Promise((e,o)=>{var s=e=>{try{a(r.next(e))}catch(t){o(t)}},i=e=>{try{a(r.throw(e))}catch(t){o(t)}},a=t=>t.done?e(t.value):Promise.resolve(t.value).then(s,i);a((r=r.apply(t,n)).next())});var t,n,r}static inject(){if(!$.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');!function(){var e;if((null==l?void 0:l.owner)===window.document&&l)return;const t=new Uint32Array(4);(null==(e=window.crypto)?void 0:e.getRandomValues)?window.crypto.getRandomValues(t):t.forEach((e,n)=>t[n]=Math.floor(4294967296*Math.random())),l={owner:window.document,id:`${Date.now()}-${Array.from(t).join("-")}`,acknowledged:!1,lifecycle:!1,receivers:new Set}}(),$.postMessage({type:"inject"}),function(e){const t=l,n=!t.receivers.has(e),r=!t.lifecycle,o=(e,n)=>{if(t.acknowledged)try{window.parent.postMessage(d({type:a,data:n,id:0},t.id,e),"*")}catch(r){}},s=()=>o("leave"),i=()=>o("fragment",window.location.href),c=e=>{e.persisted&&o("resume")};try{if(window.addEventListener("message",e),t.receivers.add(e),!r)return;window.addEventListener("pagehide",s),window.addEventListener("pageshow",c),window.addEventListener("hashchange",i),t.lifecycle=!0}catch(u){const o=[];r&&(o.push(()=>window.removeEventListener("pagehide",s)),o.push(()=>window.removeEventListener("pageshow",c)),o.push(()=>window.removeEventListener("hashchange",i))),n&&o.push(()=>window.removeEventListener("message",e));for(const e of o)try{e()}catch(f){}throw n&&t.receivers.delete(e),u}}($.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{P(this)}catch(n){this.destroyed=!0;try{I(this)}catch(r){}throw n}}onMessage(e){if(this.destroyed||!u(e,this.$iframe.contentWindow)||T(this,e.data))return;const{type:t,data:n,id:r}=e.data;if("inject"===t)this.injected=!0;void 0!==r&&Object.prototype.hasOwnProperty.call(this.promises,r)&&this.promises[r]&&("error"===t?this.promises[r].reject(new Error(n)):this.promises[r].resove(n),delete this.promises[r]),this.messageCallback&&this.messageCallback({type:t,data:n})}postMessage(e){return M(this),function(e,{type:t,data:n}){return new Promise((r,o)=>{if(e.destroyed)return void o(new Error("The instance has been destroyed"));const s=f.get(e)||new Set;f.set(e,s);const i=t=>!!s.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete e.promises[t.id],s.size||f.delete(e),!0),a={callbacks:{resove(e){i(a)&&r(e)},reject(e){i(a)&&o(e)}},cancel(e){i(a)&&o(e)}};s.add(a);const c=()=>{var r,o;if(a.timer=void 0,s.has(a))if(e.destroyed)a.cancel(new Error("The instance has been destroyed"));else try{if(null==(r=m.get(e))||r.prepare(),!s.has(a))return;if(e.injected){const r=Math.max(Date.now(),h+1);h=r,a.id=r,e.promises[r]=a.callbacks;const s={type:t,data:n,id:r};e.$iframe.contentWindow.postMessage((null==(o=m.get(e))?void 0:o.envelope(s))||s,"*")}else a.timer=setTimeout(c,200)}catch(i){a.cancel(i)}};c()})}(this,e)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),n=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:n})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,I(this)}}return $}); diff --git a/docs/compiled/artplayer-tool-iframe.mjs b/docs/compiled/artplayer-tool-iframe.mjs index 0deb5d536..e7076f494 100644 --- a/docs/compiled/artplayer-tool-iframe.mjs +++ b/docs/compiled/artplayer-tool-iframe.mjs @@ -4,8 +4,104 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ +const sessionType = "artplayer-tool-iframe:session"; +function sessionMetadata(packet) { + const value = packet.__artplayerIframe; + if (value?.version === 1 && typeof value.document === "string" && value.document && ["inject", "message", "ack", "leave", "resume", "fragment"].includes(value.phase)) + return value; +} +function withSession(packet, documentId, phase) { + return { ...packet, __artplayerIframe: { version: 1, document: documentId, phase } }; +} +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"; +} +let session; +function prepareChildSession() { + if (session?.owner === window.document && session) + return; + const random = new Uint32Array(4); + if (window.crypto?.getRandomValues) + window.crypto.getRandomValues(random); + else + random.forEach((_, index) => random[index] = Math.floor(Math.random() * 4294967296)); + session = { owner: window.document, id: `${Date.now()}-${Array.from(random).join("-")}`, acknowledged: false, lifecycle: false, receivers: /* @__PURE__ */ new Set() }; +} +function childEnvelope(packet) { + if (session && (packet.type === "inject" || session.acknowledged)) + return withSession(packet, session.id, packet.type === "inject" ? "inject" : "message"); + return packet; +} +function consumeChildSession(packet) { + const metadata = sessionMetadata(packet); + if (!metadata) + return false; + if (packet.type === sessionType) { + if (session && metadata.document === session.id && metadata.phase === "ack") + session.acknowledged = true; + return true; + } + return !session || metadata.document !== session.id; +} +function connectChildSession(receiver) { + const current = session; + const added = !current.receivers.has(receiver); + const installing = !current.lifecycle; + const notify = (phase, data) => { + if (!current.acknowledged) + return; + try { + window.parent.postMessage(withSession({ type: sessionType, data, id: 0 }, current.id, phase), "*"); + } catch { + } + }; + const leave = () => notify("leave"); + const fragment = () => notify("fragment", window.location.href); + const resume = (event) => { + if (event.persisted) + notify("resume"); + }; + try { + window.addEventListener("message", receiver); + current.receivers.add(receiver); + if (!installing) + return; + window.addEventListener("pagehide", leave); + window.addEventListener("pageshow", resume); + window.addEventListener("hashchange", fragment); + current.lifecycle = true; + } catch (error) { + const cleanups = []; + if (installing) { + cleanups.push(() => window.removeEventListener("pagehide", leave)); + cleanups.push(() => window.removeEventListener("pageshow", resume)); + cleanups.push(() => window.removeEventListener("hashchange", fragment)); + } + if (added) + cleanups.push(() => window.removeEventListener("message", receiver)); + for (const cleanup of cleanups) { + try { + cleanup(); + } catch { + } + } + if (added) + current.receivers.delete(receiver); + throw error; + } +} const requests = /* @__PURE__ */ new WeakMap(); +const boundaries = /* @__PURE__ */ new WeakMap(); let lastId = 0; +function setRequestBoundary(host, boundary) { + if (boundary) + boundaries.set(host, boundary); + else + boundaries.delete(host); +} function postRequest(host, { type, data }) { return new Promise((resolve, reject) => { if (host.destroyed) { @@ -35,6 +131,10 @@ function postRequest(host, { type, data }) { if (finish(request)) reject(error); } + }, + cancel(error) { + if (finish(request)) + reject(error); } }; pending.add(request); @@ -43,40 +143,209 @@ function postRequest(host, { type, data }) { if (!pending.has(request)) return; if (host.destroyed) { - request.callbacks.reject(new Error("The instance has been destroyed")); + request.cancel(new Error("The instance has been destroyed")); return; } try { + boundaries.get(host)?.prepare(); + if (!pending.has(request)) + return; if (host.injected) { const id = Math.max(Date.now(), lastId + 1); lastId = id; request.id = id; host.promises[id] = request.callbacks; - host.$iframe.contentWindow.postMessage({ type, data, id }, "*"); + const packet = { type, data, id }; + host.$iframe.contentWindow.postMessage(boundaries.get(host)?.envelope(packet) || packet, "*"); } else { request.timer = setTimeout(loop, 200); } } catch (error) { - request.callbacks.reject(error); + request.cancel(error); } }; loop(); }); } -function cancelRequests(host) { +function cancelRequests(host, reason = new Error("The instance has been destroyed")) { const pending = requests.get(host); if (!pending) return; for (const request of [...pending]) - request.callbacks.reject(new Error("The instance has been destroyed")); + request.cancel(reason); +} +function captureRequests(host) { + const captured = [...requests.get(host) || []]; + return (reason) => { + for (const request of captured) + request.cancel(reason); + }; +} +const navigations = /* @__PURE__ */ new WeakMap(); +const withoutHash = (value) => value.split("#")[0]; +function sourceOf(host) { + const frame = host.$iframe; + return frame.hasAttribute?.("srcdoc") ? `srcdoc:${frame.getAttribute("srcdoc")}` : `src:${withoutHash(frame.src || "")}`; +} +function rawSourceOf(host) { + const frame = host.$iframe; + return frame.hasAttribute?.("srcdoc") ? `srcdoc:${frame.getAttribute("srcdoc")}` : `src:${frame.getAttribute?.("src") ?? frame.src ?? ""}`; +} +function invalidate(host, state) { + if (!state.waiting) { + if (state.documentId) + state.cancelPrevious = captureRequests(host); + else + cancelRequests(host, new Error("The iframe document has changed")); + } + state.waiting = true; + host.injected = false; +} +function leaveDocument(host, state) { + if (state.cancelPrevious) + state.cancelPrevious(new Error("The iframe document has changed")); + else if (!state.waiting) + cancelRequests(host, new Error("The iframe document has changed")); + state.cancelPrevious = void 0; + state.waiting = true; + host.injected = false; +} +function sourceChanged(host, state, records) { + if (sourceOf(host) !== state.source) + return true; + if (!state.documentId) + return false; + if (rawSourceOf(host) !== state.rawSource) + return true; + return records.some((record) => { + if (record.attributeName === "srcdoc") + return true; + if (record.attributeName !== "src" || host.$iframe.hasAttribute?.("srcdoc")) + return false; + return true; + }); +} +function observeSource(host, state, records) { + const rawSource = rawSourceOf(host); + if (!records.length && rawSource === state.rawSource) + return; + const changed = sourceChanged(host, state, records); + state.rawSource = rawSource; + state.source = sourceOf(host); + if (changed) + invalidate(host, state); +} +function prepareNavigation(host) { + const state = navigations.get(host); + if (!state || host.destroyed) + return; + const records = state.observer?.takeRecords() || []; + observeSource(host, state, records); +} +function createNavigation(host) { + const state = { source: sourceOf(host), rawSource: rawSourceOf(host), hasHandshake: false, waiting: false }; + navigations.set(host, state); + setRequestBoundary(host, { + prepare: () => prepareNavigation(host), + envelope: (packet) => state.documentId ? withSession(packet, state.documentId, "message") : packet + }); + return { + start() { + if (typeof window.MutationObserver !== "function") + return; + state.observer = new window.MutationObserver((records) => { + if (host.destroyed) + return; + observeSource(host, state, records); + }); + state.observer.observe(host.$iframe, { attributes: true, attributeOldValue: true, attributeFilter: ["src", "srcdoc"] }); + }, + dispose() { + navigations.delete(host); + setRequestBoundary(host, void 0); + state.cancelPrevious = void 0; + state.observer?.disconnect(); + } + }; +} +function activate(host, state, documentId) { + if (state.hasHandshake && state.documentId !== documentId) { + if (state.cancelPrevious) + state.cancelPrevious(new Error("The iframe document has changed")); + else if (!state.waiting) + cancelRequests(host, new Error("The iframe document has changed")); + } + state.cancelPrevious = void 0; + state.documentId = documentId; + state.hasHandshake = true; + state.waiting = false; + host.injected = true; + try { + host.$iframe.contentWindow?.postMessage(withSession({ type: sessionType, data: void 0, id: 0 }, documentId, "ack"), "*"); + } catch { + } +} +function consumeNavigation(host, packet) { + const state = navigations.get(host); + if (!state) + return false; + prepareNavigation(host); + const metadata = sessionMetadata(packet); + if (metadata && packet.type === sessionType) { + if (metadata.phase === "resume") { + activate(host, state, metadata.document); + } else if (metadata.document === state.documentId) { + if (metadata.phase === "leave") + leaveDocument(host, state); + else if (metadata.phase === "fragment" && state.cancelPrevious && !host.$iframe.hasAttribute?.("srcdoc") && packet.data === host.$iframe.src) + activate(host, state, metadata.document); + } + return true; + } + if (packet.type === "inject") { + if (metadata?.phase === "inject") { + if (state.waiting && metadata.document === state.documentId) + return true; + activate(host, state, metadata.document); + } else { + if (state.waiting) { + state.cancelPrevious?.(new Error("The iframe document has changed")); + state.cancelPrevious = void 0; + state.documentId = void 0; + } + state.hasHandshake = true; + state.waiting = false; + } + return false; + } + return Boolean(metadata && (state.waiting && !state.cancelPrevious || metadata.document !== state.documentId)); } const connections = /* @__PURE__ */ new WeakMap(); function connect(host) { const owner = window; const receiver = host.onMessage; - connections.set(host, () => owner.removeEventListener("message", receiver)); + const cleanups = [() => owner.removeEventListener("message", receiver)]; + connections.set(host, () => { + let failed = false; + let failure; + for (const cleanup of cleanups) { + try { + cleanup(); + } catch (error) { + if (!failed) { + failed = true; + failure = error; + } + } + } + if (failed) + throw failure; + }); owner.addEventListener("message", receiver); host.$iframe.src = host.url; + const navigation = createNavigation(host); + cleanups.push(navigation.dispose); + navigation.start(); } function releaseConnection(host) { const disconnect = connections.get(host); @@ -87,12 +356,6 @@ function releaseConnection(host) { 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; @@ -102,11 +365,11 @@ class ArtplayerToolIframe { throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe'); } window.parent.postMessage( - { + childEnvelope({ type, data, id - }, + }), "*" ); } @@ -114,7 +377,7 @@ class ArtplayerToolIframe { if (!ArtplayerToolIframe.iframe) { throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe'); } - if (!acceptsMessage(event, window.parent)) + if (!acceptsMessage(event, window.parent) || consumeChildSession(event.data)) return; const { type, data, id } = event.data; switch (type) { @@ -141,8 +404,9 @@ ${data} if (!ArtplayerToolIframe.iframe) { throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe'); } + prepareChildSession(); ArtplayerToolIframe.postMessage({ type: "inject" }); - window.addEventListener("message", ArtplayerToolIframe.onMessage); + connectChildSession(ArtplayerToolIframe.onMessage); } constructor({ iframe, url }) { if (iframe instanceof HTMLIFrameElement === false) { @@ -170,7 +434,7 @@ ${data} } } onMessage(event) { - if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow)) + if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow) || consumeNavigation(this, event.data)) return; const { type, data, id } = event.data; switch (type) { @@ -191,6 +455,7 @@ ${data} } } postMessage(message) { + prepareNavigation(this); return postRequest(this, message); } commit(callback) { diff --git a/package.json b/package.json index 5a8ce0b3e..d84fc2979 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:docs && yarn test:imports", "test:imports": "node --test test/esm.test.js test/i18n.test.js test/ssr.test.js", "typecheck": "node scripts/typecheck.mjs", - "test:unit": "node --test test/iframe-boundaries.test.js test/iframe-lifecycle.test.js test/iframe.test.js test/mediabunny.test.js test/mediabunny-shim.test.js test/mediabunny-coordination.test.js test/mediabunny-video.test.js test/mediabunny-audio.test.js test/mediabunny-hls.test.js test/mediabunny-entry.test.js test/mediabunny-capability.test.js test/mediabunny-load.test.js test/mediabunny-input.test.js test/dpip.test.js test/dpip-lifecycle.test.js test/canvas.test.js test/canvas-lifecycle.test.js test/ambilight.test.js test/ambilight-lifecycle.test.js test/ambilight-proxy.test.js test/vast.test.js test/vast-lifecycle.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js", + "test:unit": "node --test test/iframe-navigation.test.js test/iframe-boundaries.test.js test/iframe-lifecycle.test.js test/iframe.test.js test/mediabunny.test.js test/mediabunny-shim.test.js test/mediabunny-coordination.test.js test/mediabunny-video.test.js test/mediabunny-audio.test.js test/mediabunny-hls.test.js test/mediabunny-entry.test.js test/mediabunny-capability.test.js test/mediabunny-load.test.js test/mediabunny-input.test.js test/dpip.test.js test/dpip-lifecycle.test.js test/canvas.test.js test/canvas-lifecycle.test.js test/ambilight.test.js test/ambilight-lifecycle.test.js test/ambilight-proxy.test.js test/vast.test.js test/vast-lifecycle.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js", "test:coverage": "node --test test/coverage.test.js && node scripts/coverage.mjs", "test": "yarn test:node && yarn test:baseline", "test:browser": "playwright test", @@ -80,7 +80,7 @@ "test:mediabunny-types-package": "node refactor/scripts/mb-package-types.mjs", "test:mediabunny-soak": "playwright test --config playwright.soak.config.js", "generate:media:hls": "node scripts/generate-hls-fixture.mjs", - "test:iframe": "node --test test/iframe-boundaries.test.js test/iframe.test.js test/iframe-lifecycle.test.js refactor/scripts/iframe-contract.test.mjs" + "test:iframe": "node --test test/iframe-navigation.test.js test/iframe-boundaries.test.js test/iframe.test.js test/iframe-lifecycle.test.js refactor/scripts/iframe-contract.test.mjs" }, "browserslist": "last 1 Chrome version", "devDependencies": { diff --git a/packages/artplayer-tool-iframe/ARCHITECTURE.md b/packages/artplayer-tool-iframe/ARCHITECTURE.md index 1488af647..3c830dd1d 100644 --- a/packages/artplayer-tool-iframe/ARCHITECTURE.md +++ b/packages/artplayer-tool-iframe/ARCHITECTURE.md @@ -8,6 +8,11 @@ two lifecycle flags; it does not depend on ArtPlayer or import the entry class. `src/connection.ts` owns listener acquisition/release and ensures request cancellation runs even if listener removal throws. `src/protocol.ts` checks the selected window peer and packet shape before either public receiver processes it. +`src/navigation.ts` owns parent document state, source observation and suspended +request snapshots. `src/child-session.ts` owns the child document marker and its +acknowledged pagehide/pageshow/hashchange notifications. Requests accept an +internal boundary hook rather than importing the connection or navigation modules; +there is no runtime dependency cycle or dependency on a particular core version. The entry initializes the same seven enumerable, writable fields in the same order. Internal request ownership lives in a module WeakMap, keeping instance @@ -44,6 +49,36 @@ The public ID is a correlation number, and is no longer always equal to Date.now Public callback invocation now removes its completed registry entry immediately. The own-property guard prevents inherited names such as `toString` being treated as requests. These differences are recorded under PKG-IFRAME-03. +Internal cancellation holds the native rejection separately from public callback +properties. Replacing/deleting a public entry does not make its owned Promise +unreachable during destroy or document departure; ordinary response dispatch +continues to respect the public callbacks. + +## Document ownership + +New inject packets advertise optional `__artplayerIframe` metadata. A cooperating +parent acknowledges it through tagged `artplayer-tool-iframe:session` traffic; +the public message callback still receives only its original type/data packet. +Ordinary child messages stay unmarked when the parent has not acknowledged the +extension. The document ID correlates work and is not an authentication token. +See [ADR-026](../../refactor/iframe-document-protocol.md) for the complete wire boundary. + +Parent source attribute changes begin a provisional navigation: capture the old +pending set and pause new sends. Confirmed pagehide or a different document's +inject cancels the captured set, preserving work queued for the new document. +A hashchange report matching the actual target src completes a same-document +transition without cancellation. This also handles relative/absolute src spelling +and setting an old fragment after the child changed its own hash. Raw attribute +tracking prevents a changed base URL resolution alone from inventing navigation. + +Repeated inject for the active document keeps requests; an old inject cannot +reactivate a document while its replacement is pending. Marked replies and +notifications from other documents are discarded; marked old commands are not +executed by a new child. No load-event reset is used, so inject-before-load works. +Connection cleanup disposes the observer and request hook, then cancels all owned +requests. Child listeners belong to the child document, are installed once, and +are rolled back on partial acquisition failure. A destroyed parent ignores late +private notifications. The existing API adds no static child destroy method. ## Compatibility still under review @@ -68,9 +103,12 @@ sandbox or a parent-origin allowlist. Upgrading one side does not secure the unchanged historical receiver on the other side. See the independent decision in [iframe-message-boundary.md](../../refactor/iframe-message-boundary.md). -Navigation/reinjection remains unfinished. A child can inject before iframe load; -blindly resetting state on load would lose a valid handshake. IFRAME-LIFE-01 and -IFRAME-TRUST-01 remain open for complete lifecycle/integration and release review. +Legacy peers keep the ordinary envelope and support observed changes to different +source addresses; their same-address reloads/internal navigation cannot provide +document identity without upgrading the child. No claim is made that a normal +history reload is BFCache: actual persisted restoration, full-player integration, +devices and externally interrupted navigation remain PKG-IFRAME-05/release gates. +IFRAME-LIFE-01 and IFRAME-TRUST-01 remain open for those integration/review scopes. Public declarations remain in `types/artplayer-tool-iframe.d.ts`; source typing does not yet establish historical declaration/entry compatibility. PKG-IFRAME-04 @@ -92,6 +130,10 @@ publication is implied by this source migration. malformed packets, actual HTTP redirects, opaque sandbox and normal new/old parent-child wire combinations. `ARTPLAYER_IFRAME_BOUNDARIES_ONLY=1` omits the mixed-version controls when reproducing a candidate boundary failure. +- `yarn test:browser test/browser/iframe-navigation.spec.js`: source/srcdoc, rapid + navigation, self-navigation, load ordering, fragment identity, stale packets, + legacy children and history with actual persisted-state reporting. There is no + implicit request timeout. Handle rejection when a document leaves or is destroyed. - Set `ARTPLAYER_IFRAME_LIFECYCLE_ONLY=1` for candidate lifecycle browser rows; `ARTPLAYER_IFRAME_ARTIFACT` selects an actual built file. For an unchanged candidate test against the old workspace, set `ARTPLAYER_IFRAME_BASELINE=1`. diff --git a/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.js b/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.js index b7b8a537c..58a109a1d 100644 --- a/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.js +++ b/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.js @@ -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;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}); +!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="artplayer-tool-iframe:session";function t(e){const t=e.__artplayerIframe;if(1===t?.version&&"string"===typeof t.document&&t.document&&["inject","message","ack","leave","resume","fragment"].includes(t.phase))return t}function n(e,t,n){return{...e,__artplayerIframe:{version:1,document:t,phase:n}}}function r(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const n=e.data;return"object"===typeof n&&null!==n&&"type"in n&&"string"===typeof n.type}let o;const s=new WeakMap,i=new WeakMap;let a=0;function c(e,t){t?i.set(e,t):i.delete(e)}function d(e,t=new Error("The instance has been destroyed")){const n=s.get(e);if(n)for(const r of[...n])r.cancel(t)}const u=new WeakMap;function f(e){const t=e.$iframe;return t.hasAttribute?.("srcdoc")?`srcdoc:${t.getAttribute("srcdoc")}`:`src:${n=t.src||"",n.split("#")[0]}`;var n}function m(e){const t=e.$iframe;return t.hasAttribute?.("srcdoc")?`srcdoc:${t.getAttribute("srcdoc")}`:`src:${t.getAttribute?.("src")??t.src??""}`}function h(e,t){t.waiting||(t.documentId?t.cancelPrevious=function(e){const t=[...s.get(e)||[]];return e=>{for(const n of t)n.cancel(e)}}(e):d(e,new Error("The iframe document has changed"))),t.waiting=!0,e.injected=!1}function l(e,t,n){const r=m(e);if(!n.length&&r===t.rawSource)return;const o=function(e,t,n){return f(e)!==t.source||!!t.documentId&&(m(e)!==t.rawSource||n.some(t=>"srcdoc"===t.attributeName||"src"===t.attributeName&&!e.$iframe.hasAttribute?.("srcdoc")))}(e,t,n);t.rawSource=r,t.source=f(e),o&&h(e,t)}function w(e){const t=u.get(e);if(!t||e.destroyed)return;const n=t.observer?.takeRecords()||[];l(e,t,n)}function p(t,r,o){r.hasHandshake&&r.documentId!==o&&(r.cancelPrevious?r.cancelPrevious(new Error("The iframe document has changed")):r.waiting||d(t,new Error("The iframe document has changed"))),r.cancelPrevious=void 0,r.documentId=o,r.hasHandshake=!0,r.waiting=!1,t.injected=!0;try{t.$iframe.contentWindow?.postMessage(n({type:e,data:void 0,id:0},o,"ack"),"*")}catch{}}function g(n,r){const o=u.get(n);if(!o)return!1;w(n);const s=t(r);if(s&&r.type===e)return"resume"===s.phase?p(n,o,s.document):s.document===o.documentId&&("leave"===s.phase?function(e,t){t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||d(e,new Error("The iframe document has changed")),t.cancelPrevious=void 0,t.waiting=!0,e.injected=!1}(n,o):"fragment"===s.phase&&o.cancelPrevious&&!n.$iframe.hasAttribute?.("srcdoc")&&r.data===n.$iframe.src&&p(n,o,s.document)),!0;if("inject"===r.type){if("inject"===s?.phase){if(o.waiting&&s.document===o.documentId)return!0;p(n,o,s.document)}else o.waiting&&(o.cancelPrevious?.(new Error("The iframe document has changed")),o.cancelPrevious=void 0,o.documentId=void 0),o.hasHandshake=!0,o.waiting=!1;return!1}return Boolean(s&&(o.waiting&&!o.cancelPrevious||s.document!==o.documentId))}const y=new WeakMap;function v(e){const t=window,r=e.onMessage,o=[()=>t.removeEventListener("message",r)];y.set(e,()=>{let e,t=!1;for(const r of o)try{r()}catch(n){t||(t=!0,e=n)}if(t)throw e}),t.addEventListener("message",r),e.$iframe.src=e.url;const s=function(e){const t={source:f(e),rawSource:m(e),hasHandshake:!1,waiting:!1};return u.set(e,t),c(e,{prepare:()=>w(e),envelope:e=>t.documentId?n(e,t.documentId,"message"):e}),{start(){"function"===typeof window.MutationObserver&&(t.observer=new window.MutationObserver(n=>{e.destroyed||l(e,t,n)}),t.observer.observe(e.$iframe,{attributes:!0,attributeOldValue:!0,attributeFilter:["src","srcdoc"]}))},dispose(){u.delete(e),c(e,void 0),t.cancelPrevious=void 0,t.observer?.disconnect()}}}(e);o.push(s.dispose),s.start()}function b(e){const t=y.get(e);y.delete(e);try{t?.()}finally{d(e)}}class E{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:r=0}){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');var s;window.parent.postMessage((s={type:e,data:t,id:r},o&&("inject"===s.type||o.acknowledged)?n(s,o.id,"inject"===s.type?"inject":"message"):s),"*")}static async onMessage(n){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!r(n,window.parent)||function(n){const r=t(n);return!!r&&(n.type===e?(o&&r.document===o.id&&"ack"===r.phase&&(o.acknowledged=!0),!0):!o||r.document!==o.id)}(n.data))return;const{type:s,data:i,id:a}=n.data;if("commit"===s)try{if(i.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${i}\n})`,t=await new Function(e)();E.postMessage({type:"response",data:t,id:a})}else{const e=new Function(i)();E.postMessage({type:"response",data:e,id:a})}}catch(c){throw E.postMessage({type:"error",data:c.message,id:a}),c}}static inject(){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');!function(){if(o?.owner===window.document&&o)return;const e=new Uint32Array(4);window.crypto?.getRandomValues?window.crypto.getRandomValues(e):e.forEach((t,n)=>e[n]=Math.floor(4294967296*Math.random())),o={owner:window.document,id:`${Date.now()}-${Array.from(e).join("-")}`,acknowledged:!1,lifecycle:!1,receivers:new Set}}(),E.postMessage({type:"inject"}),function(t){const r=o,s=!r.receivers.has(t),i=!r.lifecycle,a=(t,o)=>{if(r.acknowledged)try{window.parent.postMessage(n({type:e,data:o,id:0},r.id,t),"*")}catch{}},c=()=>a("leave"),d=()=>a("fragment",window.location.href),u=e=>{e.persisted&&a("resume")};try{if(window.addEventListener("message",t),r.receivers.add(t),!i)return;window.addEventListener("pagehide",c),window.addEventListener("pageshow",u),window.addEventListener("hashchange",d),r.lifecycle=!0}catch(f){const e=[];i&&(e.push(()=>window.removeEventListener("pagehide",c)),e.push(()=>window.removeEventListener("pageshow",u)),e.push(()=>window.removeEventListener("hashchange",d))),s&&e.push(()=>window.removeEventListener("message",t));for(const t of e)try{t()}catch{}throw s&&r.receivers.delete(t),f}}(E.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{v(this)}catch(n){this.destroyed=!0;try{b(this)}catch{}throw n}}onMessage(e){if(this.destroyed||!r(e,this.$iframe.contentWindow)||g(this,e.data))return;const{type:t,data:n,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(n)):this.promises[o].resove(n),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:n})}postMessage(e){return w(this),function(e,{type:t,data:n}){return new Promise((r,o)=>{if(e.destroyed)return void o(new Error("The instance has been destroyed"));const c=s.get(e)||new Set;s.set(e,c);const d=t=>!!c.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete e.promises[t.id],c.size||s.delete(e),!0),u={callbacks:{resove(e){d(u)&&r(e)},reject(e){d(u)&&o(e)}},cancel(e){d(u)&&o(e)}};c.add(u);const f=()=>{if(u.timer=void 0,c.has(u))if(e.destroyed)u.cancel(new Error("The instance has been destroyed"));else try{if(i.get(e)?.prepare(),!c.has(u))return;if(e.injected){const r=Math.max(Date.now(),a+1);a=r,u.id=r,e.promises[r]=u.callbacks;const o={type:t,data:n,id:r};e.$iframe.contentWindow.postMessage(i.get(e)?.envelope(o)||o,"*")}else u.timer=setTimeout(f,200)}catch(r){u.cancel(r)}};f()})}(this,e)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),n=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:n})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,b(this)}}return E}); diff --git a/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.legacy.js b/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.legacy.js index 1d8339ba4..171c31876 100644 --- a/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.legacy.js +++ b/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.legacy.js @@ -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;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}); +!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";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;const a="artplayer-tool-iframe:session";function c(e){const t=e.__artplayerIframe;if(1===(null==t?void 0:t.version)&&"string"===typeof t.document&&t.document&&["inject","message","ack","leave","resume","fragment"].includes(t.phase))return t}function d(e,a,c){return d=((e,t)=>{for(var n in t||(t={}))o.call(t,n)&&i(e,n,t[n]);if(r)for(var n of r(t))s.call(t,n)&&i(e,n,t[n]);return e})({},e),t(d,n({__artplayerIframe:{version:1,document:a,phase:c}}));var d}function u(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const n=e.data;return"object"===typeof n&&null!==n&&"type"in n&&"string"===typeof n.type}let l;const f=new WeakMap,m=new WeakMap;let h=0;function p(e,t){t?m.set(e,t):m.delete(e)}function w(e,t=new Error("The instance has been destroyed")){const n=f.get(e);if(n)for(const r of[...n])r.cancel(t)}const v=new WeakMap;function y(e){var t;const n=e.$iframe;return(null==(t=n.hasAttribute)?void 0:t.call(n,"srcdoc"))?`srcdoc:${n.getAttribute("srcdoc")}`:`src:${r=n.src||"",r.split("#")[0]}`;var r}function g(e){var t,n,r,o;const s=e.$iframe;return(null==(t=s.hasAttribute)?void 0:t.call(s,"srcdoc"))?`srcdoc:${s.getAttribute("srcdoc")}`:`src:${null!=(o=null!=(r=null==(n=s.getAttribute)?void 0:n.call(s,"src"))?r:s.src)?o:""}`}function b(e,t){t.waiting||(t.documentId?t.cancelPrevious=function(e){const t=[...f.get(e)||[]];return e=>{for(const n of t)n.cancel(e)}}(e):w(e,new Error("The iframe document has changed"))),t.waiting=!0,e.injected=!1}function E(e,t,n){const r=g(e);if(!n.length&&r===t.rawSource)return;const o=function(e,t,n){return y(e)!==t.source||!!t.documentId&&(g(e)!==t.rawSource||n.some(t=>{var n,r;return"srcdoc"===t.attributeName||"src"===t.attributeName&&!(null==(r=(n=e.$iframe).hasAttribute)?void 0:r.call(n,"srcdoc"))}))}(e,t,n);t.rawSource=r,t.source=y(e),o&&b(e,t)}function M(e){var t;const n=v.get(e);if(!n||e.destroyed)return;E(e,n,(null==(t=n.observer)?void 0:t.takeRecords())||[])}function j(e,t,n){var r;t.hasHandshake&&t.documentId!==n&&(t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||w(e,new Error("The iframe document has changed"))),t.cancelPrevious=void 0,t.documentId=n,t.hasHandshake=!0,t.waiting=!1,e.injected=!0;try{null==(r=e.$iframe.contentWindow)||r.postMessage(d({type:a,data:void 0,id:0},n,"ack"),"*")}catch(o){}}function T(e,t){var n,r,o;const s=v.get(e);if(!s)return!1;M(e);const i=c(t);if(i&&t.type===a)return"resume"===i.phase?j(e,s,i.document):i.document===s.documentId&&("leave"===i.phase?function(e,t){t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||w(e,new Error("The iframe document has changed")),t.cancelPrevious=void 0,t.waiting=!0,e.injected=!1}(e,s):"fragment"===i.phase&&s.cancelPrevious&&!(null==(r=(n=e.$iframe).hasAttribute)?void 0:r.call(n,"srcdoc"))&&t.data===e.$iframe.src&&j(e,s,i.document)),!0;if("inject"===t.type){if("inject"===(null==i?void 0:i.phase)){if(s.waiting&&i.document===s.documentId)return!0;j(e,s,i.document)}else s.waiting&&(null==(o=s.cancelPrevious)||o.call(s,new Error("The iframe document has changed")),s.cancelPrevious=void 0,s.documentId=void 0),s.hasHandshake=!0,s.waiting=!1;return!1}return Boolean(i&&(s.waiting&&!s.cancelPrevious||i.document!==s.documentId))}const k=new WeakMap;function P(e){const t=window,n=e.onMessage,r=[()=>t.removeEventListener("message",n)];k.set(e,()=>{let e,t=!1;for(const o of r)try{o()}catch(n){t||(t=!0,e=n)}if(t)throw e}),t.addEventListener("message",n),e.$iframe.src=e.url;const o=function(e){const t={source:y(e),rawSource:g(e),hasHandshake:!1,waiting:!1};return v.set(e,t),p(e,{prepare:()=>M(e),envelope:e=>t.documentId?d(e,t.documentId,"message"):e}),{start(){"function"===typeof window.MutationObserver&&(t.observer=new window.MutationObserver(n=>{e.destroyed||E(e,t,n)}),t.observer.observe(e.$iframe,{attributes:!0,attributeOldValue:!0,attributeFilter:["src","srcdoc"]}))},dispose(){var n;v.delete(e),p(e,void 0),t.cancelPrevious=void 0,null==(n=t.observer)||n.disconnect()}}}(e);r.push(o.dispose),o.start()}function I(e){const t=k.get(e);k.delete(e);try{null==t||t()}finally{w(e)}}class ${static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:n=0}){if(!$.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');var r;window.parent.postMessage((r={type:e,data:t,id:n},l&&("inject"===r.type||l.acknowledged)?d(r,l.id,"inject"===r.type?"inject":"message"):r),"*")}static onMessage(e){return t=this,n=null,r=function*(){if(!$.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!u(e,window.parent)||function(e){const t=c(e);return!!t&&(e.type===a?(l&&t.document===l.id&&"ack"===t.phase&&(l.acknowledged=!0),!0):!l||t.document!==l.id)}(e.data))return;const{type:t,data:n,id:r}=e.data;if("commit"===t)try{if(n.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${n}\n})`,t=yield new Function(e)();$.postMessage({type:"response",data:t,id:r})}else{const e=new Function(n)();$.postMessage({type:"response",data:e,id:r})}}catch(o){throw $.postMessage({type:"error",data:o.message,id:r}),o}},new Promise((e,o)=>{var s=e=>{try{a(r.next(e))}catch(t){o(t)}},i=e=>{try{a(r.throw(e))}catch(t){o(t)}},a=t=>t.done?e(t.value):Promise.resolve(t.value).then(s,i);a((r=r.apply(t,n)).next())});var t,n,r}static inject(){if(!$.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');!function(){var e;if((null==l?void 0:l.owner)===window.document&&l)return;const t=new Uint32Array(4);(null==(e=window.crypto)?void 0:e.getRandomValues)?window.crypto.getRandomValues(t):t.forEach((e,n)=>t[n]=Math.floor(4294967296*Math.random())),l={owner:window.document,id:`${Date.now()}-${Array.from(t).join("-")}`,acknowledged:!1,lifecycle:!1,receivers:new Set}}(),$.postMessage({type:"inject"}),function(e){const t=l,n=!t.receivers.has(e),r=!t.lifecycle,o=(e,n)=>{if(t.acknowledged)try{window.parent.postMessage(d({type:a,data:n,id:0},t.id,e),"*")}catch(r){}},s=()=>o("leave"),i=()=>o("fragment",window.location.href),c=e=>{e.persisted&&o("resume")};try{if(window.addEventListener("message",e),t.receivers.add(e),!r)return;window.addEventListener("pagehide",s),window.addEventListener("pageshow",c),window.addEventListener("hashchange",i),t.lifecycle=!0}catch(u){const o=[];r&&(o.push(()=>window.removeEventListener("pagehide",s)),o.push(()=>window.removeEventListener("pageshow",c)),o.push(()=>window.removeEventListener("hashchange",i))),n&&o.push(()=>window.removeEventListener("message",e));for(const e of o)try{e()}catch(f){}throw n&&t.receivers.delete(e),u}}($.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{P(this)}catch(n){this.destroyed=!0;try{I(this)}catch(r){}throw n}}onMessage(e){if(this.destroyed||!u(e,this.$iframe.contentWindow)||T(this,e.data))return;const{type:t,data:n,id:r}=e.data;if("inject"===t)this.injected=!0;void 0!==r&&Object.prototype.hasOwnProperty.call(this.promises,r)&&this.promises[r]&&("error"===t?this.promises[r].reject(new Error(n)):this.promises[r].resove(n),delete this.promises[r]),this.messageCallback&&this.messageCallback({type:t,data:n})}postMessage(e){return M(this),function(e,{type:t,data:n}){return new Promise((r,o)=>{if(e.destroyed)return void o(new Error("The instance has been destroyed"));const s=f.get(e)||new Set;f.set(e,s);const i=t=>!!s.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete e.promises[t.id],s.size||f.delete(e),!0),a={callbacks:{resove(e){i(a)&&r(e)},reject(e){i(a)&&o(e)}},cancel(e){i(a)&&o(e)}};s.add(a);const c=()=>{var r,o;if(a.timer=void 0,s.has(a))if(e.destroyed)a.cancel(new Error("The instance has been destroyed"));else try{if(null==(r=m.get(e))||r.prepare(),!s.has(a))return;if(e.injected){const r=Math.max(Date.now(),h+1);h=r,a.id=r,e.promises[r]=a.callbacks;const s={type:t,data:n,id:r};e.$iframe.contentWindow.postMessage((null==(o=m.get(e))?void 0:o.envelope(s))||s,"*")}else a.timer=setTimeout(c,200)}catch(i){a.cancel(i)}};c()})}(this,e)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),n=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:n})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,I(this)}}return $}); diff --git a/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.mjs b/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.mjs index 0deb5d536..e7076f494 100644 --- a/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.mjs +++ b/packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.mjs @@ -4,8 +4,104 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ +const sessionType = "artplayer-tool-iframe:session"; +function sessionMetadata(packet) { + const value = packet.__artplayerIframe; + if (value?.version === 1 && typeof value.document === "string" && value.document && ["inject", "message", "ack", "leave", "resume", "fragment"].includes(value.phase)) + return value; +} +function withSession(packet, documentId, phase) { + return { ...packet, __artplayerIframe: { version: 1, document: documentId, phase } }; +} +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"; +} +let session; +function prepareChildSession() { + if (session?.owner === window.document && session) + return; + const random = new Uint32Array(4); + if (window.crypto?.getRandomValues) + window.crypto.getRandomValues(random); + else + random.forEach((_, index) => random[index] = Math.floor(Math.random() * 4294967296)); + session = { owner: window.document, id: `${Date.now()}-${Array.from(random).join("-")}`, acknowledged: false, lifecycle: false, receivers: /* @__PURE__ */ new Set() }; +} +function childEnvelope(packet) { + if (session && (packet.type === "inject" || session.acknowledged)) + return withSession(packet, session.id, packet.type === "inject" ? "inject" : "message"); + return packet; +} +function consumeChildSession(packet) { + const metadata = sessionMetadata(packet); + if (!metadata) + return false; + if (packet.type === sessionType) { + if (session && metadata.document === session.id && metadata.phase === "ack") + session.acknowledged = true; + return true; + } + return !session || metadata.document !== session.id; +} +function connectChildSession(receiver) { + const current = session; + const added = !current.receivers.has(receiver); + const installing = !current.lifecycle; + const notify = (phase, data) => { + if (!current.acknowledged) + return; + try { + window.parent.postMessage(withSession({ type: sessionType, data, id: 0 }, current.id, phase), "*"); + } catch { + } + }; + const leave = () => notify("leave"); + const fragment = () => notify("fragment", window.location.href); + const resume = (event) => { + if (event.persisted) + notify("resume"); + }; + try { + window.addEventListener("message", receiver); + current.receivers.add(receiver); + if (!installing) + return; + window.addEventListener("pagehide", leave); + window.addEventListener("pageshow", resume); + window.addEventListener("hashchange", fragment); + current.lifecycle = true; + } catch (error) { + const cleanups = []; + if (installing) { + cleanups.push(() => window.removeEventListener("pagehide", leave)); + cleanups.push(() => window.removeEventListener("pageshow", resume)); + cleanups.push(() => window.removeEventListener("hashchange", fragment)); + } + if (added) + cleanups.push(() => window.removeEventListener("message", receiver)); + for (const cleanup of cleanups) { + try { + cleanup(); + } catch { + } + } + if (added) + current.receivers.delete(receiver); + throw error; + } +} const requests = /* @__PURE__ */ new WeakMap(); +const boundaries = /* @__PURE__ */ new WeakMap(); let lastId = 0; +function setRequestBoundary(host, boundary) { + if (boundary) + boundaries.set(host, boundary); + else + boundaries.delete(host); +} function postRequest(host, { type, data }) { return new Promise((resolve, reject) => { if (host.destroyed) { @@ -35,6 +131,10 @@ function postRequest(host, { type, data }) { if (finish(request)) reject(error); } + }, + cancel(error) { + if (finish(request)) + reject(error); } }; pending.add(request); @@ -43,40 +143,209 @@ function postRequest(host, { type, data }) { if (!pending.has(request)) return; if (host.destroyed) { - request.callbacks.reject(new Error("The instance has been destroyed")); + request.cancel(new Error("The instance has been destroyed")); return; } try { + boundaries.get(host)?.prepare(); + if (!pending.has(request)) + return; if (host.injected) { const id = Math.max(Date.now(), lastId + 1); lastId = id; request.id = id; host.promises[id] = request.callbacks; - host.$iframe.contentWindow.postMessage({ type, data, id }, "*"); + const packet = { type, data, id }; + host.$iframe.contentWindow.postMessage(boundaries.get(host)?.envelope(packet) || packet, "*"); } else { request.timer = setTimeout(loop, 200); } } catch (error) { - request.callbacks.reject(error); + request.cancel(error); } }; loop(); }); } -function cancelRequests(host) { +function cancelRequests(host, reason = new Error("The instance has been destroyed")) { const pending = requests.get(host); if (!pending) return; for (const request of [...pending]) - request.callbacks.reject(new Error("The instance has been destroyed")); + request.cancel(reason); +} +function captureRequests(host) { + const captured = [...requests.get(host) || []]; + return (reason) => { + for (const request of captured) + request.cancel(reason); + }; +} +const navigations = /* @__PURE__ */ new WeakMap(); +const withoutHash = (value) => value.split("#")[0]; +function sourceOf(host) { + const frame = host.$iframe; + return frame.hasAttribute?.("srcdoc") ? `srcdoc:${frame.getAttribute("srcdoc")}` : `src:${withoutHash(frame.src || "")}`; +} +function rawSourceOf(host) { + const frame = host.$iframe; + return frame.hasAttribute?.("srcdoc") ? `srcdoc:${frame.getAttribute("srcdoc")}` : `src:${frame.getAttribute?.("src") ?? frame.src ?? ""}`; +} +function invalidate(host, state) { + if (!state.waiting) { + if (state.documentId) + state.cancelPrevious = captureRequests(host); + else + cancelRequests(host, new Error("The iframe document has changed")); + } + state.waiting = true; + host.injected = false; +} +function leaveDocument(host, state) { + if (state.cancelPrevious) + state.cancelPrevious(new Error("The iframe document has changed")); + else if (!state.waiting) + cancelRequests(host, new Error("The iframe document has changed")); + state.cancelPrevious = void 0; + state.waiting = true; + host.injected = false; +} +function sourceChanged(host, state, records) { + if (sourceOf(host) !== state.source) + return true; + if (!state.documentId) + return false; + if (rawSourceOf(host) !== state.rawSource) + return true; + return records.some((record) => { + if (record.attributeName === "srcdoc") + return true; + if (record.attributeName !== "src" || host.$iframe.hasAttribute?.("srcdoc")) + return false; + return true; + }); +} +function observeSource(host, state, records) { + const rawSource = rawSourceOf(host); + if (!records.length && rawSource === state.rawSource) + return; + const changed = sourceChanged(host, state, records); + state.rawSource = rawSource; + state.source = sourceOf(host); + if (changed) + invalidate(host, state); +} +function prepareNavigation(host) { + const state = navigations.get(host); + if (!state || host.destroyed) + return; + const records = state.observer?.takeRecords() || []; + observeSource(host, state, records); +} +function createNavigation(host) { + const state = { source: sourceOf(host), rawSource: rawSourceOf(host), hasHandshake: false, waiting: false }; + navigations.set(host, state); + setRequestBoundary(host, { + prepare: () => prepareNavigation(host), + envelope: (packet) => state.documentId ? withSession(packet, state.documentId, "message") : packet + }); + return { + start() { + if (typeof window.MutationObserver !== "function") + return; + state.observer = new window.MutationObserver((records) => { + if (host.destroyed) + return; + observeSource(host, state, records); + }); + state.observer.observe(host.$iframe, { attributes: true, attributeOldValue: true, attributeFilter: ["src", "srcdoc"] }); + }, + dispose() { + navigations.delete(host); + setRequestBoundary(host, void 0); + state.cancelPrevious = void 0; + state.observer?.disconnect(); + } + }; +} +function activate(host, state, documentId) { + if (state.hasHandshake && state.documentId !== documentId) { + if (state.cancelPrevious) + state.cancelPrevious(new Error("The iframe document has changed")); + else if (!state.waiting) + cancelRequests(host, new Error("The iframe document has changed")); + } + state.cancelPrevious = void 0; + state.documentId = documentId; + state.hasHandshake = true; + state.waiting = false; + host.injected = true; + try { + host.$iframe.contentWindow?.postMessage(withSession({ type: sessionType, data: void 0, id: 0 }, documentId, "ack"), "*"); + } catch { + } +} +function consumeNavigation(host, packet) { + const state = navigations.get(host); + if (!state) + return false; + prepareNavigation(host); + const metadata = sessionMetadata(packet); + if (metadata && packet.type === sessionType) { + if (metadata.phase === "resume") { + activate(host, state, metadata.document); + } else if (metadata.document === state.documentId) { + if (metadata.phase === "leave") + leaveDocument(host, state); + else if (metadata.phase === "fragment" && state.cancelPrevious && !host.$iframe.hasAttribute?.("srcdoc") && packet.data === host.$iframe.src) + activate(host, state, metadata.document); + } + return true; + } + if (packet.type === "inject") { + if (metadata?.phase === "inject") { + if (state.waiting && metadata.document === state.documentId) + return true; + activate(host, state, metadata.document); + } else { + if (state.waiting) { + state.cancelPrevious?.(new Error("The iframe document has changed")); + state.cancelPrevious = void 0; + state.documentId = void 0; + } + state.hasHandshake = true; + state.waiting = false; + } + return false; + } + return Boolean(metadata && (state.waiting && !state.cancelPrevious || metadata.document !== state.documentId)); } const connections = /* @__PURE__ */ new WeakMap(); function connect(host) { const owner = window; const receiver = host.onMessage; - connections.set(host, () => owner.removeEventListener("message", receiver)); + const cleanups = [() => owner.removeEventListener("message", receiver)]; + connections.set(host, () => { + let failed = false; + let failure; + for (const cleanup of cleanups) { + try { + cleanup(); + } catch (error) { + if (!failed) { + failed = true; + failure = error; + } + } + } + if (failed) + throw failure; + }); owner.addEventListener("message", receiver); host.$iframe.src = host.url; + const navigation = createNavigation(host); + cleanups.push(navigation.dispose); + navigation.start(); } function releaseConnection(host) { const disconnect = connections.get(host); @@ -87,12 +356,6 @@ function releaseConnection(host) { 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; @@ -102,11 +365,11 @@ class ArtplayerToolIframe { throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe'); } window.parent.postMessage( - { + childEnvelope({ type, data, id - }, + }), "*" ); } @@ -114,7 +377,7 @@ class ArtplayerToolIframe { if (!ArtplayerToolIframe.iframe) { throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe'); } - if (!acceptsMessage(event, window.parent)) + if (!acceptsMessage(event, window.parent) || consumeChildSession(event.data)) return; const { type, data, id } = event.data; switch (type) { @@ -141,8 +404,9 @@ ${data} if (!ArtplayerToolIframe.iframe) { throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe'); } + prepareChildSession(); ArtplayerToolIframe.postMessage({ type: "inject" }); - window.addEventListener("message", ArtplayerToolIframe.onMessage); + connectChildSession(ArtplayerToolIframe.onMessage); } constructor({ iframe, url }) { if (iframe instanceof HTMLIFrameElement === false) { @@ -170,7 +434,7 @@ ${data} } } onMessage(event) { - if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow)) + if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow) || consumeNavigation(this, event.data)) return; const { type, data, id } = event.data; switch (type) { @@ -191,6 +455,7 @@ ${data} } } postMessage(message) { + prepareNavigation(this); return postRequest(this, message); } commit(callback) { diff --git a/packages/artplayer-tool-iframe/src/child-session.ts b/packages/artplayer-tool-iframe/src/child-session.ts new file mode 100644 index 000000000..f67407717 --- /dev/null +++ b/packages/artplayer-tool-iframe/src/child-session.ts @@ -0,0 +1,92 @@ +import type { Packet } from './requests' +import { sessionMetadata, sessionType, withSession } from './protocol' + +interface ChildSession { + owner: Document + id: string + acknowledged: boolean + lifecycle: boolean + receivers: Set<(event: MessageEvent) => void> +} + +let session: ChildSession | undefined + +export function prepareChildSession(): void { + if (session?.owner === window.document && session) + return + const random = new Uint32Array(4) + if (window.crypto?.getRandomValues) + window.crypto.getRandomValues(random) + else + random.forEach((_, index) => random[index] = Math.floor(Math.random() * 0x100000000)) + session = { owner: window.document, id: `${Date.now()}-${Array.from(random).join('-')}`, acknowledged: false, lifecycle: false, receivers: new Set() } +} + +export function childEnvelope(packet: Packet): Packet { + if (session && (packet.type === 'inject' || session.acknowledged)) + return withSession(packet, session.id, packet.type === 'inject' ? 'inject' : 'message') + return packet +} + +export function consumeChildSession(packet: Packet): boolean { + const metadata = sessionMetadata(packet) + if (!metadata) + return false + if (packet.type === sessionType) { + if (session && metadata.document === session.id && metadata.phase === 'ack') + session.acknowledged = true + return true + } + return !session || metadata.document !== session.id +} + +export function connectChildSession(receiver: (event: MessageEvent) => void): void { + const current = session! + const added = !current.receivers.has(receiver) + const installing = !current.lifecycle + const notify = (phase: 'leave' | 'resume' | 'fragment', data?: unknown) => { + if (!current.acknowledged) + return + try { + window.parent.postMessage(withSession({ type: sessionType, data, id: 0 }, current.id, phase), '*') + } + catch { + // The parent may have disappeared; this private lifecycle notification is best effort. + } + } + const leave = () => notify('leave') + const fragment = () => notify('fragment', window.location.href) + const resume = (event: PageTransitionEvent) => { + if (event.persisted) + notify('resume') + } + try { + window.addEventListener('message', receiver) + current.receivers.add(receiver) + if (!installing) + return + window.addEventListener('pagehide', leave) + window.addEventListener('pageshow', resume) + window.addEventListener('hashchange', fragment) + current.lifecycle = true + } + catch (error) { + const cleanups: (() => void)[] = [] + if (installing) { + cleanups.push(() => window.removeEventListener('pagehide', leave)) + cleanups.push(() => window.removeEventListener('pageshow', resume)) + cleanups.push(() => window.removeEventListener('hashchange', fragment)) + } + if (added) + cleanups.push(() => window.removeEventListener('message', receiver)) + for (const cleanup of cleanups) { + try { + cleanup() + } + catch { /* Preserve the acquisition error while releasing the other listeners. */ } + } + if (added) + current.receivers.delete(receiver) + throw error + } +} diff --git a/packages/artplayer-tool-iframe/src/connection.ts b/packages/artplayer-tool-iframe/src/connection.ts index 350dc3114..d85d9179e 100644 --- a/packages/artplayer-tool-iframe/src/connection.ts +++ b/packages/artplayer-tool-iframe/src/connection.ts @@ -1,4 +1,5 @@ import type { Packet, RequestHost } from './requests' +import { createNavigation } from './navigation' import { cancelRequests } from './requests' interface ConnectionHost extends RequestHost { @@ -11,9 +12,29 @@ const connections = new WeakMap void>() export function connect(host: ConnectionHost): void { const owner = window const receiver = host.onMessage - connections.set(host, () => owner.removeEventListener('message', receiver)) + const cleanups = [() => owner.removeEventListener('message', receiver)] + connections.set(host, () => { + let failed = false + let failure: unknown + for (const cleanup of cleanups) { + try { + cleanup() + } + catch (error) { + if (!failed) { + failed = true + failure = error + } + } + } + if (failed) + throw failure + }) owner.addEventListener('message', receiver) host.$iframe.src = host.url + const navigation = createNavigation(host) + cleanups.push(navigation.dispose) + navigation.start() } export function releaseConnection(host: ConnectionHost): void { diff --git a/packages/artplayer-tool-iframe/src/index.ts b/packages/artplayer-tool-iframe/src/index.ts index 3d69189d2..c16087362 100644 --- a/packages/artplayer-tool-iframe/src/index.ts +++ b/packages/artplayer-tool-iframe/src/index.ts @@ -1,5 +1,7 @@ import type { Callbacks, Packet } from './requests' +import { childEnvelope, connectChildSession, consumeChildSession, prepareChildSession } from './child-session' import { connect, releaseConnection } from './connection' +import { consumeNavigation, prepareNavigation } from './navigation' import { acceptsMessage } from './protocol' import { postRequest } from './requests' @@ -21,11 +23,11 @@ export default class ArtplayerToolIframe { } window.parent.postMessage( - { + childEnvelope({ type, data, id, - }, + }), '*', ) } @@ -35,7 +37,7 @@ export default class ArtplayerToolIframe { throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe') } - if (!acceptsMessage(event, window.parent)) + if (!acceptsMessage(event, window.parent) || consumeChildSession(event.data)) return const { type, data, id } = event.data @@ -69,8 +71,9 @@ export default class ArtplayerToolIframe { throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe') } + prepareChildSession() ArtplayerToolIframe.postMessage({ type: 'inject' }) - window.addEventListener('message', ArtplayerToolIframe.onMessage) + connectChildSession(ArtplayerToolIframe.onMessage) } constructor({ iframe, url }: { iframe: HTMLIFrameElement, url: string }) { @@ -105,7 +108,7 @@ export default class ArtplayerToolIframe { } onMessage(event: MessageEvent) { - if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow)) + if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow) || consumeNavigation(this, event.data)) return const { type, data, id } = event.data @@ -134,6 +137,7 @@ export default class ArtplayerToolIframe { } postMessage(message: Packet): Promise { + prepareNavigation(this) return postRequest(this, message) } diff --git a/packages/artplayer-tool-iframe/src/navigation.ts b/packages/artplayer-tool-iframe/src/navigation.ts new file mode 100644 index 000000000..da007dc36 --- /dev/null +++ b/packages/artplayer-tool-iframe/src/navigation.ts @@ -0,0 +1,166 @@ +import type { Packet, RequestHost } from './requests' +import { sessionMetadata, sessionType, withSession } from './protocol' +import { cancelRequests, captureRequests, setRequestBoundary } from './requests' + +interface Navigation { + source: string + rawSource: string + documentId?: string + hasHandshake: boolean + waiting: boolean + observer?: MutationObserver + cancelPrevious?: (reason: unknown) => void +} + +const navigations = new WeakMap() +const withoutHash = (value: string) => value.split('#')[0]! +function sourceOf(host: RequestHost): string { + const frame = host.$iframe + return frame.hasAttribute?.('srcdoc') ? `srcdoc:${frame.getAttribute('srcdoc')}` : `src:${withoutHash(frame.src || '')}` +} + +function rawSourceOf(host: RequestHost): string { + const frame = host.$iframe + return frame.hasAttribute?.('srcdoc') ? `srcdoc:${frame.getAttribute('srcdoc')}` : `src:${frame.getAttribute?.('src') ?? frame.src ?? ''}` +} + +function invalidate(host: RequestHost, state: Navigation): void { + if (!state.waiting) { + if (state.documentId) + state.cancelPrevious = captureRequests(host) + else + cancelRequests(host, new Error('The iframe document has changed')) + } + state.waiting = true + host.injected = false +} + +function leaveDocument(host: RequestHost, state: Navigation): void { + if (state.cancelPrevious) + state.cancelPrevious(new Error('The iframe document has changed')) + else if (!state.waiting) + cancelRequests(host, new Error('The iframe document has changed')) + state.cancelPrevious = undefined + state.waiting = true + host.injected = false +} + +function sourceChanged(host: RequestHost, state: Navigation, records: MutationRecord[]): boolean { + if (sourceOf(host) !== state.source) + return true + if (!state.documentId) + return false + if (rawSourceOf(host) !== state.rawSource) + return true + return records.some((record) => { + if (record.attributeName === 'srcdoc') + return true + if (record.attributeName !== 'src' || host.$iframe.hasAttribute?.('srcdoc')) + return false + return true + }) +} + +function observeSource(host: RequestHost, state: Navigation, records: MutationRecord[]): void { + const rawSource = rawSourceOf(host) + if (!records.length && rawSource === state.rawSource) + return + const changed = sourceChanged(host, state, records) + state.rawSource = rawSource + state.source = sourceOf(host) + if (changed) + invalidate(host, state) +} + +export function prepareNavigation(host: RequestHost): void { + const state = navigations.get(host) + if (!state || host.destroyed) + return + const records = state.observer?.takeRecords() || [] + observeSource(host, state, records) +} + +export function createNavigation(host: RequestHost): { start: () => void, dispose: () => void } { + const state: Navigation = { source: sourceOf(host), rawSource: rawSourceOf(host), hasHandshake: false, waiting: false } + navigations.set(host, state) + setRequestBoundary(host, { + prepare: () => prepareNavigation(host), + envelope: packet => state.documentId ? withSession(packet, state.documentId, 'message') : packet, + }) + return { + start() { + if (typeof window.MutationObserver !== 'function') + return + state.observer = new window.MutationObserver((records) => { + if (host.destroyed) + return + observeSource(host, state, records) + }) + state.observer.observe(host.$iframe, { attributes: true, attributeOldValue: true, attributeFilter: ['src', 'srcdoc'] }) + }, + dispose() { + navigations.delete(host) + setRequestBoundary(host, undefined) + state.cancelPrevious = undefined + state.observer?.disconnect() + }, + } +} + +function activate(host: RequestHost, state: Navigation, documentId: string): void { + if (state.hasHandshake && state.documentId !== documentId) { + if (state.cancelPrevious) + state.cancelPrevious(new Error('The iframe document has changed')) + else if (!state.waiting) + cancelRequests(host, new Error('The iframe document has changed')) + } + state.cancelPrevious = undefined + state.documentId = documentId + state.hasHandshake = true + state.waiting = false + host.injected = true + try { + host.$iframe.contentWindow?.postMessage(withSession({ type: sessionType, data: undefined, id: 0 }, documentId, 'ack'), '*') + } + catch { + // A failed private acknowledgement does not replace the public inject callback. + } +} + +export function consumeNavigation(host: RequestHost, packet: Packet): boolean { + const state = navigations.get(host) + if (!state) + return false + prepareNavigation(host) + const metadata = sessionMetadata(packet) + if (metadata && packet.type === sessionType) { + if (metadata.phase === 'resume') { + activate(host, state, metadata.document) + } + else if (metadata.document === state.documentId) { + if (metadata.phase === 'leave') + leaveDocument(host, state) + else if (metadata.phase === 'fragment' && state.cancelPrevious && !host.$iframe.hasAttribute?.('srcdoc') && packet.data === host.$iframe.src) + activate(host, state, metadata.document) + } + return true + } + if (packet.type === 'inject') { + if (metadata?.phase === 'inject') { + if (state.waiting && metadata.document === state.documentId) + return true + activate(host, state, metadata.document) + } + else { + if (state.waiting) { + state.cancelPrevious?.(new Error('The iframe document has changed')) + state.cancelPrevious = undefined + state.documentId = undefined + } + state.hasHandshake = true + state.waiting = false + } + return false + } + return Boolean(metadata && ((state.waiting && !state.cancelPrevious) || metadata.document !== state.documentId)) +} diff --git a/packages/artplayer-tool-iframe/src/protocol.ts b/packages/artplayer-tool-iframe/src/protocol.ts index 500198ef5..9ce002ee7 100644 --- a/packages/artplayer-tool-iframe/src/protocol.ts +++ b/packages/artplayer-tool-iframe/src/protocol.ts @@ -1,5 +1,27 @@ import type { Packet } from './requests' +export const sessionType = 'artplayer-tool-iframe:session' +export type SessionPhase = 'inject' | 'message' | 'ack' | 'leave' | 'resume' | 'fragment' +export interface SessionMetadata { + version: 1 + document: string + phase: SessionPhase +} + +interface SessionPacket extends Packet { + __artplayerIframe: SessionMetadata +} + +export function sessionMetadata(packet: Packet): SessionMetadata | undefined { + const value = (packet as Partial).__artplayerIframe + if (value?.version === 1 && typeof value.document === 'string' && value.document && ['inject', 'message', 'ack', 'leave', 'resume', 'fragment'].includes(value.phase)) + return value +} + +export function withSession(packet: Packet, documentId: string, phase: SessionPhase): SessionPacket { + return { ...packet, __artplayerIframe: { version: 1, document: documentId, phase } } +} + export function acceptsMessage(event: MessageEvent, peer: Window | null): event is MessageEvent { if (event.source !== undefined && event.source !== null && event.source !== peer) return false diff --git a/packages/artplayer-tool-iframe/src/requests.ts b/packages/artplayer-tool-iframe/src/requests.ts index 2855a545c..52c257b74 100644 --- a/packages/artplayer-tool-iframe/src/requests.ts +++ b/packages/artplayer-tool-iframe/src/requests.ts @@ -20,11 +20,24 @@ interface Pending { id?: number timer?: ReturnType callbacks: Callbacks + cancel: (reason: unknown) => void } const requests = new WeakMap>() +interface RequestBoundary { + prepare: () => void + envelope: (packet: Packet) => Packet +} +const boundaries = new WeakMap() let lastId = 0 +export function setRequestBoundary(host: RequestHost, boundary: RequestBoundary | undefined): void { + if (boundary) + boundaries.set(host, boundary) + else + boundaries.delete(host) +} + export function postRequest(host: RequestHost, { type, data }: Packet): Promise { return new Promise((resolve, reject) => { if (host.destroyed) { @@ -55,6 +68,10 @@ export function postRequest(host: RequestHost, { type, data }: Packet): Promise< reject(error) }, }, + cancel(error) { + if (finish(request)) + reject(error) + }, } pending.add(request) const loop = () => { @@ -62,33 +79,45 @@ export function postRequest(host: RequestHost, { type, data }: Packet): Promise< if (!pending.has(request)) return if (host.destroyed) { - request.callbacks.reject(new Error('The instance has been destroyed')) + request.cancel(new Error('The instance has been destroyed')) return } try { + boundaries.get(host)?.prepare() + if (!pending.has(request)) + return if (host.injected) { const id = Math.max(Date.now(), lastId + 1) lastId = id request.id = id host.promises[id] = request.callbacks - host.$iframe.contentWindow!.postMessage({ type, data, id }, '*') + const packet = { type, data, id } + host.$iframe.contentWindow!.postMessage(boundaries.get(host)?.envelope(packet) || packet, '*') } else { request.timer = setTimeout(loop, 200) } } catch (error) { - request.callbacks.reject(error) + request.cancel(error) } } loop() }) } -export function cancelRequests(host: RequestHost): void { +export function cancelRequests(host: RequestHost, reason = new Error('The instance has been destroyed')): void { const pending = requests.get(host) if (!pending) return for (const request of [...pending]) - request.callbacks.reject(new Error('The instance has been destroyed')) + request.cancel(reason) +} + +export function captureRequests(host: RequestHost): (reason: unknown) => void { + const captured = [...(requests.get(host) || [])] + return (reason) => { + for (const request of captured) + request.cancel(reason) + } } diff --git a/refactor/baselines/iframe-navigation-validation.json b/refactor/baselines/iframe-navigation-validation.json new file mode 100644 index 000000000..111d7e143 --- /dev/null +++ b/refactor/baselines/iframe-navigation-validation.json @@ -0,0 +1,9072 @@ +{ + "task": "PKG-IFRAME-03", + "status": "done", + "checkpoint": "verified-document-ownership-and-internal-structure", + "sourceSha256LF": { + "package.json": "1a1441c26e7d7a130db9ec6b984a28b8d925f4f51c113404585b287cef53f943", + "packages/artplayer-tool-iframe/src/index.ts": "64fd8f39b3d23e886ddecda38ae2b1e17b5b93c156825b1de23915c71f33991e", + "packages/artplayer-tool-iframe/src/requests.ts": "74bc15f2102eb45fa00d3b801b629aa1a280ea20af491949ad644e765cb3dbe9", + "packages/artplayer-tool-iframe/src/connection.ts": "a0b2f5a34f1c479f874d824429d1429804f2fabea53015a8e76b9548e8eb208d", + "packages/artplayer-tool-iframe/src/protocol.ts": "c1046b798d79b2765648a7b5e7caa0d8554d2b12f074e960c297429575fa841f", + "packages/artplayer-tool-iframe/src/navigation.ts": "f17f00448e6b337772bd2feb4183cf670e2560d8ab2c1bef63b494ce815c9a7d", + "packages/artplayer-tool-iframe/src/child-session.ts": "0078dd6c209c9f7608c165277b80be40696d90433848b9025e25fc15ec4bf3d5", + "packages/artplayer-tool-iframe/tsconfig.json": "712a3fa32ed57692d16bf854a0e77ffaecd04236efa0f557905aab7291e0aef6", + "packages/artplayer-tool-iframe/types/artplayer-tool-iframe.d.ts": "4f02aa22a6b373393ead533ae3421ad5acf0de7116057f351021c72d3448bd1e", + "packages/artplayer-tool-iframe/ARCHITECTURE.md": "1d750d410f3934d099cf38bf464017bf614257f7aee31a10b95f4d8ce00a0e11", + "test/iframe-navigation.test.js": "8a5f5a1823c66dcdbd53d976d855f65ad68e2922c89bc0b43957a3e241317523", + "test/iframe-boundaries.test.js": "31540e0eaca4050ab496da03bd2e31c5f97c8e30efba10454db1b285a2c4c1a1", + "test/iframe-lifecycle.test.js": "96273d46077c28069504643a989a4d628e875c9aa49fb62e28ac160f7e7aaae1", + "test/helpers/iframe.js": "0aae4805e1bfa8d6cddf1e558daa080fc67f7af8f10b92bc5e8df0d4d28f63f0", + "test/browser/iframe.spec.js": "50add3cec28e94947ac48466860056cb43b9f47b0d08ded816124805567484d0", + "test/browser/iframe-navigation.spec.js": "472e7716a0a1ea263283dba22fc30012f8ac1c9a29e7483e965cc8023e1217a8", + "test/browser/iframe-boundaries.spec.js": "212eb5c3fb10c4b4fe0f1ca89ffd294bd932d29b4e1907e53afed612cf52396e", + "test/browser/iframe-boundary-child.html": "4721de185f606de7d576e71395127257e476765455e2a947ded79df4ebed901a", + "test/browser/server.mjs": "44f49dbeccc47248a0561d5cbea4058e530b3e41d9d0d7ae82b59bcd0c1d7a6d", + "refactor/iframe-document-protocol.md": "2ad6eb902f045ad44a14068747cbd8b0142df62a4ee8d035aee06503d39e03c1" + }, + "artifacts": { + "packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.js": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.legacy.js": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.mjs": "ac4c5efa670c0429fc95bdab7902df60f5b5540f0dad9c7e65c2bd660796dc83" + }, + "sourceBundleSha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "precedingBuild": { + "commit": "b8cdafedd19fe403817ae2ff52b143c1168ce29d", + "file": "refactor/.cache/iframe03-navigation-before.js", + "sha256": "243474c6f31b15fd6c705e05a3b9c3120c005c0514b9299f565a8797590b91dc", + "node": { + "tests": 15, + "passed": 2, + "failed": 13, + "log": "refactor/.cache/iframe03-navigation-before-node-final.log", + "scope": "Before adding the separate candidate consecutive-source regression." + }, + "browser": { + "tests": 39, + "passed": 12, + "failed": 27, + "report": "refactor/.cache/iframe03-navigation-before-final-results/report.json", + "reportSha256": "a55dc76f217fc43576082378c39197291e5bfc7ae0f410a97e3e0fc5ef95779b", + "results": "refactor/.cache/iframe03-navigation-before-final-results/results", + "scope": "Recorded before correcting candidate rapid-navigation queue expectation; historical rapid cases already fail earlier at old request cancellation." + } + }, + "diagnosticFailures": [ + { + "report": "refactor/.cache/iframe03-navigation-source-results/report.json", + "passed": 342, + "issue": "Intermediate source matrix before additional attribute-fragment regression and subsequent fixes; not final acceptance." + }, + { + "report": "refactor/.cache/iframe03-navigation-fragment-failure-results/report.json", + "failed": 3, + "issue": "Candidate cancelled a pending request while the actual same document survived an attribute fragment change." + }, + { + "report": "refactor/.cache/iframe03-navigation-fragment-fixed-results/report.json", + "passed": 3, + "issue": "Intermediate Chromium fragment repair probe, before raw-attribute and consecutive-navigation guards." + }, + { + "log": "refactor/.cache/iframe03-navigation-rapid-failure.log", + "failed": 1, + "issue": "Candidate recaptured newly queued requests on consecutive source mutations. Fixed one snapshot per departing document; final unsent queue waits for final injection." + }, + { + "report": "refactor/.cache/iframe03-navigation-legacy-teardown-failure-results/report.json", + "sha256": "c2afe936a1db956bed95ac4d9ad72c67330567331cf888cd239919b33a108e92", + "passed": 206, + "failed": 1, + "issue": "Firefox cross-origin malformed case completed all assertions, tool.destroy/frame removal and browser diagnostics (trace pw:api@59, expect@65). Native Close context pw:api@69 failed during fixture teardown at 20s. Root cause not established; not counted as a passing matrix or claimed fixed. Unchanged focused case then passed 10 repetitions; final unchanged complete legacy matrix is recorded separately.", + "probe": { + "report": "refactor/.cache/iframe03-navigation-legacy-teardown-probe-results/report.json", + "sha256": "e04a13d9505c6fbfcbb08b7b9eab680eb30d00fb8e08b8e396ca04ce9af4cdf9", + "passed": 10 + }, + "followUp": "PKG-IFRAME-05 and release review retain browser harness reproducibility; preserve original trace if the symptom recurs." + } + ], + "node": [ + { + "kind": "source", + "tests": 50, + "navigation": 16, + "boundary": 18, + "lifecycle": 16, + "result": "pass", + "log": "refactor/.cache/iframe03-navigation-source-node.log", + "sha256": "7583e58901ceed3246f93a886244cafe264db245705de79c271d7c6c1229f618" + }, + { + "kind": "main", + "tests": 50, + "navigation": 16, + "boundary": 18, + "lifecycle": 16, + "result": "pass", + "log": "refactor/.cache/iframe03-navigation-main-node.log", + "sha256": "277a6f74f539c939d5360c0ffe638d764a15c6abf372e87dd0b5c882c8f4d427" + }, + { + "kind": "legacy", + "tests": 50, + "navigation": 16, + "boundary": 18, + "lifecycle": 16, + "result": "pass", + "log": "refactor/.cache/iframe03-navigation-legacy-node.log", + "sha256": "bf03f5b6a40220fa372e64ca05a5a2f720261f1eae0fe5ae233bfbbcbdffb406" + } + ], + "browser": [ + { + "kind": "source", + "passed": 351, + "navigationCases": 99, + "legacyChildNavigationCases": 18, + "boundaryCases": 60, + "lifecycleCases": 30, + "historicalAssertions": 144, + "history": { + "total": 9, + "actualBfcache": 0, + "ordinaryReload": 9 + }, + "report": "refactor/.cache/iframe03-navigation-source-final-results/report.json", + "sha256": "b0d3c5b2a2d4be26006009ab39f83b206def3d10340a5b34f7eef83a573f41cd", + "results": "refactor/.cache/iframe03-navigation-source-final-results/results", + "records": [ + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232156189-1696047357-4146416724-1213574400-2033063232", + "1789232156189-1696047357-4146416724-1213574400-2033063232", + "1789232156189-1696047357-4146416724-1213574400-2033063232" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232156805-2420485649-3616672582-56713062-623647374", + "1789232156948-2530123604-3249536506-582490928-2340810991" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.ogydddbe5c9" + }, + "restored": { + "witness": "0.ogydddbe5c9", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232157930-4185190910-1182891468-2450710335-983808041", + "1789232157930-4185190910-1182891468-2450710335-983808041", + "1789232157930-4185190910-1182891468-2450710335-983808041" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232158823-2903640642-115947439-3251290606-1153178039", + "1789232158975-2044464161-2546028676-685132042-2483242120" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.yofpe77fkcp" + }, + "restored": { + "witness": "0.yofpe77fkcp", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232159944-3779060456-2872368370-2244568100-1688434875", + "1789232159944-3779060456-2872368370-2244568100-1688434875", + "1789232159944-3779060456-2872368370-2244568100-1688434875" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232160824-1549697405-152488477-3964905018-2600548475", + "1789232160971-1479938812-736043644-3476939814-1762919579" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.0najbmhdhh2b" + }, + "restored": { + "witness": "0.0najbmhdhh2b", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232182367-1075618172-1054693888-3882667944-1488825696", + "1789232182367-1075618172-1054693888-3882667944-1488825696", + "1789232182367-1075618172-1054693888-3882667944-1488825696" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232183500-4161724069-3239591468-3712416277-948386368", + "1789232183677-558145951-2135322438-2900712840-3784295323" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.ecevb0bacno" + }, + "restored": { + "witness": "0.ecevb0bacno", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232186275-235801628-2905541301-2362980405-1156174581", + "1789232186275-235801628-2905541301-2362980405-1156174581", + "1789232186275-235801628-2905541301-2362980405-1156174581" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232187488-3051068883-4290026600-1291589782-379800685", + "1789232187621-3231079156-630717569-2222409987-3401812413" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.jlcmii5pwn" + }, + "restored": { + "witness": "0.jlcmii5pwn", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232189115-896854802-396286369-4052225631-4213486805", + "1789232189115-896854802-396286369-4052225631-4213486805", + "1789232189115-896854802-396286369-4052225631-4213486805" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232190514-4111836606-3491465209-3375922321-3237275013", + "1789232190686-551138465-1776784638-3198442099-1947460257" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.r1kdk816a1l" + }, + "restored": { + "witness": "0.r1kdk816a1l", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232222260-1320328412-356444427-3916451747-3514165417", + "1789232222260-1320328412-356444427-3916451747-3514165417", + "1789232222260-1320328412-356444427-3916451747-3514165417" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232223391-3999111788-3414547468-1869754148-1379764391", + "1789232223631-2119349264-658427233-3089938984-339413712" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.x3j8hilsbi" + }, + "restored": { + "witness": "0.x3j8hilsbi", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232226307-1605712367-2693554559-1619423257-3404019873", + "1789232226307-1605712367-2693554559-1619423257-3404019873", + "1789232226307-1605712367-2693554559-1619423257-3404019873" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232228194-334061872-1975494352-833629985-4067372207", + "1789232228503-1330262761-1477648546-3093758824-1324176656" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 14 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.wghk0evdph" + }, + "restored": { + "witness": "0.wghk0evdph", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232230854-4045300185-3788481707-1048895257-3654550687", + "1789232230854-4045300185-3788481707-1048895257-3654550687", + "1789232230854-4045300185-3788481707-1048895257-3654550687" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232232820-4125213008-2519926081-1673177914-3010888568", + "1789232233133-3492440768-1159069162-580929497-2924043386" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 9 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.zpbm4a8iat8" + }, + "restored": { + "witness": "0.zpbm4a8iat8", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-source", + "sha256": "3748a8b38801d858cb018ffb9d690146bd2d3ce6bca086212401e7baa4cbf2cf", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + } + ] + }, + { + "kind": "main", + "passed": 351, + "navigationCases": 99, + "legacyChildNavigationCases": 18, + "boundaryCases": 60, + "lifecycleCases": 30, + "historicalAssertions": 144, + "history": { + "total": 9, + "actualBfcache": 0, + "ordinaryReload": 9 + }, + "report": "refactor/.cache/iframe03-navigation-main-results/report.json", + "sha256": "29040af85c54dd8df3ffabc1e5c741e5375a14bb4980949272060d9dc23e4235", + "results": "refactor/.cache/iframe03-navigation-main-results/results", + "records": [ + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232311093-407076534-1818085175-3576899445-547350250", + "1789232311093-407076534-1818085175-3576899445-547350250", + "1789232311093-407076534-1818085175-3576899445-547350250" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232311668-4051515271-2042120322-3960481396-1146198638", + "1789232311813-1492875844-3366482853-926224160-3777788645" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.9wmeho88emt" + }, + "restored": { + "witness": "0.9wmeho88emt", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232312763-1501573177-2037467643-1307688133-1445512009", + "1789232312763-1501573177-2037467643-1307688133-1445512009", + "1789232312763-1501573177-2037467643-1307688133-1445512009" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232313620-2351772579-2421832418-2550930112-1484945826", + "1789232313772-1793440842-1876793334-3916684450-2101459367" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.exg1sbtmvtk" + }, + "restored": { + "witness": "0.exg1sbtmvtk", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232314724-589599216-4190860607-956693786-3174814308", + "1789232314724-589599216-4190860607-956693786-3174814308", + "1789232314724-589599216-4190860607-956693786-3174814308" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232315575-3722326957-2543313151-3902194754-2742950198", + "1789232315721-2914656262-1864457151-1392402011-3025616821" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.56ehrcg0tg7" + }, + "restored": { + "witness": "0.56ehrcg0tg7", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232338028-4190277092-402043666-1869252158-418110248", + "1789232338028-4190277092-402043666-1869252158-418110248", + "1789232338028-4190277092-402043666-1869252158-418110248" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232339253-3439017635-1620707514-1016429403-217092934", + "1789232339419-1752483673-1775926730-3580908493-1645093412" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.37sbhbusp4w" + }, + "restored": { + "witness": "0.37sbhbusp4w", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232341682-673637628-1303147348-1814153350-3854032517", + "1789232341682-673637628-1303147348-1814153350-3854032517", + "1789232341682-673637628-1303147348-1814153350-3854032517" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232343137-1477067114-1601868753-774714833-1402492981", + "1789232343263-2576298341-1657988862-2939866708-2549193637" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.7rg295k2jei" + }, + "restored": { + "witness": "0.7rg295k2jei", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232344875-1253446882-1630055561-1754109776-906750217", + "1789232344875-1253446882-1630055561-1754109776-906750217", + "1789232344875-1253446882-1630055561-1754109776-906750217" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232346122-537223018-1346041554-1983342104-1753421886", + "1789232346299-89050844-1336957273-3680958949-2592630830" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.mbeae3w6yv" + }, + "restored": { + "witness": "0.mbeae3w6yv", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232376964-3855681123-4271679715-212737900-4226619412", + "1789232376964-3855681123-4271679715-212737900-4226619412", + "1789232376964-3855681123-4271679715-212737900-4226619412" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232378090-3132796365-3536904286-1213917764-1224228146", + "1789232378250-3448179080-3605138903-647461343-3625578540" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.vp3zj420nxr" + }, + "restored": { + "witness": "0.vp3zj420nxr", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232380831-2298232968-2009240199-1383188780-3540104289", + "1789232380831-2298232968-2009240199-1383188780-3540104289", + "1789232380831-2298232968-2009240199-1383188780-3540104289" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232382770-3027628665-2214741360-4153819657-1856817679", + "1789232383111-4057897379-3491583805-2471601229-2691725068" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 14 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.gp3o0n1fyuc" + }, + "restored": { + "witness": "0.gp3o0n1fyuc", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232385459-4041734317-2503663093-592271631-2310564742", + "1789232385459-4041734317-2503663093-592271631-2310564742", + "1789232385459-4041734317-2503663093-592271631-2310564742" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232387175-3604907531-788970734-63229914-1547039048", + "1789232387482-2746236162-3346929073-1884687420-2752880199" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 14 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.am2za6n80b9" + }, + "restored": { + "witness": "0.am2za6n80b9", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + } + ] + }, + { + "kind": "legacy", + "passed": 207, + "navigationCases": 99, + "legacyChildNavigationCases": 18, + "boundaryCases": 60, + "lifecycleCases": 30, + "historicalAssertions": 0, + "history": { + "total": 9, + "actualBfcache": 0, + "ordinaryReload": 9 + }, + "report": "refactor/.cache/iframe03-navigation-legacy-results/report.json", + "sha256": "937f422cd5b7c91bfd4ed248a1b5f91c34e27e4bd1f540209e8f4611d0591b38", + "results": "refactor/.cache/iframe03-navigation-legacy-results/results", + "records": [ + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232751049-930693104-570326415-2289196110-2590235352", + "1789232751049-930693104-570326415-2289196110-2590235352", + "1789232751049-930693104-570326415-2289196110-2590235352" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232751688-2248888185-3641607349-3631729352-3973233809", + "1789232751854-3848423724-1781183907-3852695546-3551175803" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.g8nllil73r9" + }, + "restored": { + "witness": "0.g8nllil73r9", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232752779-3094865060-2883197906-3156698690-1050569622", + "1789232752779-3094865060-2883197906-3156698690-1050569622", + "1789232752779-3094865060-2883197906-3156698690-1050569622" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232753628-2301767624-2511923989-273962715-3840470655", + "1789232753777-804975393-661349429-3266229981-3653488996" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.bsd5bijv7pw" + }, + "restored": { + "witness": "0.bsd5bijv7pw", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232754690-1854368516-1953708905-3480812445-2191184949", + "1789232754690-1854368516-1953708905-3480812445-2191184949", + "1789232754690-1854368516-1953708905-3480812445-2191184949" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232755376-1153396270-4139235946-4279238137-819781588", + "1789232755518-1134492055-681317214-1444957499-4247721769" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.9v3436encuj" + }, + "restored": { + "witness": "0.9v3436encuj", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232768427-2669948644-671315341-2276337086-4005359146", + "1789232768427-2669948644-671315341-2276337086-4005359146", + "1789232768427-2669948644-671315341-2276337086-4005359146" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232769176-3785147901-2418037032-3541779918-940349561", + "1789232769342-3582033469-3627539106-2382744066-4107600495" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.3lnbzkqwbqc" + }, + "restored": { + "witness": "0.3lnbzkqwbqc", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232771814-1092207335-755582740-2004657505-2003433885", + "1789232771814-1092207335-755582740-2004657505-2003433885", + "1789232771814-1092207335-755582740-2004657505-2003433885" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232773003-1578486460-4177420789-4088406981-1667031924", + "1789232773123-2127523754-3593858342-1712324099-3613014977" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.p5s63ix7kjl" + }, + "restored": { + "witness": "0.p5s63ix7kjl", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232774690-2886360156-628507868-1781690841-1355515050", + "1789232774690-2886360156-628507868-1781690841-1355515050", + "1789232774690-2886360156-628507868-1781690841-1355515050" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232775907-130228500-933739953-470083914-1048075423", + "1789232776070-2492660222-2517745402-1129323105-1860728516" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.vskcd3ys4l" + }, + "restored": { + "witness": "0.vskcd3ys4l", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232791877-1836497296-3491989077-3902008641-1785542349", + "1789232791877-1836497296-3491989077-3902008641-1785542349", + "1789232791877-1836497296-3491989077-3902008641-1785542349" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232793309-1251723494-391280762-3145596648-3105784467", + "1789232793504-1045113396-2358853868-3566928430-2930426437" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.8f8ppzds0m6" + }, + "restored": { + "witness": "0.8f8ppzds0m6", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232795627-3714954151-1635929480-2696386756-790827654", + "1789232795627-3714954151-1635929480-2696386756-790827654", + "1789232795627-3714954151-1635929480-2696386756-790827654" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232797452-725289296-1854179468-2643552830-2634155906", + "1789232797678-2206018652-1201866087-3496491637-2991817469" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.x0sjx7vvtj" + }, + "restored": { + "witness": "0.x0sjx7vvtj", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "inject-before-load", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "after load" + }, + "order": [ + "inject", + "load" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 7 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "duplicate-inject", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": 12 + }, + "documentIds": [ + "1789232800119-1622419352-3373258987-1243293605-3944879779", + "1789232800119-1622419352-3373258987-1243293605-3944879779", + "1789232800119-1622419352-3373258987-1243293605-3944879779" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 11 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "attribute-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 17 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "child-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 15 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "rapid-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "intermediate": { + "status": "resolved", + "value": 2 + }, + "new": { + "status": "resolved", + "value": "3" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "same-source-reload", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "documentIds": [ + "1789232801351-3346286220-3512902330-4147502953-2173269774", + "1789232801573-1386408679-3423312897-334546413-1956996966" + ] + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "fragment-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "same document" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 8 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "attribute-fragment", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "state": { + "status": "resolved", + "value": "attribute fragment" + }, + "injected": true + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 13 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "stale-packets", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 19 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "history-back", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "pageshow": { + "epoch": "1", + "persisted": false, + "witness": "0.0elnkwe2pnx" + }, + "restored": { + "witness": "0.0elnkwe2pnx", + "epoch": "1" + }, + "actualBfcache": false + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 22 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "srcdoc-navigation", + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "srcdoc": { + "status": "resolved", + "value": "about:srcdoc" + }, + "srcdocHeld": { + "status": "rejected", + "error": "The iframe document has changed" + } + }, + "injected": true, + "pending": 0 + }, + "scope": "Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.", + "timelineEntries": 25 + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "published-artplayer-plugin-iframe.js", + "sha256": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "same-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "cross-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://localhost:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "candidate-artifact", + "sha256": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a", + "relation": "opaque-origin", + "scenario": "legacy-child-source-change", + "child": { + "name": "workspace.js", + "sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86" + }, + "parentOrigin": "http://127.0.0.1:8084", + "childOrigin": "http://127.0.0.1:8084", + "result": { + "states": { + "old": { + "status": "rejected", + "error": "The iframe document has changed" + }, + "new": { + "status": "resolved", + "value": "2" + } + }, + "pending": 0 + }, + "scope": "Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer." + } + ] + } + ], + "checks": [ + { + "command": "yarn ci:check", + "result": "pass", + "exitCode": 0, + "tests": 1539, + "unit": 1365, + "engineering": 14, + "baseline": 160, + "repeatedContracts": 44, + "productionTypeScriptFiles": 330, + "log": "refactor/.cache/iframe03-navigation-ci.log", + "sha256": "5eb57710f26f70bf69bf268dda9126ceb7f4572d0d9a2e8993b9199341d7ced2" + }, + { + "command": "yarn test:imports", + "result": "pass", + "exitCode": 0, + "tests": 3, + "log": "refactor/.cache/iframe03-navigation-imports.log" + }, + { + "command": "yarn build artplayer-tool-iframe", + "result": "pass", + "log": "refactor/.cache/iframe03-navigation-build.log" + } + ], + "limitations": [ + "IFRAME-04 public declaration and package-consumer reconciliation remains pending.", + "IFRAME-05 retains full old/new core and demo integration, actual BFCache/device and externally interrupted navigation acceptance.", + "Legacy unmarked peers preserve ordinary protocol; same-address reload, self-navigation and document-level late filtering cannot be guaranteed through unchanged code.", + "Missing/null-source local calls and unmarked custom messages preserve their documented legacy path.", + "Document markers correlate sessions, not origin permissions or executable-code sandboxing. The selected parent and child remain trusted.", + "No release, push, tag or publication readiness is claimed." + ], + "verifiedAt": "2026-09-12T17:07:06.288Z" +} diff --git a/refactor/changes/2026-09-13-PKG-IFRAME-03-navigation.md b/refactor/changes/2026-09-13-PKG-IFRAME-03-navigation.md new file mode 100644 index 000000000..550e4c530 --- /dev/null +++ b/refactor/changes/2026-09-13-PKG-IFRAME-03-navigation.md @@ -0,0 +1,78 @@ +# PKG-IFRAME-03 document ownership and internal structure + +The public class now delegates connection cleanup, request ownership, envelope +admission, parent navigation and child lifecycle to six strict TS modules. +Requests receive an internal boundary hook; child and parent session code use +the shared envelope helpers without importing the public class or core. The +module map and ownership/maintenance commands are in the package architecture. +Earlier request and peer-boundary checkpoints remain separate evidence. + +## Compatibility decision and defect changes + +ADR-026 adds optional document metadata to the existing type/data/id protocol. +Normal new/old wire combinations preserve the public callback data and receiver, +constructor/field descriptors, resove spelling, generic responses and the old +function-body/resolve commit convention. New private lifecycle traffic starts +only after acknowledgement and is not forwarded through the public message API. +An unchanged peer remains on the legacy path; its limitations are explicit. + +Document departure now rejects owned work with `The iframe document has changed`. +The code pauses new sends while replacing a source, captures only the old request +set, and preserves requests queued for the replacement. Old pagehide/repeated +inject cannot cancel or activate the replacement's queue. Different-document +responses/notifications and commands are filtered. Destroy still owns all remaining +requests even if consumers replaced/deleted their public callback records. + +The first source matrix passed 342, but an independent fragment review found a +real regression in three Chromium cases: the document witness was unchanged while +the candidate rejected its request. A source setter is not proof of document +departure. The final design captures requests provisionally and waits for pagehide +or another document marker before cancelling; a matching native hashchange report +preserves same-document work. The failing report is retained. Raw attribute +tracking also avoids inventing navigation when only a src getter's base resolution +changes. These repairs are not made by weakening the document-identity assertions. + +A later ownership review reproduced another candidate defect: repeated source +mutations recaptured and cancelled requests queued after navigation began. The +snapshot now belongs to the departing document and is captured once. Unsent work +waits for the final document to inject, including when an intermediate target is +superseded. The browser rapid-navigation expectation was corrected to this explicit +contract; a separate Node regression proves both before/after-pagehide orderings. + +## Evidence and limits + +The navigation tests include marked and legacy peers, synchronous post after src, +rapid changes, source/srcdoc priority, repeated injection, inject-before-load, +same-address reload, native fragment transitions, old packet replay, history and +listener/observer cleanup. A controlled load barrier proves the inject-before-load +order. Browser history records actual pageshow.persisted rather than treating all +history navigation as cached restoration. Stale-packet cases replay old metadata +from owned fixtures to isolate routing; they are not a claim of cross-site access. + +Final counts, source/artifact hashes, frozen preceding-build association and +reports are in `baselines/iframe-navigation-validation.json`. Public declaration +reconciliation remains PKG-IFRAME-04; full old/new core/demo integration, actual +BFCache/device and interrupted navigation evidence remain PKG-IFRAME-05/review. +The corresponding risks remain open with that owner; no distribution or release +gate is silently closed. No dependency, version, package manager, push or publish. + +Rollback: revert this task completion and rebuild artplayer-tool-iframe normally. +Earlier frozen npm/Git evidence remains intact. Dedicated commit subject: +`refactor(iframe): [PKG-IFRAME-03] scope requests to active documents`. + +Final source/main/legacy each pass 50 Node assertions (16 navigation, 18 boundary, +16 request lifecycle). Native browsers pass source 351, main 351 and legacy 207; +each includes 117 navigation/legacy-child, 60 boundary/mixed and 30 lifecycle cases. +Source/main additionally preserve 144 historical defect assertions. Final matrices +have no skips, automatic retries/flakes or unhandled browser errors. The preceding +legacy run was 206 pass/1 Firefox context-close teardown timeout, after all product +assertions, destroy/frame removal and diagnostics had completed in the trace. +No root cause or fix is claimed: the unchanged case passed ten focused repetitions, +then the unchanged full legacy matrix passed. Original trace/report remain archived; +IFRAME-05/release review retain harness reproducibility if the symptom recurs. +History details remain in the evidence; +ordinary reloads are not BFCache. Full CI passes 1539 (1365 unit, 14 engineering, +160 baseline), 44 repeated contracts and 330 production TS files. Three import/SSR +files pass. Source, artifact, report and preceding Git hashes plus all three docs +copies are verified. PKG-IFRAME-03 is done; 04/05/06 and the three iframe risks +remain open. No package version or publication gate is advanced by this task. diff --git a/refactor/decisions.md b/refactor/decisions.md index ec8edf75f..cb5c50e12 100644 --- a/refactor/decisions.md +++ b/refactor/decisions.md @@ -32,6 +32,10 @@ ## 开始实现前需补齐的决定 +ADR-026:Iframe采用可选文档标记与两阶段导航归属,保留旧端wire和公开回调; +原生片段跳转不取消同文档请求。协议、拒绝时机和未升级端/真实BFCache的边界见 +[文档协议](iframe-document-protocol.md)。 + ADR-025:Iframe绑定实际父子窗口,保留跨源/重定向/opaque-origin与公开local receiver, 同时拒绝无关窗口和无效消息。独立依据、兼容影响与剩余信任限制见 [Iframe消息边界](iframe-message-boundary.md);本轮不将来源绑定视为导航或全包发布验收。 diff --git a/refactor/iframe-document-protocol.md b/refactor/iframe-document-protocol.md new file mode 100644 index 000000000..bcb61dc5a --- /dev/null +++ b/refactor/iframe-document-protocol.md @@ -0,0 +1,64 @@ +# ADR-026:兼容的文档标记与导航归属 + +关联PKG-IFRAME-03/05;2026-09-13。实现与验证以本轮记录为准。 + +## 问题与取舍 + +WindowProxy在导航中保持身份。旧协议只用Date.now的请求ID,无法区分某个inject、 +响应或UI通知属于哪个子文档。直接在iframe load时清空状态也不正确:实际子页可以 +先inject,再等待图片等资源完成load。只观察src属性同样不足,片段跳转不会更换文档。 + +本轮先采用直接属性取消的候选,真实Chromium三个attribute-fragment场景证明它误拒绝 +同文档请求。修复使用“导航意图—确认离开”两个阶段;失败报告保留,不靠放宽断言通过。 +不更换公开传输为另一套RPC,不要求旧页面改写commit函数,也不把WindowProxy当作文档ID。 + +## 可选扩展与旧端兼容 + +公开type/data/id、任意非error同ID响应、message({type,data})回调及其this保持原样。 +新增内部可选字段`__artplayerIframe`,包含version=1、document字符串和phase。 +文档标记是关联标识,不是秘密或认证令牌;来源信任仍按ADR-025。 + +| 消息 | 行为 | +| --- | --- | +| inject | 新子页在原inject封套上附文档标记;旧父页仍只读取原三个字段 | +| ack | 新父页识别标记后,使用带标记的`artplayer-tool-iframe:session`确认;不进入公开message回调 | +| message | 确认后,子页普通postMessage/响应带文档标记;父页发出的请求也标注目标文档 | +| leave | 已确认子页在原生pagehide发送私有通知,父页取消原文档所属请求 | +| resume | 原生pageshow.persisted恢复时通知;不伪造普通inject回调 | +| fragment | 原生hashchange报告实际location.href;匹配父页目标src时完成同文档跳转 | + +没有新父页ack时,新子页的普通消息保持旧封套,也不发新的私有生命周期通知。 +没有子页文档标记时,新父页继续使用旧封套。实际npm主类与初始工作区主类在父/子 +两侧均有正常wire组合;额外helper的不同协议仍由IFRAME-04/06单独处理。 +原生window监听器会看见可选字段和已协商的私有控制流;工具的公开message回调不暴露私有控制包。 + +## 请求与导航状态 + +1. 监听src/srcdoc属性;公开postMessage入口和等待轮询也消费尚未送达的MutationObserver记录。 +2. 已标记的文档开始导航时,捕获当时仍属于它的请求集合,暂停后续发送。新请求排队等待。 +3. pagehide或另一个文档inject确认换页后,只取消捕获的旧集合;之后排队的新请求保留。 + 在任何新文档注入前连续修改目标,只更新目标,不重新捕获排队请求;这些尚未发送的请求交给最终注入的文档。 +4. 片段跳转仍在同一文档:hashchange报告的完整URL必须匹配实际目标src,释放暂停并保留旧请求。 + 不把src相对/绝对写法或重新设置片段属性误当作新文档;不以load事件猜测文档身份。 +5. 不同标记的迟到响应/通知被忽略,发给旧标记的commit不会在新子页执行。 +6. destroy解除监听、observer、请求边界和捕获集合;立即拒绝仍归属实例的全部请求。 + +文档确认离开时的Error消息为`The iframe document has changed`;destroy沿用 +`The instance has been destroyed`。调用方需要处理commit/postMessage的拒绝。 +未确认离开前,原文档已完成的响应仍可结算原请求;这属于活文档的正常完成,不是假定所有导航意图都是换页。 + +公开promises记录保留resove/reject和对象身份。普通响应仍尊重用户替换的公开回调; +内部取消独立持有原Promise拒绝入口,不能因用户删除/替换记录而泄漏原Promise。 + +## 明确限制与后续门槛 + +- 旧端没有文档标记;不同有效源地址的属性导航可以管理,但同地址重载、子页内部导航和文档级迟到过滤 + 不能通过未升级的一侧可靠证明。完整文档保护需双方使用新实现,旧正常协议继续兼容。 +- MutationObserver不可用时,只能在公开方法/轮询时检查可观察的源变化;语法legacy目标不等于补齐DOM能力。 +- 未标记的自定义原生消息仍按旧协议接受;其文档级归属由应用管理。SDK提供的消息在协商后携带标记。 +- 历史返回用例记录实际pageshow.persisted。普通重新加载不能计作原生BFCache验证;完整播放器、 + 原生BFCache/设备、外部中断导航与文档站实际组合仍在IFRAME-05及发布复盘核验,未由本轮自动豁免。 +- 本协议不验证父页origin许可,也不把可执行commit变成代码沙箱;嵌入父页和选定子内容仍需可信。 + +验证入口为test/iframe-navigation.test.js和test/browser/iframe-navigation.spec.js,记录见 +baselines/iframe-navigation-validation.json。回退本轮源码后使用正常package build重建,不手改产物。 diff --git a/refactor/plan.md b/refactor/plan.md index e9ed95723..2981ebb55 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 222 项,范围 22 个包及工作区/示例。 -状态:todo 105 / doing 10 / blocked 0 / done 107 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 105 / doing 9 / blocked 0 / done 108 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -346,9 +346,9 @@ | --- | --- | --- | --- | --- | --- | --- | | PKG-IFRAME-01 | artplayer-tool-iframe
核对包契约与历史用法 | BASE-05 | constructor/commit/message/inject、postMessage 协议与历史公开拼写 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done | | PKG-IFRAME-02 | artplayer-tool-iframe
建立特有行为与错误测试 | PKG-IFRAME-01, ENG-03, ENG-05 | 跨窗口消息、ID 匹配、请求失败、重复 inject、销毁中请求 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done | -| PKG-IFRAME-03 | artplayer-tool-iframe
整理内部职责与资源 | PKG-IFRAME-02, CORE-02, BASE-07 | 请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | doing | +| PKG-IFRAME-03 | artplayer-tool-iframe
整理内部职责与资源 | PKG-IFRAME-02, CORE-02, BASE-07 | 请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done | | PKG-IFRAME-04 | artplayer-tool-iframe
迁移自有源码和公开类型 | PKG-IFRAME-03, ENG-04, ENG-06, CORE-07 | 消息联合类型、回调/Promise 推导、旧公开字段兼容;旧npm export=与实际namespace、额外helper协议分别核验 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | -| PKG-IFRAME-05 | artplayer-tool-iframe
验证新旧核心和组合 | PKG-IFRAME-04, CORE-22 | 真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-IFRAME-05 | artplayer-tool-iframe
验证新旧核心和组合 | PKG-IFRAME-04, CORE-22 | 真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论;新旧核心/demo、实际 BFCache/设备和外部中断导航验收,旧端无文档标记的限制明确 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | | PKG-IFRAME-06 | artplayer-tool-iframe
验证分发并同步文档 | PKG-IFRAME-05, ENG-07 | iframe.js、示例集成和原 script/class 导出验证;旧包名/额外helper深入口与新工具名的迁移结论 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | ## 5 包迁移:artplayer-tool-thumbnail @@ -532,5 +532,5 @@ - PKG-MB-09: [记录](changes/2026-09-12-PKG-MB-09-native-pip-checkpoint.md) [记录](baselines/mb-native-pip-checkpoint.json) [记录](changes/2026-09-12-PKG-MB-09-sustained-playback-checkpoint.md) [记录](baselines/mb-sustained-validation.json) [记录](baselines/mb-sustained-media.json) - PKG-IFRAME-01: [记录](changes/2026-09-12-PKG-IFRAME-01-contract.md) [记录](baselines/iframe-release.json) [记录](baselines/iframe-contract.md) [记录](baselines/iframe-contract-validation.json) - PKG-IFRAME-02: [记录](changes/2026-09-12-PKG-IFRAME-02-behavior.md) [记录](baselines/iframe-behavior-validation.json) -- PKG-IFRAME-03: [记录](changes/2026-09-12-PKG-IFRAME-03-requests-checkpoint.md) [记录](baselines/iframe-requests-checkpoint.json) [记录](changes/2026-09-12-PKG-IFRAME-03-boundaries-checkpoint.md) [记录](baselines/iframe-boundaries-checkpoint.json) [记录](iframe-message-boundary.md) +- PKG-IFRAME-03: [记录](changes/2026-09-12-PKG-IFRAME-03-requests-checkpoint.md) [记录](baselines/iframe-requests-checkpoint.json) [记录](changes/2026-09-12-PKG-IFRAME-03-boundaries-checkpoint.md) [记录](baselines/iframe-boundaries-checkpoint.json) [记录](iframe-message-boundary.md) [记录](changes/2026-09-13-PKG-IFRAME-03-navigation.md) [记录](baselines/iframe-navigation-validation.json) [记录](iframe-document-protocol.md) - PKG-FACTORY-01: [记录](baselines/factory-assignment-gaps.json) [记录](baselines/factory-compatibility-proposals.json) [记录](factory-compatibility-decision.md) [记录](changes/2026-09-12-PKG-FACTORY-01-decision.md) diff --git a/refactor/progress.md b/refactor/progress.md index f88eb46d5..dca175bf4 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,19 @@ # 进度与证据 +## PKG-IFRAME-03 完成:按文档管理请求与六模块拆分 + +入口、连接、请求、消息边界、父页导航和子页生命周期拆为六个严格TS模块。 +保留公开字段/回调/resove和旧协议;协商文档标记用于换页取消、迟到消息过滤, +连续切源只取消旧文档请求,未发送队列等待最终注入。实际片段导航回归和重复捕获 +请求问题均先复现后修复,失败报告保留。ADR-026说明两阶段导航及旧端能力限制。 +源码/main/legacy各50项Node通过;真实三引擎分别351/351/207通过,无跳过。 +每份含117导航/旧子页、60边界/互通和30生命周期,source/main另含144历史断言。 +完整CI1539与44重复契约、3导入/SSR通过,330生产TS;产物/docs/报告哈希核对。 +见[决策](iframe-document-protocol.md)、[变更](changes/2026-09-13-PKG-IFRAME-03-navigation.md) +和[验证](baselines/iframe-navigation-validation.json)。222项:108 done、9 doing、105 todo。 +IFRAME三个风险仍open:04公开声明/旧消费,05完整播放器/demo、实际BFCache/设备和 +外部中断导航,06分发仍需完成。本项专用本地提交,不推送或发布。 + ## PKG-IFRAME-03 构造清理与窗口来源检查点(doing) 增加connection/protocol两个严格TS模块;构造失败清理监听和重入请求,destroy即使 diff --git a/refactor/risk-table.md b/refactor/risk-table.md index 247f8851a..53bb75f33 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -174,6 +174,6 @@ | MB-CAP-01 | open / 已复现 | Current Windows WebKit lacks WebCodecs and Web Audio constructors needed by historical MediaBunny proxies | PKG-MB-02, PKG-MB-09 | | MB-READY-01 | resolved / 已复现 | MediaBunny historical readiness can repeat for trackless input and occur after capability errors | PKG-MB-04, PKG-MB-09 | | DPIP-DISPLAY-01 | resolved / 已复现 | Web fullscreen body placement reclaims a player adopted into another document | CORE-22, PKG-DPIP-05 | -| IFRAME-LIFE-01 | open / 已复现 | Iframe timestamp IDs and unowned pending requests/timers lack terminal cleanup | PKG-IFRAME-02, PKG-IFRAME-03 | +| IFRAME-LIFE-01 | open / 已复现 | Iframe timestamp IDs and unowned pending requests/timers lack terminal cleanup | PKG-IFRAME-02, PKG-IFRAME-03, PKG-IFRAME-05 | | IFRAME-TRUST-01 | open / 已复现 | Iframe executable commit protocol accepts messages without source/origin validation | PKG-IFRAME-03, PKG-IFRAME-05 | | IFRAME-DIST-01 | open / 已复现 | Iframe tool name is unavailable at registry observation and old archive includes distinct helper exports | PKG-IFRAME-04, PKG-IFRAME-06 | diff --git a/refactor/risks.json b/refactor/risks.json index 6ac8a91ce..7c7fc46ce 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -3771,11 +3771,12 @@ "title": "Iframe timestamp IDs and unowned pending requests/timers lack terminal cleanup", "owners": [ "PKG-IFRAME-02", - "PKG-IFRAME-03" + "PKG-IFRAME-03", + "PKG-IFRAME-05" ], "status": "open", "confirmation": "reproduced", - "compatibleResolution": "Owned requests fix collision/polling/send/destroy failures; connection cleanup now releases partial construction and cancels requests even if listener removal fails. Navigation/reinjection and document-generation handling remain for PKG-IFRAME-03; keep open until complete actual iframe lifecycle acceptance.", + "compatibleResolution": "Owned requests and cleanup cover terminal failures. ADR-026 adds document-scoped cancellation, provisional source changes, same-document fragment preservation and queued final navigation. Keep open for PKG-IFRAME-05 full player/demo, actual BFCache/device and interrupted-navigation acceptance; unchanged legacy peers have documented document-identity limits.", "closureCriteria": "Old behavior and candidate fixes have deterministic race/resource tests plus actual iframe integration.", "evidence": [ "refactor/baselines/iframe-contract.md", @@ -3786,7 +3787,10 @@ "refactor/changes/2026-09-12-PKG-IFRAME-03-requests-checkpoint.md", "refactor/baselines/iframe-requests-checkpoint.json", "refactor/changes/2026-09-12-PKG-IFRAME-03-boundaries-checkpoint.md", - "refactor/baselines/iframe-boundaries-checkpoint.json" + "refactor/baselines/iframe-boundaries-checkpoint.json", + "refactor/changes/2026-09-13-PKG-IFRAME-03-navigation.md", + "refactor/baselines/iframe-navigation-validation.json", + "refactor/iframe-document-protocol.md" ] }, { @@ -3798,7 +3802,7 @@ ], "status": "open", "confirmation": "reproduced", - "compatibleResolution": "ADR-025 binds native messages to the selected iframe/parent and rejects malformed envelopes while preserving local receiver calls and same/cross/redirect/opaque origins. Executable commit still trusts the embedding parent and selected content; navigation/document generation and complete integration/release review remain open.", + "compatibleResolution": "ADR-025 binds actual native peers; ADR-026 correlates negotiated document messages without breaking normal legacy wire. This is not an origin allowlist or commit sandbox. Keep open for PKG-IFRAME-05 complete integration/release review and documented legacy/custom unmarked-message limits.", "closureCriteria": "Controlled and real same/cross-origin evidence plus an explicit documented compatibility decision and supported trust model.", "evidence": [ "refactor/baselines/iframe-contract.md", @@ -3808,7 +3812,10 @@ "refactor/changes/2026-09-12-PKG-IFRAME-02-behavior.md", "refactor/changes/2026-09-12-PKG-IFRAME-03-boundaries-checkpoint.md", "refactor/baselines/iframe-boundaries-checkpoint.json", - "refactor/iframe-message-boundary.md" + "refactor/iframe-message-boundary.md", + "refactor/changes/2026-09-13-PKG-IFRAME-03-navigation.md", + "refactor/baselines/iframe-navigation-validation.json", + "refactor/iframe-document-protocol.md" ] }, { diff --git a/refactor/tasks.json b/refactor/tasks.json index 5e1e3d38d..eaf02ee91 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -3656,7 +3656,7 @@ "CORE-02", "BASE-07" ], - "status": "doing", + "status": "done", "risk": "H", "deliverable": "请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策", "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", @@ -3665,7 +3665,10 @@ "baselines/iframe-requests-checkpoint.json", "changes/2026-09-12-PKG-IFRAME-03-boundaries-checkpoint.md", "baselines/iframe-boundaries-checkpoint.json", - "iframe-message-boundary.md" + "iframe-message-boundary.md", + "changes/2026-09-13-PKG-IFRAME-03-navigation.md", + "baselines/iframe-navigation-validation.json", + "iframe-document-protocol.md" ] }, { @@ -3700,7 +3703,7 @@ ], "status": "todo", "risk": "H", - "deliverable": "真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论", + "deliverable": "真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论;新旧核心/demo、实际 BFCache/设备和外部中断导航验收,旧端无文档标记的限制明确", "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", "evidence": [] }, diff --git a/test/browser/iframe-boundaries.spec.js b/test/browser/iframe-boundaries.spec.js index 5fb96ef52..163846374 100644 --- a/test/browser/iframe-boundaries.spec.js +++ b/test/browser/iframe-boundaries.spec.js @@ -116,7 +116,7 @@ for (const item of cases) { for (const payload of [null, false, 3, 'packet', {}, { type: 3 }]) window.targetFrame.contentWindow.postMessage(payload, '*') }) - await expect.poll(() => child.evaluate(() => window.received.length)).toBe(6) + await expect.poll(() => child.evaluate(() => window.received.filter(packet => !packet.internal).length)).toBe(6) const value = await page.evaluate(() => window.tool.commit(() => { return 12 })) diff --git a/test/browser/iframe-boundary-child.html b/test/browser/iframe-boundary-child.html index 7394e50b4..6fcc01992 100644 --- a/test/browser/iframe-boundary-child.html +++ b/test/browser/iframe-boundary-child.html @@ -5,11 +5,22 @@ window.Tool = window[parameters.get('global')]; window.received = []; window.executions = 0; + window.documentWitness = Math.random().toString(36); + addEventListener('pagehide', event => parent.postMessage({ type: 'fixture-pagehide', data: { epoch: parameters.get('epoch'), persisted: event.persisted } }, '*')); + addEventListener('pageshow', event => parent.postMessage({ type: 'fixture-pageshow', data: { epoch: parameters.get('epoch'), persisted: event.persisted, witness: window.documentWitness } }, '*')); addEventListener('message', event => { - received.push({ type: event.data?.type, id: event.data?.id, fromParent: event.source === parent, origin: event.origin }); + received.push({ type: event.data?.type, id: event.data?.id, fromParent: event.source === parent, origin: event.origin, internal: event.data?.type === 'artplayer-tool-iframe:session' && event.data?.__artplayerIframe?.version === 1 }); if (event.data?.type === 'hold') window.held = event.data; parent.postMessage({ type: 'fixture-observed', data: { count: received.length, type: event.data?.type, id: event.data?.id } }, '*'); }); if (parameters.get('auto') !== '0') Tool.inject(); parent.postMessage({ type: 'fixture-ready' }, '*'); + + diff --git a/test/browser/iframe-navigation.spec.js b/test/browser/iframe-navigation.spec.js new file mode 100644 index 000000000..cfb77ba31 --- /dev/null +++ b/test/browser/iframe-navigation.spec.js @@ -0,0 +1,291 @@ +import fs from 'node:fs' +import { hash } from '../../refactor/scripts/releases.mjs' +import { iframeCandidate, iframeHistorical } from '../helpers/iframe.js' +import { expect, test } from './fixtures.js' + +const implementation = await iframeCandidate() +const scenarios = ['inject-before-load', 'duplicate-inject', 'attribute-navigation', 'child-navigation', 'rapid-navigation', 'same-source-reload', 'fragment-navigation', 'attribute-fragment', 'stale-packets', 'history-back', 'srcdoc-navigation'] +const childHtml = fs.readFileSync(new URL('./iframe-boundary-child.html', import.meta.url), 'utf8') + +for (const relation of ['same-origin', 'cross-origin', 'opaque-origin']) { + for (const scenario of scenarios) { + test(`Iframe document ${relation}/${scenario}/${implementation.name}`, async ({ page }, testInfo) => { + await page.goto('/test/player.html?core=published') + const parentOrigin = new URL(page.url()).origin + const childOrigin = relation === 'cross-origin' ? parentOrigin.replace('127.0.0.1', 'localhost') : parentOrigin + const urlFor = (epoch, auto = true) => `${childOrigin}/test/iframe-boundary-child.html?global=${implementation.global}&auto=${auto ? 1 : 0}&epoch=${epoch}` + const url = urlFor(1) + (scenario === 'inject-before-load' ? '&barrier=1' : '') + let releaseBarrier + await page.route('**/iframe-load-barrier.svg', async (route) => { + await new Promise(resolve => releaseBarrier = resolve) + await route.fulfill({ contentType: 'image/svg+xml', body: '' }) + }) + await page.route('**/iframe-boundary-lib.js', route => route.fulfill({ contentType: 'text/javascript', body: implementation.code })) + await page.addScriptTag({ content: `(() => { const module = { exports: {} }; const exports = module.exports; ${implementation.code}; window.IframeFactory = module.exports.default || module.exports; })();` }) + await page.evaluate(({ url, opaque }) => { + window.timeline = [] + window.states = {} + window.callbacks = [] + const frame = document.createElement('iframe') + if (opaque) + frame.sandbox = 'allow-scripts' + document.body.append(frame) + window.targetFrame = frame + frame.addEventListener('load', () => window.timeline.push({ kind: 'load' })) + addEventListener('message', event => window.timeline.push({ kind: 'message', packet: event.data, fromChild: event.source === frame.contentWindow, origin: event.origin })) + window.tool = new window.IframeFactory({ iframe: frame, url }) + window.tool.message(packet => window.callbacks.push(packet)) + window.track = (key, promise) => { + window.states[key] = { status: 'pending' } + promise.then(value => window.states[key] = { status: 'resolved', value }, error => window.states[key] = { status: 'rejected', error: error.message }) + } + }, { url: scenario === 'attribute-fragment' && relation === 'same-origin' ? url.replace(parentOrigin, '') : url, opaque: relation === 'opaque-origin' }) + let result + try { + await expect.poll(() => page.evaluate(() => window.tool.injected)).toBe(true) + let child = page.frames().find(frame => frame.url() === url) + const first = await page.evaluate(() => window.timeline.find(item => item.packet?.type === 'inject').packet.__artplayerIframe?.document || 'unmarked') + if (first !== 'unmarked') + await expect.poll(() => child.evaluate(() => window.received.some(packet => packet.internal))).toBe(true) + const witness = await child.evaluate(() => window.documentWitness) + await page.evaluate(() => window.track('old', window.tool.postMessage({ type: 'hold' }))) + await expect.poll(() => child.evaluate(() => Boolean(window.held))).toBe(true) + const heldId = await child.evaluate(() => window.held.id) + if (scenario === 'inject-before-load') { + await expect.poll(() => Boolean(releaseBarrier)).toBe(true) + expect(await page.evaluate(() => window.timeline.filter(item => item.kind === 'load').length)).toBe(0) + releaseBarrier() + await expect.poll(() => page.evaluate(() => window.timeline.some(item => item.kind === 'load'))).toBe(true) + expect(await page.evaluate(() => window.states.old.status)).toBe('pending') + expect(await page.evaluate(() => window.tool.injected)).toBe(true) + await child.evaluate(() => window.Tool.postMessage({ type: 'response', id: window.held.id, data: 'after load' })) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('resolved') + result = await page.evaluate(() => ({ state: window.states.old, order: window.timeline.filter(item => item.kind === 'load' || item.packet?.type === 'inject').map(item => item.kind === 'load' ? 'load' : 'inject') })) + expect(result.order).toEqual(['inject', 'load']) + } + else if (scenario === 'duplicate-inject') { + await child.evaluate(() => { + window.Tool.inject() + window.Tool.inject() + }) + await expect.poll(() => page.evaluate(() => window.timeline.filter(item => item.packet?.type === 'inject').length)).toBe(3) + expect(await page.evaluate(() => window.states.old.status)).toBe('pending') + await child.evaluate(() => window.Tool.postMessage({ type: 'response', id: window.held.id, data: 12 })) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('resolved') + result = await page.evaluate(() => ({ state: window.states.old, documentIds: window.timeline.filter(item => item.packet?.type === 'inject').map(item => item.packet.__artplayerIframe?.document || 'unmarked') })) + expect(result.documentIds.every(value => value === first)).toBe(true) + } + else if (scenario === 'fragment-navigation') { + await child.evaluate(() => location.hash = 'chapter') + await expect.poll(() => child.evaluate(() => location.hash)).toBe('#chapter') + expect(await child.evaluate(() => window.documentWitness)).toBe(witness) + await child.evaluate(() => window.Tool.postMessage({ type: 'response', id: window.held.id, data: 'same document' })) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('resolved') + result = await page.evaluate(() => ({ state: window.states.old, injected: window.tool.injected })) + expect(result.injected).toBe(true) + } + else if (scenario === 'attribute-fragment') { + await child.evaluate(() => location.hash = 'child') + await page.evaluate(() => window.targetFrame.src = `${window.targetFrame.src.split('#')[0]}#parent`) + await expect.poll(() => child.evaluate(() => location.hash)).toBe('#parent') + expect(await child.evaluate(() => window.documentWitness)).toBe(witness) + expect(await page.evaluate(() => window.states.old.status)).toBe('pending') + await child.evaluate(() => location.hash = 'child-again') + await page.evaluate(() => { + const attribute = window.targetFrame.src + window.targetFrame.src = attribute + }) + await expect.poll(() => child.evaluate(() => location.hash)).toBe('#parent') + expect(await child.evaluate(() => window.documentWitness)).toBe(witness) + expect(await page.evaluate(() => window.states.old.status)).toBe('pending') + await child.evaluate(() => window.Tool.postMessage({ type: 'response', id: window.held.id, data: 'attribute fragment' })) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('resolved') + result = await page.evaluate(() => ({ state: window.states.old, injected: window.tool.injected })) + expect(result.injected).toBe(true) + } + else if (scenario === 'same-source-reload') { + await page.evaluate(() => { + const currentSource = window.targetFrame.src + window.targetFrame.src = currentSource + }) + await expect.poll(() => page.evaluate(() => window.timeline.filter(item => item.packet?.type === 'inject').length)).toBe(2) + child = page.frames().find(frame => frame.url() === url) + expect(await child.evaluate(() => window.documentWitness)).not.toBe(witness) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('rejected') + result = await page.evaluate(() => ({ state: window.states.old, documentIds: window.timeline.filter(item => item.packet?.type === 'inject').map(item => item.packet.__artplayerIframe.document) })) + expect(result.documentIds[0]).not.toBe(result.documentIds[1]) + } + else if (scenario === 'srcdoc-navigation') { + const html = childHtml.replace('src="/iframe-boundary-lib.js"', `src="${parentOrigin}/iframe-boundary-lib.js"`).replace('new URL(location.href).searchParams', `new URLSearchParams('global=${implementation.global}&auto=0&epoch=srcdoc')`) + await page.evaluate((html) => { + window.targetFrame.srcdoc = html + window.track('srcdoc', window.tool.commit(() => { + return document.URL + })) + }, html) + await expect.poll(() => page.frames().some(frame => frame.url() === 'about:srcdoc')).toBe(true) + child = page.frames().find(frame => frame.url() === 'about:srcdoc') + await expect.poll(() => child.evaluate(() => Boolean(window.Tool))).toBe(true) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('rejected') + expect(await page.evaluate(() => window.tool.injected)).toBe(false) + await child.evaluate(() => window.Tool.inject()) + await expect.poll(() => page.evaluate(() => window.states.srcdoc.status)).toBe('resolved') + expect(await page.evaluate(() => window.states.srcdoc.value)).toBe('about:srcdoc') + await page.evaluate((url) => { + window.track('srcdocHeld', window.tool.postMessage({ type: 'hold' })) + window.targetFrame.src = url + }, urlFor(2)) + await expect.poll(() => child.evaluate(() => Boolean(window.held))).toBe(true) + expect(await page.evaluate(() => window.states.srcdocHeld.status)).toBe('pending') + await page.evaluate(() => window.targetFrame.removeAttribute('srcdoc')) + await expect.poll(() => page.frames().some(frame => frame.url() === urlFor(2))).toBe(true) + await expect.poll(() => page.evaluate(() => window.states.srcdocHeld.status)).toBe('rejected') + const value = await page.evaluate(() => window.tool.commit(() => { + return new URL(location.href).searchParams.get('epoch') + })) + expect(value).toBe('2') + result = await page.evaluate(() => ({ states: window.states, injected: window.tool.injected, pending: Object.keys(window.tool.promises).length })) + expect(result.pending).toBe(0) + } + else { + const next = urlFor(scenario === 'rapid-navigation' ? 3 : 2, false) + if (scenario === 'child-navigation' || scenario === 'history-back') { + await child.evaluate(url => location.href = url, next) + } + else { + await page.evaluate(({ next, intermediate }) => { + if (intermediate) { + window.targetFrame.src = intermediate + window.track('intermediate', window.tool.commit(() => { + return 2 + })) + } + window.targetFrame.src = next + window.track('new', window.tool.commit(() => { + return new URL(location.href).searchParams.get('epoch') + })) + }, { next, intermediate: scenario === 'rapid-navigation' ? urlFor(2, false) : null }) + } + await expect.poll(() => page.frames().some(frame => frame.url() === next)).toBe(true) + child = page.frames().find(frame => frame.url() === next) + await expect.poll(() => child.evaluate(() => Boolean(window.Tool))).toBe(true) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('rejected') + expect(await page.evaluate(() => window.states.old.error)).toBe('The iframe document has changed') + expect(await page.evaluate(() => window.tool.injected)).toBe(false) + if (scenario === 'rapid-navigation') + expect(await page.evaluate(() => window.states.intermediate.status)).toBe('pending') + await child.evaluate(() => window.Tool.inject()) + await expect.poll(() => page.evaluate(() => window.tool.injected)).toBe(true) + const current = await page.evaluate(() => window.timeline.filter(item => item.packet?.type === 'inject').at(-1).packet.__artplayerIframe.document) + expect(current).not.toBe(first) + if (scenario === 'stale-packets') { + await child.evaluate(({ document, id }) => parent.postMessage({ type: 'old-notification', data: 'stale', id, __artplayerIframe: { version: 1, document, phase: 'message' } }, '*'), { document: first, id: heldId }) + await expect.poll(() => page.evaluate(() => window.timeline.some(item => item.packet?.type === 'old-notification'))).toBe(true) + expect(await page.evaluate(() => window.callbacks.some(packet => packet.type === 'old-notification'))).toBe(false) + await page.evaluate(document => window.targetFrame.contentWindow.postMessage({ type: 'commit', data: 'window.executions++; return 999', id: 999, __artplayerIframe: { version: 1, document, phase: 'message' } }, '*'), first) + await expect.poll(() => child.evaluate(() => window.received.some(packet => packet.id === 999))).toBe(true) + expect(await child.evaluate(() => window.executions)).toBe(0) + } + if (scenario === 'history-back') { + const beforeBack = await page.evaluate(() => window.timeline.filter(item => item.packet?.type === 'fixture-pageshow').length) + await child.evaluate(() => history.back()) + await expect.poll(() => page.evaluate(count => window.timeline.filter(item => item.packet?.type === 'fixture-pageshow').length > count, beforeBack)).toBe(true) + child = page.frames().find(frame => frame.url() === url) + await expect.poll(() => page.evaluate(() => window.tool.injected)).toBe(true) + const restored = await child.evaluate(() => ({ witness: window.documentWitness, epoch: new URL(location.href).searchParams.get('epoch') })) + const pageshow = await page.evaluate(() => window.timeline.filter(item => item.packet?.type === 'fixture-pageshow').at(-1).packet.data) + expect(restored.epoch).toBe('1') + if (pageshow.persisted) + expect(restored.witness).toBe(witness) + const value = await page.evaluate(() => window.tool.commit(() => { + return new URL(location.href).searchParams.get('epoch') + })) + expect(value).toBe('1') + result = { pageshow, restored, actualBfcache: pageshow.persisted } + } + else { + const value = await page.evaluate(() => window.tool.commit(() => { + return new URL(location.href).searchParams.get('epoch') + })) + expect(value).toBe(scenario === 'rapid-navigation' ? '3' : '2') + if (scenario === 'rapid-navigation') { + await expect.poll(() => page.evaluate(() => window.states.intermediate.status)).toBe('resolved') + expect(await page.evaluate(() => window.states.intermediate.value)).toBe(2) + } + if (scenario !== 'child-navigation') { + await expect.poll(() => page.evaluate(() => window.states.new.status)).toBe('resolved') + expect(await page.evaluate(() => window.states.new.value)).toBe(value) + } + result = await page.evaluate(() => ({ states: window.states, pending: Object.keys(window.tool.promises).length })) + expect(result.pending).toBe(0) + } + } + const timeline = await page.evaluate(() => window.timeline) + expect(await page.evaluate(() => window.callbacks.some(packet => packet.type === 'artplayer-tool-iframe:session'))).toBe(false) + await testInfo.attach('iframe-navigation', { contentType: 'application/json', body: JSON.stringify({ implementation: implementation.name, sha256: hash(implementation.code), relation, scenario, parentOrigin, childOrigin, result, timeline, scope: 'Actual native frame navigation and postMessage; history-back records actual pageshow.persisted rather than assuming bfcache. Delayed-load barrier forces injection before load. Stale-packet tests replay old metadata from the controlled current frame to isolate document filtering. No media/player integration.' }) }) + } + finally { + releaseBarrier?.() + await page.evaluate(() => { + window.tool.destroy() + document.querySelectorAll('iframe').forEach(frame => frame.remove()) + }) + } + }) + } +} + +for (const historical of (await iframeHistorical()).filter(item => ['published-artplayer-plugin-iframe.js', 'workspace.js'].includes(item.name))) { + for (const relation of ['same-origin', 'cross-origin', 'opaque-origin']) { + test(`Iframe legacy child navigation ${relation}/${historical.name}/${implementation.name}`, async ({ page }, testInfo) => { + await page.goto('/test/player.html?core=published') + const parentOrigin = new URL(page.url()).origin + const childOrigin = relation === 'cross-origin' ? parentOrigin.replace('127.0.0.1', 'localhost') : parentOrigin + const first = `${childOrigin}/test/iframe-boundary-child.html?global=${historical.global}&auto=1&epoch=1` + const second = first.replace('auto=1&epoch=1', 'auto=0&epoch=2') + await page.route('**/iframe-boundary-lib.js', route => route.fulfill({ contentType: 'text/javascript', body: historical.code })) + await page.addScriptTag({ content: `(() => { const module = { exports: {} }; const exports = module.exports; ${implementation.code}; window.IframeFactory = module.exports.default || module.exports; })();` }) + await page.evaluate(({ first, opaque }) => { + const frame = document.createElement('iframe') + if (opaque) + frame.sandbox = 'allow-scripts' + document.body.append(frame) + window.targetFrame = frame + window.tool = new window.IframeFactory({ iframe: frame, url: first }) + window.states = {} + window.track = (key, promise) => { + window.states[key] = { status: 'pending' } + promise.then(value => window.states[key] = { status: 'resolved', value }, error => window.states[key] = { status: 'rejected', error: error.message }) + } + }, { first, opaque: relation === 'opaque-origin' }) + try { + await expect.poll(() => page.evaluate(() => window.tool.injected)).toBe(true) + await page.evaluate((second) => { + window.track('old', window.tool.postMessage({ type: 'hold' })) + window.targetFrame.src = second + window.track('new', window.tool.commit(() => { + return new URL(location.href).searchParams.get('epoch') + })) + }, second) + await expect.poll(() => page.frames().some(frame => frame.url() === second)).toBe(true) + const child = page.frames().find(frame => frame.url() === second) + await expect.poll(() => child.evaluate(() => Boolean(window.Tool))).toBe(true) + await expect.poll(() => page.evaluate(() => window.states.old.status)).toBe('rejected') + expect(await page.evaluate(() => window.tool.injected)).toBe(false) + await child.evaluate(() => window.Tool.inject()) + await expect.poll(() => page.evaluate(() => window.states.new.status)).toBe('resolved') + const result = await page.evaluate(() => ({ states: window.states, pending: Object.keys(window.tool.promises).length })) + expect(result.states.new.value).toBe('2') + expect(result.states.old.error).toBe('The iframe document has changed') + expect(result.pending).toBe(0) + await testInfo.attach('iframe-navigation', { contentType: 'application/json', body: JSON.stringify({ implementation: implementation.name, sha256: hash(implementation.code), relation, scenario: 'legacy-child-source-change', child: { name: historical.name, sha256: hash(historical.code) }, parentOrigin, childOrigin, result, scope: 'Actual source attribute navigation with an immutable historical child. No document metadata or internal child navigation protection is claimed for an unchanged legacy peer.' }) }) + } + finally { + await page.evaluate(() => { + window.tool.destroy() + window.targetFrame.remove() + }) + } + }) + } +} diff --git a/test/iframe-navigation.test.js b/test/iframe-navigation.test.js new file mode 100644 index 000000000..7c65ee8f0 --- /dev/null +++ b/test/iframe-navigation.test.js @@ -0,0 +1,341 @@ +import assert from 'node:assert/strict' +// eslint-disable-next-line test/no-import-node-test -- Controlled document markers and owned MutationObserver callbacks. +import test from 'node:test' +import { iframeCandidate, iframeEnvironment } from './helpers/iframe.js' + +const implementation = await iframeCandidate() +const flush = () => new Promise(resolve => setImmediate(resolve)) +const control = 'artplayer-tool-iframe:session' +function marked(type, document, phase, data, id = 0) { + return { type, data, id, __artplayerIframe: { version: 1, document, phase } } +} +function observe(promise) { + const state = { status: 'pending' } + promise.then(value => Object.assign(state, { status: 'resolved', value }), error => Object.assign(state, { status: 'rejected', error: error.message })) + return state +} +function setup() { + const env = iframeEnvironment(implementation) + const observers = [] + env.box.MutationObserver = class { + records = [] + disconnected = false + constructor(callback) { + this.callback = callback + observers.push(this) + } + + observe(target, options) { + this.target = target + this.options = options + } + + takeRecords() { return this.records.splice(0) } + disconnect() { + this.disconnected = true + this.records = [] + } + } + const frame = new env.Frame() + frame.hasAttribute = () => false + frame.getAttribute = name => name === 'src' ? frame.src : null + const instance = new env.Factory({ iframe: frame, url: '/first' }) + const inject = (document = 'first') => env.dispatch(marked('inject', document, 'inject'), frame.contentWindow) + const navigate = (value) => { + const oldValue = frame.src + frame.src = value + assert(observers[0], 'a navigation observer must own native attribute changes') + observers[0].records.push({ attributeName: 'src', oldValue }) + } + const tick = () => { + for (const [id, timer] of [...env.timers]) { + env.timers.delete(id) + timer.callback() + } + } + return { ...env, instance, frame, observers, inject, navigate, tick } +} + +test('Iframe document handshake keeps public callback data while acknowledging the peer privately', () => { + const env = setup() + const seen = [] + env.instance.message(packet => seen.push({ ...packet })) + env.inject() + assert.equal(env.instance.injected, true) + assert.deepEqual(seen, [{ type: 'inject', data: undefined }]) + assert.equal(env.sent[0].packet.type, control) + assert.deepEqual(JSON.parse(JSON.stringify(env.sent[0].packet.__artplayerIframe)), { version: 1, document: 'first', phase: 'ack' }) + assert.deepEqual(Object.keys(env.instance), ['url', '$iframe', 'promises', 'injected', 'destroyed', 'messageCallback', 'onMessage']) + env.instance.destroy() +}) + +test('Iframe requests and replies remain associated with their active document', async () => { + const env = setup() + env.inject() + const state = observe(env.instance.postMessage({ type: 'query' })) + const request = env.sent.at(-1).packet + assert.equal(request.__artplayerIframe.document, 'first') + env.dispatch(marked('response', 'wrong', 'message', 'wrong reply', request.id), env.frame.contentWindow) + await flush() + assert.equal(state.status, 'pending') + env.dispatch(marked('custom', 'first', 'message', 7, request.id), env.frame.contentWindow) + await flush() + assert.deepEqual(state, { status: 'resolved', value: 7 }) + env.instance.destroy() +}) + +test('Iframe a different document handshake cancels old requests and drops old notifications', async () => { + const env = setup() + env.inject() + const state = observe(env.instance.postMessage({ type: 'query' })) + const id = env.sent.at(-1).packet.id + const messages = [] + env.instance.message(packet => messages.push(packet.type)) + env.inject('second') + env.dispatch(marked('response', 'first', 'message', 'late', id), env.frame.contentWindow) + env.dispatch(marked('custom-old', 'first', 'message', 'late'), env.frame.contentWindow) + await flush() + assert.deepEqual(state, { status: 'rejected', error: 'The iframe document has changed' }) + assert.deepEqual(messages, ['inject']) + assert.equal(Object.keys(env.instance.promises).length, 0) + env.instance.destroy() +}) + +test('Iframe repeated injection from the same document preserves its pending requests', async () => { + const env = setup() + env.inject() + const state = observe(env.instance.postMessage({ type: 'query' })) + const id = env.sent.at(-1).packet.id + env.inject() + env.dispatch(marked('response', 'first', 'message', 8, id), env.frame.contentWindow) + await flush() + assert.deepEqual(state, { status: 'resolved', value: 8 }) + env.instance.destroy() +}) + +test('Iframe synchronous post after src change cancels old work and queues for the new injection', async () => { + const env = setup() + env.inject() + const first = observe(env.instance.postMessage({ type: 'query' })) + env.navigate('/second') + const second = observe(env.instance.postMessage({ type: 'query' })) + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + await flush() + assert.deepEqual(first, { status: 'rejected', error: 'The iframe document has changed' }) + assert.equal(second.status, 'pending') + assert.equal(env.instance.injected, false) + assert.equal(env.observers[0].records.length, 0) + assert.equal(env.sent.filter(item => item.packet.type === 'query').length, 1) + env.inject('second') + env.tick() + const request = env.sent.at(-1).packet + assert.equal(request.__artplayerIframe.document, 'second') + env.dispatch(marked('response', 'second', 'message', 9, request.id), env.frame.contentWindow) + await flush() + assert.deepEqual(second, { status: 'resolved', value: 9 }) + assert.equal(env.instance.url, '/first') + env.instance.destroy() +}) + +test('Iframe old pagehide and repeated old inject cannot cancel or activate a newly queued navigation', async () => { + const env = setup() + env.inject() + env.navigate('/second') + const state = observe(env.instance.postMessage({ type: 'query' })) + env.inject('first') + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + await flush() + assert.equal(state.status, 'pending') + assert.equal(env.instance.injected, false) + env.inject('second') + env.tick() + const request = env.sent.at(-1).packet + env.dispatch(marked('response', 'second', 'message', 10, request.id), env.frame.contentWindow) + await flush() + assert.deepEqual(state, { status: 'resolved', value: 10 }) + env.instance.destroy() +}) + +test('Iframe native attribute observation suspends sends and confirmed departure cancels old work', async () => { + const env = setup() + env.inject() + const state = observe(env.instance.postMessage({ type: 'query' })) + env.navigate('/second') + const observer = env.observers[0] + observer.callback(observer.takeRecords()) + await flush() + assert.equal(state.status, 'pending') + assert.equal(env.instance.injected, false) + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + await flush() + assert.deepEqual(state, { status: 'rejected', error: 'The iframe document has changed' }) + assert.equal(env.instance.injected, false) + env.instance.destroy() + assert.equal(observer.disconnected, true) + observer.callback([{ attributeName: 'src', oldValue: '/second' }]) + assert.equal(env.timers.size, 0) +}) + +test('Iframe consecutive source mutations preserve requests queued after navigation started', async () => { + for (const departed of [false, true]) { + const env = setup() + env.inject() + const old = observe(env.instance.postMessage({ type: 'query' })) + env.navigate('/second') + const queued = observe(env.instance.postMessage({ type: 'query' })) + if (departed) + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + env.navigate('/third') + env.observers[0].callback(env.observers[0].takeRecords()) + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + await flush() + assert.equal(old.error, 'The iframe document has changed') + assert.equal(queued.status, 'pending') + env.inject('third') + env.tick() + const request = env.sent.at(-1).packet + env.dispatch(marked('response', 'third', 'message', 13, request.id), env.frame.contentWindow) + await flush() + assert.deepEqual(queued, { status: 'resolved', value: 13 }) + env.instance.destroy() + } +}) + +test('Iframe confirmed fragment navigation preserves requests; a same-source document departure cancels them', async () => { + const env = setup() + env.inject() + const state = observe(env.instance.postMessage({ type: 'query' })) + env.navigate('/first#chapter') + const observer = env.observers[0] + observer.callback(observer.takeRecords()) + env.dispatch(marked(control, 'first', 'fragment', '/first#chapter'), env.frame.contentWindow) + await flush() + assert.equal(state.status, 'pending') + assert.equal(env.instance.injected, true) + env.navigate('/first#chapter') + observer.callback(observer.takeRecords()) + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + await flush() + assert.deepEqual(state, { status: 'rejected', error: 'The iframe document has changed' }) + env.instance.destroy() +}) + +test('Iframe pagehide cancels current work; a restored document can resume after another document', async () => { + const env = setup() + env.inject() + const first = observe(env.instance.postMessage({ type: 'query' })) + env.dispatch(marked(control, 'first', 'leave'), env.frame.contentWindow) + await flush() + assert.equal(first.error, 'The iframe document has changed') + env.inject('second') + const second = observe(env.instance.postMessage({ type: 'query' })) + env.dispatch(marked(control, 'first', 'resume'), env.frame.contentWindow) + await flush() + assert.equal(second.error, 'The iframe document has changed') + const restored = observe(env.instance.postMessage({ type: 'query' })) + assert.equal(env.sent.at(-1).packet.__artplayerIframe.document, 'first') + env.instance.destroy() + await flush() + assert.equal(restored.error, 'The instance has been destroyed') +}) + +test('Iframe legacy peer remains unmarked and source replacement still waits for its ordinary injection', async () => { + const env = setup() + env.dispatch({ type: 'inject' }, env.frame.contentWindow) + const first = observe(env.instance.postMessage({ type: 'query' })) + assert.deepEqual(Object.keys(env.sent.at(-1).packet), ['type', 'data', 'id']) + env.navigate('/second') + const second = observe(env.instance.postMessage({ type: 'query' })) + env.dispatch({ type: 'inject' }, env.frame.contentWindow) + env.tick() + const request = env.sent.at(-1).packet + assert.deepEqual(Object.keys(request), ['type', 'data', 'id']) + env.dispatch({ type: 'response', data: 11, id: request.id }, env.frame.contentWindow) + await flush() + assert.equal(first.error, 'The iframe document has changed') + assert.deepEqual(second, { status: 'resolved', value: 11 }) + env.instance.destroy() +}) + +test('Iframe child advertises a document without changing ordinary messages to an unmodified parent', () => { + const env = iframeEnvironment(implementation, true) + env.Factory.inject() + const injection = env.sent[0].packet + assert.equal(injection.type, 'inject') + assert.equal(injection.id, 0) + assert.equal(injection.data, undefined) + assert.equal(injection.__artplayerIframe.version, 1) + assert.equal(typeof injection.__artplayerIframe.document, 'string') + env.Factory.postMessage({ type: 'custom', data: 1 }) + assert.deepEqual(Object.keys(env.sent.at(-1).packet), ['type', 'data', 'id']) + for (const callback of env.handlers.get('pagehide') || []) callback({}) + assert.equal(env.sent.length, 2) +}) + +test('Iframe child tags acknowledged responses, ignores stale-document commands and hides lifecycle from legacy parents', async () => { + const env = iframeEnvironment(implementation, true) + env.Factory.inject() + const document = env.sent[0].packet.__artplayerIframe.document + await env.Factory.onMessage({ data: marked(control, document, 'ack'), source: env.box.parent }) + await env.Factory.onMessage({ data: marked('commit', 'old-document', 'message', 'return 7', 7), source: env.box.parent }) + assert.equal(env.sent.length, 1) + await env.Factory.onMessage({ data: marked('commit', document, 'message', 'return 8', 8), source: env.box.parent }) + assert.equal(env.sent.at(-1).packet.data, 8) + assert.equal(env.sent.at(-1).packet.__artplayerIframe.document, document) + env.Factory.inject() + assert.equal(env.handlers.get('pagehide').size, 1) + assert.equal(env.handlers.get('pageshow').size, 1) + for (const callback of env.handlers.get('pagehide')) callback({}) + assert.equal(env.sent.at(-1).packet.__artplayerIframe.phase, 'leave') + for (const callback of env.handlers.get('pageshow')) callback({ persisted: true }) + assert.equal(env.sent.at(-1).packet.__artplayerIframe.phase, 'resume') +}) + +test('Iframe failed child listener acquisition releases partial registrations and can be retried', () => { + const env = iframeEnvironment(implementation, true) + const add = env.box.addEventListener + const failure = new Error('pageshow listener failure') + env.box.addEventListener = (name, callback) => { + add(name, callback) + if (name === 'pageshow') + throw failure + } + assert.throws(() => env.Factory.inject(), error => error === failure) + for (const name of ['message', 'pagehide', 'pageshow']) assert.equal(env.handlers.get(name).size, 0) + env.box.addEventListener = add + env.Factory.inject() + for (const name of ['message', 'pagehide', 'pageshow']) assert.equal(env.handlers.get(name).size, 1) +}) + +test('Iframe internal cancellation retains ownership when a consumer replaces public reject', async () => { + const env = setup() + env.inject() + const state = observe(env.instance.postMessage({ type: 'query' })) + const id = env.sent.at(-1).packet.id + let calls = 0 + env.instance.promises[id].reject = () => calls++ + env.dispatch(marked('error', 'first', 'message', 'remote error', id), env.frame.contentWindow) + await flush() + assert.equal(calls, 1) + assert.equal(state.status, 'pending') + env.instance.destroy() + await flush() + assert.deepEqual(state, { status: 'rejected', error: 'The instance has been destroyed' }) + assert.equal(calls, 1) + assert.equal(Object.keys(env.instance.promises).length, 0) +}) + +test('Iframe a changed src getter resolution without an attribute mutation does not invent a navigation', async () => { + const env = setup() + env.inject() + env.frame.getAttribute = name => name === 'src' ? '/first' : null + Object.defineProperty(env.frame, 'src', { value: 'https://new-base.example/first' }) + const state = observe(env.instance.postMessage({ type: 'query' })) + assert.equal(env.instance.injected, true) + assert.equal(env.sent.at(-1).packet.type, 'query') + env.dispatch(marked('response', 'first', 'message', 13, env.sent.at(-1).packet.id), env.frame.contentWindow) + await flush() + assert.deepEqual(state, { status: 'resolved', value: 13 }) + env.instance.destroy() +})