diff --git a/docs/assets/ts/artplayer-plugin-document-pip.d.ts b/docs/assets/ts/artplayer-plugin-document-pip.d.ts index df061d9f4..4fa0afdc9 100644 --- a/docs/assets/ts/artplayer-plugin-document-pip.d.ts +++ b/docs/assets/ts/artplayer-plugin-document-pip.d.ts @@ -1,22 +1,53 @@ -interface Option { - width?: number - height?: number - placeholder?: string - fallbackToVideoPiP?: boolean +// Generated from the package public declaration by yarn build:ts. Do not edit. +/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */ +declare namespace artplayerPluginDocumentPipDefinitions { + export interface Option { + /** Requested window width. @default 480 */ + width?: number + /** Requested window height. @default 270 */ + height?: number + /** Text displayed in the original player container while the window is active. */ + placeholder?: string + /** Use the core video PiP property when Document PiP is unavailable. @default true */ + fallbackToVideoPiP?: boolean + } + /** Historical assignable result; preserved for direct and extracted return types. */ + export interface Result { + name: 'artplayerPluginDocumentPip' + /** Runtime is a readonly capability snapshot; the published field stays assignable. */ + isSupported: boolean + /** Runtime is a readonly live getter; the published field stays assignable. */ + isActive: boolean + /** Runtime returns Promise; the published void action remains assignable here. */ + open: () => void + /** Runtime returns Promise; the published void action remains assignable here. */ + close: () => void + toggle: () => void + } + /** Exact view of an unmodified runtime result. */ + export interface AsyncResult extends Omit { + readonly isSupported: boolean + readonly isActive: boolean + open: () => Promise + close: () => Promise + } + /** Exact published factory signature, including compatibility with replacement functions. */ + export type Factory = (option: Option) => (art: Artplayer) => Result + /** Opt-in runtime view with omitted options, self default and precise async actions. */ + export interface RuntimeFactory { + (option?: Option): (art: Artplayer) => AsyncResult + readonly default: RuntimeFactory + } + /** Keep the published callable type; use RuntimeFactory explicitly for its broader runtime shape. */ + export function artplayerPluginDocumentPip(option: Option): (art: Artplayer) => Result } - -interface Result { - name: 'artplayerPluginDocumentPip' - isSupported: boolean - isActive: boolean - open: () => void - close: () => void - toggle: () => void +declare const artplayerPluginDocumentPip: typeof artplayerPluginDocumentPipDefinitions.artplayerPluginDocumentPip +declare namespace artplayerPluginDocumentPip { + export type Option = artplayerPluginDocumentPipDefinitions.Option + export type Result = artplayerPluginDocumentPipDefinitions.Result + export type AsyncResult = artplayerPluginDocumentPipDefinitions.AsyncResult + export type Factory = artplayerPluginDocumentPipDefinitions.Factory + export type RuntimeFactory = artplayerPluginDocumentPipDefinitions.RuntimeFactory } - -declare const artplayerPluginDocumentPip: (option: Option) => (art: Artplayer) => Result - -export default artplayerPluginDocumentPip - export = artplayerPluginDocumentPip export as namespace artplayerPluginDocumentPip; diff --git a/docs/compiled/artplayer-plugin-document-pip.js b/docs/compiled/artplayer-plugin-document-pip.js index 46b687611..7751a1940 100644 --- a/docs/compiled/artplayer-plugin-document-pip.js +++ b/docs/compiled/artplayer-plugin-document-pip.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.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";function e(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const t=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function n(t){let n=!1,o=0,i=null,r=null,c=null;const l=()=>!n&&t.alive(),s=e=>e===o&&l();function u(){o++,r?.finish(),r=null,c?.cancel(),c=null}function a(t){const n=e(t.releases.splice(0));return n.push(...e([()=>t.window.close()])),n}async function d(e){if(!s(e))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,await n.promise,c===n&&(c=null),s(e)&&t.resize()}async function p(){u();const e=o,n=i;if(i=null,!n)return;const r=a(n);if(n.announced)try{t.activate(!1)}catch(c){r.push(c)}r.length&&l()&&t.report("close",r[0]),s(e)&&await d(e)}return{get active(){return null!==i},get opening(){return null!==r},open:async function(){if(!l()||i)return;if(r)return r.promise;u();const n=o;let c,f;const m=new Promise((e,t)=>{c=e,f=t}),h={promise:m,finish:c};r=h;const y=()=>{r===h&&(r=null),c()},g=o=>{if(s(n)){const n=i;i=null,n&&(a(n),n.announced&&e([()=>t.activate(!1)]));try{t.report("open",o)}catch(r){f(r)}}},v=async o=>{if(!s(n))return void(i?.window!==o&&e([()=>o.close()]));const r={window:o,releases:[],announced:!1};i=r;try{const e=t.project(o.document);if(r.releases.push(e.destroy),e.mount(),!s(n))return void a(r);for(const[i,c]of[["resize",()=>{s(n)&&t.nativeResize()}],["pagehide",()=>{p()}],["unload",()=>{p()}]])if(r.releases.unshift(()=>o.removeEventListener(i,c)),o.addEventListener(i,c),!s(n))return void a(r);r.announced=!0,t.activate(!0),await d(n)}catch(c){g(c)}};try{const e=t.request();Promise.resolve(e).then(v,g).then(y,e=>{s(n)&&f(e),y()})}catch(w){try{g(w)}finally{y()}}return m},close:p,destroy(){n||(n=!0,p().catch(()=>{}))}}}return"undefined"!==typeof document&&function(e){const n="artplayer-plugin-document-pip",o=e.getElementById(n);if(o)return void(o.textContent=t);const i=e.createElement("style");i.id=n,i.textContent=t;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const o=e.getElementById(n);o?o.textContent=t:(e.head||e.documentElement).appendChild(i)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),function(t={}){const o={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...t};return t=>{const i=window,r="documentPictureInPicture"in i&&"function"===typeof i.documentPictureInPicture?.requestWindow;let c=t,l=t.template.$player,s=t.isDestroy;const u=t.constructor.utils,a=()=>!s&&!!c&&!c.isDestroy,d=n({alive:a,request:()=>i.documentPictureInPicture.requestWindow({width:o.width,height:o.height}),project:t=>function(t,n,o){const i=t.ownerDocument,r=t.parentNode,c=t.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const l=i.createElement("div");l.className="artplayer-document-pip-placeholder",l.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",l.textContent=o??"";const s=n.createElement("div");s.id="__art_dpip_root";const u=[];let a=!1;const d=()=>{const e=l.parentNode===r?l:c?.parentNode===r?c:null;if(t.parentNode!==r||t.nextSibling!==e)try{r.insertBefore(t,e)}catch(n){throw i.body.appendChild(t),n}},p=()=>{const t=e([d,()=>l.remove(),...u.splice(0).map(e=>()=>e.remove()),()=>s.remove()]);if(t.length)throw t[0]};return{mount(){if(!a){if(r.insertBefore(l,c?.parentNode===r?c:null),a||n.body.appendChild(s),a||function(e,t,n,o){const i=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},r=t.createElement("style");if(r.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",i(r),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",i(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),i(n)})}catch{}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,i(n)})}catch{}}(i,n,e=>u.push(e),()=>!a),!a){const e=n.adoptNode(t);a||s.appendChild(e)}a&&p()}},destroy(){a||(a=!0,p())}}}(l,t,o.placeholder),activate(e){c&&l&&(e?u.addClass(l,"artplayer-document-pip"):u.removeClass(l,"artplayer-document-pip"),a()&&(c.events.bindGlobalEvents?.(),a()&&c.emit("document-pip",e)))},resize:()=>{a()&&c.emit("resize")},nativeResize:()=>{a()&&c.resize?.()},report(e,t){a()&&(c.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});async function p(){if(a())return!r&&o.fallbackToVideoPiP?(c.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):d.open()}function f(){a()&&(d.active||d.opening?d.close():p())}let m=function(t,n,o){const i=t.constructor.utils,r=[];let c=!1;return{mount(){!c&&o()&&(r.push(()=>t.controls.remove("document-pip")),t.controls.add({name:"document-pip",position:"right",index:40,tooltip:t.i18n.get("PIP Mode"),mounted:e=>{if(c||!o())return;i.append(e,t.icons.pip);const l=()=>{o()&&n()};r.push(()=>e.removeEventListener("click",l));const s=t.proxy(e,"click",l);if(c?s():r.push(s),c||!o())return;const u=n=>{o()&&i.tooltip(e,t.i18n.get(n?"Exit PIP Mode":"PIP Mode"))};r.push(()=>t.off("document-pip",u)),t.on("document-pip",u)}}),c&&t.controls.remove("document-pip"))},destroy(){if(c)return;c=!0;const t=e(r.splice(0).reverse());if(t.length)throw t[0]}}}(t,f,a);function h(){if(s)return;s=!0;const t=c,n=m;m=null;const o=e([d.destroy,()=>n?.destroy(),()=>t?.off("destroy",h)]);c=null,l=null,o.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",o[0])}const y={name:"artplayerPluginDocumentPip",get isSupported(){return r},get isActive(){return d.active},open:p,close:d.close,toggle:f};if(s)return c=null,l=null,y;try{t.on("destroy",h),a()?m?.mount():t.off("destroy",h)}catch(g){throw h(),g}return y}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";function e(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const t=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function n(t){let n=!1,o=0,i=null,r=null,c=null;const l=()=>!n&&t.alive(),s=e=>e===o&&l();function u(){o++,r?.finish(),r=null,c?.cancel(),c=null}function a(t){const n=e(t.releases.splice(0));return n.push(...e([()=>t.window.close()])),n}async function d(e){if(!s(e))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,await n.promise,c===n&&(c=null),s(e)&&t.resize()}async function p(){u();const e=o,n=i;if(i=null,!n)return;const r=a(n);if(n.announced)try{t.activate(!1)}catch(c){r.push(c)}r.length&&l()&&t.report("close",r[0]),s(e)&&await d(e)}return{get active(){return null!==i},get opening(){return null!==r},open:async function(){if(!l()||i)return;if(r)return r.promise;u();const n=o;let c,f;const m=new Promise((e,t)=>{c=e,f=t}),h={promise:m,finish:c};r=h;const y=()=>{r===h&&(r=null),c()},g=o=>{if(s(n)){const n=i;i=null,n&&(a(n),n.announced&&e([()=>t.activate(!1)]));try{t.report("open",o)}catch(r){f(r)}}},v=async o=>{if(!s(n))return void(i?.window!==o&&e([()=>o.close()]));const r={window:o,releases:[],announced:!1};i=r;try{const e=t.project(o.document);if(r.releases.push(e.destroy),e.mount(),!s(n))return void a(r);for(const[i,c]of[["resize",()=>{s(n)&&t.nativeResize()}],["pagehide",()=>{p()}],["unload",()=>{p()}]])if(r.releases.unshift(()=>o.removeEventListener(i,c)),o.addEventListener(i,c),!s(n))return void a(r);r.announced=!0,t.activate(!0),await d(n)}catch(c){g(c)}};try{const e=t.request();Promise.resolve(e).then(v,g).then(y,e=>{s(n)&&f(e),y()})}catch(w){try{g(w)}finally{y()}}return m},close:p,destroy(){n||(n=!0,p().catch(()=>{}))}}}function o(t={}){const o={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...t};return t=>{const i=window,r="documentPictureInPicture"in i&&"function"===typeof i.documentPictureInPicture?.requestWindow;let c=t,l=t.template.$player,s=t.isDestroy;const u=t.constructor.utils,a=()=>!s&&!!c&&!c.isDestroy,d=n({alive:a,request:()=>i.documentPictureInPicture.requestWindow({width:o.width,height:o.height}),project:t=>function(t,n,o){const i=t.ownerDocument,r=t.parentNode,c=t.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const l=i.createElement("div");l.className="artplayer-document-pip-placeholder",l.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",l.textContent=o??"";const s=n.createElement("div");s.id="__art_dpip_root";const u=[];let a=!1;const d=()=>{const e=l.parentNode===r?l:c?.parentNode===r?c:null;if(t.parentNode!==r||t.nextSibling!==e)try{r.insertBefore(t,e)}catch(n){throw i.body.appendChild(t),n}},p=()=>{const t=e([d,()=>l.remove(),...u.splice(0).map(e=>()=>e.remove()),()=>s.remove()]);if(t.length)throw t[0]};return{mount(){if(!a){if(r.insertBefore(l,c?.parentNode===r?c:null),a||n.body.appendChild(s),a||function(e,t,n,o){const i=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},r=t.createElement("style");if(r.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",i(r),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",i(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),i(n)})}catch{}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,i(n)})}catch{}}(i,n,e=>u.push(e),()=>!a),!a){const e=n.adoptNode(t);a||s.appendChild(e)}a&&p()}},destroy(){a||(a=!0,p())}}}(l,t,o.placeholder),activate(e){c&&l&&(e?u.addClass(l,"artplayer-document-pip"):u.removeClass(l,"artplayer-document-pip"),a()&&(c.events.bindGlobalEvents?.(),a()&&c.emit("document-pip",e)))},resize:()=>{a()&&c.emit("resize")},nativeResize:()=>{a()&&c.resize?.()},report(e,t){a()&&(c.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});async function p(){if(a())return!r&&o.fallbackToVideoPiP?(c.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):d.open()}function f(){a()&&(d.active||d.opening?d.close():p())}let m=function(t,n,o){const i=t.constructor.utils,r=[];let c=!1;return{mount(){!c&&o()&&(r.push(()=>t.controls.remove("document-pip")),t.controls.add({name:"document-pip",position:"right",index:40,tooltip:t.i18n.get("PIP Mode"),mounted:e=>{if(c||!o())return;i.append(e,t.icons.pip);const l=()=>{o()&&n()};r.push(()=>e.removeEventListener("click",l));const s=t.proxy(e,"click",l);if(c?s():r.push(s),c||!o())return;const u=n=>{o()&&i.tooltip(e,t.i18n.get(n?"Exit PIP Mode":"PIP Mode"))};r.push(()=>t.off("document-pip",u)),t.on("document-pip",u)}}),c&&t.controls.remove("document-pip"))},destroy(){if(c)return;c=!0;const t=e(r.splice(0).reverse());if(t.length)throw t[0]}}}(t,f,a);function h(){if(s)return;s=!0;const t=c,n=m;m=null;const o=e([d.destroy,()=>n?.destroy(),()=>t?.off("destroy",h)]);c=null,l=null,o.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",o[0])}const y={name:"artplayerPluginDocumentPip",get isSupported(){return r},get isActive(){return d.active},open:p,close:d.close,toggle:f};if(s)return c=null,l=null,y;try{t.on("destroy",h),a()?m?.mount():t.off("destroy",h)}catch(g){throw h(),g}return y}}const i=Object.assign(o,{default:o});return"undefined"!==typeof document&&function(e){const n="artplayer-plugin-document-pip",o=e.getElementById(n);if(o)return void(o.textContent=t);const i=e.createElement("style");i.id=n,i.textContent=t;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const o=e.getElementById(n);o?o.textContent=t:(e.head||e.documentElement).appendChild(i)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),i}); diff --git a/docs/compiled/artplayer-plugin-document-pip.legacy.js b/docs/compiled/artplayer-plugin-document-pip.legacy.js index 177afc32b..be093411d 100644 --- a/docs/compiled/artplayer-plugin-document-pip.legacy.js +++ b/docs/compiled/artplayer-plugin-document-pip.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.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,t,n)=>new Promise((o,r)=>{var i=e=>{try{c(n.next(e))}catch(t){r(t)}},l=e=>{try{c(n.throw(e))}catch(t){r(t)}},c=e=>e.done?o(e.value):Promise.resolve(e.value).then(i,l);c((n=n.apply(e,t)).next())});function l(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const c=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function u(e){let t=!1,n=0,o=null,r=null,c=null;const u=()=>!t&&e.alive(),s=e=>e===n&&u();function a(){n++,null==r||r.finish(),r=null,null==c||c.cancel(),c=null}function d(e){const t=l(e.releases.splice(0));return t.push(...l([()=>e.window.close()])),t}function p(t){return i(this,null,function*(){if(!s(t))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,yield n.promise,c===n&&(c=null),s(t)&&e.resize()})}function f(){return i(this,null,function*(){a();const t=n,r=o;if(o=null,!r)return;const i=d(r);if(r.announced)try{e.activate(!1)}catch(l){i.push(l)}i.length&&u()&&e.report("close",i[0]),s(t)&&(yield p(t))})}return{get active(){return null!==o},get opening(){return null!==r},open:function(){return i(this,null,function*(){if(!u()||o)return;if(r)return r.promise;a();const t=n;let c,m;const h=new Promise((e,t)=>{c=e,m=t}),y={promise:h,finish:c};r=y;const v=()=>{r===y&&(r=null),c()},g=n=>{if(s(t)){const t=o;o=null,t&&(d(t),t.announced&&l([()=>e.activate(!1)]));try{e.report("open",n)}catch(r){m(r)}}},P=n=>i(null,null,function*(){if(!s(t))return void((null==o?void 0:o.window)!==n&&l([()=>n.close()]));const r={window:n,releases:[],announced:!1};o=r;try{const o=e.project(n.document);if(r.releases.push(o.destroy),o.mount(),!s(t))return void d(r);for(const[i,l]of[["resize",()=>{s(t)&&e.nativeResize()}],["pagehide",()=>{f()}],["unload",()=>{f()}]])if(r.releases.unshift(()=>n.removeEventListener(i,l)),n.addEventListener(i,l),!s(t))return void d(r);r.announced=!0,e.activate(!0),yield p(t)}catch(i){g(i)}});try{const n=e.request();Promise.resolve(n).then(P,g).then(v,e=>{s(t)&&m(e),v()})}catch(w){try{g(w)}finally{v()}}return h})},close:f,destroy(){t||(t=!0,f().catch(()=>{}))}}}return"undefined"!==typeof document&&function(e){const t="artplayer-plugin-document-pip",n=e.getElementById(t);if(n)return void(n.textContent=c);const o=e.createElement("style");o.id=t,o.textContent=c;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const n=e.getElementById(t);n?n.textContent=c:(e.head||e.documentElement).appendChild(o)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),function(e={}){const c=((e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n=window,o="documentPictureInPicture"in n&&"function"===typeof(null==(t=n.documentPictureInPicture)?void 0:t.requestWindow);let r=e,s=e.template.$player,a=e.isDestroy;const d=e.constructor.utils,p=()=>!a&&!!r&&!r.isDestroy,f=u({alive:p,request:()=>n.documentPictureInPicture.requestWindow({width:c.width,height:c.height}),project:e=>function(e,t,n){const o=e.ownerDocument,r=e.parentNode,i=e.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const c=o.createElement("div");c.className="artplayer-document-pip-placeholder",c.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",c.textContent=null!=n?n:"";const u=t.createElement("div");u.id="__art_dpip_root";const s=[];let a=!1;const d=()=>{const t=c.parentNode===r?c:(null==i?void 0:i.parentNode)===r?i:null;if(e.parentNode!==r||e.nextSibling!==t)try{r.insertBefore(e,t)}catch(n){throw o.body.appendChild(e),n}},p=()=>{const e=l([d,()=>c.remove(),...s.splice(0).map(e=>()=>e.remove()),()=>u.remove()]);if(e.length)throw e[0]};return{mount(){if(!a){if(r.insertBefore(c,(null==i?void 0:i.parentNode)===r?i:null),a||t.body.appendChild(u),a||function(e,t,n,o){const r=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},i=t.createElement("style");if(i.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",r(i),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",r(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),r(n)})}catch(l){}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,r(n)})}catch(l){}}(o,t,e=>s.push(e),()=>!a),!a){const n=t.adoptNode(e);a||u.appendChild(n)}a&&p()}},destroy(){a||(a=!0,p())}}}(s,e,c.placeholder),activate(e){var t,n;r&&s&&(e?d.addClass(s,"artplayer-document-pip"):d.removeClass(s,"artplayer-document-pip"),p()&&(null==(n=(t=r.events).bindGlobalEvents)||n.call(t),p()&&r.emit("document-pip",e)))},resize:()=>{p()&&r.emit("resize")},nativeResize:()=>{var e;p()&&(null==(e=r.resize)||e.call(r))},report(e,t){p()&&(r.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});function m(){return i(this,null,function*(){if(p())return!o&&c.fallbackToVideoPiP?(r.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):f.open()})}function h(){p()&&(f.active||f.opening?f.close():m())}let y=function(e,t,n){const o=e.constructor.utils,r=[];let i=!1;return{mount(){!i&&n()&&(r.push(()=>e.controls.remove("document-pip")),e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:l=>{if(i||!n())return;o.append(l,e.icons.pip);const c=()=>{n()&&t()};r.push(()=>l.removeEventListener("click",c));const u=e.proxy(l,"click",c);if(i?u():r.push(u),i||!n())return;const s=t=>{n()&&o.tooltip(l,e.i18n.get(t?"Exit PIP Mode":"PIP Mode"))};r.push(()=>e.off("document-pip",s)),e.on("document-pip",s)}}),i&&e.controls.remove("document-pip"))},destroy(){if(i)return;i=!0;const e=l(r.splice(0).reverse());if(e.length)throw e[0]}}}(e,h,p);function v(){if(a)return;a=!0;const e=r,t=y;y=null;const n=l([f.destroy,()=>null==t?void 0:t.destroy(),()=>null==e?void 0:e.off("destroy",v)]);r=null,s=null,n.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",n[0])}const g={name:"artplayerPluginDocumentPip",get isSupported(){return o},get isActive(){return f.active},open:m,close:f.close,toggle:h};if(a)return r=null,s=null,g;try{e.on("destroy",v),p()?null==y||y.mount():e.off("destroy",v)}catch(P){throw v(),P}return g}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,t,n)=>new Promise((o,r)=>{var i=e=>{try{c(n.next(e))}catch(t){r(t)}},l=e=>{try{c(n.throw(e))}catch(t){r(t)}},c=e=>e.done?o(e.value):Promise.resolve(e.value).then(i,l);c((n=n.apply(e,t)).next())});function l(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const c=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function u(e){let t=!1,n=0,o=null,r=null,c=null;const u=()=>!t&&e.alive(),s=e=>e===n&&u();function a(){n++,null==r||r.finish(),r=null,null==c||c.cancel(),c=null}function d(e){const t=l(e.releases.splice(0));return t.push(...l([()=>e.window.close()])),t}function p(t){return i(this,null,function*(){if(!s(t))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,yield n.promise,c===n&&(c=null),s(t)&&e.resize()})}function f(){return i(this,null,function*(){a();const t=n,r=o;if(o=null,!r)return;const i=d(r);if(r.announced)try{e.activate(!1)}catch(l){i.push(l)}i.length&&u()&&e.report("close",i[0]),s(t)&&(yield p(t))})}return{get active(){return null!==o},get opening(){return null!==r},open:function(){return i(this,null,function*(){if(!u()||o)return;if(r)return r.promise;a();const t=n;let c,m;const h=new Promise((e,t)=>{c=e,m=t}),y={promise:h,finish:c};r=y;const v=()=>{r===y&&(r=null),c()},g=n=>{if(s(t)){const t=o;o=null,t&&(d(t),t.announced&&l([()=>e.activate(!1)]));try{e.report("open",n)}catch(r){m(r)}}},P=n=>i(null,null,function*(){if(!s(t))return void((null==o?void 0:o.window)!==n&&l([()=>n.close()]));const r={window:n,releases:[],announced:!1};o=r;try{const o=e.project(n.document);if(r.releases.push(o.destroy),o.mount(),!s(t))return void d(r);for(const[i,l]of[["resize",()=>{s(t)&&e.nativeResize()}],["pagehide",()=>{f()}],["unload",()=>{f()}]])if(r.releases.unshift(()=>n.removeEventListener(i,l)),n.addEventListener(i,l),!s(t))return void d(r);r.announced=!0,e.activate(!0),yield p(t)}catch(i){g(i)}});try{const n=e.request();Promise.resolve(n).then(P,g).then(v,e=>{s(t)&&m(e),v()})}catch(w){try{g(w)}finally{v()}}return h})},close:f,destroy(){t||(t=!0,f().catch(()=>{}))}}}function s(e={}){const c=((e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n=window,o="documentPictureInPicture"in n&&"function"===typeof(null==(t=n.documentPictureInPicture)?void 0:t.requestWindow);let r=e,s=e.template.$player,a=e.isDestroy;const d=e.constructor.utils,p=()=>!a&&!!r&&!r.isDestroy,f=u({alive:p,request:()=>n.documentPictureInPicture.requestWindow({width:c.width,height:c.height}),project:e=>function(e,t,n){const o=e.ownerDocument,r=e.parentNode,i=e.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const c=o.createElement("div");c.className="artplayer-document-pip-placeholder",c.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",c.textContent=null!=n?n:"";const u=t.createElement("div");u.id="__art_dpip_root";const s=[];let a=!1;const d=()=>{const t=c.parentNode===r?c:(null==i?void 0:i.parentNode)===r?i:null;if(e.parentNode!==r||e.nextSibling!==t)try{r.insertBefore(e,t)}catch(n){throw o.body.appendChild(e),n}},p=()=>{const e=l([d,()=>c.remove(),...s.splice(0).map(e=>()=>e.remove()),()=>u.remove()]);if(e.length)throw e[0]};return{mount(){if(!a){if(r.insertBefore(c,(null==i?void 0:i.parentNode)===r?i:null),a||t.body.appendChild(u),a||function(e,t,n,o){const r=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},i=t.createElement("style");if(i.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",r(i),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",r(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),r(n)})}catch(l){}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,r(n)})}catch(l){}}(o,t,e=>s.push(e),()=>!a),!a){const n=t.adoptNode(e);a||u.appendChild(n)}a&&p()}},destroy(){a||(a=!0,p())}}}(s,e,c.placeholder),activate(e){var t,n;r&&s&&(e?d.addClass(s,"artplayer-document-pip"):d.removeClass(s,"artplayer-document-pip"),p()&&(null==(n=(t=r.events).bindGlobalEvents)||n.call(t),p()&&r.emit("document-pip",e)))},resize:()=>{p()&&r.emit("resize")},nativeResize:()=>{var e;p()&&(null==(e=r.resize)||e.call(r))},report(e,t){p()&&(r.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});function m(){return i(this,null,function*(){if(p())return!o&&c.fallbackToVideoPiP?(r.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):f.open()})}function h(){p()&&(f.active||f.opening?f.close():m())}let y=function(e,t,n){const o=e.constructor.utils,r=[];let i=!1;return{mount(){!i&&n()&&(r.push(()=>e.controls.remove("document-pip")),e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:l=>{if(i||!n())return;o.append(l,e.icons.pip);const c=()=>{n()&&t()};r.push(()=>l.removeEventListener("click",c));const u=e.proxy(l,"click",c);if(i?u():r.push(u),i||!n())return;const s=t=>{n()&&o.tooltip(l,e.i18n.get(t?"Exit PIP Mode":"PIP Mode"))};r.push(()=>e.off("document-pip",s)),e.on("document-pip",s)}}),i&&e.controls.remove("document-pip"))},destroy(){if(i)return;i=!0;const e=l(r.splice(0).reverse());if(e.length)throw e[0]}}}(e,h,p);function v(){if(a)return;a=!0;const e=r,t=y;y=null;const n=l([f.destroy,()=>null==t?void 0:t.destroy(),()=>null==e?void 0:e.off("destroy",v)]);r=null,s=null,n.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",n[0])}const g={name:"artplayerPluginDocumentPip",get isSupported(){return o},get isActive(){return f.active},open:m,close:f.close,toggle:h};if(a)return r=null,s=null,g;try{e.on("destroy",v),p()?null==y||y.mount():e.off("destroy",v)}catch(P){throw v(),P}return g}}const a=Object.assign(s,{default:s});return"undefined"!==typeof document&&function(e){const t="artplayer-plugin-document-pip",n=e.getElementById(t);if(n)return void(n.textContent=c);const o=e.createElement("style");o.id=t,o.textContent=c;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const n=e.getElementById(t);n?n.textContent=c:(e.head||e.documentElement).appendChild(o)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),a}); diff --git a/docs/compiled/artplayer-plugin-document-pip.mjs b/docs/compiled/artplayer-plugin-document-pip.mjs index 88245fb0d..e6eb109cc 100644 --- a/docs/compiled/artplayer-plugin-document-pip.mjs +++ b/docs/compiled/artplayer-plugin-document-pip.mjs @@ -473,8 +473,9 @@ function artplayerPluginDocumentPip(userOptions = {}) { return result; }; } +const index = Object.assign(artplayerPluginDocumentPip, { default: artplayerPluginDocumentPip }); if (typeof document !== "undefined") installStyle(document); export { - artplayerPluginDocumentPip as default + index as default }; diff --git a/package.json b/package.json index 11d57bb93..a104b118e 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,8 @@ "test:ambilight-types-package": "node refactor/scripts/ambilight-package-types.mjs", "test:canvas": "node --test test/canvas.test.js test/canvas-lifecycle.test.js", "test:canvas-types-package": "node refactor/scripts/canvas-package-types.mjs", - "test:dpip": "node --test test/dpip.test.js test/dpip-lifecycle.test.js" + "test:dpip": "node --test test/dpip.test.js test/dpip-lifecycle.test.js", + "test:dpip-types-package": "node refactor/scripts/dpip-package-types.mjs" }, "browserslist": "last 1 Chrome version", "devDependencies": { diff --git a/packages/artplayer-plugin-document-pip/ARCHITECTURE.md b/packages/artplayer-plugin-document-pip/ARCHITECTURE.md index 99780764a..d3219cca8 100644 --- a/packages/artplayer-plugin-document-pip/ARCHITECTURE.md +++ b/packages/artplayer-plugin-document-pip/ARCHITECTURE.md @@ -3,8 +3,14 @@ The public factory still returns a synchronous plugin initializer. Its result has `name`, readonly runtime getters `isSupported`/`isActive`, async `open`/`close` returning `Promise`, and synchronous `toggle` returning `undefined`. -The published declarations currently describe void actions and writable flags; -public declaration compatibility is tracked separately in PKG-DPIP-04. +The public `Result` preserves published void actions and writable flags for legacy +assignments. `AsyncResult` is an opt-in precise view for an unmodified runtime +result, and the implementation is checked against it. The default factory keeps +its exact published required-argument signature, including plain replacement +function assignments. RuntimeFactory explicitly describes omitted options and +self `.default` access. `.d.mts` and `.d.cts` wrappers map ESM/CJS consumers; old resolvers +use the base declaration and legacy typesVersions path. A self `.default` alias +supports the two historical runtime export shapes without adding named exports. | File | Responsibility | | --- | --- | @@ -68,5 +74,7 @@ file for browser verification and never silently falls back to source. The iframe matrix uses real DOM with controlled window APIs. It does not prove native Document PiP activation, window focus/keyboard, continuous playback or device support. Native video/Canvas/Mediabunny combinations and the observed -WebKit dimension reports remain PKG-DPIP-05. Full archive/demo/type acceptance is -PKG-DPIP-04/06. See the repository `refactor/dpip-validation.md` for exact evidence. +WebKit dimension reports remain PKG-DPIP-05. Full archive/demo acceptance is +PKG-DPIP-06. Installed type consumers are verified by `yarn test:dpip-types-package`; +historical missing runtime/type entry errors are exact negative cases, not waived +candidate failures. See the repository `refactor/dpip-validation.md` for evidence. diff --git a/packages/artplayer-plugin-document-pip/README.md b/packages/artplayer-plugin-document-pip/README.md index d51f39192..512909800 100644 --- a/packages/artplayer-plugin-document-pip/README.md +++ b/packages/artplayer-plugin-document-pip/README.md @@ -6,6 +6,59 @@ Document PIP plugin for ArtPlayer [https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-document-pip/index.js&example=document.pip) +## TypeScript and module formats + +```ts +import Artplayer from 'artplayer' +import type { AsyncResult } from 'artplayer-plugin-document-pip' +import documentPip from 'artplayer-plugin-document-pip' + +const art = new Artplayer({ + container: '#player', + url: 'video.mp4', + plugins: [documentPip({ width: 480, height: 270 })], +}) + +// Use this view for an unmodified plugin result when precise Promise types are needed. +const pip = art.plugins.artplayerPluginDocumentPip as AsyncResult +await pip.open() +await pip.close() +``` + +At runtime, options may be omitted. Width and height default to 480 and 270, and +`fallbackToVideoPiP` defaults to true. `placeholder` sets the text left in the +original player container while its document window is active. + +The default `Result` retains the published writable boolean fields and void +actions so old assignments and inferred initializer types still compile. +At runtime, `isSupported` and `isActive` are readonly getters, `open` and `close` +return `Promise`, and `toggle` returns `undefined`. The opt-in `AsyncResult` +describes those runtime values; it should not be applied to a mock or a result +whose methods have been replaced. It does not change any runtime behavior. + +The default factory declaration keeps the exact published required-argument +signature, including assignment of an old replacement function to `typeof +documentPip`. Automatically adding an optional overload or a required `.default` +property would break such assignments. `Option`, `Result`, `AsyncResult`, `Factory` +and `RuntimeFactory` are available as named types. Use the explicit runtime view +to type omitted options, self `.default` access and precise async results: + +```ts +import type { RuntimeFactory } from 'artplayer-plugin-document-pip' +const runtimeFactory = documentPip as RuntimeFactory +runtimeFactory() // precise initializer for the unmodified runtime factory +``` + +ESM uses the default import. CommonJS supports both `require(package)(options)` +and the historical `require(package).default(options)` shape; `.default` is the +same factory. The `/legacy` entry and generated browser editor declarations have +matching types. These syntax targets do not add native Document PiP support to +browsers that lack the API. + +The historical TypeScript `import plugin = require(package)` module view retains +`plugin.default(options)`. Direct CommonJS calls are available at runtime; use +`RuntimeFactory` for an explicitly typed direct-call view. + ## Maintenance Source is split into strict TypeScript modules for window ownership, DOM migration, diff --git a/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.js b/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.js index 46b687611..7751a1940 100644 --- a/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.js +++ b/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.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.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";function e(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const t=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function n(t){let n=!1,o=0,i=null,r=null,c=null;const l=()=>!n&&t.alive(),s=e=>e===o&&l();function u(){o++,r?.finish(),r=null,c?.cancel(),c=null}function a(t){const n=e(t.releases.splice(0));return n.push(...e([()=>t.window.close()])),n}async function d(e){if(!s(e))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,await n.promise,c===n&&(c=null),s(e)&&t.resize()}async function p(){u();const e=o,n=i;if(i=null,!n)return;const r=a(n);if(n.announced)try{t.activate(!1)}catch(c){r.push(c)}r.length&&l()&&t.report("close",r[0]),s(e)&&await d(e)}return{get active(){return null!==i},get opening(){return null!==r},open:async function(){if(!l()||i)return;if(r)return r.promise;u();const n=o;let c,f;const m=new Promise((e,t)=>{c=e,f=t}),h={promise:m,finish:c};r=h;const y=()=>{r===h&&(r=null),c()},g=o=>{if(s(n)){const n=i;i=null,n&&(a(n),n.announced&&e([()=>t.activate(!1)]));try{t.report("open",o)}catch(r){f(r)}}},v=async o=>{if(!s(n))return void(i?.window!==o&&e([()=>o.close()]));const r={window:o,releases:[],announced:!1};i=r;try{const e=t.project(o.document);if(r.releases.push(e.destroy),e.mount(),!s(n))return void a(r);for(const[i,c]of[["resize",()=>{s(n)&&t.nativeResize()}],["pagehide",()=>{p()}],["unload",()=>{p()}]])if(r.releases.unshift(()=>o.removeEventListener(i,c)),o.addEventListener(i,c),!s(n))return void a(r);r.announced=!0,t.activate(!0),await d(n)}catch(c){g(c)}};try{const e=t.request();Promise.resolve(e).then(v,g).then(y,e=>{s(n)&&f(e),y()})}catch(w){try{g(w)}finally{y()}}return m},close:p,destroy(){n||(n=!0,p().catch(()=>{}))}}}return"undefined"!==typeof document&&function(e){const n="artplayer-plugin-document-pip",o=e.getElementById(n);if(o)return void(o.textContent=t);const i=e.createElement("style");i.id=n,i.textContent=t;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const o=e.getElementById(n);o?o.textContent=t:(e.head||e.documentElement).appendChild(i)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),function(t={}){const o={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...t};return t=>{const i=window,r="documentPictureInPicture"in i&&"function"===typeof i.documentPictureInPicture?.requestWindow;let c=t,l=t.template.$player,s=t.isDestroy;const u=t.constructor.utils,a=()=>!s&&!!c&&!c.isDestroy,d=n({alive:a,request:()=>i.documentPictureInPicture.requestWindow({width:o.width,height:o.height}),project:t=>function(t,n,o){const i=t.ownerDocument,r=t.parentNode,c=t.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const l=i.createElement("div");l.className="artplayer-document-pip-placeholder",l.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",l.textContent=o??"";const s=n.createElement("div");s.id="__art_dpip_root";const u=[];let a=!1;const d=()=>{const e=l.parentNode===r?l:c?.parentNode===r?c:null;if(t.parentNode!==r||t.nextSibling!==e)try{r.insertBefore(t,e)}catch(n){throw i.body.appendChild(t),n}},p=()=>{const t=e([d,()=>l.remove(),...u.splice(0).map(e=>()=>e.remove()),()=>s.remove()]);if(t.length)throw t[0]};return{mount(){if(!a){if(r.insertBefore(l,c?.parentNode===r?c:null),a||n.body.appendChild(s),a||function(e,t,n,o){const i=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},r=t.createElement("style");if(r.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",i(r),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",i(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),i(n)})}catch{}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,i(n)})}catch{}}(i,n,e=>u.push(e),()=>!a),!a){const e=n.adoptNode(t);a||s.appendChild(e)}a&&p()}},destroy(){a||(a=!0,p())}}}(l,t,o.placeholder),activate(e){c&&l&&(e?u.addClass(l,"artplayer-document-pip"):u.removeClass(l,"artplayer-document-pip"),a()&&(c.events.bindGlobalEvents?.(),a()&&c.emit("document-pip",e)))},resize:()=>{a()&&c.emit("resize")},nativeResize:()=>{a()&&c.resize?.()},report(e,t){a()&&(c.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});async function p(){if(a())return!r&&o.fallbackToVideoPiP?(c.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):d.open()}function f(){a()&&(d.active||d.opening?d.close():p())}let m=function(t,n,o){const i=t.constructor.utils,r=[];let c=!1;return{mount(){!c&&o()&&(r.push(()=>t.controls.remove("document-pip")),t.controls.add({name:"document-pip",position:"right",index:40,tooltip:t.i18n.get("PIP Mode"),mounted:e=>{if(c||!o())return;i.append(e,t.icons.pip);const l=()=>{o()&&n()};r.push(()=>e.removeEventListener("click",l));const s=t.proxy(e,"click",l);if(c?s():r.push(s),c||!o())return;const u=n=>{o()&&i.tooltip(e,t.i18n.get(n?"Exit PIP Mode":"PIP Mode"))};r.push(()=>t.off("document-pip",u)),t.on("document-pip",u)}}),c&&t.controls.remove("document-pip"))},destroy(){if(c)return;c=!0;const t=e(r.splice(0).reverse());if(t.length)throw t[0]}}}(t,f,a);function h(){if(s)return;s=!0;const t=c,n=m;m=null;const o=e([d.destroy,()=>n?.destroy(),()=>t?.off("destroy",h)]);c=null,l=null,o.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",o[0])}const y={name:"artplayerPluginDocumentPip",get isSupported(){return r},get isActive(){return d.active},open:p,close:d.close,toggle:f};if(s)return c=null,l=null,y;try{t.on("destroy",h),a()?m?.mount():t.off("destroy",h)}catch(g){throw h(),g}return y}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";function e(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const t=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function n(t){let n=!1,o=0,i=null,r=null,c=null;const l=()=>!n&&t.alive(),s=e=>e===o&&l();function u(){o++,r?.finish(),r=null,c?.cancel(),c=null}function a(t){const n=e(t.releases.splice(0));return n.push(...e([()=>t.window.close()])),n}async function d(e){if(!s(e))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,await n.promise,c===n&&(c=null),s(e)&&t.resize()}async function p(){u();const e=o,n=i;if(i=null,!n)return;const r=a(n);if(n.announced)try{t.activate(!1)}catch(c){r.push(c)}r.length&&l()&&t.report("close",r[0]),s(e)&&await d(e)}return{get active(){return null!==i},get opening(){return null!==r},open:async function(){if(!l()||i)return;if(r)return r.promise;u();const n=o;let c,f;const m=new Promise((e,t)=>{c=e,f=t}),h={promise:m,finish:c};r=h;const y=()=>{r===h&&(r=null),c()},g=o=>{if(s(n)){const n=i;i=null,n&&(a(n),n.announced&&e([()=>t.activate(!1)]));try{t.report("open",o)}catch(r){f(r)}}},v=async o=>{if(!s(n))return void(i?.window!==o&&e([()=>o.close()]));const r={window:o,releases:[],announced:!1};i=r;try{const e=t.project(o.document);if(r.releases.push(e.destroy),e.mount(),!s(n))return void a(r);for(const[i,c]of[["resize",()=>{s(n)&&t.nativeResize()}],["pagehide",()=>{p()}],["unload",()=>{p()}]])if(r.releases.unshift(()=>o.removeEventListener(i,c)),o.addEventListener(i,c),!s(n))return void a(r);r.announced=!0,t.activate(!0),await d(n)}catch(c){g(c)}};try{const e=t.request();Promise.resolve(e).then(v,g).then(y,e=>{s(n)&&f(e),y()})}catch(w){try{g(w)}finally{y()}}return m},close:p,destroy(){n||(n=!0,p().catch(()=>{}))}}}function o(t={}){const o={width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture",...t};return t=>{const i=window,r="documentPictureInPicture"in i&&"function"===typeof i.documentPictureInPicture?.requestWindow;let c=t,l=t.template.$player,s=t.isDestroy;const u=t.constructor.utils,a=()=>!s&&!!c&&!c.isDestroy,d=n({alive:a,request:()=>i.documentPictureInPicture.requestWindow({width:o.width,height:o.height}),project:t=>function(t,n,o){const i=t.ownerDocument,r=t.parentNode,c=t.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const l=i.createElement("div");l.className="artplayer-document-pip-placeholder",l.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",l.textContent=o??"";const s=n.createElement("div");s.id="__art_dpip_root";const u=[];let a=!1;const d=()=>{const e=l.parentNode===r?l:c?.parentNode===r?c:null;if(t.parentNode!==r||t.nextSibling!==e)try{r.insertBefore(t,e)}catch(n){throw i.body.appendChild(t),n}},p=()=>{const t=e([d,()=>l.remove(),...u.splice(0).map(e=>()=>e.remove()),()=>s.remove()]);if(t.length)throw t[0]};return{mount(){if(!a){if(r.insertBefore(l,c?.parentNode===r?c:null),a||n.body.appendChild(s),a||function(e,t,n,o){const i=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},r=t.createElement("style");if(r.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",i(r),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",i(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),i(n)})}catch{}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,i(n)})}catch{}}(i,n,e=>u.push(e),()=>!a),!a){const e=n.adoptNode(t);a||s.appendChild(e)}a&&p()}},destroy(){a||(a=!0,p())}}}(l,t,o.placeholder),activate(e){c&&l&&(e?u.addClass(l,"artplayer-document-pip"):u.removeClass(l,"artplayer-document-pip"),a()&&(c.events.bindGlobalEvents?.(),a()&&c.emit("document-pip",e)))},resize:()=>{a()&&c.emit("resize")},nativeResize:()=>{a()&&c.resize?.()},report(e,t){a()&&(c.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});async function p(){if(a())return!r&&o.fallbackToVideoPiP?(c.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):d.open()}function f(){a()&&(d.active||d.opening?d.close():p())}let m=function(t,n,o){const i=t.constructor.utils,r=[];let c=!1;return{mount(){!c&&o()&&(r.push(()=>t.controls.remove("document-pip")),t.controls.add({name:"document-pip",position:"right",index:40,tooltip:t.i18n.get("PIP Mode"),mounted:e=>{if(c||!o())return;i.append(e,t.icons.pip);const l=()=>{o()&&n()};r.push(()=>e.removeEventListener("click",l));const s=t.proxy(e,"click",l);if(c?s():r.push(s),c||!o())return;const u=n=>{o()&&i.tooltip(e,t.i18n.get(n?"Exit PIP Mode":"PIP Mode"))};r.push(()=>t.off("document-pip",u)),t.on("document-pip",u)}}),c&&t.controls.remove("document-pip"))},destroy(){if(c)return;c=!0;const t=e(r.splice(0).reverse());if(t.length)throw t[0]}}}(t,f,a);function h(){if(s)return;s=!0;const t=c,n=m;m=null;const o=e([d.destroy,()=>n?.destroy(),()=>t?.off("destroy",h)]);c=null,l=null,o.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",o[0])}const y={name:"artplayerPluginDocumentPip",get isSupported(){return r},get isActive(){return d.active},open:p,close:d.close,toggle:f};if(s)return c=null,l=null,y;try{t.on("destroy",h),a()?m?.mount():t.off("destroy",h)}catch(g){throw h(),g}return y}}const i=Object.assign(o,{default:o});return"undefined"!==typeof document&&function(e){const n="artplayer-plugin-document-pip",o=e.getElementById(n);if(o)return void(o.textContent=t);const i=e.createElement("style");i.id=n,i.textContent=t;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const o=e.getElementById(n);o?o.textContent=t:(e.head||e.documentElement).appendChild(i)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),i}); diff --git a/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.legacy.js b/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.legacy.js index 177afc32b..be093411d 100644 --- a/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.legacy.js +++ b/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.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.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,t,n)=>new Promise((o,r)=>{var i=e=>{try{c(n.next(e))}catch(t){r(t)}},l=e=>{try{c(n.throw(e))}catch(t){r(t)}},c=e=>e.done?o(e.value):Promise.resolve(e.value).then(i,l);c((n=n.apply(e,t)).next())});function l(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const c=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function u(e){let t=!1,n=0,o=null,r=null,c=null;const u=()=>!t&&e.alive(),s=e=>e===n&&u();function a(){n++,null==r||r.finish(),r=null,null==c||c.cancel(),c=null}function d(e){const t=l(e.releases.splice(0));return t.push(...l([()=>e.window.close()])),t}function p(t){return i(this,null,function*(){if(!s(t))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,yield n.promise,c===n&&(c=null),s(t)&&e.resize()})}function f(){return i(this,null,function*(){a();const t=n,r=o;if(o=null,!r)return;const i=d(r);if(r.announced)try{e.activate(!1)}catch(l){i.push(l)}i.length&&u()&&e.report("close",i[0]),s(t)&&(yield p(t))})}return{get active(){return null!==o},get opening(){return null!==r},open:function(){return i(this,null,function*(){if(!u()||o)return;if(r)return r.promise;a();const t=n;let c,m;const h=new Promise((e,t)=>{c=e,m=t}),y={promise:h,finish:c};r=y;const v=()=>{r===y&&(r=null),c()},g=n=>{if(s(t)){const t=o;o=null,t&&(d(t),t.announced&&l([()=>e.activate(!1)]));try{e.report("open",n)}catch(r){m(r)}}},P=n=>i(null,null,function*(){if(!s(t))return void((null==o?void 0:o.window)!==n&&l([()=>n.close()]));const r={window:n,releases:[],announced:!1};o=r;try{const o=e.project(n.document);if(r.releases.push(o.destroy),o.mount(),!s(t))return void d(r);for(const[i,l]of[["resize",()=>{s(t)&&e.nativeResize()}],["pagehide",()=>{f()}],["unload",()=>{f()}]])if(r.releases.unshift(()=>n.removeEventListener(i,l)),n.addEventListener(i,l),!s(t))return void d(r);r.announced=!0,e.activate(!0),yield p(t)}catch(i){g(i)}});try{const n=e.request();Promise.resolve(n).then(P,g).then(v,e=>{s(t)&&m(e),v()})}catch(w){try{g(w)}finally{v()}}return h})},close:f,destroy(){t||(t=!0,f().catch(()=>{}))}}}return"undefined"!==typeof document&&function(e){const t="artplayer-plugin-document-pip",n=e.getElementById(t);if(n)return void(n.textContent=c);const o=e.createElement("style");o.id=t,o.textContent=c;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const n=e.getElementById(t);n?n.textContent=c:(e.head||e.documentElement).appendChild(o)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),function(e={}){const c=((e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n=window,o="documentPictureInPicture"in n&&"function"===typeof(null==(t=n.documentPictureInPicture)?void 0:t.requestWindow);let r=e,s=e.template.$player,a=e.isDestroy;const d=e.constructor.utils,p=()=>!a&&!!r&&!r.isDestroy,f=u({alive:p,request:()=>n.documentPictureInPicture.requestWindow({width:c.width,height:c.height}),project:e=>function(e,t,n){const o=e.ownerDocument,r=e.parentNode,i=e.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const c=o.createElement("div");c.className="artplayer-document-pip-placeholder",c.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",c.textContent=null!=n?n:"";const u=t.createElement("div");u.id="__art_dpip_root";const s=[];let a=!1;const d=()=>{const t=c.parentNode===r?c:(null==i?void 0:i.parentNode)===r?i:null;if(e.parentNode!==r||e.nextSibling!==t)try{r.insertBefore(e,t)}catch(n){throw o.body.appendChild(e),n}},p=()=>{const e=l([d,()=>c.remove(),...s.splice(0).map(e=>()=>e.remove()),()=>u.remove()]);if(e.length)throw e[0]};return{mount(){if(!a){if(r.insertBefore(c,(null==i?void 0:i.parentNode)===r?i:null),a||t.body.appendChild(u),a||function(e,t,n,o){const r=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},i=t.createElement("style");if(i.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",r(i),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",r(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),r(n)})}catch(l){}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,r(n)})}catch(l){}}(o,t,e=>s.push(e),()=>!a),!a){const n=t.adoptNode(e);a||u.appendChild(n)}a&&p()}},destroy(){a||(a=!0,p())}}}(s,e,c.placeholder),activate(e){var t,n;r&&s&&(e?d.addClass(s,"artplayer-document-pip"):d.removeClass(s,"artplayer-document-pip"),p()&&(null==(n=(t=r.events).bindGlobalEvents)||n.call(t),p()&&r.emit("document-pip",e)))},resize:()=>{p()&&r.emit("resize")},nativeResize:()=>{var e;p()&&(null==(e=r.resize)||e.call(r))},report(e,t){p()&&(r.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});function m(){return i(this,null,function*(){if(p())return!o&&c.fallbackToVideoPiP?(r.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):f.open()})}function h(){p()&&(f.active||f.opening?f.close():m())}let y=function(e,t,n){const o=e.constructor.utils,r=[];let i=!1;return{mount(){!i&&n()&&(r.push(()=>e.controls.remove("document-pip")),e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:l=>{if(i||!n())return;o.append(l,e.icons.pip);const c=()=>{n()&&t()};r.push(()=>l.removeEventListener("click",c));const u=e.proxy(l,"click",c);if(i?u():r.push(u),i||!n())return;const s=t=>{n()&&o.tooltip(l,e.i18n.get(t?"Exit PIP Mode":"PIP Mode"))};r.push(()=>e.off("document-pip",s)),e.on("document-pip",s)}}),i&&e.controls.remove("document-pip"))},destroy(){if(i)return;i=!0;const e=l(r.splice(0).reverse());if(e.length)throw e[0]}}}(e,h,p);function v(){if(a)return;a=!0;const e=r,t=y;y=null;const n=l([f.destroy,()=>null==t?void 0:t.destroy(),()=>null==e?void 0:e.off("destroy",v)]);r=null,s=null,n.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",n[0])}const g={name:"artplayerPluginDocumentPip",get isSupported(){return o},get isActive(){return f.active},open:m,close:f.close,toggle:h};if(a)return r=null,s=null,g;try{e.on("destroy",v),p()?null==y||y.mount():e.off("destroy",v)}catch(P){throw v(),P}return g}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginDocumentPip=t(),define(function(){return e.artplayerPluginDocumentPip})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginDocumentPip=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(t,n,o)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,i=(e,t,n)=>new Promise((o,r)=>{var i=e=>{try{c(n.next(e))}catch(t){r(t)}},l=e=>{try{c(n.throw(e))}catch(t){r(t)}},c=e=>e.done?o(e.value):Promise.resolve(e.value).then(i,l);c((n=n.apply(e,t)).next())});function l(e){const t=[];for(const o of e)try{o()}catch(n){t.push(n)}return t}const c=".artplayer-document-pip.art-video-player{width:100%!important;height:100%!important}";function u(e){let t=!1,n=0,o=null,r=null,c=null;const u=()=>!t&&e.alive(),s=e=>e===n&&u();function a(){n++,null==r||r.finish(),r=null,null==c||c.cancel(),c=null}function d(e){const t=l(e.releases.splice(0));return t.push(...l([()=>e.window.close()])),t}function p(t){return i(this,null,function*(){if(!s(t))return;const n=function(){let e;const t=new Promise(t=>{e=t});let n=setTimeout(()=>{n=null,e()},100);return{promise:t,cancel(){null!==n&&clearTimeout(n),n=null,e()}}}();c=n,yield n.promise,c===n&&(c=null),s(t)&&e.resize()})}function f(){return i(this,null,function*(){a();const t=n,r=o;if(o=null,!r)return;const i=d(r);if(r.announced)try{e.activate(!1)}catch(l){i.push(l)}i.length&&u()&&e.report("close",i[0]),s(t)&&(yield p(t))})}return{get active(){return null!==o},get opening(){return null!==r},open:function(){return i(this,null,function*(){if(!u()||o)return;if(r)return r.promise;a();const t=n;let c,m;const h=new Promise((e,t)=>{c=e,m=t}),y={promise:h,finish:c};r=y;const v=()=>{r===y&&(r=null),c()},g=n=>{if(s(t)){const t=o;o=null,t&&(d(t),t.announced&&l([()=>e.activate(!1)]));try{e.report("open",n)}catch(r){m(r)}}},P=n=>i(null,null,function*(){if(!s(t))return void((null==o?void 0:o.window)!==n&&l([()=>n.close()]));const r={window:n,releases:[],announced:!1};o=r;try{const o=e.project(n.document);if(r.releases.push(o.destroy),o.mount(),!s(t))return void d(r);for(const[i,l]of[["resize",()=>{s(t)&&e.nativeResize()}],["pagehide",()=>{f()}],["unload",()=>{f()}]])if(r.releases.unshift(()=>n.removeEventListener(i,l)),n.addEventListener(i,l),!s(t))return void d(r);r.announced=!0,e.activate(!0),yield p(t)}catch(i){g(i)}});try{const n=e.request();Promise.resolve(n).then(P,g).then(v,e=>{s(t)&&m(e),v()})}catch(w){try{g(w)}finally{v()}}return h})},close:f,destroy(){t||(t=!0,f().catch(()=>{}))}}}function s(e={}){const c=((e,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(e,l,i[l]);if(t)for(var l of t(i))o.call(i,l)&&r(e,l,i[l]);return e})({width:480,height:270,fallbackToVideoPiP:!0,placeholder:"Playing in Document Picture-in-Picture"},e);return e=>{var t;const n=window,o="documentPictureInPicture"in n&&"function"===typeof(null==(t=n.documentPictureInPicture)?void 0:t.requestWindow);let r=e,s=e.template.$player,a=e.isDestroy;const d=e.constructor.utils,p=()=>!a&&!!r&&!r.isDestroy,f=u({alive:p,request:()=>n.documentPictureInPicture.requestWindow({width:c.width,height:c.height}),project:e=>function(e,t,n){const o=e.ownerDocument,r=e.parentNode,i=e.nextSibling;if(!r)throw new Error("Document Picture-in-Picture requires a mounted player");const c=o.createElement("div");c.className="artplayer-document-pip-placeholder",c.style.cssText="display:flex;justify-content:center;align-items:center;width:100%;height:100%;",c.textContent=null!=n?n:"";const u=t.createElement("div");u.id="__art_dpip_root";const s=[];let a=!1;const d=()=>{const t=c.parentNode===r?c:(null==i?void 0:i.parentNode)===r?i:null;if(e.parentNode!==r||e.nextSibling!==t)try{r.insertBefore(e,t)}catch(n){throw o.body.appendChild(e),n}},p=()=>{const e=l([d,()=>c.remove(),...s.splice(0).map(e=>()=>e.remove()),()=>u.remove()]);if(e.length)throw e[0]};return{mount(){if(!a){if(r.insertBefore(c,(null==i?void 0:i.parentNode)===r?i:null),a||t.body.appendChild(u),a||function(e,t,n,o){const r=e=>{o()&&(n(e),t.head.appendChild(e),o()||e.remove())},i=t.createElement("style");if(i.textContent="\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n ",r(i),!t.querySelector('meta[name="viewport"]')){const e=t.createElement("meta");e.name="viewport",e.content="width=device-width,initial-scale=1",r(e)}try{e.querySelectorAll('link[rel="stylesheet"]').forEach(e=>{const n=t.createElement("link");n.rel="stylesheet",n.href=e.href,e.media&&(n.media=e.media),e.crossOrigin&&(n.crossOrigin=e.crossOrigin),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),r(n)})}catch(l){}try{e.querySelectorAll("style").forEach(e=>{const n=t.createElement("style");n.textContent=e.textContent,r(n)})}catch(l){}}(o,t,e=>s.push(e),()=>!a),!a){const n=t.adoptNode(e);a||u.appendChild(n)}a&&p()}},destroy(){a||(a=!0,p())}}}(s,e,c.placeholder),activate(e){var t,n;r&&s&&(e?d.addClass(s,"artplayer-document-pip"):d.removeClass(s,"artplayer-document-pip"),p()&&(null==(n=(t=r.events).bindGlobalEvents)||n.call(t),p()&&r.emit("document-pip",e)))},resize:()=>{p()&&r.emit("resize")},nativeResize:()=>{var e;p()&&(null==(e=r.resize)||e.call(r))},report(e,t){p()&&(r.notice.show=`Document Picture-in-Picture ${e} failed`,console.warn(`[artplayer-plugin-document-pip] ${e} failed:`,t))}});function m(){return i(this,null,function*(){if(p())return!o&&c.fallbackToVideoPiP?(r.pip=!0,void console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture")):f.open()})}function h(){p()&&(f.active||f.opening?f.close():m())}let y=function(e,t,n){const o=e.constructor.utils,r=[];let i=!1;return{mount(){!i&&n()&&(r.push(()=>e.controls.remove("document-pip")),e.controls.add({name:"document-pip",position:"right",index:40,tooltip:e.i18n.get("PIP Mode"),mounted:l=>{if(i||!n())return;o.append(l,e.icons.pip);const c=()=>{n()&&t()};r.push(()=>l.removeEventListener("click",c));const u=e.proxy(l,"click",c);if(i?u():r.push(u),i||!n())return;const s=t=>{n()&&o.tooltip(l,e.i18n.get(t?"Exit PIP Mode":"PIP Mode"))};r.push(()=>e.off("document-pip",s)),e.on("document-pip",s)}}),i&&e.controls.remove("document-pip"))},destroy(){if(i)return;i=!0;const e=l(r.splice(0).reverse());if(e.length)throw e[0]}}}(e,h,p);function v(){if(a)return;a=!0;const e=r,t=y;y=null;const n=l([f.destroy,()=>null==t?void 0:t.destroy(),()=>null==e?void 0:e.off("destroy",v)]);r=null,s=null,n.length&&console.warn("[artplayer-plugin-document-pip] cleanup failed:",n[0])}const g={name:"artplayerPluginDocumentPip",get isSupported(){return o},get isActive(){return f.active},open:m,close:f.close,toggle:h};if(a)return r=null,s=null,g;try{e.on("destroy",v),p()?null==y||y.mount():e.off("destroy",v)}catch(P){throw v(),P}return g}}const a=Object.assign(s,{default:s});return"undefined"!==typeof document&&function(e){const t="artplayer-plugin-document-pip",n=e.getElementById(t);if(n)return void(n.textContent=c);const o=e.createElement("style");o.id=t,o.textContent=c;const r=()=>{e.removeEventListener("DOMContentLoaded",r);const n=e.getElementById(t);n?n.textContent=c:(e.head||e.documentElement).appendChild(o)};"loading"===e.readyState?e.addEventListener("DOMContentLoaded",r):r()}(document),a}); diff --git a/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.mjs b/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.mjs index 88245fb0d..e6eb109cc 100644 --- a/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.mjs +++ b/packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.mjs @@ -473,8 +473,9 @@ function artplayerPluginDocumentPip(userOptions = {}) { return result; }; } +const index = Object.assign(artplayerPluginDocumentPip, { default: artplayerPluginDocumentPip }); if (typeof document !== "undefined") installStyle(document); export { - artplayerPluginDocumentPip as default + index as default }; diff --git a/packages/artplayer-plugin-document-pip/package.json b/packages/artplayer-plugin-document-pip/package.json index 87551eefd..9cf18aed8 100644 --- a/packages/artplayer-plugin-document-pip/package.json +++ b/packages/artplayer-plugin-document-pip/package.json @@ -19,19 +19,36 @@ ], "exports": { ".": { - "types": "./types/artplayer-plugin-document-pip.d.ts", - "import": "./dist/artplayer-plugin-document-pip.mjs", - "require": "./dist/artplayer-plugin-document-pip.js" + "import": { + "types": "./types/artplayer-plugin-document-pip.d.mts", + "default": "./dist/artplayer-plugin-document-pip.mjs" + }, + "require": { + "types": "./types/artplayer-plugin-document-pip.d.cts", + "default": "./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" + "import": { + "types": "./types/artplayer-plugin-document-pip.d.mts", + "default": "./dist/artplayer-plugin-document-pip.legacy.js" + }, + "require": { + "types": "./types/artplayer-plugin-document-pip.d.cts", + "default": "./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" + "browserslist": "last 1 Chrome version", + "typesVersions": { + "*": { + "legacy": [ + "types/artplayer-plugin-document-pip.d.ts" + ] + } + } } diff --git a/packages/artplayer-plugin-document-pip/src/index.ts b/packages/artplayer-plugin-document-pip/src/index.ts index 7c96f6170..d2d54cbf6 100644 --- a/packages/artplayer-plugin-document-pip/src/index.ts +++ b/packages/artplayer-plugin-document-pip/src/index.ts @@ -1,5 +1,5 @@ import type Artplayer from 'artplayer' -import type PublicPlugin from '../types/artplayer-plugin-document-pip' +import type { AsyncResult, Option } from '../types/artplayer-plugin-document-pip' import type { WindowApi } from './window-session' import { createControl } from './control' import { createProjection } from './projection' @@ -7,9 +7,7 @@ import { releaseAll } from './resources' import { installStyle } from './styles' import { createWindowSession } from './window-session' -type Option = Parameters[0] - -export default function artplayerPluginDocumentPip(userOptions: Option = {}) { +function artplayerPluginDocumentPip(userOptions: Option = {}) { const options = { width: 480, height: 270, fallbackToVideoPiP: true, placeholder: 'Playing in Document Picture-in-Picture', ...userOptions } return (art: Artplayer) => { const browser = window as Window & { documentPictureInPicture?: WindowApi } @@ -83,7 +81,7 @@ export default function artplayerPluginDocumentPip(userOptions: Option = {}) { if (errors.length) console.warn('[artplayer-plugin-document-pip] cleanup failed:', errors[0]) } - const result = { + const result: AsyncResult = { name: 'artplayerPluginDocumentPip' as const, get isSupported() { return isSupported }, get isActive() { return session.active }, @@ -111,5 +109,7 @@ export default function artplayerPluginDocumentPip(userOptions: Option = {}) { } } +export default Object.assign(artplayerPluginDocumentPip, { default: artplayerPluginDocumentPip }) + if (typeof document !== 'undefined') installStyle(document) diff --git a/packages/artplayer-plugin-document-pip/tsconfig.json b/packages/artplayer-plugin-document-pip/tsconfig.json index c9218405d..bba301755 100644 --- a/packages/artplayer-plugin-document-pip/tsconfig.json +++ b/packages/artplayer-plugin-document-pip/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { "allowJs": false }, - "include": ["src/**/*.ts", "types/**/*.d.ts", "../../types/assets.d.ts"] + "include": ["src/**/*.ts", "types/**/*.d.ts", "types/**/*.d.mts", "types/**/*.d.cts", "../../types/assets.d.ts"] } diff --git a/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.cts b/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.cts new file mode 100644 index 000000000..b341592a6 --- /dev/null +++ b/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.cts @@ -0,0 +1,5 @@ +import type { Factory } from './artplayer-plugin-document-pip.js' + +declare const artplayerPluginDocumentPip: Factory +export default artplayerPluginDocumentPip +export type { AsyncResult, Factory, Option, Result, RuntimeFactory } from './artplayer-plugin-document-pip.js' diff --git a/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.mts b/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.mts new file mode 100644 index 000000000..b341592a6 --- /dev/null +++ b/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.mts @@ -0,0 +1,5 @@ +import type { Factory } from './artplayer-plugin-document-pip.js' + +declare const artplayerPluginDocumentPip: Factory +export default artplayerPluginDocumentPip +export type { AsyncResult, Factory, Option, Result, RuntimeFactory } from './artplayer-plugin-document-pip.js' diff --git a/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts b/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts index 56f36dfc4..5725f8f42 100644 --- a/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts +++ b/packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts @@ -1,21 +1,47 @@ import type Artplayer from 'artplayer' -interface Option { +export interface Option { + /** Requested window width. @default 480 */ width?: number + /** Requested window height. @default 270 */ height?: number + /** Text displayed in the original player container while the window is active. */ placeholder?: string + /** Use the core video PiP property when Document PiP is unavailable. @default true */ fallbackToVideoPiP?: boolean } -interface Result { +/** Historical assignable result; preserved for direct and extracted return types. */ +export interface Result { name: 'artplayerPluginDocumentPip' + /** Runtime is a readonly capability snapshot; the published field stays assignable. */ isSupported: boolean + /** Runtime is a readonly live getter; the published field stays assignable. */ isActive: boolean + /** Runtime returns Promise; the published void action remains assignable here. */ open: () => void + /** Runtime returns Promise; the published void action remains assignable here. */ close: () => void toggle: () => void } -declare const artplayerPluginDocumentPip: (option: Option) => (art: Artplayer) => Result +/** Exact view of an unmodified runtime result. */ +export interface AsyncResult extends Omit { + readonly isSupported: boolean + readonly isActive: boolean + open: () => Promise + close: () => Promise +} +/** Exact published factory signature, including compatibility with replacement functions. */ +export type Factory = (option: Option) => (art: Artplayer) => Result + +/** Opt-in runtime view with omitted options, self default and precise async actions. */ +export interface RuntimeFactory { + (option?: Option): (art: Artplayer) => AsyncResult + readonly default: RuntimeFactory +} + +/** Keep the published callable type; use RuntimeFactory explicitly for its broader runtime shape. */ +declare function artplayerPluginDocumentPip(option: Option): (art: Artplayer) => Result export default artplayerPluginDocumentPip diff --git a/refactor/baselines/dpip-types-validation.json b/refactor/baselines/dpip-types-validation.json new file mode 100644 index 000000000..71fdb93e1 --- /dev/null +++ b/refactor/baselines/dpip-types-validation.json @@ -0,0 +1,360 @@ +{ + "schemaVersion": 1, + "task": "PKG-DPIP-04", + "status": "done", + "checks": [ + { + "command": "node --test refactor/scripts/dpip-types.test.mjs", + "result": "pass", + "tests": 4, + "scope": "five compiler modes, whole factory/direct and extracted Result replacements, four real historical declarations, fourteen invalid uses, semantic editor globals and actual three-format exports" + }, + { + "command": "yarn build:ts && yarn build artplayer-plugin-document-pip", + "result": "pass", + "formats": [ + "main", + "legacy", + "esm" + ] + }, + { + "command": "yarn test:dpip-types-package", + "result": "pass-with-exact-historical-controls", + "cases": 27, + "candidateZeroDiagnostic": 7, + "historicalZeroDiagnostic": 12, + "historicalFailureCases": 8, + "candidateInvalidUsesPerMode": 14, + "report": "refactor/.cache/dpip-package-types-2bH82Z/report.json", + "missingRuntime": "Published1.0.0 require verified as MODULE_NOT_FOUND; never substituted with Git source" + }, + { + "command": "ARTPLAYER_DPIP_ARTIFACT=
playwright test test/browser/dpip-lifecycle.spec.js", + "result": "pass", + "tests": 18, + "skipped": 0, + "browsers": [ + { + "project": "chromium", + "version": "153.0.8010.12", + "platform": "win32" + }, + { + "project": "firefox", + "version": "155.0", + "platform": "win32" + }, + { + "project": "webkit", + "version": "26.6", + "platform": "win32" + } + ], + "scope": "Main hash matches final build after declaration-only revisions; two cores and three engines use native iframe DOM with controlled window APIs, not native Document PiP" + }, + { + "command": "focused eslint --no-fix", + "result": "pass" + }, + { + "command": "yarn ci:check", + "result": "pass", + "tests": { + "unit": 1006, + "engineering": 14, + "baseline": 120, + "mainTotal": 1140, + "repeatedContractExecutions": 44 + }, + "strictProductionTypeScriptFiles": 290 + } + ], + "limitations": [ + "Default factory retains its exact required-argument shape to preserve whole-factory replacement assignability. RuntimeFactory explicitly provides optional options, self default and precise async results. Canvas/Ambilight factory regressions are a separate open PKG-FACTORY-01 release dependency.", + "Default Result deliberately retains published writable fields and void action inference; exact async/readonly behavior is available via the explicit AsyncResult view.", + "The 27 installed compiler cases include eight exact historical failures; candidate cases must all compile without diagnostics.", + "Published 1.0.0 runtime remains absent and is verified as MODULE_NOT_FOUND, not repaired in place.", + "Browser iframe validation controls window APIs and does not prove native Document PiP activation, media continuity, devices or proxy combinations; task05 remains.", + "Full demo and distribution acceptance remains task06." + ], + "parentCommit": "80d37d66f8797ed89feff554a25d623943571974", + "inputs": [ + { + "file": "packages/artplayer-plugin-document-pip/src/index.ts", + "sha256LF": "28ba9b809589f4c58acc7d36bc2bb11b75832e8e6e009487c741c5b47dc4a590" + }, + { + "file": "packages/artplayer-plugin-document-pip/package.json", + "sha256LF": "5f3671f759364be52faf3810e1534a7711270f975f06d3489d95982fbae0eafb" + }, + { + "file": "packages/artplayer-plugin-document-pip/tsconfig.json", + "sha256LF": "583e4ac1afa99e3a29c7f899df9fdeefcbd14d3847d69143e3fa6a8facac6d99" + }, + { + "file": "packages/artplayer-plugin-document-pip/README.md", + "sha256LF": "8a6b5ff395b92dce960d92b0681640d94c7de44f1181cd02408724964d51cf48" + }, + { + "file": "packages/artplayer-plugin-document-pip/ARCHITECTURE.md", + "sha256LF": "422cd5847c8c8dffece1b619644a5e441af84ddb7d727d6f03d433f9d7117af9" + }, + { + "file": "packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts", + "sha256LF": "bea8feeec01c0711a7f669f65f18ecdc299f89101ec75ea8c001bb9a218b0663" + }, + { + "file": "packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.mts", + "sha256LF": "0dd487fba4fbe05614d6d00bb6e275e9211da3bd8e8c1296e5c89a4306ed5a73" + }, + { + "file": "packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.cts", + "sha256LF": "0dd487fba4fbe05614d6d00bb6e275e9211da3bd8e8c1296e5c89a4306ed5a73" + }, + { + "file": "test/types/dpip.ts", + "sha256LF": "3571e661790f845e4a7d293325cb261d5cf2e57c2bccb5d05c75fb70ef150525" + }, + { + "file": "refactor/fixtures/consumers/dpip-published.ts", + "sha256LF": "184e29c1e4074f786d7c582cd7a251a42ce20b34ad1baf98b5b2a2480f9e7088" + }, + { + "file": "refactor/scripts/dpip-types.test.mjs", + "sha256LF": "90fcef9d140ca3cf63e97cb089fb53c4965e4d2b54741a15b15b4a7b836e86f6" + }, + { + "file": "refactor/scripts/dpip-package-types.mjs", + "sha256LF": "85ef013a770e609399d84fbaf8ec559fa1771d6c66d2f99514060d9fa2425fe2" + }, + { + "file": "scripts/build-ts.js", + "sha256LF": "24ea26bb5a244cbc09485c36c917a4c511d3da1dd1a3e1e14d9b0f4711b9dda6" + }, + { + "file": "scripts/typecheck.mjs", + "sha256LF": "82300d2b6c9aaffac17448a09168c0a6b4ff7f9f9ff61b3106b1ac9d5db81519" + }, + { + "file": "package.json", + "sha256LF": "c1414a62bc6c02d0712db43bbf4de68d22d2ed36de9e66378fe193ba3bc0b733" + }, + { + "file": "docs/assets/ts/artplayer-plugin-document-pip.d.ts", + "sha256LF": "42faa0a6549149efd01b46c3c59246bd4dc33f2383b63b04e9f5376de29fdb8e" + } + ], + "artifacts": [ + { + "file": "packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.js", + "sha256LF": "56440aad3ed06be55ec3a57d781f7de239e9aecf40a067e88f2cffcd01a86d6a" + }, + { + "file": "docs/compiled/artplayer-plugin-document-pip.js", + "sha256LF": "56440aad3ed06be55ec3a57d781f7de239e9aecf40a067e88f2cffcd01a86d6a" + }, + { + "file": "packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.legacy.js", + "sha256LF": "67dd14de3cc16a04ae6c1938dcba61b1355f4a15e5fa06f62a41b18d14d4d356" + }, + { + "file": "docs/compiled/artplayer-plugin-document-pip.legacy.js", + "sha256LF": "67dd14de3cc16a04ae6c1938dcba61b1355f4a15e5fa06f62a41b18d14d4d356" + }, + { + "file": "packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.mjs", + "sha256LF": "541b4ad6e1cbadd9156ee1f317559c97b9fddae37668ef32046f1fa47c392ec2" + }, + { + "file": "docs/compiled/artplayer-plugin-document-pip.mjs", + "sha256LF": "541b4ad6e1cbadd9156ee1f317559c97b9fddae37668ef32046f1fa47c392ec2" + } + ], + "logs": [ + { + "file": "refactor/.cache/dpip04-installed-first.log", + "sha256": "8e67d5ebc1febaad102c362743589af8be40c2cd2bcb26e72b933842c00ed656" + }, + { + "file": "refactor/.cache/dpip04-installed-final.log", + "sha256": "00bf798308821d08c5b7b73c646314ae0826ea52f9ca83d6edf2a138129626c0" + }, + { + "file": "refactor/.cache/dpip04-installed-variance.log", + "sha256": "6410a24d45bda348ed9fe2e17479241d1aa9d3e1eb4525f6151a1527c40b1fcd" + }, + { + "file": "refactor/.cache/dpip04-factory-replacement-regression.log", + "sha256": "cf07a16de8e07f3cd6c2ba60cf232e87cc519aab3638e80566f2b120c88e6e13" + }, + { + "file": "refactor/.cache/dpip04-types-variance.log", + "sha256": "031fde27eb07f3ee61ff89db137afd6726f2482779a86c51d8ac0a21406bd6e9" + }, + { + "file": "refactor/.cache/dpip04-editor-variance.log", + "sha256": "34114a66ac839a9fcb76de7cf13a5cce3bfd6adf12f9829cd0d58683028f910b" + }, + { + "file": "refactor/.cache/dpip04-build-variance.log", + "sha256": "dc2aa2fe5a7979faa11e7c913ba13ad7ad66697c3d3e827fa93b1f5389c60391" + }, + { + "file": "refactor/.cache/dpip04-lint-variance-final.log", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "file": "refactor/.cache/dpip04-browser-final.log", + "sha256": "91ce0c3f58faef0fef43987a088154147dc1eaeb4ebcf9ef32870dda763221b7" + }, + { + "file": "refactor/.cache/dpip04-ci-final.log", + "sha256": "c7b406fa037e15578b848c39a1eace715b16d25a6784a432257b36f71092cb65" + }, + { + "file": "refactor/.cache/dpip-package-types-2bH82Z/report.json", + "sha256": "f7a7e0c139931f1a5b91fa50853f0097bcf2762e0604c17acf1c3ac99f001f7f" + }, + { + "file": "refactor/.cache/dpip04-final-results/report.json", + "sha256": "8b4b1bf68d717e9e4edcac8e15b43c149f2693b68547c534938decab96a3e5e1" + } + ], + "installedPackages": [ + { + "name": "artplayer", + "archive": "D:\\github\\ArtPlayer\\refactor\\.cache\\dpip-package-types-2bH82Z\\artplayer.tgz", + "sha256": "2139af017670a4f30f667bf5fdc1aa680f3e03b9c8d3cb767fc92d6345aedff5", + "files": { + "package/ARCHITECTURE.md": "7ebedaee4d06925e0f7bf2ad4a2e6093aa416c91ea4d6154015854baf507e95e", + "package/README.md": "1e185e65f67fc2081b4182bbc6c4558ea05b6e3fa3acc5dd0c3ac7df1d542b09", + "package/THIRD_PARTY_NOTICES": "b77b5b46b79fa0cda850b0781f78c3b1112c4ed9672fa291956fe8eff53098e7", + "package/dist/artplayer.cts": "0e91e907d021db02a68004603e6190505fdc0806d873ebb6af171aa089a81da7", + "package/dist/artplayer.js": "dc1460b77abdd401158e098b25a1abf280c53bb92d401fc387a4864dc7b18357", + "package/dist/artplayer.legacy.js": "49781a25f3d680c7964eec066b792966da71f03ccc3e7936cd5e0e9563e83008", + "package/dist/artplayer.mjs": "ad4e69b1a7a9584ab79204b871f51f4ae6561dc2dece2c64fa9c4884acd36154", + "package/dist/artplayer.mts": "f6292596a9ccb1d43a6d6a12c35f859b1889ad15924c5ae0f9f280941aade313", + "package/dist/artplayer.ts": "26a42ac66811e70f68a8ebe62cbf304eb1993451b3e658961be98e7106162527", + "package/dist/component.ts": "aa1c43be67322781b4b355b143bc69d9f29d22e578e4974d6a13e957a7c0334f", + "package/dist/config.ts": "c4fd8681bf32b10c743e3e561c532520c8f32e43fd765524850b15e55cb91c72", + "package/dist/cssVar.ts": "e027d82fb4f01c9ce7559cf679b2d5ee1962d3f7e5b4dd64ca21f472b933efb6", + "package/dist/emitter.ts": "9c62551cdcc6dd3966bed8a7a85dd477435db977c91a294d2ac8f162f9592537", + "package/dist/events.ts": "af191f862af4ec8933b09113b8c074603ae254a8b70460d0f3006646cd74ae42", + "package/dist/i18n.ts": "34b0c684668044f7600c80b9d3979f8fb730138007b7cb4e7034326b340156fb", + "package/dist/i18n/ar.js": "bd0bef65f4f7dc3f8ed562904cc6fa9071ff4537fb64c1e0fc3d554141bcd3cb", + "package/dist/i18n/ar.mjs": "59310b7bbeea83bbb7d73aadc5ca82a6ec269c3530d19aa741c94d5c64fc5da8", + "package/dist/i18n/cs.js": "6e2c93daba24c2e48dfa206bcf4f2f2a8a02713b856e404d2e4e4ecd8309ca2f", + "package/dist/i18n/cs.mjs": "c73fba18797d62d7b2581e67fe7340c35fe84510b2250ff1ecaad253d9cabbac", + "package/dist/i18n/es.js": "f4133ac6ea06b69a474b33c4a1809a4066e2376bb9464a3f3aa8330f01f1944a", + "package/dist/i18n/es.mjs": "1390bca3def2be115e811de337df0a0c3f63998e51359f283023246245c552a7", + "package/dist/i18n/fa.js": "8d3ef2e0f0cc0ea480c2167b6fcb87cdf444e90759c3519e8daa139fec576da4", + "package/dist/i18n/fa.mjs": "ab441e8a2d79043b29ceca87c783bf06874bb9d3a149c1604bc167eb481be2a9", + "package/dist/i18n/fr.js": "89dc4194a6c0a962b9ce756b52c90401c1acf3b159f265f3bc0d7d6d7d987f03", + "package/dist/i18n/fr.mjs": "99491878430fb7b6f2b7bf93da0588a831704b412e01116f23ba1d9d45863816", + "package/dist/i18n/id.js": "4c6dc86db741bcc2857df55a9d037e82e91d375fa6fd22e0562809ff621b92db", + "package/dist/i18n/id.mjs": "383e5803a6b6686c6de4e867770241de75b6f517dcca2bdedc6f2004bf6e1fb3", + "package/dist/i18n/pl.js": "3a38828b1c3d719c0aca9906cf6a46c23555a8411f8d57645f0e0ce8147dc664", + "package/dist/i18n/pl.mjs": "079ed96732979035297af387c64a7b99519b5a43107fb86735a654ea4fe8e9b5", + "package/dist/i18n/ru.js": "62fac9dddb302eb16382e6e9301fc4b2c66f5f69d4a358a26b67026a5fa4e787", + "package/dist/i18n/ru.mjs": "a893aeaee1d79409db72e324fbff200e3864f33ed168f04d91d25f7cf2efa765", + "package/dist/i18n/tr.js": "1492c36b069a7d73db4f3913bd18085faff7afd8b3c158138fe264e31600e38c", + "package/dist/i18n/tr.mjs": "a90478cac078836b76c2a98261907610fee07f3e4b28671b8e7dbf533778f918", + "package/dist/i18n/vi.js": "c7216ef7e608a79b7e2c479a07bf310d4ab79577947ac4a62d676faaced0e9cf", + "package/dist/i18n/vi.mjs": "66270fdfa0b5da396322d1769169b7df37a030ba15ac18eb30bd87b3af8074ec", + "package/dist/i18n/zh-tw.js": "11c49857d6d40a5ffd224ffa59c9026e71621b345f63c5a086326db80a22371a", + "package/dist/i18n/zh-tw.mjs": "a38e630cb96de96c15d824686aec750e25cf6c8ada01285a292442a81566314f", + "package/dist/icons.ts": "0d8e8e52e52130dd4a29bab551dd7a2a954797e42e92a6e068c85d583e23e6a4", + "package/dist/language.cts": "2248040d86a8e34626755c4ecf53ea0174706c653073cf0e15884a030d173120", + "package/dist/language.mts": "c391e863012c77769e661afbf8fa949e9373aa88d17f58cbba7f5696edb8077f", + "package/dist/legacy/language.ts": "c452ffd764ff9b29b819b3475c42395d2ea7a33560d8c186ef5df3844b9524c3", + "package/dist/option.ts": "850e5264219b8b438c80694402225b690b131786677a5da0d22739ec2352d263", + "package/dist/playback.ts": "1ceaed3aa1cef511fe8b20f4874647f6065c723ad805b742a0a9247e16bb1bb5", + "package/dist/player.ts": "f1e50257df2ea592d0a0e1f36078dda77eaf2cf3b3d795307501396562d99f28", + "package/dist/plugin.ts": "2a57e148fda00ee687da5036b890b0f611cb94bb403a1ed52602179060259d35", + "package/dist/quality.ts": "7ed6ed78cea52991b2f6ddd2bd3b7bd8c5146fdfff7486fe8b814c3e632f1567", + "package/dist/runtime.cts": "52cfff1daeb6841a90212c8fa8d46ca46d6650bb7ed1b59b62115d854b8ad652", + "package/dist/runtime.mts": "1b09bc0ee0f0ee2f788689eaff441bdeda1fab0ce783e71b61b9792d81072b03", + "package/dist/runtime.ts": "ec4b1d56993eb482a77eb0f94b701047549d009e6ba6433f27e7d464fef30c2b", + "package/dist/runtime/component.ts": "840213299c942fe058eb5436977ceec066b9dccda24c55ae9f464b399c979e39", + "package/dist/runtime/construction.ts": "24cc5cda1f614314db382271a9b0d5583b781894cfdf6c548700b1b5270467ee", + "package/dist/runtime/events.ts": "52848f57d35eb1037cf74c8877521edf99a015bcd77f30ef6bbcba1807a99bfe", + "package/dist/runtime/media.ts": "8828f80953aec3e95328cefe691661e8897cb27cb309483cf806ec45a8549ae3", + "package/dist/runtime/option.ts": "bb672e49ffe74a6fc78543217f6de80d7d738890146df0857c709d4dc283e4ce", + "package/dist/runtime/player.ts": "a4a24794e26cfb9e4310bf0f459a7a407e85bf81b4f3a4feb6294331af8036fb", + "package/dist/runtime/plugin.ts": "9ad482f2a77914a91450419680b8af6b314b926f0831c2f7f6d7c466690f95c9", + "package/dist/runtime/services.ts": "8e4648d8c61bff47343f9e1c2b995af69fc00947264b826109ceadcbaf553254", + "package/dist/runtime/setting.ts": "c48d20957b57f79f985ef76a2950cc8a5cfa25dafa8ec5939e562661778e6218", + "package/dist/runtime/subtitle.ts": "13241c4f9a87517aa2cf7b3e0bb8cedaa12fa0b4d3f8934285797583b752557e", + "package/dist/runtime/template.ts": "da9975513a1938e7f386f4f65f718f0fc595164bfeac8f0cd99a3e97a54919a1", + "package/dist/runtime/utils.ts": "cab9916f5224a3b047812b9f759cc9cc62105662599744067a6955020ab36916", + "package/dist/setting.ts": "d12a75b656fff70cbb30be4bffec46d9c4273636e8722bce971a4d2b188712a1", + "package/dist/subtitle.ts": "d25b470e47d6a9bd696d9c1ad8adb58e56a208f05695186d513bc8c43c2e8acf", + "package/dist/template.ts": "68aed9e97d006d6be4fabb8504ca84dafab770b0925f4d6e7319e67c82f21b0d", + "package/dist/utils.ts": "494ec447ab467a07ddd7a2c2abf778b3fce69fd28a09aaa8ced9759f8de2e3f6", + "package/package.json": "82e92699e7c29847f32ac6767ece0401290e7d7a12854722bdbcfd09b90b7954", + "package/types/COMPATIBILITY.md": "a7da9e102a116104b513df4f7451247b7759bc502d3375f30bd5b14a541826e0", + "package/types/README.md": "1bd9868e773610e6312fd48a1c5aa20772d29df0af40c3db66e75b7ab4a1aee0", + "package/types/artplayer.d.cts": "3685065e4263abcfd9d953176e461d5b3eb990b0363b54689a7f55deba770fef", + "package/types/artplayer.d.mts": "b664fec51ee5c5381f2ceab25d99d52aee56feab04a2ee7b4ea5b2145ea5fa0e", + "package/types/artplayer.d.ts": "5d0162adf7ac6d0f2bb9b5cfe361f28657c4d9c540cadbf36eba3cc954ce50f8", + "package/types/component.d.ts": "ae5bc1ddeaa1ee1ebbc62573e32423993727079205c64751a5a314170e588a32", + "package/types/config.d.ts": "36f9a84cd436f17701a0d11d3417fc1fe0414e0c52c80083b94a85dfc329e37e", + "package/types/cssVar.d.ts": "93217860fff2ebf750f606d95ddd22220a58837119e63bdf2f5f78fd7488458b", + "package/types/emitter.d.ts": "7e1f9a2a8ce65feb95734f1ed52d1334e57aa388bbef2a43d8bc53a9b6f6623c", + "package/types/events.d.ts": "f83624c9268a284477e8bd793fe3562a2363b72f2a44d5c64fe8c6a6cede8830", + "package/types/i18n.d.ts": "f4f2f05bdfda73c74fef34767cb18ee8e11b743120b1c4598e9714d7846018e5", + "package/types/icons.d.ts": "326a67ba7bdcf52862c5b2a269e540140aff98d05c7b96196485a77f84fe5960", + "package/types/language.d.cts": "f7928e108cf7b7814c2d75cb0a525333e95873fca6cd6d89a740450656b9c1cd", + "package/types/language.d.mts": "6619a26d604b7cccbe2f596243d87ae37cfaae33b8b52874ec071d9787446f9e", + "package/types/legacy/language.d.ts": "c7abda4d506fd933c350e9030290bf9e64347a921d683a66115da1995ebe0a81", + "package/types/option.d.ts": "ccf2c8ddc537dc65c9682d39f044726e23bff18f476b622512d7e6a4b949b5f6", + "package/types/playback.d.ts": "58705c273df6e76a77a6575e769a9ec6c013785c25080f2551aa22415788d870", + "package/types/player.d.ts": "92b00211b70ac71336e495899df972a0519dd138111846044fe4e0f967966177", + "package/types/plugin.d.ts": "fc3594a41c51d8248713e33c486fb1f6a518ac5c7ce31be6988a6cd8d052c5f3", + "package/types/quality.d.ts": "1ac1a48b4f74ff9ba1ce60443e1463d50d1c6a2e5d87d63dc7d2a8eb7f4c2c34", + "package/types/runtime.d.cts": "7ee988dfea9a0ac71a34a656f96f7b74e78aa92547cfdfab7ff7e1139a77d4a3", + "package/types/runtime.d.mts": "dcb85f59a8b7714918ced0c1d18c2bb24e8b80b56d8c594e019dcbdb5ad88b08", + "package/types/runtime.d.ts": "9c6ccd39a1be293f17ae46dae8ea077053e12635ee79d73a5e3b3a559230fcff", + "package/types/runtime/component.d.ts": "1b4c0cee44568649e80140fe778febfcae88af0ac85515f1cbeff78ab0c6d14f", + "package/types/runtime/construction.d.ts": "7a87bedf6f7ffff0c46078aa5f1551e0077d35574e286516121f5f935e2d9ce4", + "package/types/runtime/events.d.ts": "a1e2f9d387475453eaf95c2a5ee79e228636c0bb859bda3fcc46da46574a0c31", + "package/types/runtime/media.d.ts": "8fc89401be7fe25542c169d07dd5675f10916ed20be8493e19695966cf3864a8", + "package/types/runtime/option.d.ts": "6e334e1a76fdcc40b4665c02523bd31c3994d96078fadeb40e23422aa54c1a1d", + "package/types/runtime/player.d.ts": "8ac6383502e4872e83659838844856903031a81a0adc8e8535feb78453aa042c", + "package/types/runtime/plugin.d.ts": "8528f2b17843149f42f9cc16d6fd70baa238c9dc2c329b67d2c38096799c69bd", + "package/types/runtime/services.d.ts": "604c9f8e4b6c0da818f96576bf9f4b0e96085a9003927b2f7ba30027b1ba237e", + "package/types/runtime/setting.d.ts": "349c1fcb205ad312916bd3ee55e6bf241ea8a569fb2ab6c80822e69fc518f7d7", + "package/types/runtime/subtitle.d.ts": "269ff84678d327b3a9dc2f5bc6cc0d731d1e081b85422e474621d5d792efb153", + "package/types/runtime/template.d.ts": "7a62f968a38b4bf9109a4439557c02074eb1d62ba1f6e21a8eb194e91f0badfe", + "package/types/runtime/utils.d.ts": "6bf731705d86853e066dbaf3b8d4003b6548423fe615b7412b722bd0d3a6e48b", + "package/types/setting.d.ts": "08305a75dff96f06490430e099338b463df471b550c1d0dac3abc8995b39eb09", + "package/types/subtitle.d.ts": "b18314e2d64efdb6045830b6e12f615ae2ed585416130e562329ad3ea337f6ce", + "package/types/template.d.ts": "4792bc0c2cbcb7966e4375118bd34b326166e0831862e94ace4cf6b1bbe6a8c8", + "package/types/utils.d.ts": "fca0d3d814df94a25f9eb067c86fa0cf272e2791bac793b91229d57680797712" + } + }, + { + "name": "artplayer-plugin-document-pip", + "archive": "D:\\github\\ArtPlayer\\refactor\\.cache\\dpip-package-types-2bH82Z\\artplayer-plugin-document-pip.tgz", + "sha256": "8e7b16e5735b5e83251b3102e228d202b67bd16e52104a328bf1d50903bd32a3", + "files": { + "package/ARCHITECTURE.md": "422cd5847c8c8dffece1b619644a5e441af84ddb7d727d6f03d433f9d7117af9", + "package/README.md": "3a9553f9f8d9d12f0f76582d54d301d99b64f1836540e0f7b00bf20eb4e3d8f7", + "package/dist/artplayer-plugin-document-pip.js": "56440aad3ed06be55ec3a57d781f7de239e9aecf40a067e88f2cffcd01a86d6a", + "package/dist/artplayer-plugin-document-pip.legacy.js": "67dd14de3cc16a04ae6c1938dcba61b1355f4a15e5fa06f62a41b18d14d4d356", + "package/dist/artplayer-plugin-document-pip.mjs": "541b4ad6e1cbadd9156ee1f317559c97b9fddae37668ef32046f1fa47c392ec2", + "package/package.json": "5f3671f759364be52faf3810e1534a7711270f975f06d3489d95982fbae0eafb", + "package/types/artplayer-plugin-document-pip.d.cts": "0dd487fba4fbe05614d6d00bb6e275e9211da3bd8e8c1296e5c89a4306ed5a73", + "package/types/artplayer-plugin-document-pip.d.mts": "0dd487fba4fbe05614d6d00bb6e275e9211da3bd8e8c1296e5c89a4306ed5a73", + "package/types/artplayer-plugin-document-pip.d.ts": "bea8feeec01c0711a7f669f65f18ecdc299f89101ec75ea8c001bb9a218b0663" + } + } + ], + "browserArtifacts": [ + { + "file": "refactor/.cache/dpip04-final-results/results/.last-run.json", + "sha256": "91d1c43004802cd49950d78eb11c8fa7d05da8ffffe219a8b13b2f561bc00903" + } + ] +} diff --git a/refactor/baselines/factory-assignment-gaps.json b/refactor/baselines/factory-assignment-gaps.json new file mode 100644 index 000000000..55a4cfebd --- /dev/null +++ b/refactor/baselines/factory-assignment-gaps.json @@ -0,0 +1,36 @@ +{ + "compiler": "5.9.3", + "records": [ + { + "name": "artplayer-proxy-canvas", + "version": "1.1.0", + "source": "import Artplayer from 'artplayer'; import plugin from 'artplayer-proxy-canvas'; const replacement: typeof plugin = (_option?: Parameters[0]) => (_art: Artplayer) => document.createElement('canvas'); void replacement;", + "historical": [], + "current": [ + { + "file": "test/types/consumer.ts", + "code": 2741, + "line": 1, + "message": "Property 'default' is missing in type '(_option?: Parameters[0]) => (_art: Artplayer) => HTMLCanvasElement' but required in type 'Factory'." + } + ] + }, + { + "name": "artplayer-plugin-ambilight", + "version": "1.1.0", + "source": "import Artplayer from 'artplayer'; import plugin from 'artplayer-plugin-ambilight'; const replacement: typeof plugin = (_option?: Parameters[0]) => (_art: Artplayer) => ({ name: 'artplayerPluginAmbilight' as const, start() {}, stop() {} }); void replacement;", + "historical": [], + "current": [ + { + "file": "test/types/consumer.ts", + "code": 2741, + "line": 1, + "message": "Property 'default' is missing in type '(_option?: Option | undefined) => (_art: Artplayer) => { name: \"artplayerPluginAmbilight\"; start(): void; stop(): void; }' but required in type 'Factory'." + } + ] + } + ], + "introducedBy": "PKG-DPIP-04", + "followup": "PKG-FACTORY-01", + "scope": "Exact supplied consumer source passes actual published declarations and fails current declarations with missing required default property. Historical declaration bytes are frozen by each package release baseline." +} diff --git a/refactor/changes/2026-09-12-PKG-DPIP-04-types.md b/refactor/changes/2026-09-12-PKG-DPIP-04-types.md new file mode 100644 index 000000000..a92f0e37f --- /dev/null +++ b/refactor/changes/2026-09-12-PKG-DPIP-04-types.md @@ -0,0 +1,48 @@ +# PKG-DPIP-04 公开类型与两代导出 + +公开命名类型统一Option、Result、AsyncResult、Factory、RuntimeFactory。默认Result保留 +可写boolean与void动作,不改变旧调用直接推导的返回值、initializer可赋值性或 +ReturnType结果;默认工厂保持完整的必填参数函数形状,包括typeof工厂的替换赋值和 +Parameters必填tuple。RuntimeFactory显式描述省略options、self.default与AsyncResult。 +不能简单把旧void动作改成Promise,因为用户可以 +合法创建Result或覆盖方法为`() => {}`。AsyncResult供未修改的实际结果显式断言, +准确描述readonly getter和Promise动作;生产入口也用此类型检查实现。 +这是兼容视图与精确视图并存,不把Ads的推导修正授权用于此插件。 + +main/legacy的.default自别名兼容1.0.1/1.0.2 namespace.default与1.1.0直接工厂。 +ESM仍只有default运行时出口。新增.d.mts/.d.cts和import/require条件声明,typesVersions +保持旧编译器legacy解析。编辑器声明由语义生成器更新,README/ARCHITECTURE解释 +真实异步语义、默认旧推导及何时用AsyncResult。声明仅增加类型出口,不增加运行时API。 + +四组专项验证五个编译器/模块模式、14项非法用法、四份实际发布声明、生成全局声明 +以及实际三格式出口。历史源码/声明用例能创建Result、替换open/close及整个工厂;候选也必须 +继续编译,不能只验证readonly精确视图而漏掉这类合法旧代码。 + +仓库外真实安装矩阵共27场景(四发布×5 + 候选7),都经过offline安装、frozen重装、 +完整归档成员哈希核对,确认不是workspace链接,类型解析不得逃逸到仓库。候选7场景 +和历史12场景零诊断;另外8个精确历史失败: + +- 1.0.0:NodeNext CJS/ESM和bundler均2307。运行时require另验证MODULE_NOT_FOUND, + 不用Git代码补齐缺失归档。旧node解析还能找到types,与现代exports失败分开记录。 +- 1.0.1:同三种现代解析均7016;声明在tarball里,但exports中没有对应类型路径。 +- 1.0.2和1.1.0:NodeNext ESM各7个精确诊断,顺序为 + 2322/2344/2349/2349/2344/2344/2349,默认导入被解释成不可调用的CJS namespace, + 连带Parameters/ReturnType错误。其他所测模式保持正常。 + +候选每种模式均拒绝14项非法用法;历史负例不是8项候选豁免,27场景也不代表全零错误。 +首次安装遇到1.0.0现代解析2307,第二次进一步观察到1.0.2的Parameters赋值never产生 +额外2322;两份中间诊断完整保留,最终检查用精确版本/模式/诊断列表,不接受任意错误。 + +额外反向赋值审查复现了首版声明的2741:为默认工厂增加必需.default类型属性,会让 +旧的普通替换函数无法赋值;仅保留末重载的Parameters还不够。最终默认声明改为旧的 +完整必填函数形状,精确/可选调用只通过显式RuntimeFactory视图提供。CommonJS声明 +保留旧import=模块.default访问,ESM声明单独指定默认可调用类型以避免namespace错误。 +运行时仍同时支持直接require与.default。此项没有请求用户接受类型破坏。 + +结果与哈希见[证据](../baselines/dpip-types-validation.json),维护说明见[入口](../dpip-validation.md)。 +05原生文档窗口/设备/代理组合和06完整分发/demo仍继续;不推送、发布或升级版本。 +回退需要同时回退types、条件入口、运行时.default和对应生成产物,保留历史归档。 + +横向复查也证明Canvas/Ambilight的实际发布声明接受旧工厂替换,而当前声明各出现2741。新增PKG-FACTORY-01紧接本任务修复,并加入两包05与REL-01依赖;FACTORY-TYPE-01保持open,复现源码与结果见baselines/factory-assignment-gaps.json。此前完成记录保留为历史检查点,不冒充此新用法已通过。 + +最终四组专项、编辑器/三格式构建、27安装场景(19零诊断+8精确历史失败)及最终main哈希对应的18浏览器通过。完整CI1140项(1006单元+14工程+120基线),另44重复契约、290生产TS严格检查通过。任务done并独立提交;下一步PKG-FACTORY-01,DPIP05/06继续。 diff --git a/refactor/dpip-validation.md b/refactor/dpip-validation.md index 2f0678776..a05ecae74 100644 --- a/refactor/dpip-validation.md +++ b/refactor/dpip-validation.md @@ -42,3 +42,16 @@ test/helpers/dpip.js是受控DOM/window边界:验证ownerDocument、节点身 选择明确构建文件(不fallback);最终产物证据与宽矩阵历史证据分开保存。 本阶段保留原生窗口和媒体/代理验收门槛,详见[03记录](changes/2026-09-12-PKG-DPIP-03-lifecycle.md) 及[03证据](baselines/dpip-lifecycle-validation.json)。04继续公开类型/导出/安装消费者。 + +## 公开类型和真实安装(04) + +`node --test refactor/scripts/dpip-types.test.mjs`验证默认Result旧推导、显式AsyncResult、 +完整旧工厂形状、四历史声明、编辑器与实际产物。合法旧工厂/initializer和 +void方法替换必须继续编译;RuntimeFactory显式提供可选options和精确返回,不改变默认 +函数的反向可赋值性。14项非法用法在五个仓库 +编译模式及七个安装消费者模式均需被拒绝。 +`yarn test:dpip-types-package`在仓库外安装四实际发布和候选,offline/frozen重装并逐文件 +校验字节。27模式包含8历史失败:1.0.0现代解析三项2307、1.0.1三项7016、1.0.2和 +1.1.0各一项NodeNext ESM七诊断;候选7项全部零诊断。1.0.0的require必须复现缺失运行时, +不能称作可执行版本。详见[04记录](changes/2026-09-12-PKG-DPIP-04-types.md)和 +[04证据](baselines/dpip-types-validation.json)。05/06的原生设备、demo和分发门槛保留。 diff --git a/refactor/fixtures/consumers/dpip-published.ts b/refactor/fixtures/consumers/dpip-published.ts new file mode 100644 index 000000000..3f48ffd80 --- /dev/null +++ b/refactor/fixtures/consumers/dpip-published.ts @@ -0,0 +1,16 @@ +import Artplayer from 'artplayer' +import dpip from 'artplayer-plugin-document-pip' + +const options: Parameters[0] = { width: 640, height: 360, placeholder: 'Active', fallbackToVideoPiP: true } +const art = new Artplayer({ container: '#player', url: 'video.mp4', plugins: [dpip(options)] }) +const result = dpip(options)(art) +const returned: void = result.open() +result.open = () => {} +result.close = () => {} +const fake: ReturnType> = { name: 'artplayerPluginDocumentPip', isSupported: true, isActive: false, open() {}, close() {}, toggle() {} } +fake.isActive = true +fake.isSupported = false +const initializer: ReturnType = () => fake +const inferredInitializer = dpip(options) +const oldReplacement: typeof inferredInitializer = () => fake +void [returned, initializer, inferredInitializer, oldReplacement] diff --git a/refactor/plan.md b/refactor/plan.md index 745e3da44..d9c8bcb7f 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -2,9 +2,9 @@ > 由 tasks.json 生成。请修改数据后运行 `node refactor/scripts/plan.mjs --write`,不要手改本表。 -基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 221 项,范围 22 个包及工作区/示例。 +基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 222 项,范围 22 个包及工作区/示例。 -状态:todo 119 / doing 6 / blocked 0 / done 96 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 119 / doing 6 / blocked 0 / done 97 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -16,7 +16,7 @@ | --- | --- | --- | | artplayer | 5.4.1 | CORE-01, CORE-02, CORE-03, CORE-04, CORE-05, CORE-06, CORE-07, CORE-08, CORE-09, CORE-10, CORE-11, CORE-12, CORE-13, CORE-14, CORE-15, CORE-16, CORE-17, CORE-18, CORE-19, CORE-20, CORE-21, CORE-23, CORE-22, CORE-24 | | artplayer-plugin-ads | 2.1.0 | PKG-ADS-01, PKG-ADS-02, PKG-ADS-03, PKG-ADS-04, PKG-ADS-05, PKG-ADS-06 | -| artplayer-plugin-ambilight | 1.1.0 | PKG-AMBILIGHT-01, PKG-AMBILIGHT-02, PKG-AMBILIGHT-03, PKG-AMBILIGHT-04, PKG-AMBILIGHT-PROXY-01, PKG-AMBILIGHT-05, PKG-AMBILIGHT-06 | +| artplayer-plugin-ambilight | 1.1.0 | PKG-AMBILIGHT-01, PKG-AMBILIGHT-02, PKG-AMBILIGHT-03, PKG-AMBILIGHT-04, PKG-AMBILIGHT-PROXY-01, PKG-AMBILIGHT-05, PKG-AMBILIGHT-06, PKG-FACTORY-01 | | artplayer-plugin-asr | 2.1.0 | PKG-ASR-01, PKG-ASR-02, PKG-ASR-03, PKG-ASR-04, PKG-ASR-05, PKG-ASR-06 | | artplayer-plugin-audio-track | 1.1.0 | PKG-AUDIO-01, PKG-AUDIO-02, PKG-AUDIO-03, PKG-AUDIO-04, PKG-AUDIO-05, PKG-AUDIO-06 | | artplayer-plugin-auto-thumbnail | 1.1.0 | PKG-AUTO-THUMB-01, PKG-AUTO-THUMB-02, PKG-AUTO-THUMB-03, PKG-AUTO-THUMB-04, PKG-AUTO-THUMB-05, PKG-AUTO-THUMB-06 | @@ -31,7 +31,7 @@ | artplayer-plugin-multiple-subtitles | 1.2.0 | PKG-MULTI-SUB-01, PKG-MULTI-SUB-02, PKG-MULTI-SUB-03, PKG-MULTI-SUB-04, PKG-MULTI-SUB-05, PKG-MULTI-SUB-06 | | artplayer-plugin-vast | 1.2.0 | PKG-VAST-01, PKG-VAST-02, PKG-VAST-03, PKG-VAST-04, PKG-VAST-05, PKG-VAST-06 | | artplayer-plugin-vtt-thumbnail | 1.1.0 | PKG-VTT-THUMB-01, PKG-VTT-THUMB-02, PKG-VTT-THUMB-03, PKG-VTT-THUMB-04, PKG-VTT-THUMB-05, PKG-VTT-THUMB-06 | -| artplayer-proxy-canvas | 1.1.0 | PKG-AMBILIGHT-PROXY-01, PKG-CANVAS-01, PKG-CANVAS-02, PKG-CANVAS-03, PKG-CANVAS-04, PKG-CANVAS-05, PKG-CANVAS-06 | +| artplayer-proxy-canvas | 1.1.0 | PKG-AMBILIGHT-PROXY-01, PKG-CANVAS-01, PKG-CANVAS-02, PKG-CANVAS-03, PKG-CANVAS-04, PKG-CANVAS-05, PKG-CANVAS-06, PKG-FACTORY-01 | | artplayer-proxy-mediabunny | 1.2.0 | PKG-MB-01, PKG-MB-02, PKG-MB-03, PKG-MB-04, PKG-MB-05, PKG-MB-06, PKG-MB-07, PKG-MB-08, PKG-MB-09, PKG-MB-10 | | artplayer-tool-iframe | 1.1.0 | PKG-IFRAME-01, PKG-IFRAME-02, PKG-IFRAME-03, PKG-IFRAME-04, PKG-IFRAME-05, PKG-IFRAME-06 | | artplayer-tool-thumbnail | 4.4.0 | PKG-TOOL-THUMB-01, PKG-TOOL-THUMB-02, PKG-TOOL-THUMB-03, PKG-TOOL-THUMB-04, PKG-TOOL-THUMB-05, PKG-TOOL-THUMB-06 | @@ -153,7 +153,7 @@ | PKG-AMBILIGHT-03 | artplayer-plugin-ambilight
整理内部职责与资源 | PKG-AMBILIGHT-02, CORE-03, CORE-12 | 取色计算与绘帧分离,统一 RAF 和 DOM 清理 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | M | done | | PKG-AMBILIGHT-04 | artplayer-plugin-ambilight
迁移自有源码和公开类型 | PKG-AMBILIGHT-03, ENG-04, ENG-06, CORE-07 | canvas 上下文、参数及 start/stop 的明确类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | M | done | | PKG-AMBILIGHT-PROXY-01 | artplayer-plugin-ambilight, artplayer-proxy-canvas
修复Canvas代理输出尺寸与取色区域 | PKG-AMBILIGHT-04, CORE-22 | 按Canvas实际输出buffer取色,原生video保留intrinsic尺寸,明确5.1.7没有proxy配置 | 旧错误复现、三引擎实际代理九色区域对照及原生视频回归通过;不把本子项当作最终代理/设备验收 | M | done | -| PKG-AMBILIGHT-05 | artplayer-plugin-ambilight
验证新旧核心和组合 | PKG-AMBILIGHT-04, CORE-22, PKG-AMBILIGHT-PROXY-01, PKG-CANVAS-04 | 原生 video、canvas proxy 的能力边界及销毁无帧循环 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | M | todo | +| PKG-AMBILIGHT-05 | artplayer-plugin-ambilight
验证新旧核心和组合 | PKG-AMBILIGHT-04, CORE-22, PKG-AMBILIGHT-PROXY-01, PKG-CANVAS-04, PKG-FACTORY-01 | 原生 video、canvas proxy 的能力边界及销毁无帧循环 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | M | todo | | PKG-AMBILIGHT-06 | artplayer-plugin-ambilight
验证分发并同步文档 | PKG-AMBILIGHT-05, ENG-07 | ambilight.js 示例及样式/分发验证 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | M | todo | ## 5 包迁移:artplayer-plugin-audio-track @@ -296,7 +296,7 @@ | PKG-DPIP-01 | artplayer-plugin-document-pip
核对包契约与历史用法 | BASE-05 | width/height/placeholder/fallbackToVideoPiP、open/close/toggle 返回 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done | | PKG-DPIP-02 | artplayer-plugin-document-pip
建立特有行为与错误测试 | PKG-DPIP-01, ENG-03, ENG-05 | 不支持/拒绝、重复打开、pagehide、核心销毁和视频 PiP fallback | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done | | PKG-DPIP-03 | artplayer-plugin-document-pip
整理内部职责与资源 | PKG-DPIP-02, CORE-16, CORE-17 | 窗口生命周期、DOM 迁移、样式与事件 document 重绑分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done | -| PKG-DPIP-04 | artplayer-plugin-document-pip
迁移自有源码和公开类型 | PKG-DPIP-03, ENG-04, ENG-06, CORE-07 | Document PiP 可选能力和真实状态/返回类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-DPIP-04 | artplayer-plugin-document-pip
迁移自有源码和公开类型 | PKG-DPIP-03, ENG-04, ENG-06, CORE-07 | Document PiP 可选能力和真实状态/返回类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done | | PKG-DPIP-05 | artplayer-plugin-document-pip
验证新旧核心和组合 | PKG-DPIP-04, CORE-22, PKG-CANVAS-04, PKG-MB-04 | 原生视频及两个 proxy、键盘/焦点/全屏与关闭还原 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | | PKG-DPIP-06 | artplayer-plugin-document-pip
验证分发并同步文档 | PKG-DPIP-05, ENG-07 | document.pip.js、浏览器能力矩阵、旧接口与恢复证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | @@ -322,7 +322,7 @@ | PKG-CANVAS-02 | artplayer-proxy-canvas
建立特有行为与错误测试 | PKG-CANVAS-01, ENG-03, ENG-05 | ready/loadeddata/canplay、play/seek、回调、resize 与销毁 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done | | PKG-CANVAS-03 | artplayer-proxy-canvas
整理内部职责与资源 | PKG-CANVAS-02, CORE-06, CORE-11, CORE-16 | video adapter/原 canvas 方法/RAF 绘制/事件订阅分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done | | PKG-CANVAS-04 | artplayer-proxy-canvas
迁移自有源码和公开类型 | PKG-CANVAS-03, ENG-04, ENG-06, CORE-07 | canvas 与媒体能力的精确组合类型,保持 Result | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done | -| PKG-CANVAS-05 | artplayer-proxy-canvas
验证新旧核心和组合 | PKG-CANVAS-04, CORE-22, PKG-DPIP-04 | 真实 video/canvas 绘制、字幕和 document PiP 恢复 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-CANVAS-05 | artplayer-proxy-canvas
验证新旧核心和组合 | PKG-CANVAS-04, CORE-22, PKG-DPIP-04, PKG-FACTORY-01 | 真实 video/canvas 绘制、字幕和 document PiP 恢复 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | | PKG-CANVAS-06 | artplayer-proxy-canvas
验证分发并同步文档 | PKG-CANVAS-05, ENG-07 | canvas.js、三种产物、调用兼容与资源证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | ## 5 包迁移:artplayer-proxy-mediabunny @@ -391,7 +391,7 @@ | ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | | --- | --- | --- | --- | --- | --- | --- | | REL-08 | workspace
提前建立逐包发布准入台账 | BASE-08, ENG-07 | 每批包/版本/源码/锁文件/工具/tarball integrity、必需测试/设备证据、限制和回退映射 | 受影响能力缺证据明确阻止对应批次;无关批次可独立准备,旧证据在候选内容变化后失效;站点采用真实构建/URL/资源验收,npm 分发依据历史核实,不从版本清单推断新增发布范围;关联 risks.json 和 third-party.json;受影响 bundle/worker/WASM/font/模型的来源与许可通知缺口必须有审查结论,未决项阻止对应批次 | H | todo | -| REL-01 | workspace
提前确定分包版本与差异方案 | REL-08, CORE-21, SITE-03, PKG-CHAPTER-04, PKG-AMBILIGHT-04, PKG-AUDIO-04, PKG-AUTO-THUMB-04, PKG-VTT-THUMB-04, PKG-HLS-04, PKG-DASH-04, PKG-MULTI-SUB-04, PKG-JASSUB-04, PKG-MASK-04, PKG-ASR-04, PKG-ADS-04, PKG-VAST-04, PKG-CAST-04, PKG-DPIP-04, PKG-CANVAS-04, PKG-IFRAME-04, PKG-TOOL-THUMB-04, PKG-DANMUKU-06, PKG-MB-08 | 每包版本/变更日志/依赖/类型差异方案和独立准入状态;按 version-policy.md 冻结各包下一 major(minor/patch 归零)并核实 registry 占用 | 所有包有方案和剩余门槛,未决项明确阻止相应发布;本步骤不声称已经可发布;全部包有 major 目标,版本冲突明确处理,独立准备任务同步 manifest/锁/依赖/日志;按 BASE-05 区分 21 库与文档站分发,不机械把文档站当库上传 npm | H | todo | +| REL-01 | workspace
提前确定分包版本与差异方案 | REL-08, CORE-21, SITE-03, PKG-CHAPTER-04, PKG-AMBILIGHT-04, PKG-AUDIO-04, PKG-AUTO-THUMB-04, PKG-VTT-THUMB-04, PKG-HLS-04, PKG-DASH-04, PKG-MULTI-SUB-04, PKG-JASSUB-04, PKG-MASK-04, PKG-ASR-04, PKG-ADS-04, PKG-VAST-04, PKG-CAST-04, PKG-DPIP-04, PKG-CANVAS-04, PKG-IFRAME-04, PKG-TOOL-THUMB-04, PKG-DANMUKU-06, PKG-MB-08, PKG-FACTORY-01 | 每包版本/变更日志/依赖/类型差异方案和独立准入状态;按 version-policy.md 冻结各包下一 major(minor/patch 归零)并核实 registry 占用 | 所有包有方案和剩余门槛,未决项明确阻止相应发布;本步骤不声称已经可发布;全部包有 major 目标,版本冲突明确处理,独立准备任务同步 manifest/锁/依赖/日志;按 BASE-05 区分 21 库与文档站分发,不机械把文档站当库上传 npm | H | todo | | REL-09 | workspace
落实全包下一 major 版本及依赖元数据 | REL-01, DOC-11 | 22 包版本目标落实、适用锁文件/依赖范围/示例/变更日志同步,核实 registry 版本占用 | 版本与 policy 一致,旧核心支持保留;必要拆子任务各自提交,候选构建前完成,不执行 publish | H | todo | | REL-02 | workspace
生成候选 tarball 并验证新旧组合 | REL-01, CORE-22, ENG-07, REL-09 | 各候选本地 tarball/integrity 与新旧核心/插件消费者验证报告,外部门槛单独标注 | 隔离安装和可自动化组合通过;设备结论不伪造,最终发布绑定同一候选内容;在目标 major 版本确定后构建 pack,不在测试后改版本 | H | todo | | REL-03 | workspace
完成真机、外部 SDK 与压力验收 | REL-02, EX-03, SITE-06, MOD-05 | Safari/移动/PiP/Cast/IMA/模型/长播放完整报告 | 包集成与全项目真机/SDK/压力结论齐全才完成本汇总;独立批次先建立自己的完整门槛子任务 | H | todo | @@ -408,6 +408,12 @@ | REVIEW-02 | workspace
第二轮真实浏览器与生态集成复盘 | REVIEW-01, REL-03 | Chrome 交互、自动浏览器、新旧组合、真机/SDK/性能/资源的全范围报告 | 所需环境证据齐全,前轮修复再次核对;本轮阻断项关闭,无关 mock 不替代真实验收 | H | todo | | REVIEW-03 | workspace
第三轮 npm 候选内容与发布准备复盘 | REVIEW-02, REL-04, CI-04 | 实际候选 integrity、干净安装构建/消费者、入口/许可/版本/tag/回退及前轮证据汇总 | 最终候选完整检查通过,发布阻断项为零;准备可审阅的批次报告,不自动执行 publish;逐包核对 major 目标,不能用大版本豁免旧 API 兼容 | H | todo | +## 5 工厂类型兼容补审 + +| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| PKG-FACTORY-01 | artplayer-proxy-canvas, artplayer-plugin-ambilight
修复已迁移工厂的反向赋值兼容 | PKG-CANVAS-04, PKG-AMBILIGHT-04, PKG-DPIP-04 | 复现两包旧typeof工厂替换与新.default/可选重载冲突,修复公开类型并补安装消费者、产物和文档 | 默认工厂的历史合法反向赋值继续通过;既有类型/运行时导出逐版本核对,不能只验证Parameters或直接调用 | H | todo | + ## 完成证据与阻塞 - DOC-01: [记录](progress.md) @@ -509,7 +515,9 @@ - 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-DPIP-02: [记录](changes/2026-09-12-PKG-DPIP-02-tests.md) [记录](baselines/dpip-behavior-validation.json) [记录](dpip-validation.md) - PKG-DPIP-03: [记录](changes/2026-09-12-PKG-DPIP-03-lifecycle.md) [记录](baselines/dpip-lifecycle-validation.json) [记录](dpip-validation.md) +- PKG-DPIP-04: [记录](changes/2026-09-12-PKG-DPIP-04-types.md) [记录](baselines/dpip-types-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) - PKG-CANVAS-04: [记录](changes/2026-09-12-PKG-CANVAS-04-types.md) [记录](baselines/canvas-types-validation.json) [记录](canvas-validation.md) +- PKG-FACTORY-01: [记录](baselines/factory-assignment-gaps.json) diff --git a/refactor/progress.md b/refactor/progress.md index 5f4a1e63a..64b7aa719 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,16 @@ # 进度与证据 +## 最新完成:Document PiP-04 类型、工厂赋值与导出兼容 + +默认工厂完整保留旧必填签名与可替换性;Result保持void/可写字段,显式RuntimeFactory +和AsyncResult描述实际可选调用、self.default和异步只读状态。27安装场景含候选7及历史 +12零诊断,另8个精确历史错误对照;1.0.0缺运行时单独保留。四组专项、三格式/编辑器 +构建、最终main哈希对应的18浏览器检查与完整CI1140项通过,另44重复契约,290生产TS。 +横向复查确认Canvas/Ambilight也有旧工厂替换2741,新增PKG-FACTORY-01紧接修复,并 +加入两包05及REL-01依赖;该风险保持open。当前222项:97 done、6 doing、119 todo。 +见[本步记录](changes/2026-09-12-PKG-DPIP-04-types.md)和[证据](baselines/dpip-types-validation.json)。 +Document PiP原生组合05与完整demo/分发06仍未完成;独立本地提交,无推送/发布。 + ## 最新完成:Document PiP-03 严格TS与窗口资源修复 6个模块分离窗口申请/终态、DOM还原、样式、控件与延迟资源。20候选用例在旧源码 diff --git a/refactor/risk-table.md b/refactor/risk-table.md index 2e17cf6b4..e227a4559 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -160,9 +160,11 @@ | 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-DIST-01 | resolved / 已复现 | 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 | resolved / 已复现 | 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 | | DPIP-STYLE-01 | resolved / 已复现 | Document PiP 1.1.0 and frozen source duplicate style IDs when evaluated before DOMContentLoaded | PKG-DPIP-03 | | DPIP-MEDIA-01 | open / 已复现 | WebKit reports styled width640 for width320 media in the controlled Document PiP iframe matrix | PKG-DPIP-05 | +| DPIP-RESOLVE-01 | resolved / 已复现 | Historical Document PiP exports hide declarations or infer an uncallable CommonJS namespace in modern resolution | PKG-DPIP-04, PKG-DPIP-06 | +| FACTORY-TYPE-01 | open / 已复现 | Canvas and Ambilight default self property narrows assignability of historical factory replacements | PKG-FACTORY-01 | diff --git a/refactor/risks.json b/refactor/risks.json index e44677170..f3f119d8c 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -3460,12 +3460,19 @@ ], "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", + "status": "resolved", "evidence": [ "refactor/baselines/dpip-release.json", "refactor/baselines/dpip-contract.md", - "refactor/changes/2026-09-12-PKG-DPIP-01-contract.md" - ] + "refactor/changes/2026-09-12-PKG-DPIP-01-contract.md", + "refactor/changes/2026-09-12-PKG-DPIP-04-types.md", + "refactor/baselines/dpip-types-validation.json" + ], + "resolutionEvidence": [ + "refactor/changes/2026-09-12-PKG-DPIP-04-types.md", + "refactor/baselines/dpip-types-validation.json" + ], + "resolutionRationale": "Actual main/legacy/global/ESM and real isolated installed root/legacy consumers verify direct callable and self default identities. Conditional declaration wrappers and old resolver legacy mapping are verified; full demo/archive and device scopes remain tasks05/06." }, { "id": "DPIP-TYPE-01", @@ -3476,12 +3483,19 @@ ], "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", + "status": "resolved", "evidence": [ "refactor/baselines/dpip-release.json", "refactor/baselines/dpip-contract.md", - "refactor/changes/2026-09-12-PKG-DPIP-01-contract.md" - ] + "refactor/changes/2026-09-12-PKG-DPIP-01-contract.md", + "refactor/changes/2026-09-12-PKG-DPIP-04-types.md", + "refactor/baselines/dpip-types-validation.json" + ], + "resolutionEvidence": [ + "refactor/changes/2026-09-12-PKG-DPIP-04-types.md", + "refactor/baselines/dpip-types-validation.json" + ], + "resolutionRationale": "Exact required default factory signature and direct/extracted Result remain assignable, including whole-factory replacements. Named AsyncResult and RuntimeFactory describe unmodified runtime values explicitly. Historical import= module.default access is preserved by CJS declarations; source checks its precise result." }, { "id": "DPIP-LIFE-01", @@ -3566,6 +3580,42 @@ "refactor/changes/2026-09-12-PKG-DPIP-02-tests.md", "refactor/baselines/dpip-behavior-validation.json" ] + }, + { + "id": "DPIP-RESOLVE-01", + "title": "Historical Document PiP exports hide declarations or infer an uncallable CommonJS namespace in modern resolution", + "status": "resolved", + "confirmation": "reproduced", + "owners": [ + "PKG-DPIP-04", + "PKG-DPIP-06" + ], + "compatibleResolution": "Use format-specific declaration wrappers and explicit types conditions while preserving old resolver paths and exact historical negative controls.", + "closureCriteria": "All candidate installed modes compile with exact invalid-use rejection; each historical missing type/default namespace failure stays recorded by version and mode.", + "evidence": [ + "refactor/changes/2026-09-12-PKG-DPIP-04-types.md", + "refactor/baselines/dpip-types-validation.json" + ], + "resolutionEvidence": [ + "refactor/changes/2026-09-12-PKG-DPIP-04-types.md", + "refactor/baselines/dpip-types-validation.json" + ], + "resolutionRationale": "27 isolated installed modes preserve eight exact historical failure cases; all seven candidate modes and twelve historical modes are zero-diagnostic. Published1.0.0 runtime absence is retained separately, not fixed in place." + }, + { + "id": "FACTORY-TYPE-01", + "title": "Canvas and Ambilight default self property narrows assignability of historical factory replacements", + "status": "open", + "confirmation": "reproduced", + "owners": [ + "PKG-FACTORY-01" + ], + "compatibleResolution": "Preserve historical complete factory assignments while modeling actual export variants explicitly; do not equate unchanged Parameters with complete callable compatibility.", + "closureCriteria": "Both historical and candidate replacement fixtures, all supported export/declaration paths and installed consumers verified; unresolved variant conflicts require an explicit decision rather than silent narrowing.", + "evidence": [ + "refactor/baselines/factory-assignment-gaps.json", + "refactor/changes/2026-09-12-PKG-DPIP-04-types.md" + ] } ] } diff --git a/refactor/scripts/dpip-package-types.mjs b/refactor/scripts/dpip-package-types.mjs new file mode 100644 index 000000000..1367f0814 --- /dev/null +++ b/refactor/scripts/dpip-package-types.mjs @@ -0,0 +1,114 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import path from 'node:path' +import process from 'node:process' +import ts from 'typescript' +import compat from 'typescript-compat' +import { checkFiles, packedFiles } from '../../scripts/package-check.mjs' +import { consumerDirectory, removeConsumer, run, workspace, writeJson } from '../../scripts/package-consumer.mjs' +import { verifyDpipContract } from './dpip-contract.mjs' +import { hash, readMember } from './releases.mjs' + +async function main() { + assert.equal(process.env.npm_config_user_agent?.split(' ')[0], 'yarn/1.22.22', 'Use yarn test:dpip-types-package') + const yarn = process.env.npm_execpath + assert(yarn && fs.existsSync(yarn)) + const output = fs.mkdtempSync(path.join(workspace, 'refactor/.cache/dpip-package-types-')) + console.log(`Document PiP isolated package evidence: ${output}`) + const contract = await verifyDpipContract() + const packages = [] + for (const name of ['artplayer', 'artplayer-plugin-document-pip']) { + const archive = path.join(output, `${name}.tgz`) + fs.writeFileSync(path.join(output, `${name}-pack.log`), run([yarn, 'pack', '--filename', archive], path.join(workspace, 'packages', name))) + const manifest = JSON.parse(readMember(archive, 'package/package.json')) + const files = packedFiles(archive) + checkFiles(manifest, files, name === contract.baseline.release.name ? Object.keys(contract.baseline.release.files) : []) + packages.push({ name, archive, sha256: hash(fs.readFileSync(archive)), files: Object.fromEntries(files.map(member => [member, hash(readMember(archive, member))])) }) + } + const matrix = [] + const core = packages[0] + const candidates = [ + ...[...contract.baseline.previous].reverse().concat(contract.baseline.release).map(release => ({ ...release, archive: contract.archives.get(release.version), label: `published-${release.version}` })), + { ...packages[1], label: 'candidate' }, + ] + for (const plugin of candidates) { + const consumer = consumerDirectory() + try { + writeJson(path.join(consumer, 'package.json'), { name: 'dpip-isolated-consumer', private: true, dependencies: Object.fromEntries([core, plugin].map(pkg => [pkg.name, `file:${pkg.archive.replaceAll('\\', '/')}`])) }) + fs.copyFileSync(path.join(workspace, 'yarn.lock'), path.join(consumer, 'yarn.lock')) + fs.writeFileSync(path.join(output, `${plugin.label}-install.log`), run([yarn, 'install', '--offline', '--ignore-scripts', '--non-interactive'], consumer)) + const lock = fs.readFileSync(path.join(consumer, 'yarn.lock')) + fs.writeFileSync(path.join(output, `${plugin.label}-frozen-install.log`), run([yarn, 'install', '--offline', '--frozen-lockfile', '--ignore-scripts', '--non-interactive'], consumer)) + assert.deepEqual(fs.readFileSync(path.join(consumer, 'yarn.lock')), lock) + fs.writeFileSync(path.join(output, `${plugin.label}-yarn.lock`), lock) + for (const pkg of [core, plugin]) { + const root = path.join(consumer, 'node_modules', pkg.name) + assert.equal(fs.realpathSync(root), root, 'Installed package must not be a workspace link') + for (const [member, expected] of Object.entries(pkg.files)) + assert.equal(hash(fs.readFileSync(path.join(root, member.slice(8)))), expected, `Installed bytes differ: ${member}`) + } + const runtimeFile = path.join(consumer, 'exports.cjs') + fs.writeFileSync(runtimeFile, plugin.label === 'candidate' + ? `const assert = require('node:assert/strict'); +for (const name of ['artplayer-plugin-document-pip', 'artplayer-plugin-document-pip/legacy']) { const factory = require(name); assert.equal(typeof factory, 'function'); assert.equal(factory.default, factory); assert.equal(typeof factory(), 'function'); } +import('artplayer-plugin-document-pip').then(module => { assert.deepEqual(Object.keys(module), ['default']); assert.equal(module.default.default, module.default); }).catch(error => { console.error(error); process.exitCode = 1; });` + : plugin.version === '1.0.0' + ? `const assert = require('node:assert/strict'); assert.throws(() => require('artplayer-plugin-document-pip'), error => error.code === 'MODULE_NOT_FOUND' && error.message.includes('artplayer-plugin-document-pip')); console.log('Expected historical 1.0.0 missing runtime preserved');` + : `const assert = require('node:assert/strict'); const value = require('artplayer-plugin-document-pip'); assert.equal(typeof value, '${plugin.version === '1.1.0' ? 'function' : 'object'}'); assert.equal(typeof (value.default || value)({}), 'function');`) + fs.writeFileSync(path.join(output, `${plugin.label}-runtime.log`), run([runtimeFile], consumer)) + const modes = [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']] + if (plugin.label === 'candidate') + modes.push([ts, 'node10-commonjs-no-interop'], [compat, 'node10-commonjs-no-interop']) + for (const [compiler, mode] of modes) { + const next = mode.startsWith('nodenext') + const extension = next ? mode.endsWith('-cjs') ? 'cts' : 'mts' : 'ts' + const source = fs.readFileSync(path.join(workspace, plugin.label === 'candidate' ? 'test/types/dpip.ts' : 'refactor/fixtures/consumers/dpip-published.ts'), 'utf8') + const filename = path.join(consumer, `consumer.${extension}`) + const historical = path.join(consumer, `historical.${extension}`) + fs.copyFileSync(path.join(workspace, 'refactor/fixtures/consumers/dpip-published.ts'), historical) + const files = plugin.label === 'candidate' ? [filename, historical] : [filename] + if (mode === 'nodenext-cjs' && plugin.label === 'candidate') { + const commonjs = path.join(consumer, 'commonjs.cts') + fs.writeFileSync(commonjs, `import dpip = require('artplayer-plugin-document-pip'); import legacy = require('artplayer-plugin-document-pip/legacy'); dpip.default({ width: 640 }); legacy.default({});`) + files.push(commonjs) + } + const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], esModuleInterop: !mode.endsWith('-no-interop'), target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: next ? compiler.ModuleKind.NodeNext : mode === 'bundler-esm' ? compiler.ModuleKind.ESNext : compiler.ModuleKind.CommonJS, moduleResolution: next ? compiler.ModuleResolutionKind.NodeNext : mode === 'bundler-esm' ? compiler.ModuleResolutionKind.Bundler : compiler.ModuleResolutionKind.NodeJs } + function compile(code) { + fs.writeFileSync(filename, code) + const program = compiler.createProgram(files, options) + for (const file of program.getSourceFiles()) { + const actual = fs.realpathSync(file.fileName) + assert(actual.startsWith(fs.realpathSync(consumer) + path.sep) || (program.isSourceFileDefaultLibrary(file) && path.dirname(actual) === fs.realpathSync(path.dirname(compiler.sys.getExecutingFilePath()))), `Types escaped installed consumer: ${actual}`) + } + return compiler.getPreEmitDiagnostics(program).map(item => ({ code: item.code, message: compiler.flattenDiagnosticMessageText(item.messageText, '\n') })) + } + const diagnostics = compile(source) + const modernResolution = next || mode === 'bundler-esm' + const expected = plugin.label === 'published-1.0.0' && modernResolution + ? [2307] + : plugin.label === 'published-1.0.1' && modernResolution + ? [7016] + : ['published-1.0.2', 'published-1.1.0'].includes(plugin.label) && mode === 'nodenext-esm' + ? [2322, 2344, 2349, 2349, 2344, 2344, 2349] + : [] + const historicalFailure = expected.length !== 0 + writeJson(path.join(output, `${plugin.label}-${compiler.version}-${mode}-diagnostics.json`), { diagnostics, historicalFailure }) + assert.deepEqual(diagnostics.map(item => item.code), expected, `${plugin.label} ${compiler.version} ${mode}`) + const invalid = plugin.label === 'candidate' ? compile(source.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, '')) : [] + if (plugin.label === 'candidate') + assert.equal(invalid.length, 14, 'Installed declarations must reject all invalid uses') + matrix.push({ plugin: plugin.label, compiler: compiler.version, mode, historicalFailure, diagnostics, invalid }) + } + } + finally { + removeConsumer(consumer) + } + } + writeJson(path.join(output, 'report.json'), { suite: 'dpip-isolated-package-types', introducedBy: 'PKG-DPIP-04', scope: 'Four actual published packages and packed candidate installed outside workspace with packed candidate core; offline and frozen reinstall, exact bytes, compiler/default/import= contracts. Candidate keeps required Parameters and assignable void Result while offering opt-in AsyncResult. Published 1.0.0 missing runtime is an explicit negative control; historical NodeNext ESM diagnostics are retained. This is not native Document PiP or complete distribution/device acceptance.', packages, published: candidates.slice(0, 4).map(pkg => ({ label: pkg.label, archive: pkg.archive, sha256: hash(fs.readFileSync(pkg.archive)), missingEntrypoints: pkg.missingEntrypoints })), matrix }) + console.log(`Document PiP installed types passed: ${matrix.length} cases; ${output}`) +} + +main().catch((error) => { + console.error(error) + process.exitCode = 1 +}) diff --git a/refactor/scripts/dpip-types.test.mjs b/refactor/scripts/dpip-types.test.mjs new file mode 100644 index 000000000..571cdb8a6 --- /dev/null +++ b/refactor/scripts/dpip-types.test.mjs @@ -0,0 +1,98 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import path from 'node:path' +// eslint-disable-next-line test/no-import-node-test -- Node compatibility baseline runner. +import test from 'node:test' +import vm from 'node:vm' +import { ESLint } from 'eslint' +import ts from 'typescript' +import compat from 'typescript-compat' +import { checkPluginEditorDeclaration, generatePluginEditorDeclaration } from '../../scripts/plugin-editor-types.mjs' +import { checkConsumer } from '../../scripts/typecheck.mjs' +import { verifyDpipContract } from './dpip-contract.mjs' +import { readMember } from './releases.mjs' + +const modes = [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']] + +test('Document PiP types retain required extraction and assignable void results alongside an opt-in precise view', () => { + const source = fs.readFileSync('test/types/dpip.ts', 'utf8') + for (const [compiler, mode] of modes) { + assert.deepEqual(checkConsumer(compiler, mode, source), [], `${compiler.version} ${mode}`) + assert.equal(checkConsumer(compiler, mode, source.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, '')).length, 14) + } + assert.deepEqual(checkConsumer(ts, 'nodenext-cjs', `import dpip = require('artplayer-plugin-document-pip'); import legacy = require('artplayer-plugin-document-pip/legacy'); +const options: dpip.Option = { width: 640 }; dpip.default(options); legacy.default(options);`), []) +}) + +test('Document PiP all four published declarations accept the same old result replacements and required Parameters', async () => { + const contract = await verifyDpipContract() + const source = fs.readFileSync('refactor/fixtures/consumers/dpip-published.ts', 'utf8') + for (const version of ['1.0.0', '1.0.1', '1.0.2', '1.1.0']) { + const old = readMember(contract.archives.get(version), 'package/types/artplayer-plugin-document-pip.d.ts').toString() + for (const compiler of [ts, compat]) { + const filename = path.resolve('test/types/dpip-history.ts') + const declaration = path.resolve('test/types/dpip-history.d.ts') + function historical(code) { + const host = compiler.createCompilerHost({}) + const original = host.getSourceFile.bind(host) + host.getSourceFile = (file, language, ...rest) => path.resolve(file) === filename + ? compiler.createSourceFile(file, code.replace('from \'artplayer-plugin-document-pip\'', 'from \'./dpip-history\''), language, true) + : path.resolve(file) === declaration ? compiler.createSourceFile(file, old, language, true) : original(file, language, ...rest) + const exists = host.fileExists.bind(host) + host.fileExists = file => path.resolve(file) === declaration || exists(file) + const program = compiler.createProgram([filename, declaration], { strict: true, noEmit: true, skipLibCheck: false, types: [], esModuleInterop: true, module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs, target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'] }, host) + assert(program.getSourceFile(declaration)) + return compiler.getPreEmitDiagnostics(program).map(item => item.code) + } + const replacements = `${source}\nconst replacement: typeof dpip = (_option: Parameters[0]) => (_art: Artplayer) => fake;` + assert.deepEqual(historical(replacements), []) + assert.deepEqual(checkConsumer(compiler, 'node10-commonjs', replacements), []) + assert.deepEqual(historical(`${source}\ndpip();`), [2554]) + assert.deepEqual(historical(`${source}\nconst missing: Parameters[0] = undefined;`), [2322]) + assert.deepEqual(checkConsumer(compiler, 'node10-commonjs', `${source}\ndpip();`).map(item => item.code), [2554]) + assert.deepEqual(checkConsumer(compiler, 'node10-commonjs', `${source}\nconst missing: Parameters[0] = undefined;`).map(item => item.code), [2322]) + } + } +}) + +test('Document PiP editor globals preserve legacy results and explicitly expose readonly async actions', async () => { + const source = fs.readFileSync('packages/artplayer-plugin-document-pip/types/artplayer-plugin-document-pip.d.ts', 'utf8') + const generated = generatePluginEditorDeclaration(source, 'artplayerPluginDocumentPip') + const file = 'docs/assets/ts/artplayer-plugin-document-pip.d.ts' + const [formatted] = await new ESLint({ fix: true, fixTypes: ['layout'] }).lintText(generated, { filePath: file }) + assert.equal(formatted.errorCount, 0) + assert.equal(fs.readFileSync(file, 'utf8').replaceAll('\r\n', '\n'), formatted.output || generated) + const core = fs.readFileSync('docs/assets/ts/artplayer.d.ts', 'utf8') + const consumer = `artplayerPluginDocumentPip({ width: 640 }); +const factory = artplayerPluginDocumentPip as artplayerPluginDocumentPip.RuntimeFactory; factory(); factory.default(); +declare const runtime: artplayerPluginDocumentPip.AsyncResult; +const opening: Promise = runtime.open(); const old: artplayerPluginDocumentPip.Result = runtime; +old.open = () => {}; +// @ts-expect-error Precise runtime capability is readonly. +runtime.isSupported = false; +// @ts-expect-error Dimensions remain numeric. +artplayerPluginDocumentPip({ width: '640' });` + for (const compiler of [ts, compat]) { + assert.deepEqual(checkPluginEditorDeclaration(generated, core, consumer, compiler), []) + assert.equal(checkPluginEditorDeclaration(generated, core, consumer.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, ''), compiler).length, 2) + } +}) + +test('Document PiP production main, legacy, globals and native ESM preserve callable and default identities', async () => { + for (const suffix of ['js', 'legacy.js']) { + const source = fs.readFileSync(`packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.${suffix}`, 'utf8') + const module = { exports: {} } + vm.runInNewContext(source, { module, exports: module.exports, window: {} }) + assert.equal(typeof module.exports, 'function') + assert.equal(module.exports.default, module.exports) + assert.equal(typeof module.exports.default(), 'function') + const global = { window: {} } + vm.runInNewContext(source, global) + const factory = global.artplayerPluginDocumentPip || global.window.artplayerPluginDocumentPip + assert.equal(factory.default, factory) + } + const source = fs.readFileSync('packages/artplayer-plugin-document-pip/dist/artplayer-plugin-document-pip.mjs', 'utf8') + const module = await import(`data:text/javascript,${encodeURIComponent(source)}`) + assert.deepEqual(Object.keys(module), ['default']) + assert.equal(module.default.default, module.default) +}) diff --git a/refactor/tasks.json b/refactor/tasks.json index ce2993c43..b3a97d6e3 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -1569,7 +1569,8 @@ "PKG-AMBILIGHT-04", "CORE-22", "PKG-AMBILIGHT-PROXY-01", - "PKG-CANVAS-04" + "PKG-CANVAS-04", + "PKG-FACTORY-01" ], "status": "todo", "risk": "M", @@ -3054,11 +3055,15 @@ "ENG-06", "CORE-07" ], - "status": "todo", + "status": "done", "risk": "H", "deliverable": "Document PiP 可选能力和真实状态/返回类型", "acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容", - "evidence": [] + "evidence": [ + "changes/2026-09-12-PKG-DPIP-04-types.md", + "baselines/dpip-types-validation.json", + "dpip-validation.md" + ] }, { "id": "PKG-DPIP-05", @@ -3350,7 +3355,8 @@ "dependsOn": [ "PKG-CANVAS-04", "CORE-22", - "PKG-DPIP-04" + "PKG-DPIP-04", + "PKG-FACTORY-01" ], "status": "todo", "risk": "H", @@ -4083,7 +4089,8 @@ "PKG-IFRAME-04", "PKG-TOOL-THUMB-04", "PKG-DANMUKU-06", - "PKG-MB-08" + "PKG-MB-08", + "PKG-FACTORY-01" ], "status": "todo", "risk": "H", @@ -4269,6 +4276,27 @@ "deliverable": "最终任务/设计/证据归档和维护指南", "acceptance": "全范围任务有结论、无未解释兼容缺口;遗留项有明确后续责任", "evidence": [] + }, + { + "id": "PKG-FACTORY-01", + "phase": "5 工厂类型兼容补审", + "title": "修复已迁移工厂的反向赋值兼容", + "scope": [ + "artplayer-proxy-canvas", + "artplayer-plugin-ambilight" + ], + "dependsOn": [ + "PKG-CANVAS-04", + "PKG-AMBILIGHT-04", + "PKG-DPIP-04" + ], + "status": "todo", + "risk": "H", + "deliverable": "复现两包旧typeof工厂替换与新.default/可选重载冲突,修复公开类型并补安装消费者、产物和文档", + "acceptance": "默认工厂的历史合法反向赋值继续通过;既有类型/运行时导出逐版本核对,不能只验证Parameters或直接调用", + "evidence": [ + "baselines/factory-assignment-gaps.json" + ] } ] } diff --git a/scripts/build-ts.js b/scripts/build-ts.js index daf18f230..39518e2a2 100644 --- a/scripts/build-ts.js +++ b/scripts/build-ts.js @@ -43,7 +43,7 @@ console.log(`✨ Built ${artplayerTSoutput}`); const type = pluginsTS[index] const { name, file } = parsePluginInfo(type) const source = String(fs.readFileSync(type)) - const semanticPlugin = ['artplayerPluginHlsControl', 'artplayerPluginAudioTrack', 'artplayerPluginDashControl', 'artplayerPluginAds', 'artplayerPluginAmbilight', 'artplayerProxyCanvas'].includes(name) + const semanticPlugin = ['artplayerPluginHlsControl', 'artplayerPluginAudioTrack', 'artplayerPluginDashControl', 'artplayerPluginAds', 'artplayerPluginAmbilight', 'artplayerProxyCanvas', 'artplayerPluginDocumentPip'].includes(name) const code = semanticPlugin ? generatePluginEditorDeclaration(source, name) : `${source.replace(reg, '')}\nexport = ${name};\nexport as namespace ${name};\n` diff --git a/scripts/typecheck.mjs b/scripts/typecheck.mjs index 488a41a07..7275ab82f 100644 --- a/scripts/typecheck.mjs +++ b/scripts/typecheck.mjs @@ -76,7 +76,7 @@ export function runTypechecks() { for (const fixture of ['test/types/public.ts', 'test/types/declaration-inputs.ts', 'test/types/declaration-legacy.ts', 'test/types/plugins-public.ts', 'test/types/playback-public.ts', 'test/types/chapter-options.ts', 'test/types/chapter-exports.ts', 'test/types/hls-control.ts', 'test/types/dash-control.ts', 'test/types/ads.ts', 'refactor/fixtures/consumers/ads-published.ts', 'refactor/fixtures/consumers/ads-workspace.ts', 'refactor/fixtures/consumers/dash-control-legacy.ts', 'test/types/audio-track.ts', 'test/types/language-value.ts', 'refactor/fixtures/consumers/language.ts', 'refactor/fixtures/consumers/legacy-plugin.ts']) { assert.deepEqual(checkConsumer(compiler, mode, fs.readFileSync(path.join(root, fixture), 'utf8')), [], `Consumer failed: TS ${compiler.version} ${mode} ${fixture}`) } - for (const fixture of ['test/types/ambilight.ts', 'refactor/fixtures/consumers/ambilight-published.ts', 'test/types/canvas.ts', 'refactor/fixtures/consumers/canvas-published.ts']) + for (const fixture of ['test/types/ambilight.ts', 'refactor/fixtures/consumers/ambilight-published.ts', 'test/types/canvas.ts', 'refactor/fixtures/consumers/canvas-published.ts', 'test/types/dpip.ts', 'refactor/fixtures/consumers/dpip-published.ts']) assert.deepEqual(checkConsumer(compiler, mode, fs.readFileSync(path.join(root, fixture), 'utf8')), [], `Consumer failed: TS ${compiler.version} ${mode} ${fixture}`) if (mode === 'nodenext-cjs') assert.deepEqual(checkConsumer(compiler, mode, fs.readFileSync(path.join(root, 'test/types/commonjs.cts'), 'utf8')), [], 'CommonJS export assignment consumer failed') diff --git a/test/types/dpip.ts b/test/types/dpip.ts new file mode 100644 index 000000000..1835142d1 --- /dev/null +++ b/test/types/dpip.ts @@ -0,0 +1,67 @@ +import type { AsyncResult, Factory, Option, Result, RuntimeFactory } from 'artplayer-plugin-document-pip' +import Artplayer from 'artplayer' +import dpip from 'artplayer-plugin-document-pip' +import legacy from 'artplayer-plugin-document-pip/legacy' + +type Equal = (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? true : false +type Assert = T +type ExactParameters = Assert, [option: Option]>> +type ExactResult = Assert>, Result>> +type ExactOpen = Assert, void>> +type ExactDirectOpen = Assert, void>> +type ExactFactory = Assert (art: Artplayer) => Result>> + +const options: Option = { width: 640, height: 360, placeholder: 'Active', fallbackToVideoPiP: false } +const art = new Artplayer({ container: '#player', url: 'video.mp4', plugins: [dpip(options)] }) +const runtimeFactory = dpip as RuntimeFactory +runtimeFactory() +runtimeFactory(undefined) +runtimeFactory.default(options) +legacy(options) +declare const optional: Option | undefined +runtimeFactory(optional) +const factory: Factory = dpip +const result = factory(options)(art) +result.open = () => {} +result.close = () => {} +const mutable: Result = { name: 'artplayerPluginDocumentPip', isSupported: true, isActive: false, open() {}, close() {}, toggle() {} } +mutable.isActive = true +mutable.isSupported = false +const oldFactoryReplacement: typeof dpip = (_options: Option) => (_art: Artplayer) => mutable +const returned: void = result.open() +const asyncResult: AsyncResult = runtimeFactory()(art) +const opening: Promise = asyncResult.open() +const closing: Promise = asyncResult.close() +const toggled: void = asyncResult.toggle() +const snapshot: boolean = asyncResult.isSupported +const historical: Result = asyncResult +// @ts-expect-error Parameters extraction keeps the historical required option. +const missing: Parameters[0] = undefined +// @ts-expect-error Width is numeric. +dpip({ width: '640' }) +// @ts-expect-error Height is numeric. +dpip({ height: '360' }) +// @ts-expect-error Placeholder is text. +dpip({ placeholder: 1 }) +// @ts-expect-error Fallback is boolean. +dpip({ fallbackToVideoPiP: 'yes' }) +// @ts-expect-error Null was never a typed option. +dpip(null) +// @ts-expect-error Unknown options remain errors. +dpip({ arbitrary: true }) +// @ts-expect-error Registration requires its Artplayer host. +dpip({})() +// @ts-expect-error Plugin registration remains synchronous. +const asyncRegistration: Promise = dpip({})(art) +// @ts-expect-error The opt-in runtime state is readonly. +asyncResult.isActive = true +// @ts-expect-error The opt-in capability snapshot is readonly. +asyncResult.isSupported = true +// @ts-expect-error Exact async actions cannot be replaced with void actions in this view. +asyncResult.open = () => {} +// @ts-expect-error Legacy void defaults do not falsely promise an awaitable return. +const wrongPromise: Promise = result.open() +// @ts-expect-error Self default identity is readonly in declarations. +runtimeFactory.default = runtimeFactory +void [oldFactoryReplacement, returned, opening, closing, toggled, snapshot, historical, missing, asyncRegistration, wrongPromise] +export type { ExactDirectOpen, ExactFactory, ExactOpen, ExactParameters, ExactResult }