mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-09 03:46:16 -08:00
test(dpip): [PKG-DPIP-01] freeze actual releases and window contracts
This commit is contained in:
1 parent
224572032a
commit
efbbdb4782
16 files changed
+1041
-10
No files matched your search
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "PKG-DPIP-01",
|
||||
"status": "done",
|
||||
"checks": [
|
||||
{
|
||||
"command": "node --test refactor/scripts/dpip-contract.test.mjs refactor/scripts/contracts.test.mjs",
|
||||
"result": "pass",
|
||||
"tests": 23,
|
||||
"dpip": 16,
|
||||
"indexValidation": 7
|
||||
},
|
||||
{
|
||||
"command": "focused eslint --no-fix",
|
||||
"result": "pass"
|
||||
},
|
||||
{
|
||||
"command": "yarn ci:check",
|
||||
"result": "pass",
|
||||
"tests": {
|
||||
"unit": 938,
|
||||
"engineering": 14,
|
||||
"baseline": 116,
|
||||
"mainTotal": 1068,
|
||||
"repeatedContractExecutions": 44
|
||||
},
|
||||
"strictProductionTypeScriptFiles": 284
|
||||
}
|
||||
],
|
||||
"limitations": [
|
||||
"npm1.0.0 lacks all declared runtime files and is not a runnable fixture.",
|
||||
"Controlled DOM/window tests are not native Document PiP or device acceptance.",
|
||||
"Pending-window, delayed callback and rollback concerns remain source-observed for task02 reproduction."
|
||||
],
|
||||
"parentCommit": "224572032a418a82e9fdfb931f2b8cbba4295c27",
|
||||
"archiveScope": {
|
||||
"publishedVersions": [
|
||||
"1.1.0",
|
||||
"1.0.2",
|
||||
"1.0.1",
|
||||
"1.0.0"
|
||||
],
|
||||
"members": 21,
|
||||
"workspaceFiles": 7,
|
||||
"runnableVersions": [
|
||||
"1.1.0",
|
||||
"1.0.2",
|
||||
"1.0.1"
|
||||
],
|
||||
"missingRuntime": "1.0.0",
|
||||
"supportedCoreRange": "not inferred from Git associations"
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"file": "refactor/baselines/dpip-release.json",
|
||||
"sha256LF": "afcf54f22fb3f57186e19bdf384a130c6388e972164774ee56eeca23fc814c23"
|
||||
},
|
||||
{
|
||||
"file": "refactor/scripts/dpip-contract.mjs",
|
||||
"sha256LF": "7801c893e8c4c8f158d484a4bafd4db88a12ca6f7ec219453e2ba176a186710f"
|
||||
},
|
||||
{
|
||||
"file": "refactor/scripts/dpip-contract.test.mjs",
|
||||
"sha256LF": "b5c46dc9f918635e8b6001bb660edc31759e084ff4f419e2328341d77463aede"
|
||||
},
|
||||
{
|
||||
"file": "test/helpers/dpip.js",
|
||||
"sha256LF": "727a0a2ab9d6552198d16779739dbabed2d86691f8e6695c5bde0ed2d27b8016"
|
||||
},
|
||||
{
|
||||
"file": "refactor/contract-policy.json",
|
||||
"sha256LF": "a7654b53b8436d70d1c697f2fc70e65221bd83a5ec51bbff822958d8b1a4df53"
|
||||
},
|
||||
{
|
||||
"file": "refactor/scripts/contracts.test.mjs",
|
||||
"sha256LF": "e52835b7f59a71108f62e786a787a67748da4cbe682b08860cd8773f3255aa80"
|
||||
}
|
||||
],
|
||||
"logs": [
|
||||
{
|
||||
"file": "refactor/.cache/dpip01-missing-entry-observation.log",
|
||||
"sha256": "ec76d068fc579ffbdd03913db632553ca1fc4c0bab408444107aad830e6f1420"
|
||||
},
|
||||
{
|
||||
"file": "refactor/.cache/dpip01-capture-final.log",
|
||||
"sha256": "670debdc562d8f2e32cf9a316afef92ed2b5fd5c76a967bedcd2eb4359d701da"
|
||||
},
|
||||
{
|
||||
"file": "refactor/.cache/dpip01-targeted.log",
|
||||
"sha256": "60e3ddd5ef0457a9e3278a883ce62ca8a0efb214b895088b2373f0f47ad65f83"
|
||||
},
|
||||
{
|
||||
"file": "refactor/.cache/dpip01-lint-final.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
{
|
||||
"file": "refactor/.cache/dpip01-ci.log",
|
||||
"sha256": "e9a75c3d72ccce0f180e88f88394e6ab8df86a350353a13575f27d0677fb539d"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# Document PiP 发布契约
|
||||
|
||||
来源:dpip-release.json固定实际npm1.0.0、1.0.1、1.0.2、1.1.0四个归档,共21个文件。
|
||||
SHA512 integrity、归档SHA256、每个成员哈希、manifest入口、发布时点均可重跑核验。
|
||||
冻结当前Git的src/index.js、style.less、声明、manifest、README、.npmignore和demo
|
||||
共7个输入;未来迁移不改写这些历史哈希。
|
||||
|
||||
**1.0.0只有README、package.json和声明,缺少main/module/legacy指定的三个文件。**
|
||||
归档没有运行时代码,不能用同版本Git源码冒充已发布实现。验证器固定缺失清单,
|
||||
现有打包检查必须拒绝此归档。行为矩阵只执行实际1.0.1/1.0.2/1.1.0与冻结工作区;
|
||||
1.0.0仅作分发缺陷和类型对照。全局契约索引中的发布点不代表每类行为均可运行。
|
||||
|
||||
## 正常公开行为
|
||||
|
||||
- 工厂运行时options可省略;默认width480、height270、fallbackToVideoPiP=true,
|
||||
placeholder为Playing in Document Picture-in-Picture。工厂调用时浅拷贝一次,
|
||||
之后修改调用者对象不影响结果;显式width:undefined会覆盖480默认值。
|
||||
- 注册同步返回name/isSupported/isActive/open/close/toggle。状态为enumerable只读
|
||||
getter;isSupported在注册时检测window.documentPictureInPicture.requestWindow,
|
||||
之后新增能力不会改变此快照;isActive反映是否保存窗口引用。
|
||||
- open与close实际返回Promise<void>,toggle返回undefined并内部发起open/close。
|
||||
不支持且fallback=true时设置art.pip=true,输出warning;不支持且fallback=false
|
||||
会进入open的错误提示路径,而非假装已经打开文档窗口。
|
||||
- 始终添加document-pip右侧控件,index40、pip图标、PIP Mode提示,点击调用toggle。
|
||||
document-pip事件的true/false分别切换Exit PIP Mode/PIP Mode提示。
|
||||
- 正常open请求窗口尺寸,在原位置添加placeholder,将同一个$player通过adoptNode
|
||||
移入新document。复制全局document里的link/style及相关属性,补viewport和基础样式。
|
||||
绑定窗口resize/pagehide/unload,添加class,重绑核心全局事件,发document-pip=true,
|
||||
await sleep(100)后发resize。正常close先去窗口监听,再恢复原位置、关闭窗口、移除
|
||||
class、重绑事件、发false,await sleep(100)后发resize。普通关闭保留控件。
|
||||
- 包加载时注入固定ID样式,loading文档等待DOMContentLoaded,否则立即插入。
|
||||
这些均是受控DOM和异步边界的契约,不能当作真实窗口/用户激活/原生视频PiP验收。
|
||||
|
||||
## 声明与导出差异
|
||||
|
||||
四版声明一致:options必填、各字段可选,open/close/toggle均写void,状态字段写成
|
||||
可赋值boolean。运行时省略options、异步open/close和只读getter已由测试确认。
|
||||
04需要保留已有合法消费者,明确异步能力与历史void/Parameters提取的兼容方案;
|
||||
不能因为Ads曾获批推导修正就自动改变本包返回类型。
|
||||
|
||||
1.0.1/1.0.2的CommonJS是namespace.default,1.1.0是可调用工厂;三份可运行归档
|
||||
都有独立mjs默认导出和浏览器全局artplayerPluginDocumentPip。04/06须兼容两代访问,
|
||||
而非用1.0.0缺失runtime作导出成功证据。
|
||||
|
||||
registry gitHead关联核心依次为5.3.0、5.3.0、5.3.0-beta.3、5.3.1。这里只冻结
|
||||
对应Git manifest,不代表相同版本npm核心实现相同,更不声明连续兼容范围。
|
||||
|
||||
## 后续实现约束
|
||||
|
||||
源码观察到pending requestWindow未单独跟踪、open/close后的sleep没有取消、错误
|
||||
只写notice而缺少回滚、销毁仅调用close、全局document与实际ownerDocument可能不同。
|
||||
这些疑点登记为source-observed,由02复现后再03修复;正常流程16项通过不等于
|
||||
生命周期问题已解决。真实窗口、原生视频/Canvas/Mediabunny、焦点键盘和恢复留05。
|
||||
@@ -0,0 +1,268 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "PKG-DPIP-01",
|
||||
"capturedAt": "2026-09-12T05:31:41.167Z",
|
||||
"sourceCommit": "224572032a418a82e9fdfb931f2b8cbba4295c27",
|
||||
"registryObservation": {
|
||||
"versions": [
|
||||
"1.0.0",
|
||||
"1.0.1",
|
||||
"1.0.2",
|
||||
"1.1.0"
|
||||
],
|
||||
"latest": "1.1.0",
|
||||
"workspaceVersion": "1.1.0"
|
||||
},
|
||||
"release": {
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.1.0",
|
||||
"metadataUrl": "https://registry.npmjs.org/artplayer-plugin-document-pip/1.1.0",
|
||||
"tarball": "https://registry.npmjs.org/artplayer-plugin-document-pip/-/artplayer-plugin-document-pip-1.1.0.tgz",
|
||||
"integrity": "sha512-+HCrlO+bQwBrig1bI/IIxgGvbcG7i+aNHAnR5vLqB+RdyIY+FKCHyEe0o9yZREnbYOe0XJVqjv2buEVrouzdoQ==",
|
||||
"sha256": "b864befea9aff84b3352782a9670ebe72ff073606fec7cdc31d31e92a5ad6d8a",
|
||||
"archiveBytes": 4575,
|
||||
"publishedAt": "2026-03-12T14:20:57.572Z",
|
||||
"registryGitHead": "daf133b22630b4a0eecfa3336bbddab0e9119d96",
|
||||
"files": {
|
||||
"package/README.md": "e66acb1026ced7b058327814a8b7d31433c029c292991cdba747302c6b663d10",
|
||||
"package/dist/artplayer-plugin-document-pip.js": "261d4ae84579c569ade1b1e7e91d51e3bd00c6efbea8c51a48b8283e0f4f3496",
|
||||
"package/dist/artplayer-plugin-document-pip.legacy.js": "8e36b658196dece391add21c249b735f3abfe4082fc968d3dbbbb1ae58a77b31",
|
||||
"package/dist/artplayer-plugin-document-pip.mjs": "22b432b5fc958f6f838b83fdfcc7e5ab7144137111b1f8cf081eb2e21afd8382",
|
||||
"package/package.json": "cd0c0c17fde404f93fc6bd64f6317d29ce54908e15b956c465124dd9fe2c77f6",
|
||||
"package/types/artplayer-plugin-document-pip.d.ts": "e5bf38dd4829a075bd6d1a2e356a9ee56434b65f622fb623ac57e9fe46151077"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.1.0",
|
||||
"description": "Document PIP plugin for ArtPlayer",
|
||||
"author": "Harvey Zhao <laozhaochaguan@gmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/artplayer-plugin-document-pip.d.ts",
|
||||
"import": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"require": "./dist/artplayer-plugin-document-pip.js"
|
||||
},
|
||||
"./legacy": {
|
||||
"types": "./types/artplayer-plugin-document-pip.d.ts",
|
||||
"import": "./dist/artplayer-plugin-document-pip.legacy.js",
|
||||
"require": "./dist/artplayer-plugin-document-pip.legacy.js"
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-document-pip.js",
|
||||
"module": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"types": "./types/artplayer-plugin-document-pip.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-document-pip.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
},
|
||||
"missingEntrypoints": {},
|
||||
"historicalCore": {
|
||||
"version": "5.3.1",
|
||||
"commit": "daf133b22630b4a0eecfa3336bbddab0e9119d96",
|
||||
"file": "packages/artplayer/package.json",
|
||||
"sha256LF": "862f3697876fe915dd0ada178da766ce823aae7563ed30b3e5b11b811202929c",
|
||||
"scope": "Git association only, not actual npm compatibility verification"
|
||||
}
|
||||
},
|
||||
"previous": [
|
||||
{
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.0.2",
|
||||
"metadataUrl": "https://registry.npmjs.org/artplayer-plugin-document-pip/1.0.2",
|
||||
"tarball": "https://registry.npmjs.org/artplayer-plugin-document-pip/-/artplayer-plugin-document-pip-1.0.2.tgz",
|
||||
"integrity": "sha512-/vUpB3GsvOabRoBAZWkXXk6QZ3Ja2XbNZr3i933HSKhzpUc6zfvh3VajTkCb3CfDz37/pjR3cPbKBWnWwx+8pA==",
|
||||
"sha256": "0657a1b2e3e82ccfd29dea824baca7f93748d0107942d4befd360be7bf4efd68",
|
||||
"archiveBytes": 9233,
|
||||
"publishedAt": "2025-09-06T05:18:19.436Z",
|
||||
"registryGitHead": "fd9aeddbedffe9fd00f827a271672bc2510fb503",
|
||||
"files": {
|
||||
"package/README.md": "6802bbd78f851115f27cd856d8604c4ab898b788568e1a3eae62d12c7acb5e07",
|
||||
"package/dist/artplayer-plugin-document-pip.js": "514c047594dbb887b68f3d6aa841af4105a537c804cbb4eb11ecbeda692280f8",
|
||||
"package/dist/artplayer-plugin-document-pip.legacy.js": "07cff703943c34832fdd1b828a72fabd2093b45cd5bc37e4c9de16d1dbe4e6d3",
|
||||
"package/dist/artplayer-plugin-document-pip.mjs": "21571df888278f21d46f28355bdf2f70c531b5fa8286eb45366a34de18266f08",
|
||||
"package/package.json": "5c93563a3d0b6b1fdd8f0b89eca83bb2685d6748397fc4a5fd20403aa743201f",
|
||||
"package/types/artplayer-plugin-document-pip.d.ts": "e5bf38dd4829a075bd6d1a2e356a9ee56434b65f622fb623ac57e9fe46151077"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.0.2",
|
||||
"description": "Document PIP plugin for ArtPlayer",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"require": "./dist/artplayer-plugin-document-pip.js",
|
||||
"types": "./types/artplayer-plugin-document-pip.d.ts"
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-document-pip.js",
|
||||
"module": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"types": "./types/artplayer-plugin-document-pip.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-document-pip.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
},
|
||||
"missingEntrypoints": {},
|
||||
"historicalCore": {
|
||||
"version": "5.3.0-beta.3",
|
||||
"commit": "fd9aeddbedffe9fd00f827a271672bc2510fb503",
|
||||
"file": "packages/artplayer/package.json",
|
||||
"sha256LF": "fbadd47595d282efdfddfb3fe0b8470c2fe12319a7737a6abd77fd7155ba4f7a",
|
||||
"scope": "Git association only, not actual npm compatibility verification"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.0.1",
|
||||
"metadataUrl": "https://registry.npmjs.org/artplayer-plugin-document-pip/1.0.1",
|
||||
"tarball": "https://registry.npmjs.org/artplayer-plugin-document-pip/-/artplayer-plugin-document-pip-1.0.1.tgz",
|
||||
"integrity": "sha512-u/lCjgeanxZcMpcFZMojUF9KppzP+f1ALUt2u2MCa73CXhmb0hn/vI99hR7qALck6XamfSpDbjDw6i0p6HrScA==",
|
||||
"sha256": "dcf611aa5c4247858cb61e197f073db719a4806dc97da2d927394169d428316f",
|
||||
"archiveBytes": 9233,
|
||||
"publishedAt": "2025-09-03T10:31:57.113Z",
|
||||
"registryGitHead": "9bfd535e57ddd489da3b7875f965fee81abbac51",
|
||||
"files": {
|
||||
"package/README.md": "6802bbd78f851115f27cd856d8604c4ab898b788568e1a3eae62d12c7acb5e07",
|
||||
"package/dist/artplayer-plugin-document-pip.js": "d3878387d6110f7080dcf0f253b4c99391e7213c17c4b224c00b856e9a82a9ee",
|
||||
"package/dist/artplayer-plugin-document-pip.legacy.js": "134112d64aa571d40c65dd89b218409c62d7c87713b6cb2885cac281b55f1028",
|
||||
"package/dist/artplayer-plugin-document-pip.mjs": "8731b8ba47d65427e2804549a2912577bc9a7ad666880c9ff4fe71d13b1ccc1f",
|
||||
"package/package.json": "30167428c3e2058f48de0a5209ae9dba9ce30556a2d78e7bdf4e8d1b0c104004",
|
||||
"package/types/artplayer-plugin-document-pip.d.ts": "e5bf38dd4829a075bd6d1a2e356a9ee56434b65f622fb623ac57e9fe46151077"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.0.1",
|
||||
"description": "Document PIP plugin for ArtPlayer",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"require": "./dist/artplayer-plugin-document-pip.js"
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-document-pip.js",
|
||||
"module": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"types": "./types/artplayer-plugin-document-pip.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-document-pip.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
},
|
||||
"missingEntrypoints": {},
|
||||
"historicalCore": {
|
||||
"version": "5.3.0",
|
||||
"commit": "9bfd535e57ddd489da3b7875f965fee81abbac51",
|
||||
"file": "packages/artplayer/package.json",
|
||||
"sha256LF": "9f8756b84dcf3f5edf811e835859b13e5c64e75c154348d31178de43183954d9",
|
||||
"scope": "Git association only, not actual npm compatibility verification"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.0.0",
|
||||
"metadataUrl": "https://registry.npmjs.org/artplayer-plugin-document-pip/1.0.0",
|
||||
"tarball": "https://registry.npmjs.org/artplayer-plugin-document-pip/-/artplayer-plugin-document-pip-1.0.0.tgz",
|
||||
"integrity": "sha512-mm1OYSE7M9brzODk/VdGfk7LjfPD5FKY7iUXESsQYMsQ5T4vr1VaacprnWRk5G75E0ON4RNRNjAIwGvJ1qETDg==",
|
||||
"sha256": "3b0164391171c817ab511f740205732e65db0e8f1d65d63f0d24d8eef4251573",
|
||||
"archiveBytes": 818,
|
||||
"publishedAt": "2025-09-03T10:28:27.976Z",
|
||||
"registryGitHead": "9bfd535e57ddd489da3b7875f965fee81abbac51",
|
||||
"files": {
|
||||
"package/README.md": "6802bbd78f851115f27cd856d8604c4ab898b788568e1a3eae62d12c7acb5e07",
|
||||
"package/package.json": "259a13eee4128cac7eeb2586b237c01a098151f5411700be96b3bc603703acbd",
|
||||
"package/types/artplayer-plugin-document-pip.d.ts": "e5bf38dd4829a075bd6d1a2e356a9ee56434b65f622fb623ac57e9fe46151077"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "1.0.0",
|
||||
"description": "Document PIP plugin for ArtPlayer",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"require": "./dist/artplayer-plugin-document-pip.js"
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-document-pip.js",
|
||||
"module": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"types": "./types/artplayer-plugin-document-pip.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-document-pip.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
},
|
||||
"missingEntrypoints": {
|
||||
"main": "./dist/artplayer-plugin-document-pip.js",
|
||||
"module": "./dist/artplayer-plugin-document-pip.mjs",
|
||||
"legacy": "./dist/artplayer-plugin-document-pip.legacy.js"
|
||||
},
|
||||
"historicalCore": {
|
||||
"version": "5.3.0",
|
||||
"commit": "9bfd535e57ddd489da3b7875f965fee81abbac51",
|
||||
"file": "packages/artplayer/package.json",
|
||||
"sha256LF": "9f8756b84dcf3f5edf811e835859b13e5c64e75c154348d31178de43183954d9",
|
||||
"scope": "Git association only, not actual npm compatibility verification"
|
||||
}
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
"packages/artplayer-plugin-document-pip/src/index.js": "655818d30d82e43443e9a7ea185f91fc951eb72ad11edaaed0264182e62f32ba",
|
||||
"packages/artplayer-plugin-document-pip/src/style.less": "a75ae94a569c8fd6ce925dcc7ab6b22cfa39a4d81decb30cc447dd7108a84a22",
|
||||
"packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts": "e5bf38dd4829a075bd6d1a2e356a9ee56434b65f622fb623ac57e9fe46151077",
|
||||
"packages/artplayer-plugin-document-pip/package.json": "cd0c0c17fde404f93fc6bd64f6317d29ce54908e15b956c465124dd9fe2c77f6",
|
||||
"packages/artplayer-plugin-document-pip/README.md": "e66acb1026ced7b058327814a8b7d31433c029c292991cdba747302c6b663d10",
|
||||
"packages/artplayer-plugin-document-pip/.npmignore": "46063058e98be55dba5cf5f33d379e73eca048f4126e7af75f8011bab7f09145",
|
||||
"docs/assets/example/document.pip.js": "2600948ff0128e2e77fe08fbefa9be96543d8fcd81421534dfbfe9cb84e91fde"
|
||||
},
|
||||
"limitation": "Git core association is not a verified npm support range; native window/device, race and installed consumers remain later tasks."
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# PKG-DPIP-01 实际发布和窗口契约
|
||||
|
||||
完整捕获四个发布版本/21成员及7个Git工作区输入。首次捕获遇到1.0.0缺少main文件,
|
||||
核对tarball后确认同时缺main/module/legacy;保留首次日志并让捕获/验证明确记录缺失,
|
||||
没有用仓库源码填充。现有checkFiles对这份真实清单失败,行为测试只执行其余三份
|
||||
归档和冻结工作区,1.0.0仍保留类型与分发对照。
|
||||
|
||||
新增16项正常契约:同步Result、状态getter和能力快照、默认/fallback、控件、窗口
|
||||
节点迁移、样式属性、tooltip/事件/Promise顺序、close还原、options浅拷贝与延迟style。
|
||||
源码LESS在冻结输入上编译后注入受控loader,归档直接执行实际代码;没有修改生产源码。
|
||||
open/close的Promise与旧void声明、options可省略与必填声明、getter与可写声明、
|
||||
两代CommonJS形状等差异已登记。窗口竞争和错误回滚仅source-observed,交给02复现。
|
||||
|
||||
契约索引增加四个实际发布点,合计22工作区+15发布;家族仍264、精确索引case仍10,
|
||||
255行尚未精确索引,不能把本步通过直接填成所有契约通过。1.0.0发布点明确无runtime。
|
||||
|
||||
联合验收依赖也同步修正:Canvas05需DPIP04,DPIP05需Canvas04和MB04。三方04
|
||||
内部迁移没有循环依赖,05需使用最终包组合;原有设备/SDK要求全部保留。
|
||||
|
||||
详见[契约](../baselines/dpip-contract.md)、[维护入口](../dpip-validation.md)与
|
||||
[验证证据](../baselines/dpip-contract-validation.json)。本任务完成后独立本地提交,
|
||||
不推送/发布;下一步02建立失败回归并推进03源码修复。
|
||||
|
||||
最终23项定向检查、lint及完整CI1068项通过(938单元+14工程+116基线),另44项重复契约观察,284个生产TS文件严格检查。本步done并独立提交;正常受控窗口测试不代表原生Document PiP验收。
|
||||
@@ -320,3 +320,7 @@
|
||||
- PUB-artplayer-plugin-ambilight-1.0.0: artplayer-plugin-ambilight@1.0.0 (published-baseline);[来源](../refactor/baselines/ambilight-release.json) JSON pointer `/previous/0`。
|
||||
- PUB-artplayer-proxy-canvas-1.1.0: artplayer-proxy-canvas@1.1.0 (published-baseline);[来源](../refactor/baselines/canvas-release.json) JSON pointer `/release`。
|
||||
- PUB-artplayer-proxy-canvas-1.0.0: artplayer-proxy-canvas@1.0.0 (published-baseline);[来源](../refactor/baselines/canvas-release.json) JSON pointer `/previous/0`。
|
||||
- PUB-artplayer-plugin-document-pip-1.1.0: artplayer-plugin-document-pip@1.1.0 (published-baseline);[来源](../refactor/baselines/dpip-release.json) JSON pointer `/release`。
|
||||
- PUB-artplayer-plugin-document-pip-1.0.2: artplayer-plugin-document-pip@1.0.2 (published-baseline);[来源](../refactor/baselines/dpip-release.json) JSON pointer `/previous/0`。
|
||||
- PUB-artplayer-plugin-document-pip-1.0.1: artplayer-plugin-document-pip@1.0.1 (published-baseline);[来源](../refactor/baselines/dpip-release.json) JSON pointer `/previous/1`。
|
||||
- PUB-artplayer-plugin-document-pip-1.0.0: artplayer-plugin-document-pip@1.0.0 (published-baseline);[来源](../refactor/baselines/dpip-release.json) JSON pointer `/previous/2`。
|
||||
@@ -317,7 +317,11 @@
|
||||
"API-12": "PKG-DPIP-02"
|
||||
},
|
||||
"versionIds": [
|
||||
"WS-artplayer-plugin-document-pip"
|
||||
"WS-artplayer-plugin-document-pip",
|
||||
"PUB-artplayer-plugin-document-pip-1.1.0",
|
||||
"PUB-artplayer-plugin-document-pip-1.0.2",
|
||||
"PUB-artplayer-plugin-document-pip-1.0.1",
|
||||
"PUB-artplayer-plugin-document-pip-1.0.0"
|
||||
],
|
||||
"supportWindow": "not-inferred-from-baseline",
|
||||
"scopeReview": "Each public member, callback, option, event and capability requires package contract review; family ownership alone is not exhaustive coverage"
|
||||
@@ -822,6 +826,42 @@
|
||||
"file": "refactor/baselines/canvas-release.json",
|
||||
"pointer": "/previous/0",
|
||||
"archiveSha256": "728ba39534b3b8139bdc404ef15fe1ac5f76a95562a14e78c6973db2dcfa6f4f"
|
||||
},
|
||||
{
|
||||
"id": "PUB-artplayer-plugin-document-pip-1.1.0",
|
||||
"package": "artplayer-plugin-document-pip",
|
||||
"kind": "published-baseline",
|
||||
"version": "1.1.0",
|
||||
"file": "refactor/baselines/dpip-release.json",
|
||||
"pointer": "/release",
|
||||
"archiveSha256": "b864befea9aff84b3352782a9670ebe72ff073606fec7cdc31d31e92a5ad6d8a"
|
||||
},
|
||||
{
|
||||
"id": "PUB-artplayer-plugin-document-pip-1.0.2",
|
||||
"package": "artplayer-plugin-document-pip",
|
||||
"kind": "published-baseline",
|
||||
"version": "1.0.2",
|
||||
"file": "refactor/baselines/dpip-release.json",
|
||||
"pointer": "/previous/0",
|
||||
"archiveSha256": "0657a1b2e3e82ccfd29dea824baca7f93748d0107942d4befd360be7bf4efd68"
|
||||
},
|
||||
{
|
||||
"id": "PUB-artplayer-plugin-document-pip-1.0.1",
|
||||
"package": "artplayer-plugin-document-pip",
|
||||
"kind": "published-baseline",
|
||||
"version": "1.0.1",
|
||||
"file": "refactor/baselines/dpip-release.json",
|
||||
"pointer": "/previous/1",
|
||||
"archiveSha256": "dcf611aa5c4247858cb61e197f073db719a4806dc97da2d927394169d428316f"
|
||||
},
|
||||
{
|
||||
"id": "PUB-artplayer-plugin-document-pip-1.0.0",
|
||||
"package": "artplayer-plugin-document-pip",
|
||||
"kind": "published-baseline",
|
||||
"version": "1.0.0",
|
||||
"file": "refactor/baselines/dpip-release.json",
|
||||
"pointer": "/previous/2",
|
||||
"archiveSha256": "3b0164391171c817ab511f740205732e65db0e8f1d65d63f0d24d8eef4251573"
|
||||
}
|
||||
],
|
||||
"cases": [
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Document PiP 验证维护
|
||||
|
||||
先读[实际契约](baselines/dpip-contract.md)和dpip-release.json。验证命令:
|
||||
|
||||
`node --test refactor/scripts/dpip-contract.test.mjs`
|
||||
|
||||
16项覆盖四归档/21成员/7个Git输入、1.0.0缺失入口、声明和实际导出,再对三份可运行
|
||||
发布和冻结工作区分别测试同步注册/控件/不支持fallback、正常窗口迁移/样式/事件/还原、
|
||||
option快照/默认值/延迟样式。1.0.0不在行为矩阵中;不能用Git或新版artifact替代它。
|
||||
本文件对应测试已接入test:baseline。
|
||||
|
||||
test/helpers/dpip.js是受控DOM/window边界:验证ownerDocument、节点身份与顺序、
|
||||
样式属性、订阅和Promise顺序。requestWindow由受控窗口替身返回,不证明真实用户
|
||||
激活、弹窗、媒体连续播放、原生视频PiP或设备能力。02继续加入pending打开、关闭/
|
||||
销毁竞争、style与restore错误;03候选修复必须保留旧失败对照,04处理公开类型。
|
||||
|
||||
05的Document PiP双代理组合必须使用迁移后的Canvas和Mediabunny;Canvas05的
|
||||
文档窗口恢复必须使用迁移后的Document PiP,因此任务图分别增加相应04阶段依赖。
|
||||
这防止旧实现通过后被误当最终组合通过,不减少任何浏览器或设备验收内容。
|
||||
06再检查完整tarball、8082 document.pip示例、三种产物和回退说明。
|
||||
|
||||
证据入口:[01记录](changes/2026-09-12-PKG-DPIP-01-contract.md)、
|
||||
[01验证](baselines/dpip-contract-validation.json)。正常契约测试通过不关闭源码观察风险。
|
||||
+5
-4
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 221 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 122 / doing 6 / blocked 0 / done 93 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 121 / doing 6 / blocked 0 / done 94 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -293,11 +293,11 @@
|
||||
|
||||
| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| PKG-DPIP-01 | artplayer-plugin-document-pip<br>核对包契约与历史用法 | BASE-05 | width/height/placeholder/fallbackToVideoPiP、open/close/toggle 返回 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo |
|
||||
| PKG-DPIP-01 | artplayer-plugin-document-pip<br>核对包契约与历史用法 | BASE-05 | width/height/placeholder/fallbackToVideoPiP、open/close/toggle 返回 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
|
||||
| PKG-DPIP-02 | artplayer-plugin-document-pip<br>建立特有行为与错误测试 | PKG-DPIP-01, ENG-03, ENG-05 | 不支持/拒绝、重复打开、pagehide、核心销毁和视频 PiP fallback | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo |
|
||||
| PKG-DPIP-03 | artplayer-plugin-document-pip<br>整理内部职责与资源 | PKG-DPIP-02, CORE-16, CORE-17 | 窗口生命周期、DOM 迁移、样式与事件 document 重绑分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo |
|
||||
| PKG-DPIP-04 | artplayer-plugin-document-pip<br>迁移自有源码和公开类型 | PKG-DPIP-03, ENG-04, ENG-06, CORE-07 | Document PiP 可选能力和真实状态/返回类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
|
||||
| PKG-DPIP-05 | artplayer-plugin-document-pip<br>验证新旧核心和组合 | PKG-DPIP-04, CORE-22 | 原生视频及两个 proxy、键盘/焦点/全屏与关闭还原 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-DPIP-05 | artplayer-plugin-document-pip<br>验证新旧核心和组合 | PKG-DPIP-04, CORE-22, PKG-CANVAS-04, PKG-MB-04 | 原生视频及两个 proxy、键盘/焦点/全屏与关闭还原 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-DPIP-06 | artplayer-plugin-document-pip<br>验证分发并同步文档 | PKG-DPIP-05, ENG-07 | document.pip.js、浏览器能力矩阵、旧接口与恢复证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
|
||||
## 5 包迁移:artplayer-plugin-danmuku
|
||||
@@ -322,7 +322,7 @@
|
||||
| PKG-CANVAS-02 | artplayer-proxy-canvas<br>建立特有行为与错误测试 | PKG-CANVAS-01, ENG-03, ENG-05 | ready/loadeddata/canplay、play/seek、回调、resize 与销毁 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
|
||||
| PKG-CANVAS-03 | artplayer-proxy-canvas<br>整理内部职责与资源 | PKG-CANVAS-02, CORE-06, CORE-11, CORE-16 | video adapter/原 canvas 方法/RAF 绘制/事件订阅分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
|
||||
| PKG-CANVAS-04 | artplayer-proxy-canvas<br>迁移自有源码和公开类型 | PKG-CANVAS-03, ENG-04, ENG-06, CORE-07 | canvas 与媒体能力的精确组合类型,保持 Result | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done |
|
||||
| PKG-CANVAS-05 | artplayer-proxy-canvas<br>验证新旧核心和组合 | PKG-CANVAS-04, CORE-22 | 真实 video/canvas 绘制、字幕和 document PiP 恢复 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-CANVAS-05 | artplayer-proxy-canvas<br>验证新旧核心和组合 | PKG-CANVAS-04, CORE-22, PKG-DPIP-04 | 真实 video/canvas 绘制、字幕和 document PiP 恢复 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-CANVAS-06 | artplayer-proxy-canvas<br>验证分发并同步文档 | PKG-CANVAS-05, ENG-07 | canvas.js、三种产物、调用兼容与资源证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
|
||||
## 5 包迁移:artplayer-proxy-mediabunny
|
||||
@@ -506,6 +506,7 @@
|
||||
- PKG-VAST-01: [记录](baselines/vast-contract.md) [记录](baselines/vast-release.json) [记录](changes/2026-09-12-PKG-VAST-01-contract.md) [记录](baselines/vast-contract-validation.json)
|
||||
- PKG-VAST-02: [记录](changes/2026-09-12-PKG-VAST-02-tests.md) [记录](baselines/vast-behavior-validation.json) [记录](baselines/vast-core.json) [记录](vast-validation.md)
|
||||
- PKG-VAST-03: [记录](changes/2026-09-12-PKG-VAST-03-lifecycle.md) [记录](baselines/vast-lifecycle-validation.json) [记录](vast-compatibility-decision.md)
|
||||
- PKG-DPIP-01: [记录](changes/2026-09-12-PKG-DPIP-01-contract.md) [记录](baselines/dpip-release.json) [记录](baselines/dpip-contract.md) [记录](baselines/dpip-contract-validation.json) [记录](dpip-validation.md)
|
||||
- PKG-CANVAS-01: [记录](changes/2026-09-12-PKG-CANVAS-01-contract.md) [记录](baselines/canvas-contract.md) [记录](baselines/canvas-release.json) [记录](canvas-validation.md) [记录](baselines/canvas-contract-validation.json)
|
||||
- PKG-CANVAS-02: [记录](changes/2026-09-12-PKG-CANVAS-02-tests.md) [记录](baselines/canvas-behavior-validation.json) [记录](canvas-validation.md)
|
||||
- PKG-CANVAS-03: [记录](changes/2026-09-12-PKG-CANVAS-03-lifecycle.md) [记录](baselines/canvas-lifecycle-validation.json) [记录](canvas-validation.md)
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# 进度与证据
|
||||
|
||||
## 最新完成:Document PiP-01 实际发布契约
|
||||
|
||||
冻结四个npm归档/21成员及7个Git工作区输入。实际1.0.0缺少三个运行时入口,
|
||||
作为分发负例和类型基线,不能冒充可执行版本。三份可运行发布与冻结工作区的正常
|
||||
窗口/DOM/控件/返回值契约已覆盖;16项专项和7项索引检查通过,完整CI1068项通过,
|
||||
另44项重复契约观察,284个生产TS文件严格检查。尚未修改Document PiP生产源码;
|
||||
02继续复现窗口竞争/销毁/错误回滚,03处理实现,05保留真实窗口与设备验收。
|
||||
当前221项:94 done、6 doing、121 todo。见[本步记录](changes/2026-09-12-PKG-DPIP-01-contract.md)
|
||||
和[验证证据](baselines/dpip-contract-validation.json)。独立本地提交,不推送/发布。
|
||||
|
||||
## 最新完成:Canvas-04 公开类型与两代导出
|
||||
|
||||
公开namespace保留可选Parameters和精确HTMLCanvasElement返回,新增显式MediaCanvas
|
||||
|
||||
@@ -159,3 +159,8 @@
|
||||
| CANVAS-TYPE-01 | resolved / 源码/产物事实 | Canvas proxy declarations change required callback across generations and omit forwarded media capabilities | PKG-CANVAS-04, PKG-CANVAS-06 |
|
||||
| CANVAS-DIST-01 | resolved / 已复现 | Canvas proxy published CommonJS namespace differs from current callable export | PKG-CANVAS-04, PKG-CANVAS-06 |
|
||||
| CANVAS-PIXEL-01 | resolved / 已复现 | Historical Canvas proxy produces transparent frames with detached native video in tested WebKit | PKG-CANVAS-03, PKG-CANVAS-05 |
|
||||
| DPIP-PACK-01 | open / 已复现 | Published Document PiP 1.0.0 tarball omits every declared runtime entry | PKG-DPIP-06 |
|
||||
| DPIP-DIST-01 | open / 已复现 | Document PiP namespace.default in 1.0.1/1.0.2 differs from callable 1.1.0 export | PKG-DPIP-04, PKG-DPIP-06 |
|
||||
| DPIP-TYPE-01 | open / 已复现 | Document PiP requires options and declares void actions and writable flags that differ from runtime | PKG-DPIP-04 |
|
||||
| DPIP-LIFE-01 | open / 源码/产物事实 | Document PiP has no separate ownership for pending window requests and delayed post-transition callbacks | PKG-DPIP-02, PKG-DPIP-03, PKG-DPIP-05 |
|
||||
| DPIP-DOM-01 | open / 源码/产物事实 | Document PiP copies global-document styles and retains original parent without transactional rollback | PKG-DPIP-02, PKG-DPIP-03, PKG-DPIP-05 |
|
||||
@@ -3433,6 +3433,91 @@
|
||||
"refactor/baselines/canvas-lifecycle-validation.json"
|
||||
],
|
||||
"resolutionRationale": "Final native pixel cases verify original 320x180 media dimensions, multiple colors, alpha255, resize and source replacement across two cores and three engines. Backing video is mounted before play at intrinsic CSS size. Diagnostic zero-count and 1px regressions are preserved; this resolves the recorded Windows Playwright defect, not all Safari/mobile device validation."
|
||||
},
|
||||
{
|
||||
"id": "DPIP-PACK-01",
|
||||
"title": "Published Document PiP 1.0.0 tarball omits every declared runtime entry",
|
||||
"confirmation": "reproduced",
|
||||
"owners": [
|
||||
"PKG-DPIP-06"
|
||||
],
|
||||
"compatibleResolution": "Keep the immutable broken archive as a negative case; verify complete candidate tarball and document the historical version boundary.",
|
||||
"closureCriteria": "Candidate archive and real runtime entries verified; missing 1.0.0 runtime is documented rather than replaced or claimed fixed in place.",
|
||||
"status": "open",
|
||||
"evidence": [
|
||||
"refactor/baselines/dpip-release.json",
|
||||
"refactor/baselines/dpip-contract.md",
|
||||
"refactor/changes/2026-09-12-PKG-DPIP-01-contract.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "DPIP-DIST-01",
|
||||
"title": "Document PiP namespace.default in 1.0.1/1.0.2 differs from callable 1.1.0 export",
|
||||
"confirmation": "reproduced",
|
||||
"owners": [
|
||||
"PKG-DPIP-04",
|
||||
"PKG-DPIP-06"
|
||||
],
|
||||
"compatibleResolution": "Support old default namespace access and new callable factory without changing runtime names or entrypoints.",
|
||||
"closureCriteria": "Actual candidate root/legacy/global/ESM and installed consumers verify both access shapes.",
|
||||
"status": "open",
|
||||
"evidence": [
|
||||
"refactor/baselines/dpip-release.json",
|
||||
"refactor/baselines/dpip-contract.md",
|
||||
"refactor/changes/2026-09-12-PKG-DPIP-01-contract.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "DPIP-TYPE-01",
|
||||
"title": "Document PiP requires options and declares void actions and writable flags that differ from runtime",
|
||||
"confirmation": "reproduced",
|
||||
"owners": [
|
||||
"PKG-DPIP-04"
|
||||
],
|
||||
"compatibleResolution": "Verify historical legal callers and extraction before providing precise async and readonly capabilities; do not reuse unrelated Ads approval.",
|
||||
"closureCriteria": "Old/current consumer matrix and runtime/type distinctions are verified and documented without silently narrowing historical consumers.",
|
||||
"status": "open",
|
||||
"evidence": [
|
||||
"refactor/baselines/dpip-release.json",
|
||||
"refactor/baselines/dpip-contract.md",
|
||||
"refactor/changes/2026-09-12-PKG-DPIP-01-contract.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "DPIP-LIFE-01",
|
||||
"title": "Document PiP has no separate ownership for pending window requests and delayed post-transition callbacks",
|
||||
"confirmation": "source-observed",
|
||||
"owners": [
|
||||
"PKG-DPIP-02",
|
||||
"PKG-DPIP-03",
|
||||
"PKG-DPIP-05"
|
||||
],
|
||||
"compatibleResolution": "Reproduce overlapping open/close/destroy and retained controls/listeners before implementing terminal state and resource ownership.",
|
||||
"closureCriteria": "Historical races reproduced; candidate late windows and delayed effects cannot revive disposed players, with native lifecycle validation.",
|
||||
"status": "open",
|
||||
"evidence": [
|
||||
"refactor/baselines/dpip-release.json",
|
||||
"refactor/baselines/dpip-contract.md",
|
||||
"refactor/changes/2026-09-12-PKG-DPIP-01-contract.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "DPIP-DOM-01",
|
||||
"title": "Document PiP copies global-document styles and retains original parent without transactional rollback",
|
||||
"confirmation": "source-observed",
|
||||
"owners": [
|
||||
"PKG-DPIP-02",
|
||||
"PKG-DPIP-03",
|
||||
"PKG-DPIP-05"
|
||||
],
|
||||
"compatibleResolution": "Reproduce adoption/style/restore errors and foreign ownerDocument cases, then implement explicit document and rollback ownership.",
|
||||
"closureCriteria": "Candidate failures restore node identity, order, document bindings and styles with native window/proxy evidence.",
|
||||
"status": "open",
|
||||
"evidence": [
|
||||
"refactor/baselines/dpip-release.json",
|
||||
"refactor/baselines/dpip-contract.md",
|
||||
"refactor/changes/2026-09-12-PKG-DPIP-01-contract.md"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -44,7 +44,7 @@ function fixture(t) {
|
||||
test('Actual contract model assigns all 264 family rows and separates exact published versions from workspace snapshots', () => {
|
||||
assert.equal(actual.policy.packages.length, 22)
|
||||
assert.equal(actual.families.length, 12)
|
||||
assert.equal(actual.policy.versions.filter(version => version.kind === 'published-baseline').length, 11)
|
||||
assert.equal(actual.policy.versions.filter(version => version.kind === 'published-baseline').length, 15)
|
||||
assert.equal(actual.policy.versions.filter(version => version.kind === 'workspace-baseline').length, 22)
|
||||
assert.equal(actual.policy.cases.length, 10)
|
||||
const markdown = renderContracts(actual)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { archiveFiles, ensureArchive, hash, readMember, refactorDir } from './releases.mjs'
|
||||
|
||||
export async function verifyDpipContract() {
|
||||
const baseline = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/dpip-release.json'), 'utf8'))
|
||||
const archives = new Map()
|
||||
for (const release of [baseline.release, ...baseline.previous]) {
|
||||
const archive = await ensureArchive(release)
|
||||
assert.deepEqual(archiveFiles(archive), Object.keys(release.files).sort())
|
||||
for (const [file, expected] of Object.entries(release.files))
|
||||
assert.equal(hash(readMember(archive, file)), expected, `${release.version}/${file}`)
|
||||
assert.deepEqual(JSON.parse(readMember(archive, 'package/package.json')), release.manifest)
|
||||
const missing = Object.fromEntries(['main', 'module', 'types', 'legacy'].filter(field => release.manifest[field] && !Object.hasOwn(release.files, `package/${release.manifest[field].replace(/^\.\//, '')}`)).map(field => [field, release.manifest[field]]))
|
||||
assert.deepEqual(missing, release.missingEntrypoints, 'Missing runtime entries must remain explicit historical defects')
|
||||
if (release.historicalCore) {
|
||||
const core = release.historicalCore
|
||||
const source = execFileSync('git', ['show', `${core.commit}:${core.file}`], { encoding: 'utf8' }).replaceAll('\r\n', '\n')
|
||||
assert.equal(hash(source), core.sha256LF)
|
||||
assert.equal(JSON.parse(source).version, core.version)
|
||||
}
|
||||
archives.set(release.version, archive)
|
||||
}
|
||||
const sources = new Map()
|
||||
for (const [file, expected] of Object.entries(baseline.source)) {
|
||||
const source = execFileSync('git', ['show', `${baseline.sourceCommit}:${file}`], { encoding: 'utf8' }).replaceAll('\r\n', '\n')
|
||||
assert.equal(hash(source), expected, `Document PiP frozen source: ${file}`)
|
||||
sources.set(file, source)
|
||||
}
|
||||
return { baseline, archives, sources }
|
||||
}
|
||||
|
||||
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
const { baseline } = await verifyDpipContract()
|
||||
const releases = [baseline.release, ...baseline.previous]
|
||||
console.log(`Document PiP verified: ${releases.length} archives, ${releases.reduce((total, release) => total + Object.keys(release.files).length, 0)} members; 1.0.0 missing runtime preserved explicitly`)
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import assert from 'node:assert/strict'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Node frozen contract runner.
|
||||
import test from 'node:test'
|
||||
import vm from 'node:vm'
|
||||
import { checkFiles } from '../../scripts/package-check.mjs'
|
||||
import { dpipEnvironment, dpipHistorical } from '../../test/helpers/dpip.js'
|
||||
import { verifyDpipContract } from './dpip-contract.mjs'
|
||||
import { archiveFiles, readMember } from './releases.mjs'
|
||||
|
||||
test('Document PiP freezes four actual archives, twenty-one members and seven workspace inputs', async () => {
|
||||
const { baseline } = await verifyDpipContract()
|
||||
const releases = [baseline.release, ...baseline.previous]
|
||||
assert.deepEqual(releases.map(release => release.version), ['1.1.0', '1.0.2', '1.0.1', '1.0.0'])
|
||||
assert.equal(releases.reduce((sum, release) => sum + Object.keys(release.files).length, 0), 21)
|
||||
assert.equal(Object.keys(baseline.source).length, 7)
|
||||
assert.deepEqual(releases.map(release => release.historicalCore.version), ['5.3.1', '5.3.0-beta.3', '5.3.0', '5.3.0'])
|
||||
})
|
||||
|
||||
test('Document PiP 1.0.0 actually lacks its declared runtime; runnable fixtures never substitute Git code for that archive', async () => {
|
||||
const { baseline, archives } = await verifyDpipContract()
|
||||
const release = baseline.previous.find(item => item.version === '1.0.0')
|
||||
assert.deepEqual(Object.keys(release.missingEntrypoints), ['main', 'module', 'legacy'])
|
||||
assert.deepEqual(archiveFiles(archives.get('1.0.0')), ['package/README.md', 'package/package.json', 'package/types/artplayer-plugin-document-pip.d.ts'])
|
||||
assert.throws(() => checkFiles(release.manifest, archiveFiles(archives.get('1.0.0'))), /main/)
|
||||
const implementations = await dpipHistorical()
|
||||
assert(!implementations.some(item => item.name === 'published-1.0.0'))
|
||||
assert.equal(implementations.length, 4)
|
||||
})
|
||||
|
||||
test('Document PiP published and frozen declarations keep required options and historical void actions despite async runtime', async () => {
|
||||
const { baseline, archives, sources } = await verifyDpipContract()
|
||||
const texts = [baseline.release, ...baseline.previous].map(release => readMember(archives.get(release.version), `package/${release.manifest.types.replace(/^\.\//, '')}`).toString())
|
||||
texts.push(sources.get('packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts'))
|
||||
for (const source of texts) {
|
||||
assert.match(source, /\(option: Option\) => \(art: Artplayer\) => Result/)
|
||||
for (const field of ['width', 'height']) assert.match(source, new RegExp(`${field}\\?: number`))
|
||||
assert.match(source, /placeholder\?: string/)
|
||||
assert.match(source, /fallbackToVideoPiP\?: boolean/)
|
||||
for (const method of ['open', 'close', 'toggle']) assert.match(source, new RegExp(`${method}: \\(\\) => void`))
|
||||
assert.match(source, /isActive: boolean/)
|
||||
assert.doesNotMatch(source, /Promise</)
|
||||
}
|
||||
})
|
||||
|
||||
test('Document PiP runnable main, legacy, globals and native ESM expose actual historical export generations', async () => {
|
||||
const { baseline, archives } = await verifyDpipContract()
|
||||
for (const release of [baseline.release, ...baseline.previous].filter(release => !release.missingEntrypoints.main)) {
|
||||
for (const field of ['main', 'legacy']) {
|
||||
const code = readMember(archives.get(release.version), `package/${release.manifest[field].replace(/^\.\//, '')}`).toString()
|
||||
const env = dpipEnvironment({ code })
|
||||
assert.equal(typeof env.factory, 'function')
|
||||
assert.equal(typeof env.exported, release.version === '1.1.0' ? 'function' : 'object')
|
||||
const global = { window: {} }
|
||||
vm.runInNewContext(code, global)
|
||||
assert.equal(typeof (global.artplayerPluginDocumentPip || global.window.artplayerPluginDocumentPip), 'function')
|
||||
}
|
||||
const source = readMember(archives.get(release.version), `package/${release.manifest.module.replace(/^\.\//, '')}`).toString()
|
||||
const module = await import(`data:text/javascript,${encodeURIComponent(source)}`)
|
||||
assert.equal(typeof module.default, 'function')
|
||||
}
|
||||
})
|
||||
|
||||
for (const implementation of await dpipHistorical()) {
|
||||
test(`Document PiP ${implementation.name}: synchronous registration, controls and unsupported fallback with live readonly flags`, async () => {
|
||||
const env = dpipEnvironment(implementation, { supported: false })
|
||||
const result = env.factory()(env.art)
|
||||
assert.deepEqual(Object.keys(result), ['name', 'isSupported', 'isActive', 'open', 'close', 'toggle'])
|
||||
assert.equal(result.name, 'artplayerPluginDocumentPip')
|
||||
assert.equal(result.isSupported, false)
|
||||
assert.equal(result.isActive, false)
|
||||
assert.equal(Reflect.set(result, 'isActive', true), false)
|
||||
const { spec, node } = env.controls.get('document-pip')
|
||||
assert.equal(spec.position, 'right')
|
||||
assert.equal(spec.index, 40)
|
||||
assert.equal(spec.tooltip, 'PIP Mode')
|
||||
assert.equal(node.content, 'pip-icon')
|
||||
assert.equal(node.listeners.get('click').size, 1)
|
||||
const pending = result.open()
|
||||
assert.equal(typeof pending.then, 'function')
|
||||
assert.equal(await pending, undefined)
|
||||
assert.equal(env.art.pip, true)
|
||||
assert.equal(env.requests.length, 0)
|
||||
assert.equal(env.warnings.length, 1)
|
||||
env.window.documentPictureInPicture = { requestWindow: () => Promise.resolve(env.createWindow()) }
|
||||
assert.equal(result.isSupported, false, 'Capability is captured during registration')
|
||||
assert.equal(await result.close(), undefined)
|
||||
assert.equal(result.toggle(), undefined)
|
||||
await env.flush()
|
||||
})
|
||||
|
||||
test(`Document PiP ${implementation.name}: normal window adoption, styles, UI events and restoration retain public ordering`, async () => {
|
||||
const env = dpipEnvironment(implementation)
|
||||
const link = env.document.createElement('link')
|
||||
Object.assign(link, { rel: 'stylesheet', href: 'https://example.invalid/player.css', media: 'screen', crossOrigin: 'anonymous', referrerPolicy: 'no-referrer' })
|
||||
env.document.head.appendChild(link)
|
||||
const result = env.factory({ width: 720, height: 405, placeholder: 'PiP active' })(env.art)
|
||||
assert.equal(await result.open(), undefined)
|
||||
const win = env.windows[0]
|
||||
assert.deepEqual({ ...env.requests[0] }, { width: 720, height: 405 })
|
||||
assert.equal(result.isActive, true)
|
||||
assert.equal(env.player.ownerDocument, win.document)
|
||||
assert.equal(env.parent.children[0].textContent, 'PiP active')
|
||||
assert.equal(env.parent.children[1], env.sibling)
|
||||
assert.equal(win.document.body.children[0].children[0], env.player)
|
||||
const copied = win.document.querySelectorAll('link[rel="stylesheet"]')[0]
|
||||
for (const name of ['href', 'media', 'crossOrigin', 'referrerPolicy']) assert.equal(copied[name], link[name])
|
||||
assert.equal(win.document.querySelectorAll('style').length, 2)
|
||||
assert(win.document.querySelector('meta[name="viewport"]'))
|
||||
assert.equal(env.controls.get('document-pip').node.tooltip, 'Exit PIP Mode')
|
||||
assert.deepEqual(env.emitted.map(event => [event.name, ...event.args]), [['document-pip', true], ['resize']])
|
||||
assert.equal(await result.close(), undefined)
|
||||
assert.equal(result.isActive, false)
|
||||
assert.equal(win.closed, true)
|
||||
assert.equal(env.player.ownerDocument, env.document)
|
||||
assert.deepEqual(env.parent.children, [env.player, env.sibling])
|
||||
assert.equal(env.player.className, 'art-video-player')
|
||||
assert.equal(env.controls.get('document-pip').node.tooltip, 'PIP Mode')
|
||||
assert.deepEqual(env.emitted.map(event => [event.name, ...event.args]), [['document-pip', true], ['resize'], ['document-pip', false], ['resize']])
|
||||
assert.deepEqual(env.sleeps, [100, 100])
|
||||
assert.deepEqual(env.rebinds.map(item => item.document), [win.document, env.document])
|
||||
assert.equal([...win.listeners.values()].reduce((sum, set) => sum + set.size, 0), 0)
|
||||
})
|
||||
|
||||
test(`Document PiP ${implementation.name}: factory option snapshot, defaults and deferred style injection remain reproducible`, async () => {
|
||||
const env = dpipEnvironment(implementation, { readyState: 'loading' })
|
||||
assert.equal(env.document.getElementById('artplayer-plugin-document-pip'), null)
|
||||
env.document.readyState = 'complete'
|
||||
env.document.dispatchEvent({ type: 'DOMContentLoaded' })
|
||||
assert.match(env.document.getElementById('artplayer-plugin-document-pip').textContent, /artplayer-document-pip/)
|
||||
assert.equal(env.document.querySelectorAll('style').length, 1)
|
||||
const option = { width: undefined, placeholder: 'saved' }
|
||||
const register = env.factory(option)
|
||||
option.width = 999
|
||||
option.placeholder = 'changed'
|
||||
const result = register(env.art)
|
||||
assert.equal(result.toggle(), undefined)
|
||||
await env.flush()
|
||||
assert.deepEqual({ ...env.requests[0] }, { width: undefined, height: 270 })
|
||||
assert.equal(env.parent.children[0].textContent, 'saved')
|
||||
await result.close()
|
||||
const normal = env.factory()(env.art)
|
||||
await normal.open()
|
||||
assert.deepEqual({ ...env.requests[1] }, { width: 480, height: 270 })
|
||||
assert.equal(env.parent.children[0].textContent, 'Playing in Document Picture-in-Picture')
|
||||
await normal.close()
|
||||
})
|
||||
}
|
||||
+13
-4
@@ -2985,11 +2985,17 @@
|
||||
"dependsOn": [
|
||||
"BASE-05"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"risk": "H",
|
||||
"deliverable": "width/height/placeholder/fallbackToVideoPiP、open/close/toggle 返回",
|
||||
"acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-12-PKG-DPIP-01-contract.md",
|
||||
"baselines/dpip-release.json",
|
||||
"baselines/dpip-contract.md",
|
||||
"baselines/dpip-contract-validation.json",
|
||||
"dpip-validation.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PKG-DPIP-02",
|
||||
@@ -3055,7 +3061,9 @@
|
||||
],
|
||||
"dependsOn": [
|
||||
"PKG-DPIP-04",
|
||||
"CORE-22"
|
||||
"CORE-22",
|
||||
"PKG-CANVAS-04",
|
||||
"PKG-MB-04"
|
||||
],
|
||||
"status": "todo",
|
||||
"risk": "H",
|
||||
@@ -3333,7 +3341,8 @@
|
||||
],
|
||||
"dependsOn": [
|
||||
"PKG-CANVAS-04",
|
||||
"CORE-22"
|
||||
"CORE-22",
|
||||
"PKG-DPIP-04"
|
||||
],
|
||||
"status": "todo",
|
||||
"risk": "H",
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import vm from 'node:vm'
|
||||
import { transform } from 'esbuild'
|
||||
import less from 'less'
|
||||
import { verifyDpipContract } from '../../refactor/scripts/dpip-contract.mjs'
|
||||
import { readMember } from '../../refactor/scripts/releases.mjs'
|
||||
|
||||
export async function dpipHistorical() {
|
||||
const contract = await verifyDpipContract()
|
||||
const css = (await less.render(contract.sources.get('packages/artplayer-plugin-document-pip/src/style.less'))).css
|
||||
const source = contract.sources.get('packages/artplayer-plugin-document-pip/src/index.js').replace('import style from \'./style.less?inline\'', `const style = ${JSON.stringify(css)}`)
|
||||
return [
|
||||
...[contract.baseline.release, ...contract.baseline.previous].filter(release => !release.missingEntrypoints.main).map(release => ({ name: `published-${release.version}`, code: readMember(contract.archives.get(release.version), `package/${release.manifest.main.replace(/^\.\//, '')}`).toString() })),
|
||||
{ name: 'frozen-workspace', code: (await transform(source, { format: 'cjs', target: 'es2020' })).code },
|
||||
]
|
||||
}
|
||||
|
||||
function eventTarget() {
|
||||
const listeners = new Map()
|
||||
return {
|
||||
listeners,
|
||||
addEventListener(name, callback) {
|
||||
if (!listeners.has(name))
|
||||
listeners.set(name, new Set())
|
||||
listeners.get(name).add(callback)
|
||||
},
|
||||
removeEventListener(name, callback) { listeners.get(name)?.delete(callback) },
|
||||
dispatchEvent(event) {
|
||||
for (const callback of [...(listeners.get(event.type) || [])]) callback(event)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function adopt(node, document) {
|
||||
node.ownerDocument = document
|
||||
for (const child of node.children) adopt(child, document)
|
||||
}
|
||||
|
||||
function createNode(tag, document) {
|
||||
return {
|
||||
...eventTarget(),
|
||||
nodeName: tag.toUpperCase(),
|
||||
ownerDocument: document,
|
||||
parentNode: null,
|
||||
children: [],
|
||||
style: {},
|
||||
className: '',
|
||||
textContent: '',
|
||||
get nextSibling() {
|
||||
return this.parentNode?.children[this.parentNode.children.indexOf(this) + 1] || null
|
||||
},
|
||||
appendChild(child) { return this.insertBefore(child, null) },
|
||||
insertBefore(child, before) {
|
||||
assert(before === null || before.parentNode === this, 'Reference node must belong to this parent')
|
||||
child.remove()
|
||||
const index = before === null ? this.children.length : this.children.indexOf(before)
|
||||
this.children.splice(index, 0, child)
|
||||
child.parentNode = this
|
||||
adopt(child, this.ownerDocument)
|
||||
return child
|
||||
},
|
||||
removeChild(child) {
|
||||
assert.equal(child.parentNode, this)
|
||||
this.children.splice(this.children.indexOf(child), 1)
|
||||
child.parentNode = null
|
||||
return child
|
||||
},
|
||||
remove() { this.parentNode?.removeChild(this) },
|
||||
}
|
||||
}
|
||||
|
||||
function createDocument(readyState = 'complete') {
|
||||
const doc = { ...eventTarget(), readyState }
|
||||
doc.createElement = tag => createNode(tag, doc)
|
||||
doc.documentElement = doc.createElement('html')
|
||||
doc.head = doc.createElement('head')
|
||||
doc.body = doc.createElement('body')
|
||||
doc.documentElement.appendChild(doc.head)
|
||||
doc.documentElement.appendChild(doc.body)
|
||||
const nodes = () => {
|
||||
const result = []
|
||||
const walk = (node) => {
|
||||
result.push(node)
|
||||
for (const child of node.children) walk(child)
|
||||
}
|
||||
walk(doc.documentElement)
|
||||
return result
|
||||
}
|
||||
doc.getElementById = id => nodes().find(node => node.id === id) || null
|
||||
doc.querySelectorAll = (selector) => {
|
||||
if (selector === 'style')
|
||||
return nodes().filter(node => node.nodeName === 'STYLE')
|
||||
if (selector === 'link[rel="stylesheet"]')
|
||||
return nodes().filter(node => node.nodeName === 'LINK' && node.rel === 'stylesheet')
|
||||
if (selector === 'meta[name="viewport"]')
|
||||
return nodes().filter(node => node.nodeName === 'META' && node.name === 'viewport')
|
||||
throw new Error(`Unimplemented controlled selector: ${selector}`)
|
||||
}
|
||||
doc.querySelector = selector => doc.querySelectorAll(selector)[0] || null
|
||||
doc.adoptNode = (node) => {
|
||||
node.remove()
|
||||
adopt(node, doc)
|
||||
return node
|
||||
}
|
||||
return doc
|
||||
}
|
||||
|
||||
export function dpipEnvironment(implementation, settings = {}) {
|
||||
const document = createDocument(settings.readyState)
|
||||
const windows = []
|
||||
const requests = []
|
||||
const sleeps = []
|
||||
const emitted = []
|
||||
const warnings = []
|
||||
const subscriptions = new Map()
|
||||
const controls = new Map()
|
||||
const proxies = []
|
||||
const rebinds = []
|
||||
const window = { ...eventTarget(), document }
|
||||
document.defaultView = window
|
||||
function createWindow() {
|
||||
const win = { ...eventTarget(), document: createDocument(), closed: false, close() {
|
||||
this.closed = true
|
||||
} }
|
||||
win.document.defaultView = win
|
||||
windows.push(win)
|
||||
return win
|
||||
}
|
||||
if (settings.supported !== false) {
|
||||
window.documentPictureInPicture = { requestWindow(option) {
|
||||
requests.push(option)
|
||||
return settings.requestWindow ? settings.requestWindow(option, createWindow) : Promise.resolve(createWindow())
|
||||
} }
|
||||
}
|
||||
const parent = document.createElement('div')
|
||||
const player = document.createElement('div')
|
||||
player.className = 'art-video-player'
|
||||
const sibling = document.createElement('span')
|
||||
document.body.appendChild(parent)
|
||||
parent.appendChild(player)
|
||||
parent.appendChild(sibling)
|
||||
const utils = {
|
||||
append(node, content) { node.content = content },
|
||||
tooltip(node, value) { node.tooltip = value },
|
||||
addClass(node, name) { node.className = `${node.className} ${name}`.trim() },
|
||||
removeClass(node, name) { node.className = node.className.split(' ').filter(value => value !== name).join(' ') },
|
||||
sleep(ms) {
|
||||
sleeps.push(ms)
|
||||
return settings.sleep ? settings.sleep(ms) : Promise.resolve()
|
||||
},
|
||||
}
|
||||
const art = {
|
||||
template: { $player: player },
|
||||
constructor: { utils },
|
||||
icons: { pip: 'pip-icon' },
|
||||
i18n: { get: name => name },
|
||||
notice: { show: '' },
|
||||
pip: false,
|
||||
isDestroy: false,
|
||||
proxy(target, name, callback) {
|
||||
target.addEventListener(name, callback)
|
||||
const dispose = () => target.removeEventListener(name, callback)
|
||||
proxies.push(dispose)
|
||||
return dispose
|
||||
},
|
||||
controls: { add(spec) {
|
||||
const node = document.createElement('button')
|
||||
controls.set(spec.name, { spec, node })
|
||||
spec.mounted?.(node)
|
||||
return node
|
||||
}, remove(name) { controls.delete(name) } },
|
||||
events: { bindGlobalEvents: (...args) => rebinds.push({ args, document: player.ownerDocument }) },
|
||||
on(name, callback) {
|
||||
if (!subscriptions.has(name))
|
||||
subscriptions.set(name, new Set())
|
||||
subscriptions.get(name).add(callback)
|
||||
return art
|
||||
},
|
||||
off(name, callback) { subscriptions.get(name)?.delete(callback) },
|
||||
emit(name, ...args) {
|
||||
emitted.push({ name, args })
|
||||
for (const callback of [...(subscriptions.get(name) || [])]) callback(...args)
|
||||
},
|
||||
destroy() {
|
||||
art.isDestroy = true
|
||||
art.emit('destroy')
|
||||
},
|
||||
}
|
||||
const context = vm.createContext({ window, document, console: { warn: (...args) => warnings.push(args) }, module: { exports: {} } })
|
||||
context.exports = context.module.exports
|
||||
const evaluate = () => vm.runInContext(implementation.code, context, { timeout: 5000 })
|
||||
evaluate()
|
||||
return {
|
||||
factory: context.module.exports.default || context.module.exports,
|
||||
exported: context.module.exports,
|
||||
document,
|
||||
window,
|
||||
art,
|
||||
parent,
|
||||
player,
|
||||
sibling,
|
||||
controls,
|
||||
windows,
|
||||
requests,
|
||||
sleeps,
|
||||
emitted,
|
||||
warnings,
|
||||
proxies,
|
||||
subscriptions,
|
||||
rebinds,
|
||||
evaluate,
|
||||
createWindow,
|
||||
async flush() {
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user