refactor(iframe): [PKG-IFRAME-03] scope requests to active documents

This commit is contained in:
Harvey Zhao committed 2026-09-13 01:07:37 +08:00
1 parent b8cdafedd1
commit 1342de94ef
27 files changed
+10860 -69

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -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.
+4
View File
@@ -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);本轮不将来源绑定视为导航或全包发布验收。
+64
View File
@@ -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重建,不手改产物。
+4 -4
View File
@@ -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<br>核对包契约与历史用法 | BASE-05 | constructor/commit/message/inject、postMessage 协议与历史公开拼写 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
| PKG-IFRAME-02 | artplayer-tool-iframe<br>建立特有行为与错误测试 | PKG-IFRAME-01, ENG-03, ENG-05 | 跨窗口消息、ID 匹配、请求失败、重复 inject、销毁中请求 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
| PKG-IFRAME-03 | artplayer-tool-iframe<br>整理内部职责与资源 | PKG-IFRAME-02, CORE-02, BASE-07 | 请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | doing |
| PKG-IFRAME-03 | artplayer-tool-iframe<br>整理内部职责与资源 | PKG-IFRAME-02, CORE-02, BASE-07 | 请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
| PKG-IFRAME-04 | artplayer-tool-iframe<br>迁移自有源码和公开类型 | PKG-IFRAME-03, ENG-04, ENG-06, CORE-07 | 消息联合类型、回调/Promise 推导、旧公开字段兼容;旧npm export=与实际namespace、额外helper协议分别核验 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
| PKG-IFRAME-05 | artplayer-tool-iframe<br>验证新旧核心和组合 | PKG-IFRAME-04, CORE-22 | 真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
| PKG-IFRAME-05 | artplayer-tool-iframe<br>验证新旧核心和组合 | PKG-IFRAME-04, CORE-22 | 真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论;新旧核心/demo、实际 BFCache/设备和外部中断导航验收,旧端无文档标记的限制明确 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
| PKG-IFRAME-06 | artplayer-tool-iframe<br>验证分发并同步文档 | 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)
+14
View File
@@ -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即使
+1 -1
View File
@@ -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 |
+12 -5
View File
@@ -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"
]
},
{
+6 -3
View File
@@ -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": []
},