mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
refactor(iframe): [PKG-IFRAME-04] preserve types across module consumers
This commit is contained in:
1 parent
1342de94ef
commit
047e2df945
24 files changed
+1496
-69
No files matched your search
+107
-30
@@ -1,32 +1,109 @@
|
||||
interface Message {
|
||||
type: string
|
||||
data: any
|
||||
id?: number
|
||||
// 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 ArtplayerToolIframeDefinitions {
|
||||
export interface Option {
|
||||
iframe: HTMLIFrameElement
|
||||
url: string
|
||||
}
|
||||
/** Historical open envelope. data remains required in the default class API. */
|
||||
export interface Message<T = any> {
|
||||
type: string
|
||||
data: T
|
||||
id?: number
|
||||
}
|
||||
export interface Callbacks {
|
||||
resove: (...args: any[]) => any
|
||||
reject: (...args: any[]) => any
|
||||
}
|
||||
/** Public notifications omit the request id and all private session metadata. */
|
||||
export interface Notification<T = unknown> {
|
||||
type: string
|
||||
data: T
|
||||
}
|
||||
export type MessageCallback = (this: ArtplayerToolIframe, message: Notification) => void
|
||||
/** Actual outgoing calls allow an omitted data field. Custom message types remain valid. */
|
||||
export interface OutboundMessage<T = unknown> {
|
||||
type: string
|
||||
data?: T
|
||||
id?: number
|
||||
}
|
||||
/** Known built-in envelopes; use Message/OutboundMessage for application protocols. */
|
||||
export type ProtocolMessage<T = unknown> = {
|
||||
type: 'inject'
|
||||
data?: undefined
|
||||
id?: number
|
||||
} | {
|
||||
type: 'commit'
|
||||
data: string
|
||||
id: number
|
||||
} | {
|
||||
type: 'response'
|
||||
data: T
|
||||
id: number
|
||||
} | {
|
||||
type: 'error'
|
||||
data: unknown
|
||||
id: number
|
||||
}
|
||||
export type Resolve<T> = (value: T | PromiseLike<T>) => void
|
||||
export type ResolverCallback<T> = (resolve: Resolve<T>) => void
|
||||
/** Opt-in view. Response T is supplied by the application's protocol, not validated at runtime. */
|
||||
export interface RuntimeInstance extends Omit<ArtplayerToolIframe, 'messageCallback' | 'postMessage' | 'message'> {
|
||||
messageCallback: MessageCallback | null
|
||||
postMessage: <T = unknown>(message: OutboundMessage) => Promise<T>
|
||||
message: (callback: MessageCallback) => void
|
||||
}
|
||||
/** For the existing serialized resolve(...) protocol; callback bodies must use that exact name. */
|
||||
export interface ResolverInstance extends Omit<RuntimeInstance, 'commit'> {
|
||||
commit: <T>(callback: ResolverCallback<T>) => Promise<T>
|
||||
}
|
||||
/** Opt-in static async/optional-data view. There is no runtime self-default property. */
|
||||
export interface RuntimeConstructor {
|
||||
new (option: Option): RuntimeInstance
|
||||
readonly prototype: RuntimeInstance
|
||||
readonly iframe: boolean
|
||||
postMessage: (message: OutboundMessage) => void
|
||||
onMessage: (event: MessageEvent<OutboundMessage>) => Promise<void>
|
||||
inject: () => void
|
||||
}
|
||||
export class ArtplayerToolIframe {
|
||||
constructor(option: Option)
|
||||
static iframe: boolean
|
||||
static postMessage(message: Message): void
|
||||
static onMessage(event: MessageEvent & {
|
||||
data: Message
|
||||
}): void
|
||||
static inject(): void
|
||||
readonly promises: Record<number, Callbacks>
|
||||
readonly injected: boolean
|
||||
readonly destroyed: boolean
|
||||
readonly $iframe: HTMLIFrameElement
|
||||
readonly url: string
|
||||
readonly messageCallback: (...args: any[]) => any
|
||||
onMessage(event: MessageEvent & {
|
||||
data: Message
|
||||
}): void
|
||||
postMessage(message: Message): Promise<any>
|
||||
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>
|
||||
message(callback: (...args: any[]) => any): void
|
||||
destroy(): void
|
||||
}
|
||||
}
|
||||
|
||||
declare class ArtplayerToolIframe {
|
||||
constructor(option: { iframe: HTMLIFrameElement, url: string })
|
||||
|
||||
static iframe: boolean
|
||||
static postMessage(message: Message): void
|
||||
static onMessage(event: MessageEvent & { data: Message }): void
|
||||
static inject(): void
|
||||
|
||||
readonly promises: Record<number, { resove: (...args: any[]) => any, reject: (...args: any[]) => any }>
|
||||
readonly injected: boolean
|
||||
readonly destroyed: boolean
|
||||
readonly $iframe: HTMLIFrameElement
|
||||
readonly url: string
|
||||
readonly messageCallback: (...args: any[]) => any
|
||||
|
||||
onMessage(event: MessageEvent & { data: Message }): void
|
||||
postMessage(message: Message): Promise<any>
|
||||
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>
|
||||
message(callback: (...args: any[]) => any): void
|
||||
destroy(): void
|
||||
declare const ArtplayerToolIframe: typeof ArtplayerToolIframeDefinitions.ArtplayerToolIframe
|
||||
type ArtplayerToolIframe = ArtplayerToolIframeDefinitions.ArtplayerToolIframe
|
||||
declare namespace ArtplayerToolIframe {
|
||||
export type Option = ArtplayerToolIframeDefinitions.Option
|
||||
export type Message<T = any> = ArtplayerToolIframeDefinitions.Message<T>
|
||||
export type Callbacks = ArtplayerToolIframeDefinitions.Callbacks
|
||||
export type Notification<T = unknown> = ArtplayerToolIframeDefinitions.Notification<T>
|
||||
export type MessageCallback = ArtplayerToolIframeDefinitions.MessageCallback
|
||||
export type OutboundMessage<T = unknown> = ArtplayerToolIframeDefinitions.OutboundMessage<T>
|
||||
export type ProtocolMessage<T = unknown> = ArtplayerToolIframeDefinitions.ProtocolMessage<T>
|
||||
export type Resolve<T> = ArtplayerToolIframeDefinitions.Resolve<T>
|
||||
export type ResolverCallback<T> = ArtplayerToolIframeDefinitions.ResolverCallback<T>
|
||||
export type RuntimeInstance = ArtplayerToolIframeDefinitions.RuntimeInstance
|
||||
export type ResolverInstance = ArtplayerToolIframeDefinitions.ResolverInstance
|
||||
export type RuntimeConstructor = ArtplayerToolIframeDefinitions.RuntimeConstructor
|
||||
}
|
||||
|
||||
export default ArtplayerToolIframe
|
||||
|
||||
export = artplayerToolIframe
|
||||
export as namespace artplayerToolIframe;
|
||||
export = ArtplayerToolIframe
|
||||
export as namespace ArtplayerToolIframe;
|
||||
+2
-1
@@ -80,7 +80,8 @@
|
||||
"test:mediabunny-types-package": "node refactor/scripts/mb-package-types.mjs",
|
||||
"test:mediabunny-soak": "playwright test --config playwright.soak.config.js",
|
||||
"generate:media:hls": "node scripts/generate-hls-fixture.mjs",
|
||||
"test:iframe": "node --test test/iframe-navigation.test.js test/iframe-boundaries.test.js test/iframe.test.js test/iframe-lifecycle.test.js refactor/scripts/iframe-contract.test.mjs"
|
||||
"test:iframe": "node --test test/iframe-navigation.test.js test/iframe-boundaries.test.js test/iframe.test.js test/iframe-lifecycle.test.js refactor/scripts/iframe-contract.test.mjs refactor/scripts/iframe-types.test.mjs",
|
||||
"test:iframe-types-package": "node refactor/scripts/iframe-package-types.mjs"
|
||||
},
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -2,4 +2,5 @@ node_modules
|
||||
.DS_Store
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
src
|
||||
src
|
||||
tsconfig.json
|
||||
@@ -110,18 +110,41 @@ history reload is BFCache: actual persisted restoration, full-player integration
|
||||
devices and externally interrupted navigation remain PKG-IFRAME-05/release gates.
|
||||
IFRAME-LIFE-01 and IFRAME-TRUST-01 remain open for those integration/review scopes.
|
||||
|
||||
Public declarations remain in `types/artplayer-tool-iframe.d.ts`; source typing
|
||||
does not yet establish historical declaration/entry compatibility. PKG-IFRAME-04
|
||||
must reconcile the old npm plugin name, namespace/default and extra helper
|
||||
protocol separately. PKG-IFRAME-06 owns final distribution. No version bump or
|
||||
publication is implied by this source migration.
|
||||
Public declarations are maintained in `types/artplayer-tool-iframe.d.ts`.
|
||||
The `.d.cts` bridge describes the actual CommonJS constructor and its named types;
|
||||
`.d.mts` routes native ESM to the same class. Keep the root `types` field and
|
||||
legacy `typesVersions` entry for TS 4.3 consumers. The runtime has no self-default
|
||||
property. Ordinary default imports use interop in CommonJS consumers; modern
|
||||
TypeScript can use direct `import Iframe = require(...)` without interop.
|
||||
|
||||
The default class intentionally retains required Message.data, void static
|
||||
onMessage, readonly instance fields, non-null callback and legacy commit inference.
|
||||
RuntimeConstructor/RuntimeInstance expose optional outgoing data, async static
|
||||
receiver, nullable callback and application-supplied response types. ResolverInstance
|
||||
offers an explicit result parameter for the old serialized resolve(...) protocol.
|
||||
These are erased type views, not new runtime methods or payload validators. The
|
||||
source class satisfies RuntimeConstructor; its nullable callback intentionally
|
||||
does not satisfy the old non-null class declaration, and tests pin that difference.
|
||||
|
||||
Old npm plugin-iframe used Function callbacks and a CommonJS default namespace;
|
||||
those differ from the frozen workspace before this refactor. Installed tests
|
||||
preserve that evidence and the separate helper's static destroy protocol. They
|
||||
do not claim the renamed tool supplies the old package name or helper entrypoints.
|
||||
PKG-IFRAME-06 still owns those distribution decisions and compatibility facades.
|
||||
No version bump or publication is implied by declaration validation.
|
||||
|
||||
## Verification
|
||||
|
||||
- `yarn test:iframe`: frozen historical contract/defect assertions and candidate
|
||||
lifecycle assertions. Historical failures are not candidate acceptance.
|
||||
- `yarn typecheck`: strict source and existing consumers; full package declaration
|
||||
consumers are still a separate PKG-IFRAME-04 gate.
|
||||
- `yarn typecheck`: strict source and existing consumers, including old extraction
|
||||
and new typed views in TS 5.9 and TS 4.3.
|
||||
- `yarn test:iframe-types-package`: install the real old npm archive, frozen
|
||||
workspace pack and candidate outside the workspace with offline/frozen Yarn.
|
||||
Check declaration resolution, exact bytes, exports and positive/negative uses.
|
||||
- `yarn build:ts artplayer-tool-iframe`: regenerate only this package's standalone
|
||||
editor declaration (plus the shared core declaration). The generator uses the
|
||||
actual uppercase class global and exports named types without external imports.
|
||||
- `yarn build artplayer-tool-iframe`: normal main/legacy/ESM production output and
|
||||
generated docs copies. Never hand-edit those files.
|
||||
- `yarn test:browser test/browser/iframe.spec.js`: real same/cross-origin windows
|
||||
|
||||
@@ -6,6 +6,35 @@ Iframe tool for ArtPlayer
|
||||
|
||||
[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-tool-iframe/index.js&example=iframe)
|
||||
|
||||
## TypeScript
|
||||
|
||||
Default imports keep the historical class signatures, including `resove`,
|
||||
required message `data`, and the original `commit` result inference. Named types
|
||||
include `Option`, `Message`, `ProtocolMessage` and optional runtime views:
|
||||
|
||||
```ts
|
||||
import type { ResolverInstance, RuntimeConstructor } from 'artplayer-tool-iframe'
|
||||
import Iframe from 'artplayer-tool-iframe'
|
||||
|
||||
const Runtime = Iframe as RuntimeConstructor
|
||||
const tool = new Runtime({ iframe: document.querySelector('iframe')!, url: '/iframe.html' })
|
||||
const resolver = tool as ResolverInstance
|
||||
const value = await resolver.commit<number>((resolve) => {
|
||||
resolve(42)
|
||||
})
|
||||
```
|
||||
|
||||
`commit` serializes the function body. Keep its braces, use the literal `resolve`
|
||||
name for asynchronous replies, and do not depend on closures or an async function
|
||||
body. Handle rejection when the child document changes or the tool is destroyed.
|
||||
The runtime views are types only; they do not validate messages or sandbox code.
|
||||
|
||||
The browser global is `ArtplayerToolIframe`. Modern TypeScript CommonJS consumers
|
||||
can use `import Iframe = require('artplayer-tool-iframe')`; older Node resolution
|
||||
uses the default import with `esModuleInterop`. The class has no `.default`
|
||||
property. The historical `artplayer-plugin-iframe` package and its separate helper
|
||||
have different export/protocol details; they are not aliases for this tool.
|
||||
|
||||
## Maintenance
|
||||
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for the TypeScript module map, request
|
||||
|
||||
@@ -19,12 +19,17 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/artplayer-tool-iframe.d.ts",
|
||||
"import": "./dist/artplayer-tool-iframe.mjs",
|
||||
"require": "./dist/artplayer-tool-iframe.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-tool-iframe.d.mts",
|
||||
"default": "./dist/artplayer-tool-iframe.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-tool-iframe.d.cts",
|
||||
"default": "./dist/artplayer-tool-iframe.js"
|
||||
}
|
||||
},
|
||||
"./legacy": {
|
||||
"types": "./types/artplayer-tool-iframe.d.ts",
|
||||
"types": "./types/artplayer-tool-iframe.d.cts",
|
||||
"import": "./dist/artplayer-tool-iframe.legacy.js",
|
||||
"require": "./dist/artplayer-tool-iframe.legacy.js"
|
||||
}
|
||||
@@ -33,5 +38,10 @@
|
||||
"module": "./dist/artplayer-tool-iframe.mjs",
|
||||
"types": "./types/artplayer-tool-iframe.d.ts",
|
||||
"legacy": "./dist/artplayer-tool-iframe.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"legacy": ["types/artplayer-tool-iframe.d.ts"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* eslint-disable ts/no-redeclare -- Constructor, instance and named-type namespace intentionally merge. */
|
||||
import type * as Definition from './artplayer-tool-iframe.js'
|
||||
|
||||
declare const ArtplayerToolIframe: typeof Definition.default
|
||||
type ArtplayerToolIframe = Definition.default
|
||||
|
||||
declare namespace ArtplayerToolIframe {
|
||||
type Option = Definition.Option
|
||||
type Message<T = any> = Definition.Message<T>
|
||||
type Callbacks = Definition.Callbacks
|
||||
type Notification<T = unknown> = Definition.Notification<T>
|
||||
type MessageCallback = Definition.MessageCallback
|
||||
type OutboundMessage<T = unknown> = Definition.OutboundMessage<T>
|
||||
type ProtocolMessage<T = unknown> = Definition.ProtocolMessage<T>
|
||||
type Resolve<T> = Definition.Resolve<T>
|
||||
type ResolverCallback<T> = Definition.ResolverCallback<T>
|
||||
type RuntimeInstance = Definition.RuntimeInstance
|
||||
type ResolverInstance = Definition.ResolverInstance
|
||||
type RuntimeConstructor = Definition.RuntimeConstructor
|
||||
}
|
||||
|
||||
export = ArtplayerToolIframe
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default } from './artplayer-tool-iframe.cjs'
|
||||
export type { Callbacks, Message, MessageCallback, Notification, Option, OutboundMessage, ProtocolMessage, Resolve, ResolverCallback, ResolverInstance, RuntimeConstructor, RuntimeInstance } from './artplayer-tool-iframe.js'
|
||||
@@ -1,18 +1,76 @@
|
||||
interface Message {
|
||||
export interface Option {
|
||||
iframe: HTMLIFrameElement
|
||||
url: string
|
||||
}
|
||||
|
||||
/** Historical open envelope. data remains required in the default class API. */
|
||||
export interface Message<T = any> {
|
||||
type: string
|
||||
data: any
|
||||
data: T
|
||||
id?: number
|
||||
}
|
||||
|
||||
export interface Callbacks {
|
||||
resove: (...args: any[]) => any
|
||||
reject: (...args: any[]) => any
|
||||
}
|
||||
|
||||
/** Public notifications omit the request id and all private session metadata. */
|
||||
export interface Notification<T = unknown> {
|
||||
type: string
|
||||
data: T
|
||||
}
|
||||
|
||||
export type MessageCallback = (this: ArtplayerToolIframe, message: Notification) => void
|
||||
|
||||
/** Actual outgoing calls allow an omitted data field. Custom message types remain valid. */
|
||||
export interface OutboundMessage<T = unknown> {
|
||||
type: string
|
||||
data?: T
|
||||
id?: number
|
||||
}
|
||||
|
||||
/** Known built-in envelopes; use Message/OutboundMessage for application protocols. */
|
||||
export type ProtocolMessage<T = unknown>
|
||||
= | { type: 'inject', data?: undefined, id?: number }
|
||||
| { type: 'commit', data: string, id: number }
|
||||
| { type: 'response', data: T, id: number }
|
||||
| { type: 'error', data: unknown, id: number }
|
||||
|
||||
export type Resolve<T> = (value: T | PromiseLike<T>) => void
|
||||
export type ResolverCallback<T> = (resolve: Resolve<T>) => void
|
||||
|
||||
/** Opt-in view. Response T is supplied by the application's protocol, not validated at runtime. */
|
||||
export interface RuntimeInstance extends Omit<ArtplayerToolIframe, 'messageCallback' | 'postMessage' | 'message'> {
|
||||
messageCallback: MessageCallback | null
|
||||
postMessage: <T = unknown>(message: OutboundMessage) => Promise<T>
|
||||
message: (callback: MessageCallback) => void
|
||||
}
|
||||
|
||||
/** For the existing serialized resolve(...) protocol; callback bodies must use that exact name. */
|
||||
export interface ResolverInstance extends Omit<RuntimeInstance, 'commit'> {
|
||||
commit: <T>(callback: ResolverCallback<T>) => Promise<T>
|
||||
}
|
||||
|
||||
/** Opt-in static async/optional-data view. There is no runtime self-default property. */
|
||||
export interface RuntimeConstructor {
|
||||
new (option: Option): RuntimeInstance
|
||||
readonly prototype: RuntimeInstance
|
||||
readonly iframe: boolean
|
||||
postMessage: (message: OutboundMessage) => void
|
||||
onMessage: (event: MessageEvent<OutboundMessage>) => Promise<void>
|
||||
inject: () => void
|
||||
}
|
||||
|
||||
declare class ArtplayerToolIframe {
|
||||
constructor(option: { iframe: HTMLIFrameElement, url: string })
|
||||
constructor(option: Option)
|
||||
|
||||
static iframe: boolean
|
||||
static postMessage(message: Message): void
|
||||
static onMessage(event: MessageEvent & { data: Message }): void
|
||||
static inject(): void
|
||||
|
||||
readonly promises: Record<number, { resove: (...args: any[]) => any, reject: (...args: any[]) => any }>
|
||||
readonly promises: Record<number, Callbacks>
|
||||
readonly injected: boolean
|
||||
readonly destroyed: boolean
|
||||
readonly $iframe: HTMLIFrameElement
|
||||
|
||||
@@ -0,0 +1,723 @@
|
||||
{
|
||||
"task": "PKG-IFRAME-04",
|
||||
"status": "done",
|
||||
"checkpoint": "verified-public-types-editor-and-installed-consumers",
|
||||
"beforeCommit": "1342de94ef2e9dc3e06ddac12fcf1fc5229b648d",
|
||||
"sourceSha256LF": {
|
||||
"package.json": "1ca2df37409d1634abe58ce40f50bbee162033af4c57a9908697477e564a7909",
|
||||
"packages/artplayer-tool-iframe/package.json": "91985c93522c98be5d2a6d02dc0a39df5eeededdd94077758511873fe2290cf4",
|
||||
"packages/artplayer-tool-iframe/.npmignore": "145c5fa0341195e21cf13df3423a057282f8ea374e9a1b3065e2280e1ce1c5c1",
|
||||
"packages/artplayer-tool-iframe/README.md": "6e0b3afbad28bf0160d744b89d1a4dad997fff77fb23c61d707389f08f49e219",
|
||||
"packages/artplayer-tool-iframe/ARCHITECTURE.md": "b5754cfecc61728db0742739f488973f6d9330ebd2f2ec9b60505953fc746546",
|
||||
"packages/artplayer-tool-iframe/types/artplayer-tool-iframe.d.ts": "e1efb4c7f22de24721923f02cf0488728a6ef381505c49187eba0bc2b90b1207",
|
||||
"packages/artplayer-tool-iframe/types/artplayer-tool-iframe.d.cts": "66850135f45c81d4bd7a0de33b6a2f63a655de9000f2698f43660039727919f3",
|
||||
"packages/artplayer-tool-iframe/types/artplayer-tool-iframe.d.mts": "cd394fd68e61fab3c4474daab29852a3f87dd0086b007e7937106871272676fb",
|
||||
"docs/assets/ts/artplayer-tool-iframe.d.ts": "c06c6819146ba64bd6ee498871d9e19ab5a9e88c9cc7bed2c0c4968fa39dfed7",
|
||||
"scripts/build-ts.js": "ce6e8da55d934c31f2291326b33a577c9b7dd15b84167f3c63142085d3dcb56d",
|
||||
"scripts/plugin-editor-types.mjs": "c485550ed0f44d38c2c78faced58c2bec08d496f4bd5a66f4c3dd2ed4bc8b57e",
|
||||
"scripts/typecheck.mjs": "02aa38836fc33b01f1e2de3def1443ed4d35f038a3595e11106a4dfbff12e86d",
|
||||
"test/types/iframe.ts": "7ecdc1f7cafda5edb3dbe0908c1029ea7cf3308eb909db661f3cfec27f434b90",
|
||||
"test/types/iframe-commonjs.cts": "16ac9bea7bb5fd1e5b79301d3f4e3d2761357fbe96a05211a941e26853866729",
|
||||
"test/types/iframe-source.ts": "29d816c19301d16c81521e809245ac33783362a9023d8cd9ac26185fb3e85ad6",
|
||||
"refactor/fixtures/consumers/iframe-workspace.ts": "c81fc54c919aabab57ead9efcffc9fe3e469be7fb3b57fbcafa5fd2653d83afb",
|
||||
"refactor/scripts/iframe-types.test.mjs": "69931a4b0779f996c0af46929c92ce1c9ccc437067a42fa1e9fac9d39ab856a0",
|
||||
"refactor/scripts/iframe-package-types.mjs": "8dd0006f605752ffdbf51c58bf5ee4cca503dc6c3c1793a8b03dc14fc62d27ea"
|
||||
},
|
||||
"artifacts": {
|
||||
"packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.js": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6",
|
||||
"packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.legacy.js": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a",
|
||||
"packages/artplayer-tool-iframe/dist/artplayer-tool-iframe.mjs": "ac4c5efa670c0429fc95bdab7902df60f5b5540f0dad9c7e65c2bd660796dc83"
|
||||
},
|
||||
"browserEvidenceReuse": {
|
||||
"file": "refactor/baselines/iframe-navigation-validation.json",
|
||||
"reason": "All six production source modules and three runtime build bytes are unchanged; this task changes declarations/editor generation and manifest type routing. Native frame matrices remain 351/351/207 from task 03; installed export routing is separately tested here."
|
||||
},
|
||||
"installed": {
|
||||
"report": "refactor/.cache/iframe-package-types-AHSyi2/report.json",
|
||||
"sha256": "1dadc173afa37655cd6c148cb34483f93e82fe82ae7897f6f4dfe89b8eb8b18b",
|
||||
"task": "PKG-IFRAME-04",
|
||||
"scope": "Actual npm archive, frozen Git workspace pack and candidate Yarn tarball installed outside workspace; byte verification, offline/frozen lock and strict positive/negative consumers. Old npm CJS namespace and distinct helper are preserved observations, not claims the candidate provides old package-name/helper aliases. Native player and distribution migration remain 05/06.",
|
||||
"packages": [
|
||||
{
|
||||
"label": "published",
|
||||
"name": "artplayer-plugin-iframe",
|
||||
"archive": "D:\\github\\ArtPlayer\\refactor\\.cache\\releases\\artplayer-plugin-iframe-1.0.0.tgz",
|
||||
"sha256": "16dc92aa84d93bd99bc0a34815dc49f1609fafc1ff255eb353ea893e70b5f91f",
|
||||
"files": {
|
||||
"package/README.md": "52c0a1199b6529d60ce8f4414984f9bd1bc3a8daa5bb6cfec8f0aae0c8338e46",
|
||||
"package/dist/artplayer-helper-iframe.js": "47730ed608f0637594549b9762c01191686a4a55b3bd467132304a016d227f4a",
|
||||
"package/dist/artplayer-helper-iframe.legacy.js": "f4c3b11806cad6d984f03a2d9de63deba78cbe538ffe4044a106b0dddc5d4197",
|
||||
"package/dist/artplayer-plugin-iframe.js": "df469c3e4582b127f35798494d0845f1fc4ca2d19bbaf01b918492e035479745",
|
||||
"package/dist/artplayer-plugin-iframe.legacy.js": "15299cb5c848cc61614f7573a802443d69b7c6d0a938a1867835c7cbb4884edd",
|
||||
"package/package.json": "563a6c8407753b92b86319a5e6d9d567525146c32cb010b45b0d88ff481859f6",
|
||||
"package/src/index.js": "2e0b9efeedef0d6c4f2d2b526db35f634cd02af044e4e28dd1a0b26a5b9a02bf",
|
||||
"package/types/artplayer-plugin-iframe.d.ts": "d55d99a2488d60892a0ab82882dc96a0f373dab0c3d2a3cee978bc35aa7c2d0c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "workspace",
|
||||
"name": "artplayer-tool-iframe",
|
||||
"archive": "D:\\github\\ArtPlayer\\refactor\\.cache\\iframe-package-types-AHSyi2\\workspace.tgz",
|
||||
"sha256": "6fc603122610b785aa3ecb43f2692fb92c39e96386ca1bcab5ee23253af92ae6",
|
||||
"files": {
|
||||
"package/README.md": "6910a44b767ff80c1d1edc3c90ca7ca77a9b45307fb61d4abd9d52526c7614b3",
|
||||
"package/dist/artplayer-tool-iframe.js": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86",
|
||||
"package/dist/artplayer-tool-iframe.legacy.js": "c0755d79f316cda71f045da86749648f95faf47c09180d525fb04bb753576d5f",
|
||||
"package/dist/artplayer-tool-iframe.mjs": "cbcdb0516dd5f17ca2572a6b3e363ea63b0cfd9733f3e47689c02088f23f29b9",
|
||||
"package/package.json": "b28f5156f02a250539f0acaf302ec87fdd506f63b0e73dd308326ec78c691d03",
|
||||
"package/types/artplayer-tool-iframe.d.ts": "4f02aa22a6b373393ead533ae3421ad5acf0de7116057f351021c72d3448bd1e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "candidate",
|
||||
"name": "artplayer-tool-iframe",
|
||||
"archive": "D:\\github\\ArtPlayer\\refactor\\.cache\\iframe-package-types-AHSyi2\\candidate.tgz",
|
||||
"sha256": "25e88268584f67cb690048f8cb53312b6fcfe64d622a70bf954604a402be9471",
|
||||
"files": {
|
||||
"package/ARCHITECTURE.md": "b5754cfecc61728db0742739f488973f6d9330ebd2f2ec9b60505953fc746546",
|
||||
"package/README.md": "ef5af60bcb831667a78cc3421f6e3c7b5d9a50b3d2e571c5cd02d46fc533e9ce",
|
||||
"package/dist/artplayer-tool-iframe.js": "7408fceccb000e1b304abe30ac9bc364da7860c3896ad5aaa6af427804c237e6",
|
||||
"package/dist/artplayer-tool-iframe.legacy.js": "4e8bd39cdc37e98bff9cd19b5e0c9453ebe5231264242fc1c573aa96edb5ea8a",
|
||||
"package/dist/artplayer-tool-iframe.mjs": "ac4c5efa670c0429fc95bdab7902df60f5b5540f0dad9c7e65c2bd660796dc83",
|
||||
"package/package.json": "0de9c86eeb3f9a2fb46f9297105b5beddb8d6164163ffaa9874cf5cd68ba7a58",
|
||||
"package/types/artplayer-tool-iframe.d.cts": "66850135f45c81d4bd7a0de33b6a2f63a655de9000f2698f43660039727919f3",
|
||||
"package/types/artplayer-tool-iframe.d.mts": "cd394fd68e61fab3c4474daab29852a3f87dd0086b007e7937106871272676fb",
|
||||
"package/types/artplayer-tool-iframe.d.ts": "e760de22559caf7ffff48d7c5713485bf9f0ddbe876a93080295fb6106535bfa"
|
||||
}
|
||||
}
|
||||
],
|
||||
"matrix": [
|
||||
{
|
||||
"package": "published",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "published",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-cjs",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "published",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-esm",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "published",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "bundler-esm",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "published",
|
||||
"compiler": "4.3.5",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "workspace",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "workspace",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-cjs",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "workspace",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-esm",
|
||||
"diagnostics": [
|
||||
{
|
||||
"code": 2344,
|
||||
"message": "Type 'false' does not satisfy the constraint 'true'."
|
||||
},
|
||||
{
|
||||
"code": 2344,
|
||||
"message": "Type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")' does not satisfy the constraint 'abstract new (...args: any) => any'.\n Type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")' provides no match for the signature 'new (...args: any): any'."
|
||||
},
|
||||
{
|
||||
"code": 2344,
|
||||
"message": "Type 'false' does not satisfy the constraint 'true'."
|
||||
},
|
||||
{
|
||||
"code": 2709,
|
||||
"message": "Cannot use namespace 'Iframe' as a type."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'onMessage' does not exist on type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")'."
|
||||
},
|
||||
{
|
||||
"code": 2344,
|
||||
"message": "Type 'false' does not satisfy the constraint 'true'."
|
||||
},
|
||||
{
|
||||
"code": 2709,
|
||||
"message": "Cannot use namespace 'Iframe' as a type."
|
||||
},
|
||||
{
|
||||
"code": 2344,
|
||||
"message": "Type 'false' does not satisfy the constraint 'true'."
|
||||
},
|
||||
{
|
||||
"code": 2709,
|
||||
"message": "Cannot use namespace 'Iframe' as a type."
|
||||
},
|
||||
{
|
||||
"code": 2709,
|
||||
"message": "Cannot use namespace 'Iframe' as a type."
|
||||
},
|
||||
{
|
||||
"code": 2351,
|
||||
"message": "This expression is not constructable.\n Type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")' has no construct signatures."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'postMessage' does not exist on type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'inject' does not exist on type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'onMessage' does not exist on type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")'."
|
||||
},
|
||||
{
|
||||
"code": 7006,
|
||||
"message": "Parameter 'value' implicitly has an 'any' type."
|
||||
},
|
||||
{
|
||||
"code": 7006,
|
||||
"message": "Parameter 'additional' implicitly has an 'any' type."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'onMessage' does not exist on type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'iframe' does not exist on type 'typeof import(\"<consumer>/node_modules/artplayer-tool-iframe/types/artplayer-tool-iframe\")'."
|
||||
}
|
||||
],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "workspace",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "bundler-esm",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "workspace",
|
||||
"compiler": "4.3.5",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": [],
|
||||
"negative": []
|
||||
},
|
||||
{
|
||||
"package": "candidate",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": [],
|
||||
"negative": [
|
||||
{
|
||||
"code": 2554,
|
||||
"message": "Expected 1 arguments, but got 0."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'HTMLIFrameElement'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: string; }' is not assignable to parameter of type 'Message<any>'.\n Property 'data' is missing in type '{ type: string; }' but required in type 'Message<any>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'injected' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'void' is not assignable to type 'Promise<void>'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'default' does not exist on type 'typeof ArtplayerToolIframe'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'iframe' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2353,
|
||||
"message": "Object literal may only specify known properties, and 'id' does not exist in type 'Notification<unknown>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: \"response\"; data: string; id: number; }' is not assignable to parameter of type 'ProtocolMessage<number>'.\n Types of property 'data' are incompatible.\n Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type 'string' is not assignable to parameter of type 'number | PromiseLike<number>'."
|
||||
},
|
||||
{
|
||||
"code": 2551,
|
||||
"message": "Property 'resolve' does not exist on type 'Callbacks'. Did you mean 'resove'?"
|
||||
},
|
||||
{
|
||||
"code": 18046,
|
||||
"message": "'message.data' is of type 'unknown'."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"package": "candidate",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-cjs",
|
||||
"diagnostics": [],
|
||||
"negative": [
|
||||
{
|
||||
"code": 2554,
|
||||
"message": "Expected 1 arguments, but got 0."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'HTMLIFrameElement'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: string; }' is not assignable to parameter of type 'Message<any>'.\n Property 'data' is missing in type '{ type: string; }' but required in type 'Message<any>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'injected' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'void' is not assignable to type 'Promise<void>'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'default' does not exist on type 'typeof ArtplayerToolIframe'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'iframe' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2353,
|
||||
"message": "Object literal may only specify known properties, and 'id' does not exist in type 'Notification<unknown>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: \"response\"; data: string; id: number; }' is not assignable to parameter of type 'ProtocolMessage<number>'.\n Types of property 'data' are incompatible.\n Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type 'string' is not assignable to parameter of type 'number | PromiseLike<number>'."
|
||||
},
|
||||
{
|
||||
"code": 2551,
|
||||
"message": "Property 'resolve' does not exist on type 'Callbacks'. Did you mean 'resove'?"
|
||||
},
|
||||
{
|
||||
"code": 18046,
|
||||
"message": "'message.data' is of type 'unknown'."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"package": "candidate",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-esm",
|
||||
"diagnostics": [],
|
||||
"negative": [
|
||||
{
|
||||
"code": 2554,
|
||||
"message": "Expected 1 arguments, but got 0."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'HTMLIFrameElement'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: string; }' is not assignable to parameter of type 'Message<any>'.\n Property 'data' is missing in type '{ type: string; }' but required in type 'Message<any>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'injected' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'void' is not assignable to type 'Promise<void>'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'default' does not exist on type 'typeof ArtplayerToolIframe'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'iframe' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2353,
|
||||
"message": "Object literal may only specify known properties, and 'id' does not exist in type 'Notification<unknown>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: \"response\"; data: string; id: number; }' is not assignable to parameter of type 'ProtocolMessage<number>'.\n Types of property 'data' are incompatible.\n Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type 'string' is not assignable to parameter of type 'number | PromiseLike<number>'."
|
||||
},
|
||||
{
|
||||
"code": 2551,
|
||||
"message": "Property 'resolve' does not exist on type 'Callbacks'. Did you mean 'resove'?"
|
||||
},
|
||||
{
|
||||
"code": 18046,
|
||||
"message": "'message.data' is of type 'unknown'."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"package": "candidate",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "bundler-esm",
|
||||
"diagnostics": [],
|
||||
"negative": [
|
||||
{
|
||||
"code": 2554,
|
||||
"message": "Expected 1 arguments, but got 0."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'HTMLIFrameElement'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: string; }' is not assignable to parameter of type 'Message<any>'.\n Property 'data' is missing in type '{ type: string; }' but required in type 'Message<any>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'injected' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'void' is not assignable to type 'Promise<void>'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'default' does not exist on type 'typeof ArtplayerToolIframe'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'iframe' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2353,
|
||||
"message": "Object literal may only specify known properties, and 'id' does not exist in type 'Notification<unknown>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: \"response\"; data: string; id: number; }' is not assignable to parameter of type 'ProtocolMessage<number>'.\n Types of property 'data' are incompatible.\n Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type 'string' is not assignable to parameter of type 'number | PromiseLike<number>'."
|
||||
},
|
||||
{
|
||||
"code": 2551,
|
||||
"message": "Property 'resolve' does not exist on type 'Callbacks'. Did you mean 'resove'?"
|
||||
},
|
||||
{
|
||||
"code": 18046,
|
||||
"message": "'message.data' is of type 'unknown'."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"package": "candidate",
|
||||
"compiler": "4.3.5",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": [],
|
||||
"negative": [
|
||||
{
|
||||
"code": 2554,
|
||||
"message": "Expected 1 arguments, but got 0."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'HTMLIFrameElement'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: string; }' is not assignable to parameter of type 'Message<any>'.\n Property 'data' is missing in type '{ type: string; }' but required in type 'Message<any>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'number' is not assignable to type 'string'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number | undefined'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'injected' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'void' is not assignable to type 'Promise<void>'."
|
||||
},
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'default' does not exist on type 'typeof ArtplayerToolIframe'."
|
||||
},
|
||||
{
|
||||
"code": 2540,
|
||||
"message": "Cannot assign to 'iframe' because it is a read-only property."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type '{ type: string; data: number; id: number; }' is not assignable to type 'Notification<unknown>'.\n Object literal may only specify known properties, and 'id' does not exist in type 'Notification<unknown>'."
|
||||
},
|
||||
{
|
||||
"code": 2322,
|
||||
"message": "Type 'string' is not assignable to type 'number | undefined'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type '{ type: \"response\"; data: string; id: number; }' is not assignable to parameter of type 'ProtocolMessage<number>'.\n Type '{ type: \"response\"; data: string; id: number; }' is not assignable to type '{ type: \"response\"; data: number; id: number; }'.\n Types of property 'data' are incompatible.\n Type 'string' is not assignable to type 'number'."
|
||||
},
|
||||
{
|
||||
"code": 2345,
|
||||
"message": "Argument of type 'string' is not assignable to parameter of type 'number | PromiseLike<number>'."
|
||||
},
|
||||
{
|
||||
"code": 2551,
|
||||
"message": "Property 'resolve' does not exist on type 'Callbacks'. Did you mean 'resove'?"
|
||||
},
|
||||
{
|
||||
"code": 2571,
|
||||
"message": "Object is of type 'unknown'."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"package": "candidate",
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-cjs-no-interop",
|
||||
"diagnostics": [],
|
||||
"negative": [
|
||||
{
|
||||
"code": 2339,
|
||||
"message": "Property 'default' does not exist on type 'typeof ArtplayerToolIframe'."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"runtime": [
|
||||
{
|
||||
"package": "published",
|
||||
"commonjs": "object",
|
||||
"commonjsDefault": "function",
|
||||
"esmDefault": "object",
|
||||
"helperIsDistinct": true,
|
||||
"ssrImport": true
|
||||
},
|
||||
{
|
||||
"package": "workspace",
|
||||
"commonjs": "function",
|
||||
"commonjsDefault": "undefined",
|
||||
"esmDefault": "function",
|
||||
"helperIsDistinct": false,
|
||||
"ssrImport": true
|
||||
},
|
||||
{
|
||||
"package": "candidate",
|
||||
"commonjs": "function",
|
||||
"commonjsDefault": "undefined",
|
||||
"esmDefault": "function",
|
||||
"helperIsDistinct": false,
|
||||
"ssrImport": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"diagnostics": {
|
||||
"editorBefore": {
|
||||
"file": "refactor/.cache/iframe04-editor-before.json",
|
||||
"codes": [
|
||||
2309,
|
||||
2686,
|
||||
2303
|
||||
],
|
||||
"meaning": "Frozen default/export= combination and incorrect lowercase global; both compiler versions reproduce the same three codes, in compiler-specific ordering."
|
||||
},
|
||||
"workspaceNodeNextEsm": {
|
||||
"report": "refactor/.cache/iframe-package-types-6qThuH/workspace-5.9.3-nodenext-esm.json",
|
||||
"count": 18,
|
||||
"meaning": "Frozen workspace declaration represents a namespace rather than a constructable native ESM default. Candidate paired d.mts/d.cts routes pass the unchanged workspace fixture."
|
||||
},
|
||||
"trials": [
|
||||
"refactor/.cache/iframe04-types-first.log",
|
||||
"refactor/.cache/iframe04-types-second.log",
|
||||
"refactor/.cache/iframe04-editor-build.log",
|
||||
"refactor/.cache/iframe04-lint-fix.log"
|
||||
],
|
||||
"meaning": "Initial tests exposed historical diagnostic ordering/context differences and the known nullable-source callback mismatch; exact expectations are explicit. The editor build found method-signature lint errors, repaired in authored types before regeneration.",
|
||||
"intermediateCi": {
|
||||
"log": "refactor/.cache/iframe04-ci.log",
|
||||
"tests": 1542,
|
||||
"status": "pass-before-error-payload-review",
|
||||
"scope": "Not final acceptance after ProtocolMessage error payload was corrected to unknown."
|
||||
},
|
||||
"nonStringErrors": {
|
||||
"file": "refactor/.cache/iframe04-error-payload-probe.json",
|
||||
"sha256": "e5d81d661be5fe555def11f4366443ce463e7b0b53fbd5cca4d11b0ac64a779e",
|
||||
"observations": 10,
|
||||
"scope": "Two non-Error throws across four immutable historical artifacts and candidate source produce numeric/undefined data. Permanent baseline regression repeats these checks."
|
||||
}
|
||||
},
|
||||
"preservedDifferences": [
|
||||
"Default Message.data remains required and static onMessage remains void; RuntimeConstructor exposes the actual optional-data/Promise<void> surface.",
|
||||
"Default callback remains non-null while actual source allows null. The source satisfies RuntimeConstructor; exact historical mismatch 2419 is asserted separately, not hidden by skipLibCheck.",
|
||||
"Default commit keeps Promise<ReturnType<T>>, including old nested-Promise inference. ResolverInstance provides an explicit result for the literal resolve(...) body protocol; neither view adds async-function-body or closure support.",
|
||||
"Published Function callbacks versus callable workspace callbacks are an existing cross-package-name declaration difference, with both compiler diagnostics pinned. Old-name/helper distribution is still IFRAME-06.",
|
||||
"Historical npm native ESM default is an object despite accepted old declaration usage; the candidate tool native ESM default is a class. No old package/helper alias has been delivered here.",
|
||||
"No self-default is added. Old-style TypeScript CommonJS default imports require interop; modern direct import= is checked without interop.",
|
||||
"Known error packets carry unknown data because thrown values need not be Error objects. New typed consumers narrow before treating the payload as text."
|
||||
],
|
||||
"checks": [
|
||||
{
|
||||
"command": "yarn ci:check",
|
||||
"result": "pass",
|
||||
"exitCode": 0,
|
||||
"tests": 1543,
|
||||
"unit": 1365,
|
||||
"engineering": 14,
|
||||
"baseline": 164,
|
||||
"repeatedContracts": 44,
|
||||
"productionTypeScriptFiles": 330,
|
||||
"log": "refactor/.cache/iframe04-ci-final.log",
|
||||
"sha256": "7a0b080a0e6f708c0f8bdbd831d8e93b0970b5779f4c7ded42ea96be4fc0da64"
|
||||
},
|
||||
{
|
||||
"command": "yarn test:imports",
|
||||
"result": "pass",
|
||||
"tests": 3,
|
||||
"log": "refactor/.cache/iframe04-imports.log"
|
||||
},
|
||||
{
|
||||
"command": "yarn build:ts artplayer-tool-iframe",
|
||||
"result": "pass",
|
||||
"log": "refactor/.cache/iframe04-editor-build-verified.log"
|
||||
},
|
||||
{
|
||||
"command": "yarn build artplayer-tool-iframe",
|
||||
"result": "pass",
|
||||
"log": "refactor/.cache/iframe04-build.log",
|
||||
"scope": "All three runtime outputs remain byte-identical to task 03."
|
||||
},
|
||||
{
|
||||
"command": "yarn test:iframe-types-package",
|
||||
"result": "pass",
|
||||
"log": "refactor/.cache/iframe04-package-verified.log",
|
||||
"compilerCases": 16,
|
||||
"candidateCases": 6,
|
||||
"candidateNegativeDiagnostics": 81
|
||||
}
|
||||
],
|
||||
"remaining": [
|
||||
"PKG-IFRAME-05 full core/demo/BFCache/device/interrupted-navigation integration",
|
||||
"PKG-IFRAME-06 old package name/helper paths, emitted consumer runtime and final distribution",
|
||||
"PKG-MB-10 standalone editor treatment of split media declarations surfaced during an initial all-package generation; unrelated generated changes were restored and no completion is claimed"
|
||||
],
|
||||
"verifiedAt": "2026-09-12T17:41:36.279Z"
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
# PKG-IFRAME-04 public types and installed consumers
|
||||
|
||||
Started from 1342de94ef2e9dc3e06ddac12fcf1fc5229b648d with a clean worktree.
|
||||
The previous task completed six strict source modules and native document
|
||||
ownership. This task owns public declarations and their consumer/editor paths.
|
||||
|
||||
## Verified starting points
|
||||
|
||||
- Frozen npm plugin-iframe@1.0.0 has export= / global ArtplayerPluginIframe but
|
||||
actually returns a CommonJS default namespace. Its extra helper is a distinct
|
||||
protocol and has no dedicated declaration. No tool@1.1.0 npm archive is invented.
|
||||
- Frozen/current workspace default class has required Message.data, readonly
|
||||
instance fields, void static onMessage and Promise<ReturnType<T>> commit.
|
||||
Runtime static onMessage is async, data may be omitted and callback can be null.
|
||||
Preserve legacy extraction/replacement types; expose precise opt-in views.
|
||||
- Current main/legacy return the class directly, with no self-default property.
|
||||
Do not borrow factory.default declarations from other packages.
|
||||
- The generated editor declaration uses lowercase artplayerToolIframe although
|
||||
runtime/class is ArtplayerToolIframe, and combines default export with export=.
|
||||
Reproduce and repair generation, not the generated file by hand.
|
||||
|
||||
## Planned acceptance
|
||||
|
||||
Named option/message/protocol/callback types, unchanged default class signatures,
|
||||
precise optional runtime views, correct CJS/ESM declaration routing, strict
|
||||
current/old compiler consumers and standalone editor generation. Isolated Yarn
|
||||
pack/install must distinguish the real old npm archive, frozen workspace and
|
||||
candidate, preserve exact historical errors and verify no workspace type leakage.
|
||||
Legacy package-name/helper distribution remains independently tracked by 06;
|
||||
full player/demo/device integration remains 05. Do not claim either passed here.
|
||||
|
||||
## Implementation and decisions
|
||||
|
||||
The default .d.ts keeps all old field/method types and adds named option, envelope,
|
||||
notification and callback types. The CJS .d.cts exports the actual class with an
|
||||
instance alias and type namespace; .d.mts handles native ESM. The legacy route and
|
||||
typesVersions preserve old compiler resolution. No runtime default property or
|
||||
JavaScript method is added. Source files and all three runtime artifacts remain
|
||||
byte-identical to task 03; package/editor declaration routes are tested separately.
|
||||
|
||||
RuntimeConstructor/RuntimeInstance opt into async static receipt, optional outgoing
|
||||
data and a nullable typed callback. Generic response T is an application assertion,
|
||||
not payload validation. ResolverInstance gives an explicit result for the existing
|
||||
literal resolve(...) function-body protocol. The default nested-Promise/void commit
|
||||
inference remains unchanged; no async-function-body or closure execution is added.
|
||||
|
||||
Independent review proved error payloads may be numbers or undefined when executed
|
||||
code throws non-Error values, in four historical main/legacy builds and candidate
|
||||
source. The new ProtocolMessage error data therefore uses unknown with narrowing;
|
||||
the first green CI predated this correction and is retained as intermediate only.
|
||||
|
||||
The frozen editor yields 2309/2686/2303; semantic class generation removes the
|
||||
default/export= conflict and uses ArtplayerToolIframe with named-type aliases.
|
||||
build:ts accepts selected package names to regenerate the current package without
|
||||
rewriting unrelated packages mid-migration. Its old all-package mode remains;
|
||||
the initial all-package run exposed split MediaBunny media declaration treatment,
|
||||
now explicitly assigned to MB-10. No hand-editing of generated declarations.
|
||||
|
||||
Isolated Yarn installs cover the real npm archive, a pack made exclusively from
|
||||
frozen Git inputs, and candidate pack. Every installed file matches its archive;
|
||||
frozen reinstall preserves the lock and compiler files cannot resolve outside the
|
||||
consumer except standard libraries. Old workspace NodeNext ESM has 18 exact
|
||||
diagnostics; candidate accepts the unchanged fixture. Published Function callback
|
||||
fields and its CJS namespace are existing differences from workspace callable
|
||||
fields/direct class, not silently rewritten. Old package/helper facade and emitted
|
||||
consumer compatibility stay under IFRAME-06, with IFRAME-DIST-01 still open.
|
||||
|
||||
The default non-null callback also differs from source's nullable field. Tests pin
|
||||
exact diagnostic 2419 for the old view and prove the source satisfies the opt-in
|
||||
RuntimeConstructor. This documents a preserved type boundary, not skipLibCheck.
|
||||
|
||||
No new dependencies, version changes, push or publish. Final checks and hashes
|
||||
are in baselines/iframe-types-validation.json. Roll back this task's declarations,
|
||||
manifest and generator changes together, then regenerate the iframe editor types.
|
||||
Completion subject: `refactor(iframe): [PKG-IFRAME-04] preserve types across module consumers`.
|
||||
|
||||
## Final verification
|
||||
|
||||
Full CI passes 1543 (1365 unit + 14 engineering + 164 baseline), 44 repeated
|
||||
contracts and 330 production TS files. The four new baseline tests include
|
||||
positive/negative views, exact historical differences, error-payload runtime
|
||||
evidence and both-compiler standalone editor checks. Installed consumers verify
|
||||
16 compiler cases across three archives, including six candidate cases with
|
||||
81 rejected invalid uses; old workspace ESM errors stay explicit negative controls.
|
||||
Three import/SSR files pass. Source/declaration/editor hashes, final tarball bytes,
|
||||
all runtime source modules and byte-identical runtime/docs outputs are verified.
|
||||
Package-name/helper and full integration gates remain open under 05/06. This is
|
||||
a declaration/consumer completion, not an npm release or final browser/demo review.
|
||||
@@ -0,0 +1,37 @@
|
||||
import Iframe from 'artplayer-tool-iframe'
|
||||
|
||||
type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false
|
||||
type Assert<T extends true> = T
|
||||
interface OldMessage { type: string, data: any, id?: number }
|
||||
type ExactConstructor = Assert<Equal<ConstructorParameters<typeof Iframe>, [option: { iframe: HTMLIFrameElement, url: string }]>>
|
||||
type ExactMessage = Assert<Equal<Parameters<Iframe['postMessage']>, [message: OldMessage]>>
|
||||
type ExactStaticReceiver = Assert<Equal<ReturnType<typeof Iframe.onMessage>, void>>
|
||||
type ExactCallbacks = Assert<Equal<Iframe['promises'], Record<number, { resove: (...args: any[]) => any, reject: (...args: any[]) => any }>>>
|
||||
type ExactCallback = Assert<Equal<Iframe['messageCallback'], (...args: any[]) => any>>
|
||||
|
||||
declare const frame: HTMLIFrameElement
|
||||
const tool: Iframe = new Iframe({ iframe: frame, url: '/iframe.html' })
|
||||
const message: OldMessage = { type: 'custom', data: { enabled: true }, id: 1 }
|
||||
Iframe.postMessage(message)
|
||||
Iframe.inject()
|
||||
const staticResult: void = Iframe.onMessage(new MessageEvent('message', { data: message }))
|
||||
tool.onMessage(new MessageEvent('message', { data: message }))
|
||||
const custom: Promise<any> = tool.postMessage(message)
|
||||
const sync: Promise<number> = tool.commit(() => {
|
||||
return 1
|
||||
})
|
||||
const nested: Promise<Promise<number>> = tool.commit(() => {
|
||||
return Promise.resolve(1)
|
||||
})
|
||||
const resolver: Promise<void> = tool.commit((resolve: (value: number) => void) => {
|
||||
resolve(1)
|
||||
})
|
||||
tool.message((value, additional) => [value, additional])
|
||||
tool.promises[1] = { resove: (...args: any[]) => args, reject: (...args: any[]) => args }
|
||||
tool.promises[1].resove(1, 2)
|
||||
tool.promises[1].reject(new Error('old'))
|
||||
const replacement: typeof Iframe.onMessage = () => {}
|
||||
const enabled: boolean = Iframe.iframe
|
||||
tool.destroy()
|
||||
void [staticResult, custom, sync, nested, resolver, replacement, enabled]
|
||||
export type { ExactCallback, ExactCallbacks, ExactConstructor, ExactMessage, ExactStaticReceiver }
|
||||
+5
-4
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 222 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 105 / doing 9 / blocked 0 / done 108 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 104 / doing 9 / blocked 0 / done 109 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -338,7 +338,7 @@
|
||||
| PKG-MB-07 | artplayer-proxy-mediabunny<br>整理 HLS 配对轨道与 selector | PKG-MB-05, PKG-MB-06, CORE-14 | m3u8 配对、质量/音频选择及拓扑清理 | 实际选择高亮、切到无轨道来源清理、无重复 readiness | H | done |
|
||||
| PKG-MB-08 | artplayer-proxy-mediabunny<br>完成 TS 与媒体能力声明 | PKG-MB-07, ENG-04, ENG-06 | 8 个自有 JS 模块迁移与 Result/shim 类型 | 解码器/Stream/DOM 类型清楚,旧 Option 和 art.mediabunny 使用保持 | H | done |
|
||||
| PKG-MB-09 | artplayer-proxy-mediabunny<br>完成新旧核心和真实媒体组合 | PKG-MB-08, CORE-22 | 跨浏览器能力、长播放、DPiP、HLS 音轨/质量报告 | 资源释放、事件顺序、AV sync 与支持范围满足基线 | H | doing |
|
||||
| PKG-MB-10 | artplayer-proxy-mediabunny<br>完成分发和文档 | PKG-MB-09, ENG-07 | mediabunny.js、README、依赖版本、三产物和许可 | tarball 可消费、无意外依赖升级、旧调用与回退可用 | H | todo |
|
||||
| PKG-MB-10 | artplayer-proxy-mediabunny<br>完成分发和文档 | PKG-MB-09, ENG-07 | mediabunny.js、README、依赖版本、三产物和许可; 拆分media声明后的独立编辑器生成/辅助文件过滤与语义检查(IFRAME-04全量生成时暴露) | tarball 可消费、无意外依赖升级、旧调用与回退可用 | H | todo |
|
||||
|
||||
## 5 包迁移:artplayer-tool-iframe
|
||||
|
||||
@@ -347,9 +347,9 @@
|
||||
| PKG-IFRAME-01 | artplayer-tool-iframe<br>核对包契约与历史用法 | BASE-05 | constructor/commit/message/inject、postMessage 协议与历史公开拼写 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
|
||||
| PKG-IFRAME-02 | artplayer-tool-iframe<br>建立特有行为与错误测试 | PKG-IFRAME-01, ENG-03, ENG-05 | 跨窗口消息、ID 匹配、请求失败、重复 inject、销毁中请求 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
|
||||
| PKG-IFRAME-03 | artplayer-tool-iframe<br>整理内部职责与资源 | PKG-IFRAME-02, CORE-02, BASE-07 | 请求注册/响应匹配/监听清理分离;origin/source 安全边界独立决策 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
|
||||
| PKG-IFRAME-04 | artplayer-tool-iframe<br>迁移自有源码和公开类型 | PKG-IFRAME-03, ENG-04, ENG-06, CORE-07 | 消息联合类型、回调/Promise 推导、旧公开字段兼容;旧npm export=与实际namespace、额外helper协议分别核验 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
|
||||
| PKG-IFRAME-04 | artplayer-tool-iframe<br>迁移自有源码和公开类型 | PKG-IFRAME-03, ENG-04, ENG-06, CORE-07 | 消息联合类型、回调/Promise 推导、旧公开字段兼容;旧npm export=与实际namespace、额外helper协议分别核验 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done |
|
||||
| PKG-IFRAME-05 | artplayer-tool-iframe<br>验证新旧核心和组合 | PKG-IFRAME-04, CORE-22 | 真实同源/跨源 iframe、既有 commit 协议;安全变化有独立结论;新旧核心/demo、实际 BFCache/设备和外部中断导航验收,旧端无文档标记的限制明确 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-IFRAME-06 | artplayer-tool-iframe<br>验证分发并同步文档 | PKG-IFRAME-05, ENG-07 | iframe.js、示例集成和原 script/class 导出验证;旧包名/额外helper深入口与新工具名的迁移结论 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
| PKG-IFRAME-06 | artplayer-tool-iframe<br>验证分发并同步文档 | PKG-IFRAME-05, ENG-07 | iframe.js、示例集成和原 script/class 导出验证;旧包名/额外helper深入口与新工具名的迁移结论; 保留旧npm Function回调及namespace/helper与工具类的区别,核验实际编译后消费而非仅声明通过 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
|
||||
## 5 包迁移:artplayer-tool-thumbnail
|
||||
|
||||
@@ -533,4 +533,5 @@
|
||||
- PKG-IFRAME-01: [记录](changes/2026-09-12-PKG-IFRAME-01-contract.md) [记录](baselines/iframe-release.json) [记录](baselines/iframe-contract.md) [记录](baselines/iframe-contract-validation.json)
|
||||
- PKG-IFRAME-02: [记录](changes/2026-09-12-PKG-IFRAME-02-behavior.md) [记录](baselines/iframe-behavior-validation.json)
|
||||
- PKG-IFRAME-03: [记录](changes/2026-09-12-PKG-IFRAME-03-requests-checkpoint.md) [记录](baselines/iframe-requests-checkpoint.json) [记录](changes/2026-09-12-PKG-IFRAME-03-boundaries-checkpoint.md) [记录](baselines/iframe-boundaries-checkpoint.json) [记录](iframe-message-boundary.md) [记录](changes/2026-09-13-PKG-IFRAME-03-navigation.md) [记录](baselines/iframe-navigation-validation.json) [记录](iframe-document-protocol.md)
|
||||
- PKG-IFRAME-04: [记录](changes/2026-09-13-PKG-IFRAME-04-types.md) [记录](baselines/iframe-types-validation.json)
|
||||
- PKG-FACTORY-01: [记录](baselines/factory-assignment-gaps.json) [记录](baselines/factory-compatibility-proposals.json) [记录](factory-compatibility-decision.md) [记录](changes/2026-09-12-PKG-FACTORY-01-decision.md)
|
||||
@@ -1,5 +1,19 @@
|
||||
# 进度与证据
|
||||
|
||||
## PKG-IFRAME-04 完成:公开类型、模块入口和编辑器
|
||||
|
||||
保留默认类的required data、void静态接收、readonly、resove及旧commit推导,增加
|
||||
可选Runtime/Resolver视图、消息联合与命名类型。CJS/ESM声明分别路由,旧TS通过
|
||||
types/legacy入口;无运行时self-default。编辑器使用实际大写类名并语义生成声明。
|
||||
旧工作区NodeNext ESM的18条错误已复现并修复;旧编辑器三条错误在两编译器复现。
|
||||
独立Yarn安装旧npm、冻结工作区和候选共16编译组合,候选6组/81非法使用被拒绝;
|
||||
历史Function字段、namespace/helper及nullable回调区别明确保留,05/06仍待验收。
|
||||
复查发现非Error抛出可产生非字符串error载荷,已用四历史产物与源码复现并修正类型。
|
||||
最终CI1543与44重复契约、3导入/SSR通过,330生产TS。三运行产物及源码字节未变,
|
||||
沿用03的真实浏览器证据,不冒称新跑浏览器。分包编辑器脚本避免改写迁移中的其他包。
|
||||
见[变更](changes/2026-09-13-PKG-IFRAME-04-types.md)和[验证](baselines/iframe-types-validation.json)。
|
||||
222项:109 done、9 doing、104 todo;本项独立本地提交,三个Iframe风险仍open。
|
||||
|
||||
## PKG-IFRAME-03 完成:按文档管理请求与六模块拆分
|
||||
|
||||
入口、连接、请求、消息边界、父页导航和子页生命周期拆为六个严格TS模块。
|
||||
|
||||
+4
-2
@@ -3827,12 +3827,14 @@
|
||||
],
|
||||
"status": "open",
|
||||
"confirmation": "reproduced",
|
||||
"compatibleResolution": "Keep actual old plugin/helper exports distinct from workspace tool and document package-name/type/export migration; do not fabricate a tool release or use a renamed implementation as an old archive.",
|
||||
"compatibleResolution": "IFRAME-04 adds paired CJS/ESM declarations and verifies three actual isolated installs, including old namespace/helper and existing Function callback differences. Keep old package-name/helper facade, emitted-consumer runtime and final distribution gates with IFRAME-06; the time-scoped tool registry observation is not a release claim.",
|
||||
"closureCriteria": "Actual installed entry/declaration tests and documented old-name/helper/new-tool distribution behavior; registry observation remains time scoped.",
|
||||
"evidence": [
|
||||
"refactor/baselines/iframe-contract.md",
|
||||
"refactor/baselines/iframe-release.json",
|
||||
"refactor/changes/2026-09-12-PKG-IFRAME-01-contract.md"
|
||||
"refactor/changes/2026-09-12-PKG-IFRAME-01-contract.md",
|
||||
"refactor/changes/2026-09-13-PKG-IFRAME-04-types.md",
|
||||
"refactor/baselines/iframe-types-validation.json"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
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 { verifyIframeContract } from './iframe-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:iframe-types-package')
|
||||
const yarn = process.env.npm_execpath
|
||||
assert(yarn && fs.existsSync(yarn))
|
||||
const output = fs.mkdtempSync(path.join(workspace, 'refactor/.cache/iframe-package-types-'))
|
||||
console.log(`Iframe installed package evidence: ${output}`)
|
||||
const contract = await verifyIframeContract()
|
||||
const frozen = path.join(output, 'frozen-workspace')
|
||||
fs.mkdirSync(frozen)
|
||||
const prefix = 'packages/artplayer-tool-iframe/'
|
||||
for (const [file, bytes] of contract.sources) {
|
||||
if (!file.startsWith(prefix))
|
||||
continue
|
||||
const target = path.join(frozen, file.slice(prefix.length))
|
||||
fs.mkdirSync(path.dirname(target), { recursive: true })
|
||||
fs.writeFileSync(target, bytes)
|
||||
}
|
||||
const packages = [{ label: 'published', name: contract.baseline.release.name, archive: contract.archive, sha256: contract.baseline.release.sha256, files: contract.baseline.release.files }]
|
||||
for (const [label, folder] of [['workspace', frozen], ['candidate', path.join(workspace, 'packages/artplayer-tool-iframe')]]) {
|
||||
const archive = path.join(output, `${label}.tgz`)
|
||||
fs.writeFileSync(path.join(output, `${label}-pack.log`), run([yarn, 'pack', '--filename', archive], folder))
|
||||
const manifest = JSON.parse(readMember(archive, 'package/package.json'))
|
||||
const files = packedFiles(archive)
|
||||
checkFiles(manifest, files)
|
||||
packages.push({ label, name: manifest.name, archive, sha256: hash(fs.readFileSync(archive)), files: Object.fromEntries(files.map(member => [member, hash(readMember(archive, member))])) })
|
||||
}
|
||||
const matrix = []
|
||||
const runtime = []
|
||||
for (const pkg of packages) {
|
||||
const consumer = consumerDirectory()
|
||||
try {
|
||||
writeJson(path.join(consumer, 'package.json'), { name: 'iframe-isolated-consumer', private: true, dependencies: { [pkg.name]: `file:${pkg.archive.replaceAll('\\', '/')}` } })
|
||||
fs.writeFileSync(path.join(output, `${pkg.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, `${pkg.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, `${pkg.label}-yarn.lock`), lock)
|
||||
const installed = path.join(consumer, 'node_modules', pkg.name)
|
||||
assert.equal(fs.realpathSync(installed), installed, 'Consumer must not use workspace links')
|
||||
for (const [member, expected] of Object.entries(pkg.files))
|
||||
assert.equal(hash(fs.readFileSync(path.join(installed, member.slice(8)))), expected, member)
|
||||
const runtimeFile = path.join(consumer, 'runtime.cjs')
|
||||
fs.writeFileSync(runtimeFile, `const assert = require('node:assert/strict');
|
||||
const value = require('${pkg.name}');
|
||||
assert.equal(typeof value, '${pkg.label === 'published' ? 'object' : 'function'}');
|
||||
assert.equal(typeof value.default, '${pkg.label === 'published' ? 'function' : 'undefined'}');
|
||||
${pkg.label === 'published' ? `for (const suffix of ['js', 'legacy.js']) { const helper = require('${pkg.name}/dist/artplayer-helper-iframe.' + suffix); assert.equal(typeof helper.default, 'function'); assert.equal(typeof helper.default.destroy, 'function'); assert.equal(typeof value.default.destroy, 'undefined'); }` : `const legacy = require('${pkg.name}/legacy'); assert.equal(typeof legacy, 'function'); assert.equal(legacy.default, undefined);`}
|
||||
import('${pkg.name}').then(module => {
|
||||
assert.equal(typeof module.default, '${pkg.label === 'published' ? 'object' : 'function'}');
|
||||
${pkg.label === 'published' ? '' : 'assert.deepEqual(Object.keys(module), [\'default\']);'}
|
||||
console.log(JSON.stringify({ commonjs: typeof value, commonjsDefault: typeof value.default, esmDefault: typeof module.default, helperIsDistinct: ${pkg.label === 'published'}, ssrImport: true }));
|
||||
}).catch(error => { console.error(error); process.exitCode = 1; });`)
|
||||
const observation = run([runtimeFile], consumer)
|
||||
fs.writeFileSync(path.join(output, `${pkg.label}-runtime.log`), observation)
|
||||
runtime.push({ package: pkg.label, ...JSON.parse(observation.trim()) })
|
||||
const modes = [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']]
|
||||
if (pkg.label === 'candidate')
|
||||
modes.push([ts, 'nodenext-cjs-no-interop'])
|
||||
for (const [compiler, mode] of modes) {
|
||||
const next = mode.startsWith('nodenext')
|
||||
const noInterop = mode.endsWith('no-interop')
|
||||
const filename = path.join(consumer, `consumer.${next ? mode.includes('-cjs') ? 'cts' : 'mts' : 'ts'}`)
|
||||
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], esModuleInterop: !noInterop, 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 }
|
||||
let source = fs.readFileSync(path.join(workspace, pkg.label === 'candidate' ? noInterop ? 'test/types/iframe-commonjs.cts' : 'test/types/iframe.ts' : 'refactor/fixtures/consumers/iframe-workspace.ts'), 'utf8')
|
||||
const files = [filename]
|
||||
if (pkg.label === 'published')
|
||||
source = source.replaceAll('artplayer-tool-iframe', pkg.name).replace('Record<number, { resove: (...args: any[]) => any, reject: (...args: any[]) => any }>', 'Record<number, { resove: Function, reject: Function }>')
|
||||
if (pkg.label === 'candidate' && !noInterop) {
|
||||
const oldFile = path.join(consumer, path.basename(filename).replace('consumer', 'historical'))
|
||||
fs.copyFileSync(path.join(workspace, 'refactor/fixtures/consumers/iframe-workspace.ts'), oldFile)
|
||||
files.push(oldFile)
|
||||
}
|
||||
function compile(code) {
|
||||
fs.writeFileSync(filename, code)
|
||||
const program = compiler.createProgram(files, options)
|
||||
for (const file of program.getSourceFiles()) {
|
||||
const real = fs.realpathSync(file.fileName)
|
||||
assert(real.startsWith(fs.realpathSync(consumer) + path.sep) || (program.isSourceFileDefaultLibrary(file) && path.dirname(real) === fs.realpathSync(path.dirname(compiler.sys.getExecutingFilePath()))), `Type escaped installed consumer: ${real}`)
|
||||
}
|
||||
return compiler.getPreEmitDiagnostics(program).map(item => ({ code: item.code, message: compiler.flattenDiagnosticMessageText(item.messageText, '\n').replaceAll(consumer.replaceAll('\\', '/'), '<consumer>') }))
|
||||
}
|
||||
const diagnostics = compile(source)
|
||||
const expected = pkg.label === 'workspace' && mode === 'nodenext-esm' ? [2344, 2344, 2344, 2709, 2339, 2344, 2709, 2344, 2709, 2709, 2351, 2339, 2339, 2339, 7006, 7006, 2339, 2339] : []
|
||||
writeJson(path.join(output, `${pkg.label}-${compiler.version}-${mode}.json`), diagnostics)
|
||||
assert.deepEqual(diagnostics.map(item => item.code), expected, `${pkg.label} ${compiler.version} ${mode}`)
|
||||
const negative = pkg.label === 'candidate' ? compile(source.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, '')) : []
|
||||
if (pkg.label === 'candidate')
|
||||
assert.equal(negative.length, noInterop ? 1 : 16)
|
||||
matrix.push({ package: pkg.label, compiler: compiler.version, mode, diagnostics, negative })
|
||||
}
|
||||
}
|
||||
finally { removeConsumer(consumer) }
|
||||
}
|
||||
writeJson(path.join(output, 'report.json'), { task: 'PKG-IFRAME-04', scope: 'Actual npm archive, frozen Git workspace pack and candidate Yarn tarball installed outside workspace; byte verification, offline/frozen lock and strict positive/negative consumers. Old npm CJS namespace and distinct helper are preserved observations, not claims the candidate provides old package-name/helper aliases. Native player and distribution migration remain 05/06.', packages, matrix, runtime })
|
||||
console.log(`Iframe installed types verified: ${matrix.length} compiler cases; ${output}`)
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exitCode = 1
|
||||
})
|
||||
@@ -0,0 +1,105 @@
|
||||
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 -- Compiler and historical declaration contract runner.
|
||||
import test from 'node:test'
|
||||
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 { iframeCandidate, iframeEnvironment, iframeHistorical } from '../../test/helpers/iframe.js'
|
||||
import { verifyIframeContract } from './iframe-contract.mjs'
|
||||
import { readMember } from './releases.mjs'
|
||||
|
||||
const modes = [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']]
|
||||
const invalid = code => code.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, '')
|
||||
|
||||
test('Iframe error envelopes preserve non-string thrown messages rather than claiming string-only payloads', async () => {
|
||||
const implementations = [...(await iframeHistorical()).filter(item => !item.name.includes('helper')), await iframeCandidate()]
|
||||
for (const implementation of implementations) {
|
||||
for (const [body, expected] of [['throw { message: 7 }', 7], ['throw 3', undefined]]) {
|
||||
const env = iframeEnvironment(implementation, true)
|
||||
await assert.rejects(env.Factory.onMessage({ data: { type: 'commit', data: body, id: 1 }, source: env.box.parent }), () => true)
|
||||
assert.equal(env.sent.length, 1)
|
||||
assert.equal(env.sent[0].packet.type, 'error')
|
||||
assert.equal(env.sent[0].packet.data, expected)
|
||||
assert.equal(env.sent[0].packet.id, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Iframe public types preserve legacy extraction while precise views reject invalid protocol calls', () => {
|
||||
const source = fs.readFileSync('test/types/iframe.ts', 'utf8')
|
||||
for (const [compiler, mode] of modes) {
|
||||
assert.deepEqual(checkConsumer(compiler, mode, source), [], `${compiler.version} ${mode}`)
|
||||
assert.equal(checkConsumer(compiler, mode, invalid(source)).length, 16)
|
||||
assert.deepEqual(checkConsumer(compiler, mode, fs.readFileSync('refactor/fixtures/consumers/iframe-workspace.ts', 'utf8')), [])
|
||||
}
|
||||
const commonjs = fs.readFileSync('test/types/iframe-commonjs.cts', 'utf8')
|
||||
assert.deepEqual(checkConsumer(ts, 'nodenext-cjs', commonjs), [])
|
||||
assert.equal(checkConsumer(ts, 'nodenext-cjs', invalid(commonjs)).length, 1)
|
||||
const implementationSource = fs.readFileSync('test/types/iframe-source.ts', 'utf8')
|
||||
assert.deepEqual(checkConsumer(ts, 'node10-commonjs', implementationSource), [])
|
||||
const implementation = checkConsumer(ts, 'node10-commonjs', invalid(implementationSource))
|
||||
assert.deepEqual(implementation.map(item => item.code), [2419], 'Only the preserved non-null legacy callback differs from the actual constructor')
|
||||
assert(implementation[0].message.includes('messageCallback') && implementation[0].message.includes('null'))
|
||||
})
|
||||
|
||||
test('Iframe frozen workspace keeps exact default signatures and published Function callbacks remain a separate legacy boundary', async () => {
|
||||
const contract = await verifyIframeContract()
|
||||
const source = fs.readFileSync('refactor/fixtures/consumers/iframe-workspace.ts', 'utf8')
|
||||
const filename = path.resolve('test/types/iframe-history.ts')
|
||||
const declaration = path.resolve('test/types/iframe-history.d.ts')
|
||||
for (const compiler of [ts, compat]) {
|
||||
function historical(code, definitions) {
|
||||
const options = { 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'] }
|
||||
const host = compiler.createCompilerHost(options)
|
||||
const original = host.getSourceFile.bind(host)
|
||||
host.getSourceFile = (file, language, ...rest) => path.resolve(file) === filename
|
||||
? compiler.createSourceFile(file, code.replaceAll('artplayer-tool-iframe', './iframe-history'), language, true)
|
||||
: path.resolve(file) === declaration ? compiler.createSourceFile(file, definitions, 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], options, host)
|
||||
assert(program.getSourceFile(declaration))
|
||||
return compiler.getPreEmitDiagnostics(program).map(item => item.code)
|
||||
}
|
||||
const frozen = contract.sources.get('packages/artplayer-tool-iframe/types/artplayer-tool-iframe.d.ts')
|
||||
const published = readMember(contract.archive, 'package/types/artplayer-plugin-iframe.d.ts').toString()
|
||||
assert.deepEqual(historical(source, frozen), [])
|
||||
assert.deepEqual(historical(source, published), [2344], 'Published Function versus workspace callable field is a pre-refactor difference')
|
||||
const broad = `import Iframe from 'artplayer-tool-iframe'; declare const tool: Iframe; declare const callback: Function; tool.promises[1] = { resove: callback, reject: callback };`
|
||||
assert.deepEqual(historical(broad, published), [])
|
||||
assert.deepEqual(historical(broad, frozen), [2322, 2322])
|
||||
assert.deepEqual(checkConsumer(compiler, 'node10-commonjs', broad).map(item => item.code), [2322, 2322])
|
||||
assert.deepEqual(historical(`${source}\nIframe.postMessage({ type: 'custom' });`, frozen), [2345])
|
||||
assert.deepEqual(checkConsumer(compiler, 'node10-commonjs', `${source}\nIframe.postMessage({ type: 'custom' });`).map(item => item.code), [2345])
|
||||
}
|
||||
})
|
||||
|
||||
test('Iframe standalone editor generation fixes the frozen export errors and preserves class plus named types', async () => {
|
||||
const contract = await verifyIframeContract()
|
||||
const historical = contract.sources.get('docs/assets/ts/artplayer-tool-iframe.d.ts')
|
||||
const source = fs.readFileSync('packages/artplayer-tool-iframe/types/artplayer-tool-iframe.d.ts', 'utf8')
|
||||
const generated = generatePluginEditorDeclaration(source, 'ArtplayerToolIframe')
|
||||
const file = 'docs/assets/ts/artplayer-tool-iframe.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 consumer = `declare const frame: HTMLIFrameElement;
|
||||
const option: ArtplayerToolIframe.Option = { iframe: frame, url: '/frame' };
|
||||
const tool: ArtplayerToolIframe = new ArtplayerToolIframe(option);
|
||||
const runtime = ArtplayerToolIframe as ArtplayerToolIframe.RuntimeConstructor;
|
||||
runtime.postMessage({ type: 'custom' });
|
||||
const promise: Promise<void> = runtime.onMessage(new MessageEvent('message', { data: { type: 'custom' } }));
|
||||
// @ts-expect-error No lowercase runtime global exists.
|
||||
new artplayerToolIframe(option);
|
||||
// @ts-expect-error URL remains text.
|
||||
new ArtplayerToolIframe({ iframe: frame, url: 1 });`
|
||||
for (const compiler of [ts, compat]) {
|
||||
assert.deepEqual(checkPluginEditorDeclaration(historical, '', '', compiler).map(item => item.code).sort(), [2303, 2309, 2686])
|
||||
assert.deepEqual(checkPluginEditorDeclaration(generated, '', consumer, compiler), [])
|
||||
assert.equal(checkPluginEditorDeclaration(generated, '', invalid(consumer), compiler).length, 2)
|
||||
}
|
||||
})
|
||||
+7
-4
@@ -3598,7 +3598,7 @@
|
||||
],
|
||||
"status": "todo",
|
||||
"risk": "H",
|
||||
"deliverable": "mediabunny.js、README、依赖版本、三产物和许可",
|
||||
"deliverable": "mediabunny.js、README、依赖版本、三产物和许可; 拆分media声明后的独立编辑器生成/辅助文件过滤与语义检查(IFRAME-04全量生成时暴露)",
|
||||
"acceptance": "tarball 可消费、无意外依赖升级、旧调用与回退可用",
|
||||
"evidence": []
|
||||
},
|
||||
@@ -3684,11 +3684,14 @@
|
||||
"ENG-06",
|
||||
"CORE-07"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"risk": "H",
|
||||
"deliverable": "消息联合类型、回调/Promise 推导、旧公开字段兼容;旧npm export=与实际namespace、额外helper协议分别核验",
|
||||
"acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-13-PKG-IFRAME-04-types.md",
|
||||
"baselines/iframe-types-validation.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PKG-IFRAME-05",
|
||||
@@ -3720,7 +3723,7 @@
|
||||
],
|
||||
"status": "todo",
|
||||
"risk": "H",
|
||||
"deliverable": "iframe.js、示例集成和原 script/class 导出验证;旧包名/额外helper深入口与新工具名的迁移结论",
|
||||
"deliverable": "iframe.js、示例集成和原 script/class 导出验证;旧包名/额外helper深入口与新工具名的迁移结论; 保留旧npm Function回调及namespace/helper与工具类的区别,核验实际编译后消费而非仅声明通过",
|
||||
"acceptance": "tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录",
|
||||
"evidence": []
|
||||
},
|
||||
|
||||
+19
-8
@@ -1,5 +1,7 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { ESLint } from 'eslint'
|
||||
import { glob } from 'glob'
|
||||
import compat from 'typescript-compat'
|
||||
@@ -18,12 +20,14 @@ function parsePluginInfo(pluginPath) {
|
||||
const file = path.basename(pluginPath)
|
||||
const baseName = file.replace('.d.ts', '')
|
||||
|
||||
const name = baseName
|
||||
.split('-')
|
||||
.map((word, index) =>
|
||||
index === 0 ? word : word[0].toUpperCase() + word.slice(1),
|
||||
)
|
||||
.join('')
|
||||
const name = baseName === 'artplayer-tool-iframe'
|
||||
? 'ArtplayerToolIframe'
|
||||
: baseName
|
||||
.split('-')
|
||||
.map((word, index) =>
|
||||
index === 0 ? word : word[0].toUpperCase() + word.slice(1),
|
||||
)
|
||||
.join('')
|
||||
|
||||
return { name, file }
|
||||
}
|
||||
@@ -36,14 +40,19 @@ fs.writeFileSync(artplayerTSoutput, code.trim())
|
||||
console.log(`✨ Built ${artplayerTSoutput}`);
|
||||
|
||||
(async function () {
|
||||
const pluginsTS = glob.sync('packages/artplayer-*-*/types/*.d.ts')
|
||||
const available = glob.sync('packages/artplayer-*-*/types/*.d.ts')
|
||||
const selected = process.argv.slice(2)
|
||||
const packageOf = file => path.basename(path.dirname(path.dirname(file)))
|
||||
for (const name of selected)
|
||||
assert(available.some(file => packageOf(file) === name), `Unknown declaration package: ${name}`)
|
||||
const pluginsTS = selected.length ? available.filter(file => selected.includes(packageOf(file))) : available
|
||||
const pluginFiles = []
|
||||
|
||||
for (let index = 0; index < pluginsTS.length; index++) {
|
||||
const type = pluginsTS[index]
|
||||
const { name, file } = parsePluginInfo(type)
|
||||
const source = String(fs.readFileSync(type))
|
||||
const semanticPlugin = ['artplayerPluginHlsControl', 'artplayerPluginAudioTrack', 'artplayerPluginDashControl', 'artplayerPluginAds', 'artplayerPluginAmbilight', 'artplayerProxyCanvas', 'artplayerPluginDocumentPip'].includes(name)
|
||||
const semanticPlugin = ['artplayerPluginHlsControl', 'artplayerPluginAudioTrack', 'artplayerPluginDashControl', 'artplayerPluginAds', 'artplayerPluginAmbilight', 'artplayerProxyCanvas', 'artplayerPluginDocumentPip', 'ArtplayerToolIframe'].includes(name)
|
||||
const code = semanticPlugin
|
||||
? generatePluginEditorDeclaration(source, name)
|
||||
: `${source.replace(reg, '')}\nexport = ${name};\nexport as namespace ${name};\n`
|
||||
@@ -71,6 +80,8 @@ console.log(`✨ Built ${artplayerTSoutput}`);
|
||||
const formatter = await eslint.loadFormatter('stylish')
|
||||
throw new Error(formatter.format(results))
|
||||
}
|
||||
if (selected.length)
|
||||
return
|
||||
const commonJsPath = path.join('docs/assets/js/common.js')
|
||||
const commonJsContent = fs.readFileSync(commonJsPath, 'utf-8')
|
||||
const newLibUris = allFiles.map(file => `'./assets/ts/${file}'`).join(',\n ')
|
||||
|
||||
@@ -16,6 +16,7 @@ export function generatePluginEditorDeclaration(code, name) {
|
||||
const internal = `${name}Definitions`
|
||||
let exported = false
|
||||
let callable = false
|
||||
let classExport = false
|
||||
for (const node of source.statements) {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
assert(node.importClause?.isTypeOnly && !node.importClause.namedBindings && node.importClause.name?.text === 'Artplayer' && node.moduleSpecifier.text === 'artplayer', 'Unsupported plugin editor import')
|
||||
@@ -26,12 +27,13 @@ export function generatePluginEditorDeclaration(code, name) {
|
||||
exported = true
|
||||
continue
|
||||
}
|
||||
assert(ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isFunctionDeclaration(node), 'Unsupported plugin editor declaration')
|
||||
assert(ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node), 'Unsupported plugin editor declaration')
|
||||
assert(node.name && node.name.text !== internal, 'Invalid plugin declaration name')
|
||||
definitions.push(factory.replaceModifiers(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)]))
|
||||
if (ts.isFunctionDeclaration(node)) {
|
||||
if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) {
|
||||
assert.equal(node.name.text, name, 'Unexpected plugin callable')
|
||||
callable = true
|
||||
classExport = ts.isClassDeclaration(node)
|
||||
continue
|
||||
}
|
||||
if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
||||
@@ -43,13 +45,14 @@ export function generatePluginEditorDeclaration(code, name) {
|
||||
))
|
||||
}
|
||||
}
|
||||
assert(exported && callable, 'Plugin editor requires a default function')
|
||||
assert(exported && callable, 'Plugin editor requires a default function or class')
|
||||
const namespace = (identifier, statements) => factory.createModuleDeclaration([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createIdentifier(identifier), factory.createModuleBlock(statements), ts.NodeFlags.Namespace)
|
||||
const statements = [
|
||||
namespace(internal, definitions),
|
||||
factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createVariableDeclarationList([
|
||||
factory.createVariableDeclaration(name, undefined, factory.createTypeQueryNode(factory.createQualifiedName(factory.createIdentifier(internal), factory.createIdentifier(name)))),
|
||||
], ts.NodeFlags.Const)),
|
||||
...(classExport ? [factory.createTypeAliasDeclaration(undefined, name, undefined, factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(internal), factory.createIdentifier(name))))] : []),
|
||||
namespace(name, aliases),
|
||||
factory.createExportAssignment(undefined, true, factory.createIdentifier(name)),
|
||||
factory.createNamespaceExportDeclaration(factory.createIdentifier(name)),
|
||||
|
||||
@@ -80,6 +80,10 @@ export function runTypechecks() {
|
||||
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')
|
||||
for (const fixture of ['test/types/iframe.ts', 'refactor/fixtures/consumers/iframe-workspace.ts'])
|
||||
assert.deepEqual(checkConsumer(compiler, mode, fs.readFileSync(path.join(root, fixture), 'utf8')), [], `Iframe consumer failed: TS ${compiler.version} ${mode}`)
|
||||
if (mode === 'nodenext-cjs')
|
||||
assert.deepEqual(checkConsumer(compiler, mode, fs.readFileSync(path.join(root, 'test/types/iframe-commonjs.cts'), 'utf8')), [], 'Iframe CommonJS constructor consumer failed')
|
||||
console.log(`Consumers passed: TS ${compiler.version} ${mode}`)
|
||||
}
|
||||
const runtimeFixtures = ['test/types/runtime-leaf-consumer.ts', 'test/types/runtime-public.ts', 'test/types/runtime-construction.ts']
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/* eslint-disable ts/no-require-imports -- Verify native TypeScript CommonJS constructor imports. */
|
||||
import Iframe = require('artplayer-tool-iframe')
|
||||
import Legacy = require('artplayer-tool-iframe/legacy')
|
||||
|
||||
declare const frame: HTMLIFrameElement
|
||||
const option: Iframe.Option = { iframe: frame, url: '/frame' }
|
||||
const tool: Iframe = new Iframe(option)
|
||||
const old: Legacy = new Legacy(option)
|
||||
const message: Iframe.Message<number> = { type: 'custom', data: 2 }
|
||||
tool.postMessage(message)
|
||||
old.commit(() => {
|
||||
return 2
|
||||
})
|
||||
// @ts-expect-error Direct CommonJS constructor has no default namespace.
|
||||
const wrong = Iframe.default
|
||||
void wrong
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { RuntimeConstructor } from 'artplayer-tool-iframe'
|
||||
import type Public from 'artplayer-tool-iframe'
|
||||
import Implementation from '../../packages/artplayer-tool-iframe/src/index'
|
||||
|
||||
// @ts-expect-error Historical callback is non-null; actual runtime permits null. Keep this legacy mismatch explicit.
|
||||
const oldView: typeof Public = Implementation
|
||||
const actualView: RuntimeConstructor = Implementation
|
||||
void [oldView, actualView]
|
||||
@@ -0,0 +1,77 @@
|
||||
import type { Callbacks, Message, MessageCallback, Notification, Option, OutboundMessage, ProtocolMessage, Resolve, ResolverInstance, RuntimeConstructor } from 'artplayer-tool-iframe'
|
||||
import Iframe from 'artplayer-tool-iframe'
|
||||
import Legacy from 'artplayer-tool-iframe/legacy'
|
||||
|
||||
declare const frame: HTMLIFrameElement
|
||||
const option: Option = { iframe: frame, url: '/iframe.html' }
|
||||
const tool = new Iframe(option)
|
||||
const old = new Legacy(option)
|
||||
const Runtime = Iframe as RuntimeConstructor
|
||||
const runtime = Runtime
|
||||
const precise = new Runtime(option)
|
||||
runtime.postMessage({ type: 'custom' })
|
||||
const asyncReceiver: Promise<void> = runtime.onMessage(new MessageEvent('message', { data: { type: 'custom' } }))
|
||||
const unknownReply: Promise<unknown> = precise.postMessage({ type: 'custom' })
|
||||
const numeric: Promise<number> = precise.postMessage<number>({ type: 'query', data: 2 })
|
||||
const callback: MessageCallback = function (message) {
|
||||
const source: HTMLIFrameElement = this.$iframe
|
||||
const body: unknown = message.data
|
||||
void [source, body]
|
||||
}
|
||||
precise.message(callback)
|
||||
precise.messageCallback = null
|
||||
const resolver = tool as ResolverInstance
|
||||
const resolved: Promise<number> = resolver.commit<number>((resolve) => {
|
||||
resolve(3)
|
||||
})
|
||||
const resolve: Resolve<number> = value => void value
|
||||
resolve(Promise.resolve(1))
|
||||
const notification: Notification<number> = { type: 'custom', data: 3 }
|
||||
const packet: Message<number> = { type: 'custom', data: 3 }
|
||||
const outgoing: OutboundMessage = { type: 'arbitrary' }
|
||||
const callbacks: Callbacks = { resove() {}, reject() {} }
|
||||
function receive(packet: ProtocolMessage<number>) {
|
||||
if (packet.type === 'response') {
|
||||
const value: number = packet.data
|
||||
return value
|
||||
}
|
||||
if (packet.type === 'error' && typeof packet.data === 'string')
|
||||
return packet.data.toUpperCase()
|
||||
return packet.id
|
||||
}
|
||||
receive({ type: 'inject' })
|
||||
receive({ type: 'commit', data: 'return 1', id: 1 })
|
||||
// @ts-expect-error Constructor options are still required.
|
||||
void new Iframe()
|
||||
// @ts-expect-error A string selector is not an iframe element.
|
||||
void new Iframe({ iframe: '#frame', url: '/frame' })
|
||||
// @ts-expect-error URL is text.
|
||||
void new Iframe({ iframe: frame, url: 1 })
|
||||
// @ts-expect-error Default data remains required for old extracted types.
|
||||
tool.postMessage({ type: 'custom' })
|
||||
// @ts-expect-error Message types are strings.
|
||||
precise.postMessage({ type: 1 })
|
||||
// @ts-expect-error Public request ids remain numeric.
|
||||
runtime.postMessage({ type: 'custom', id: '1' })
|
||||
// @ts-expect-error Public flags remain readonly in the default API.
|
||||
tool.injected = true
|
||||
// @ts-expect-error The legacy static receiver return is still void.
|
||||
const notAsync: Promise<void> = Iframe.onMessage(new MessageEvent('message', { data: packet }))
|
||||
// @ts-expect-error No self-default property exists on the real constructor.
|
||||
Iframe.default(option)
|
||||
// @ts-expect-error Runtime iframe is a readonly getter.
|
||||
runtime.iframe = true
|
||||
// @ts-expect-error Public notifications do not contain a request id.
|
||||
const wrongNotification: Notification = { type: 'custom', data: 1, id: 2 }
|
||||
receive({ type: 'error', data: 1, id: 1 })
|
||||
// @ts-expect-error Error packets still require a numeric request id.
|
||||
receive({ type: 'error', data: 1, id: '1' })
|
||||
// @ts-expect-error Known response data follows its protocol parameter.
|
||||
receive({ type: 'response', data: '1', id: 1 })
|
||||
// @ts-expect-error Typed resolver rejects incompatible values.
|
||||
resolver.commit<number>(resolve => resolve('3'))
|
||||
// @ts-expect-error Historical misspelling is preserved rather than silently renamed.
|
||||
callbacks.resolve(1)
|
||||
// @ts-expect-error Runtime notifications have unknown data until the application narrows it.
|
||||
precise.message(message => message.data.toFixed())
|
||||
void [old, asyncReceiver, unknownReply, numeric, resolved, notification, outgoing, notAsync, wrongNotification]
|
||||
Reference in new issue
Block a user