mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-23 22:01:20 -08:00
refactor(vast): [PKG-VAST-04] retain published types and add accurate runtime declarations
This commit is contained in:
1 parent
c162d2b3b3
commit
e5c73fa620
34 files changed
+7819
-1495
No files matched your search
+14
-1396
File diff suppressed because it is too large.
Load diff
@@ -12,4 +12,15 @@ export default antfu({
|
|||||||
rules: {
|
rules: {
|
||||||
"eslint-comments/no-unlimited-disable": "off",
|
"eslint-comments/no-unlimited-disable": "off",
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
name: 'artplayer/frozen-vast-public-declaration',
|
||||||
|
files: ['packages/artplayer-plugin-vast/types/artplayer-plugin-vast.d.ts'],
|
||||||
|
// Keep actual npm 1.0.0 declaration bytes; strict consumers verify its contracts.
|
||||||
|
rules: {
|
||||||
|
'style/semi': 'off',
|
||||||
|
'style/indent': 'off',
|
||||||
|
'style/member-delimiter-style': 'off',
|
||||||
|
'ts/no-use-before-define': 'off',
|
||||||
|
'ts/consistent-type-definitions': 'off',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
+3
-1
@@ -148,7 +148,9 @@
|
|||||||
"check:vconsole": "node scripts/build-vconsole.mjs --check",
|
"check:vconsole": "node scripts/build-vconsole.mjs --check",
|
||||||
"test:vconsole": "node --test test/vconsole-lifecycle.test.js",
|
"test:vconsole": "node --test test/vconsole-lifecycle.test.js",
|
||||||
"test:browser:source": "node scripts/browser-check.mjs source",
|
"test:browser:source": "node scripts/browser-check.mjs source",
|
||||||
"test:browser:installed": "node scripts/browser-check.mjs installed"
|
"test:browser:installed": "node scripts/browser-check.mjs installed",
|
||||||
|
"test:vast-types": "node --test refactor/scripts/vast-types.test.mjs",
|
||||||
|
"test:vast-types-package": "node refactor/scripts/vast-package-types.mjs"
|
||||||
},
|
},
|
||||||
"browserslist": "last 1 Chrome version",
|
"browserslist": "last 1 Chrome version",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ node_modules
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
yarn.lock
|
yarn.lock
|
||||||
package-lock.json
|
package-lock.json
|
||||||
src
|
src
|
||||||
|
tsconfig.json
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# VAST implementation and maintenance
|
# VAST implementation and maintenance
|
||||||
|
|
||||||
The runtime follows the accepted published-versus-workspace initialization decision.
|
The runtime and public types follow the accepted published-versus-workspace decisions.
|
||||||
Public declaration reconciliation and real IMA validation remain separate release gates.
|
Real IMA validation and full distribution acceptance remain separate release gates.
|
||||||
|
|
||||||
## Module map
|
## Module map
|
||||||
|
|
||||||
@@ -17,8 +17,13 @@ Public declaration reconciliation and real IMA validation remain separate releas
|
|||||||
active-ad request suppression; default mode delegates those behaviors to the SDK.
|
active-ad request suppression; default mode delegates those behaviors to the SDK.
|
||||||
- `src/view.ts` creates each mode's historical overlay styles and distinct per-module container
|
- `src/view.ts` creates each mode's historical overlay styles and distinct per-module container
|
||||||
IDs, including multiple instances initialized in the same millisecond.
|
IDs, including multiple instances initialized in the same millisecond.
|
||||||
- `src/types.ts` describes the implementation context and SDK boundary. Public legacy
|
- `src/types.ts` imports shared fields from `types/runtime-api.d.ts` for the implementation
|
||||||
declarations in `types/` remain separate pending PKG-VAST-04 reconciliation.
|
context, request configuration and result, and adds only private utilities/callback typing.
|
||||||
|
- `types/artplayer-plugin-vast.d.ts` is the exact npm1.0.0 declaration compatibility surface.
|
||||||
|
`types/runtime-api.d.ts` is the accurate SDK/context/Promise source; runtime.d.ts/.d.cts
|
||||||
|
expose CJS types, while runtime.d.mts exposes native ESM types. All resolve to the same
|
||||||
|
runtime artifacts. CJS declarations intentionally duplicate a small export facade;
|
||||||
|
changes must keep runtime.d.ts and runtime.d.cts identical.
|
||||||
|
|
||||||
Dependency direction is entry -> session -> SDK/view/types. The session passes the
|
Dependency direction is entry -> session -> SDK/view/types. The session passes the
|
||||||
original `art` through the callback for compatibility; only template elements are
|
original `art` through the callback for compatibility; only template elements are
|
||||||
@@ -36,7 +41,7 @@ secondary cleanup failures are logged without replacing the original error.
|
|||||||
Explicit plugin `destroy()` releases the current ad session, resets active-ad state,
|
Explicit plugin `destroy()` releases the current ad session, resets active-ad state,
|
||||||
and permits a later `init`/`playUrl`/`playRes` while the core remains alive. Core destroy
|
and permits a later `init`/`playUrl`/`playRes` while the core remains alive. Core destroy
|
||||||
and failed attachment are terminal: request methods are inert and `init()` returns
|
and failed attachment are terminal: request methods are inert and `init()` returns
|
||||||
null. Public declaration accuracy for this invalid-lifetime case belongs to04.
|
null. The accurate runtime declaration includes that terminal null result.
|
||||||
|
|
||||||
Each session has an owner identity. Its callbacks verify that identity and core
|
Each session has an owner identity. Its callbacks verify that identity and core
|
||||||
liveness before changing visibility. Cleanup detaches the current owner and clears
|
liveness before changing visibility. Cleanup detaches the current owner and clears
|
||||||
@@ -73,7 +78,8 @@ resource ownership. Never use a retained disposed SDK as an active session.
|
|||||||
Both modes retain void request methods, async registration and SDK/callback rejection.
|
Both modes retain void request methods, async registration and SDK/callback rejection.
|
||||||
The old `require(...).default(...)` call and current callable export remain available;
|
The old `require(...).default(...)` call and current callable export remain available;
|
||||||
this does not recreate the old namespace object's reflection shape. Contradictory
|
this does not recreate the old namespace object's reflection shape. Contradictory
|
||||||
public return declarations and the new second-argument declaration remain task04.
|
historical return declarations remain unchanged at the root; `/runtime` supplies the
|
||||||
|
accurate Promise, both mode-specific contexts and the second argument.
|
||||||
See [the accepted decision](../../refactor/vast-compatibility-decision.md).
|
See [the accepted decision](../../refactor/vast-compatibility-decision.md).
|
||||||
|
|
||||||
Overlay IDs use the historical `art-` default prefix or `art-vast-` workspace prefix,
|
Overlay IDs use the historical `art-` default prefix or `art-vast-` workspace prefix,
|
||||||
@@ -103,9 +109,17 @@ import, using an already destroyed host to verify registration without loading a
|
|||||||
Set `ARTPLAYER_VAST_ARTIFACT` and `ARTPLAYER_VAST_ESM_ARTIFACT` to test actual build
|
Set `ARTPLAYER_VAST_ARTIFACT` and `ARTPLAYER_VAST_ESM_ARTIFACT` to test actual build
|
||||||
files; otherwise it builds source via the repository helper. The live alias path
|
files; otherwise it builds source via the repository helper. The live alias path
|
||||||
uses the controlled SDK in `test/vast.test.js` and the browser registration case.
|
uses the controlled SDK in `test/vast.test.js` and the browser registration case.
|
||||||
Public alias declarations and complete installed entry validation remain04/06.
|
Accurate alias types are exposed only by `/runtime`; the root remains a pure historical
|
||||||
|
factory type. Installed root/legacy/runtime imports and strict SDK type dependency
|
||||||
|
resolution are checked by `yarn test:vast-types-package`. This does not replace task06's
|
||||||
|
complete browser/distribution acceptance.
|
||||||
|
|
||||||
For state or cleanup changes start in session, for callback timing in entry, and for
|
For state or cleanup changes start in session, for callback timing in entry, and for
|
||||||
SDK request fields in sdk. Keep Node candidate assertions, historical observations,
|
SDK request fields in sdk. Keep Node candidate assertions, historical observations,
|
||||||
browser counterparts and [test maintenance](../../refactor/vast-validation.md) aligned.
|
browser counterparts and [test maintenance](../../refactor/vast-validation.md) aligned.
|
||||||
Actual IMA/media/device validation remains05, public types04, and full distribution06.
|
`yarn test:vast-types` verifies unchanged root bytes, historical type conflicts, negative
|
||||||
|
runtime consumers and editor generation in TS5.9.3/4.3.5. `yarn build:ts artplayer-plugin-vast`
|
||||||
|
regenerates the root-compatible editor global. Frozen workspace editor tests continue to
|
||||||
|
exercise the SDK declaration bundler; they are labelled historical. Public migration
|
||||||
|
is documented in [the accepted type decision](../../refactor/vast-type-decision.md).
|
||||||
|
Actual IMA/media/device validation remains05 and full distribution06.
|
||||||
@@ -25,8 +25,40 @@ artplayerPluginVast((context) => {
|
|||||||
The callback may be asynchronous. Core destruction releases the ad session and prevents
|
The callback may be asynchronous. Core destruction releases the ad session and prevents
|
||||||
later requests or recreation. Explicit plugin `destroy()` allows a new ad session while
|
later requests or recreation. Explicit plugin `destroy()` allows a new ad session while
|
||||||
the core is alive. See the architecture guide for mode-specific fields and defaults.
|
the core is alive. See the architecture guide for mode-specific fields and defaults.
|
||||||
Public TypeScript declarations for the second argument are still being reconciled in
|
## TypeScript
|
||||||
PKG-VAST-04; these are JavaScript usage examples, not completed declaration acceptance.
|
|
||||||
|
The root and `/legacy` declarations preserve npm 1.0.0's historical factory shape,
|
||||||
|
including its required callback, `any` SDK fields and inaccurate synchronous result.
|
||||||
|
Registration has always been asynchronous: await it even when using the old declarations.
|
||||||
|
|
||||||
|
Use `/runtime` for accurate SDK types, Promise results, optional callbacks and the
|
||||||
|
compatibility option. This entry uses the same JavaScript implementation:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import vast from 'artplayer-plugin-vast/runtime'
|
||||||
|
|
||||||
|
vast(({ imaPlayer }) => {
|
||||||
|
// The default mode allocates this player before the callback.
|
||||||
|
imaPlayer.addEventListener('AdStarted', onAdStarted)
|
||||||
|
})
|
||||||
|
|
||||||
|
vast((context) => {
|
||||||
|
context.playerOptions.autoResize = false
|
||||||
|
context.init()?.addEventListener('AdStarted', onAdStarted)
|
||||||
|
}, { compatibility: 'workspace-1.2' })
|
||||||
|
```
|
||||||
|
|
||||||
|
Code using unpublished workspace types should move its imports to `/runtime` as well.
|
||||||
|
`ArtplayerPluginVastOption` describes the workspace callback; `ArtplayerPluginVastInstance`
|
||||||
|
describes the awaited result with `destroy()`. A workspace resource getter can be null,
|
||||||
|
and `init()` returns null after core destruction. Default data fields retain the last
|
||||||
|
allocation after release; retaining their values does not keep that allocation alive.
|
||||||
|
|
||||||
|
CommonJS TypeScript without interop can use
|
||||||
|
`import vast = require('artplayer-plugin-vast/runtime')`. Both `vast` and `vast.default`
|
||||||
|
are typed there. The old root declaration intentionally keeps its original factory
|
||||||
|
type without adding a required `.default` member, so plain replacement functions and
|
||||||
|
historical `Parameters`/`ReturnType` extraction remain compatible.
|
||||||
|
|
||||||
## Maintenance
|
## Maintenance
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,16 @@
|
|||||||
"types": "./types/artplayer-plugin-vast.d.ts",
|
"types": "./types/artplayer-plugin-vast.d.ts",
|
||||||
"import": "./dist/artplayer-plugin-vast.legacy.js",
|
"import": "./dist/artplayer-plugin-vast.legacy.js",
|
||||||
"require": "./dist/artplayer-plugin-vast.legacy.js"
|
"require": "./dist/artplayer-plugin-vast.legacy.js"
|
||||||
|
},
|
||||||
|
"./runtime": {
|
||||||
|
"import": {
|
||||||
|
"types": "./types/runtime.d.mts",
|
||||||
|
"default": "./dist/artplayer-plugin-vast.mjs"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"types": "./types/runtime.d.cts",
|
||||||
|
"default": "./dist/artplayer-plugin-vast.js"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"main": "./dist/artplayer-plugin-vast.js",
|
"main": "./dist/artplayer-plugin-vast.js",
|
||||||
@@ -37,5 +47,15 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alugha/ima": "2.1.0",
|
"@alugha/ima": "2.1.0",
|
||||||
"@glomex/vast-ima-player": "^1.21.2"
|
"@glomex/vast-ima-player": "^1.21.2"
|
||||||
|
},
|
||||||
|
"typesVersions": {
|
||||||
|
"*": {
|
||||||
|
"legacy": [
|
||||||
|
"types/artplayer-plugin-vast.d.ts"
|
||||||
|
],
|
||||||
|
"runtime": [
|
||||||
|
"types/runtime.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,30 +1,6 @@
|
|||||||
import type { google, ImaSdk } from '@alugha/ima'
|
|
||||||
import type { Player, PlayerOptions } from '@glomex/vast-ima-player'
|
|
||||||
import type Artplayer from 'artplayer'
|
import type Artplayer from 'artplayer'
|
||||||
|
import type { WorkspaceContext } from '../types/runtime-api.js'
|
||||||
|
|
||||||
export type Utilities = Pick<typeof Artplayer.utils, 'createElement' | 'setStyles'>
|
export type Utilities = Pick<typeof Artplayer.utils, 'createElement' | 'setStyles'>
|
||||||
export type RequestConfig = Record<string, unknown>
|
export type { CompatibilityOptions, WorkspaceContext as Context, RequestConfig, RuntimeResult as Result } from '../types/runtime-api.js'
|
||||||
|
export type Callback = (context: WorkspaceContext) => unknown
|
||||||
export interface CompatibilityOptions {
|
|
||||||
compatibility?: 'workspace-1.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Context {
|
|
||||||
art: Artplayer
|
|
||||||
playUrl: (url: string, config?: RequestConfig) => void
|
|
||||||
playRes: (response: string, config?: RequestConfig) => void
|
|
||||||
init: () => Player | null
|
|
||||||
ima: ImaSdk
|
|
||||||
adsRenderingSettings: google.ima.AdsRenderingSettings
|
|
||||||
playerOptions: PlayerOptions
|
|
||||||
readonly imaPlayer: Player | null
|
|
||||||
readonly id: string | null
|
|
||||||
readonly $container: HTMLDivElement | null
|
|
||||||
readonly container: HTMLDivElement | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Callback = (context: Context) => unknown
|
|
||||||
export interface Result {
|
|
||||||
name: 'artplayerPluginVast'
|
|
||||||
destroy: () => void
|
|
||||||
}
|
|
||||||
+16
-32
@@ -1,36 +1,20 @@
|
|||||||
import type { Player, PlayerOptions } from '@glomex/vast-ima-player'
|
import type Artplayer from 'artplayer';
|
||||||
import type Artplayer from 'artplayer'
|
|
||||||
|
|
||||||
declare global {
|
export = artplayerPluginVast;
|
||||||
interface Window {
|
export as namespace artplayerPluginVast;
|
||||||
artplayerPluginVast?: typeof artplayerPluginVast
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PlayUrlFn = (url: string, config?: any) => void
|
type Option = (params: {
|
||||||
type PlayResFn = (res: string, config?: any) => void
|
art: Artplayer;
|
||||||
|
id: string;
|
||||||
|
ima: any;
|
||||||
|
imaPlayer: any;
|
||||||
|
$container: HTMLDivElement;
|
||||||
|
playUrl: (url: string) => void;
|
||||||
|
playRes: (res: string) => void;
|
||||||
|
}) => void;
|
||||||
|
|
||||||
interface VastPluginContext {
|
type Result = {
|
||||||
art: Artplayer
|
name: 'artplayerPluginVast';
|
||||||
ima: any
|
};
|
||||||
imaPlayer: Player | null
|
|
||||||
playUrl: PlayUrlFn
|
|
||||||
playRes: PlayResFn
|
|
||||||
init: () => Player
|
|
||||||
adsRenderingSettings: any
|
|
||||||
playerOptions: PlayerOptions
|
|
||||||
container: HTMLDivElement | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ArtplayerPluginVastOption = (params: VastPluginContext) => void | Promise<void>
|
declare const artplayerPluginVast: (option: Option) => (art: Artplayer) => Result;
|
||||||
|
|
||||||
export interface ArtplayerPluginVastInstance {
|
|
||||||
name: 'artplayerPluginVast'
|
|
||||||
destroy?: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
declare function artplayerPluginVast(
|
|
||||||
option: ArtplayerPluginVastOption,
|
|
||||||
): (art: Artplayer) => ArtplayerPluginVastInstance
|
|
||||||
|
|
||||||
export default artplayerPluginVast
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import type { google, ImaSdk } from '@alugha/ima'
|
||||||
|
import type { Player, PlayerOptions } from '@glomex/vast-ima-player'
|
||||||
|
import type Artplayer from 'artplayer'
|
||||||
|
|
||||||
|
export type RequestConfig = Record<string, unknown>
|
||||||
|
|
||||||
|
export interface CompatibilityOptions {
|
||||||
|
compatibility?: 'workspace-1.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Context {
|
||||||
|
art: Artplayer
|
||||||
|
ima: ImaSdk
|
||||||
|
adsRenderingSettings: google.ima.AdsRenderingSettings
|
||||||
|
playerOptions: PlayerOptions
|
||||||
|
playUrl: (url: string, config?: RequestConfig) => void
|
||||||
|
playRes: (response: string, config?: RequestConfig) => void
|
||||||
|
init: () => Player | null
|
||||||
|
readonly container: HTMLDivElement | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Published data fields retain their last allocation after release. */
|
||||||
|
export interface PublishedContext extends Context {
|
||||||
|
imaPlayer: Player
|
||||||
|
id: string
|
||||||
|
$container: HTMLDivElement
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resource getters are null before initialization and after release. */
|
||||||
|
export interface WorkspaceContext extends Context {
|
||||||
|
readonly imaPlayer: Player | null
|
||||||
|
readonly id: string | null
|
||||||
|
readonly $container: HTMLDivElement | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RuntimeContext = PublishedContext | WorkspaceContext
|
||||||
|
export type RuntimeCallback<T extends RuntimeContext = RuntimeContext> = (context: T) => unknown
|
||||||
|
|
||||||
|
export interface RuntimeResult {
|
||||||
|
name: 'artplayerPluginVast'
|
||||||
|
destroy: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Registration = (art: Artplayer) => Promise<RuntimeResult>
|
||||||
|
|
||||||
|
export interface RuntimeFactory {
|
||||||
|
(callback?: RuntimeCallback<PublishedContext>, options?: { compatibility?: undefined }): Registration
|
||||||
|
(callback: RuntimeCallback<WorkspaceContext> | undefined, options: { compatibility: 'workspace-1.2' }): Registration
|
||||||
|
(callback: RuntimeCallback | undefined, options: CompatibilityOptions): Registration
|
||||||
|
default: RuntimeFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ArtplayerPluginVastOption = RuntimeCallback<WorkspaceContext>
|
||||||
|
export type ArtplayerPluginVastInstance = RuntimeResult
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import type { RuntimeFactory } from './runtime-api.js'
|
||||||
|
|
||||||
|
declare const artplayerPluginVast: RuntimeFactory
|
||||||
|
// eslint-disable-next-line ts/no-redeclare -- Ambient merge exposes types on the CommonJS factory.
|
||||||
|
declare namespace artplayerPluginVast {
|
||||||
|
type ArtplayerPluginVastInstance = import('./runtime-api.js').ArtplayerPluginVastInstance
|
||||||
|
type ArtplayerPluginVastOption = import('./runtime-api.js').ArtplayerPluginVastOption
|
||||||
|
type CompatibilityOptions = import('./runtime-api.js').CompatibilityOptions
|
||||||
|
type Context = import('./runtime-api.js').Context
|
||||||
|
type PublishedContext = import('./runtime-api.js').PublishedContext
|
||||||
|
type Registration = import('./runtime-api.js').Registration
|
||||||
|
type RequestConfig = import('./runtime-api.js').RequestConfig
|
||||||
|
type RuntimeCallback<T extends RuntimeContext = RuntimeContext> = import('./runtime-api.js').RuntimeCallback<T>
|
||||||
|
type RuntimeContext = import('./runtime-api.js').RuntimeContext
|
||||||
|
type RuntimeFactory = import('./runtime-api.js').RuntimeFactory
|
||||||
|
type RuntimeResult = import('./runtime-api.js').RuntimeResult
|
||||||
|
type WorkspaceContext = import('./runtime-api.js').WorkspaceContext
|
||||||
|
}
|
||||||
|
export = artplayerPluginVast
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { RuntimeFactory } from './runtime-api.js'
|
||||||
|
|
||||||
|
declare const artplayerPluginVast: RuntimeFactory
|
||||||
|
export default artplayerPluginVast
|
||||||
|
export type { ArtplayerPluginVastInstance, ArtplayerPluginVastOption, CompatibilityOptions, Context, PublishedContext, Registration, RequestConfig, RuntimeCallback, RuntimeContext, RuntimeFactory, RuntimeResult, WorkspaceContext } from './runtime-api.js'
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import type { RuntimeFactory } from './runtime-api.js'
|
||||||
|
|
||||||
|
declare const artplayerPluginVast: RuntimeFactory
|
||||||
|
// eslint-disable-next-line ts/no-redeclare -- Ambient merge exposes types on the CommonJS factory.
|
||||||
|
declare namespace artplayerPluginVast {
|
||||||
|
type ArtplayerPluginVastInstance = import('./runtime-api.js').ArtplayerPluginVastInstance
|
||||||
|
type ArtplayerPluginVastOption = import('./runtime-api.js').ArtplayerPluginVastOption
|
||||||
|
type CompatibilityOptions = import('./runtime-api.js').CompatibilityOptions
|
||||||
|
type Context = import('./runtime-api.js').Context
|
||||||
|
type PublishedContext = import('./runtime-api.js').PublishedContext
|
||||||
|
type Registration = import('./runtime-api.js').Registration
|
||||||
|
type RequestConfig = import('./runtime-api.js').RequestConfig
|
||||||
|
type RuntimeCallback<T extends RuntimeContext = RuntimeContext> = import('./runtime-api.js').RuntimeCallback<T>
|
||||||
|
type RuntimeContext = import('./runtime-api.js').RuntimeContext
|
||||||
|
type RuntimeFactory = import('./runtime-api.js').RuntimeFactory
|
||||||
|
type RuntimeResult = import('./runtime-api.js').RuntimeResult
|
||||||
|
type WorkspaceContext = import('./runtime-api.js').WorkspaceContext
|
||||||
|
}
|
||||||
|
export = artplayerPluginVast
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,66 @@
|
|||||||
|
# PKG-VAST-04:恢复发布类型并提供准确的双模式声明
|
||||||
|
|
||||||
|
基线c162d2b3b3f4fe64c3d178bdf0dc3b8eea32cac5。用户本次独立确认根入口保留
|
||||||
|
npm类型、未发布工作区类型迁移到/runtime,见[vast-type-decision.md](../vast-type-decision.md)。
|
||||||
|
这不是沿用Ads或其他四包的专属授权,也没有再次修改上一步初始化行为。
|
||||||
|
|
||||||
|
## 类型和模块
|
||||||
|
|
||||||
|
根/legacy恢复实际npm1.0.0声明原文:export=、必需callback、旧字段、SDK any与
|
||||||
|
同步结果误声明。完整typeof、Parameters、ReturnType、普通函数双向赋值与两个
|
||||||
|
编译器基线均保持;默认根类型没有新增必填default属性或不同重载。
|
||||||
|
|
||||||
|
/runtime复用已有三格式JS产物。runtime-api.d.ts统一描述ImaSdk/Player/Settings/
|
||||||
|
Options、配置、Context和Promise<RuntimeResult>;CJS的d.ts/d.cts与ESM的d.mts分别
|
||||||
|
提供正确模块形状。实现types.ts引用同一份字段/配置/Result,避免手工维护重复声明。
|
||||||
|
默认回调Player/id/容器非空且可写;workspace getter可空且只读;动态选项保留联合
|
||||||
|
上下文,不能推断默认非空。init在终止后可返回null,destroy在await结果中必需。
|
||||||
|
callback可省略,default自别名在准确入口声明,SDK字段不降级为any。
|
||||||
|
|
||||||
|
用户需将未发布工作区类型导入移到/runtime,并选择workspace-1.2;原根类型仍有
|
||||||
|
已明确披露的同步误声明,实际注册仍须await。README和模块地图包含迁移说明。
|
||||||
|
本步无新依赖,继续使用已固定的Glomex1.21.2和@alugha/ima2.1.0。新增两个Yarn
|
||||||
|
类型测试脚本,集成主typecheck和baseline发现;不改变Yarn版本、lockfile或包版本。
|
||||||
|
|
||||||
|
## 编辑器与打包修复
|
||||||
|
|
||||||
|
CommonJS编辑器生成器此前只允许Factory命名空间类型,不接受旧VAST的内联函数
|
||||||
|
类型和模块私有别名,首轮构建/测试精确失败。现支持该声明形状;未知导入/导出
|
||||||
|
仍拒绝。生成文件恢复npm旧global语义;原工作区SDK/Window/命名类型测试改用
|
||||||
|
校验过的冻结源码,保留旧路径验证,新增候选声明正反例及实际Monaco检查。
|
||||||
|
|
||||||
|
根文件的五项样式/声明顺序规则仅对这一个冻结文件局部关闭,以保留npm字节;
|
||||||
|
新runtime、实现和测试继续正常lint。生成声明只保留必要的历史顺序/别名规则说明,
|
||||||
|
不以any或skipLibCheck掩盖准确入口。生成器与旧SDK依赖工具文档同步。
|
||||||
|
|
||||||
|
首次真实pack检测到内部tsconfig.json泄漏,补充该包.npmignore后通过。源文件、
|
||||||
|
tsconfig与依赖不进入包。14组消费者从仓库外离线安装实际旧包/最终候选与核心,
|
||||||
|
再强制frozen重装并验证lock无变化、每个安装成员哈希、非workspace链接及所有
|
||||||
|
类型解析路径。准确入口实际解析到安装的两层SDK声明依赖。
|
||||||
|
|
||||||
|
## 验证及边界
|
||||||
|
|
||||||
|
日志、最终文件、安装矩阵与浏览器输入见[验证记录](../baselines/vast-types-validation.json)。
|
||||||
|
|
||||||
|
- 旧根原文与候选一致;完整历史工作区消费者冲突可重跑,3项类型提取、1项反向
|
||||||
|
赋值、2项缺失字段、1项可空访问失败分别记录。首次正式断言漏计反向赋值诊断,
|
||||||
|
补齐实际错误列表;没有删去消费者或改成宽泛失败断言。
|
||||||
|
- 类型/编辑器/工程20项通过;准确runtime14条反例逐行失败,根3类非法调用保持
|
||||||
|
原错误。完整VAST受控SDK运行时82项通过。
|
||||||
|
- 真正安装14组全部通过,包含TS5.9.3/4.3.5、Node10 CJS、NodeNext CJS/ESM、
|
||||||
|
Bundler ESM、不启用interop的import=require。root/legacy/runtime CJS、root/runtime
|
||||||
|
原生ESM身份和default别名验证通过;注册用已销毁宿主,不加载真实IMA。
|
||||||
|
- 三桌面引擎的本地Monaco编译旧VAST回调/工厂、拒绝缺失callback与错误ID类型,
|
||||||
|
并实际执行主播放器样例、获得非零解码尺寸。广告工厂只做类型验证。
|
||||||
|
- 正常VAST构建三格式及docs副本与上一步运行时字节一致;生成编辑器资产通过
|
||||||
|
两编译器检查。源与测试lint、严格源TS通过;全项目typecheck通过,检查415个
|
||||||
|
生产TS文件,已有核心runtime兼容编译器5.1.6矩阵也通过。
|
||||||
|
- 初始生成器失败、旧声明样式冲突、打包tsconfig泄漏、历史反例漏计与一次无文件
|
||||||
|
修改的PowerShell转义错误分别记录,不混作产品运行时回归。
|
||||||
|
|
||||||
|
## 交接和回退
|
||||||
|
|
||||||
|
本步只完成04类型/源码声明协调,不替代05真实IMA/设备验收或06完整历史深路径/
|
||||||
|
浏览器分发。VAST-TYPE-01按用户批准限定接受,VAST-DIST/LIFE和SDK验收继续开放。
|
||||||
|
本任务独立本地提交并执行提交审计,无push/publish。回退该提交恢复此前工作区根
|
||||||
|
声明并移除/runtime类型导出及本步打包/生成器修复;上一步两种运行时模式不受影响。
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import type Artplayer from 'artplayer'
|
||||||
|
import vast from 'artplayer-plugin-vast'
|
||||||
|
|
||||||
|
type OriginalCallback = (params: {
|
||||||
|
art: Artplayer
|
||||||
|
id: string
|
||||||
|
ima: any
|
||||||
|
imaPlayer: any
|
||||||
|
$container: HTMLDivElement
|
||||||
|
playUrl: (url: string) => void
|
||||||
|
playRes: (response: string) => void
|
||||||
|
}) => void
|
||||||
|
type OriginalResult = { name: 'artplayerPluginVast' }
|
||||||
|
type OriginalFactory = (option: OriginalCallback) => (art: Artplayer) => OriginalResult
|
||||||
|
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
|
||||||
|
type FactoryCheck = Assert<Equal<typeof vast, OriginalFactory>>
|
||||||
|
type ParameterCheck = Assert<Equal<Parameters<typeof vast>, [option: OriginalCallback]>>
|
||||||
|
type ResultCheck = Assert<Equal<ReturnType<ReturnType<typeof vast>>, OriginalResult>>
|
||||||
|
|
||||||
|
const replacement: typeof vast = (_option) => (_art) => ({ name: 'artplayerPluginVast' })
|
||||||
|
const reverse: OriginalFactory = vast
|
||||||
|
vast(({ art, id, imaPlayer, $container, playUrl, playRes }) => {
|
||||||
|
const identifier: string = id
|
||||||
|
const element: HTMLDivElement = $container
|
||||||
|
imaPlayer.addEventListener('AdStarted', () => {})
|
||||||
|
const url: void = playUrl('/ad.xml')
|
||||||
|
const response: void = playRes('<VAST/>')
|
||||||
|
void [art, identifier, element, url, response]
|
||||||
|
})
|
||||||
|
export type { FactoryCheck, ParameterCheck, ResultCheck }
|
||||||
|
void [replacement, reverse]
|
||||||
+3
-2
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 262 项,范围 22 个包及工作区/示例。
|
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 262 项,范围 22 个包及工作区/示例。
|
||||||
|
|
||||||
状态:todo 48 / doing 20 / blocked 0 / done 194 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
状态:todo 47 / doing 20 / blocked 0 / done 195 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||||
|
|
||||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||||
|
|
||||||
@@ -297,7 +297,7 @@
|
|||||||
| PKG-VAST-01 | artplayer-plugin-vast<br>核对包契约与历史用法 | BASE-05 | 异步工厂、callback context、playUrl/playRes/init 与 SDK 版本;实际 npm 1.0.0 与未发布 1.2.0、SDK 1.21.0/1.21.2 的60成员归档和发布关联核心5.1.7 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
|
| PKG-VAST-01 | artplayer-plugin-vast<br>核对包契约与历史用法 | BASE-05 | 异步工厂、callback context、playUrl/playRes/init 与 SDK 版本;实际 npm 1.0.0 与未发布 1.2.0、SDK 1.21.0/1.21.2 的60成员归档和发布关联核心5.1.7 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
|
||||||
| PKG-VAST-02 | artplayer-plugin-vast<br>建立特有行为与错误测试 | PKG-VAST-01, ENG-03, ENG-05 | SDK 失败、重复初始化、广告事件、内容恢复和销毁竞态;发布 id/$container/eager 与工作区 lazy/config 覆盖、callback拒绝、加载中销毁、同毫秒多实例与晚到事件 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
|
| PKG-VAST-02 | artplayer-plugin-vast<br>建立特有行为与错误测试 | PKG-VAST-01, ENG-03, ENG-05 | SDK 失败、重复初始化、广告事件、内容恢复和销毁竞态;发布 id/$container/eager 与工作区 lazy/config 覆盖、callback拒绝、加载中销毁、同毫秒多实例与晚到事件 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
|
||||||
| PKG-VAST-03 | artplayer-plugin-vast<br>整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
|
| PKG-VAST-03 | artplayer-plugin-vast<br>整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
|
||||||
| PKG-VAST-04 | artplayer-plugin-vast<br>迁移自有源码和公开类型 | PKG-VAST-03, ENG-04, ENG-06, CORE-07, PKG-VAST-07 | IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界;修复 @alugha/ima 声明依赖链,保留 export= 和 require.default 消费;同步错误声明的兼容决策单列 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
|
| PKG-VAST-04 | artplayer-plugin-vast<br>迁移自有源码和公开类型 | PKG-VAST-03, ENG-04, ENG-06, CORE-07, PKG-VAST-07 | IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界;修复 @alugha/ima 声明依赖链,保留 export= 和 require.default 消费;同步错误声明的兼容决策单列 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done |
|
||||||
| PKG-VAST-05 | artplayer-plugin-vast<br>验证新旧核心和组合 | PKG-VAST-04, CORE-22 | 官方测试广告或受控 SDK 环境,错误后主视频状态恢复;核验真实5.1.7/5.4.1/候选核心,VAST VPN外部脚本例外逐项记录,不将受控SDK当作实际IMA验收 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
| PKG-VAST-05 | artplayer-plugin-vast<br>验证新旧核心和组合 | PKG-VAST-04, CORE-22 | 官方测试广告或受控 SDK 环境,错误后主视频状态恢复;核验真实5.1.7/5.4.1/候选核心,VAST VPN外部脚本例外逐项记录,不将受控SDK当作实际IMA验收 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||||
| PKG-VAST-06 | artplayer-plugin-vast<br>验证分发并同步文档 | PKG-VAST-05, ENG-07 | vast.js、SDK 资源、声明消费和独立版本记录;核验实际发布 namespace default、历史深路径、ESM和准确声明,版本按政策2.0.0由REL-09统一处理 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
| PKG-VAST-06 | artplayer-plugin-vast<br>验证分发并同步文档 | PKG-VAST-05, ENG-07 | vast.js、SDK 资源、声明消费和独立版本记录;核验实际发布 namespace default、历史深路径、ESM和准确声明,版本按政策2.0.0由REL-09统一处理 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||||
| PKG-VAST-07 | artplayer-plugin-vast<br>恢复旧发布VAST工厂default调用入口 | PKG-VAST-01, PKG-VAST-02 | 保留当前直接工厂并增加default自身别名,验证四类分发调用及异步注册,初始化决策独立保留 | 旧产物default用例失败,新源码/实际main/legacy/ESM通过;真实核心三浏览器控制SDK注册验证、模块文档/构建/测试入口同步;不冒充namespace反射、声明和IMA验收 | M | done |
|
| PKG-VAST-07 | artplayer-plugin-vast<br>恢复旧发布VAST工厂default调用入口 | PKG-VAST-01, PKG-VAST-02 | 保留当前直接工厂并增加default自身别名,验证四类分发调用及异步注册,初始化决策独立保留 | 旧产物default用例失败,新源码/实际main/legacy/ESM通过;真实核心三浏览器控制SDK注册验证、模块文档/构建/测试入口同步;不冒充namespace反射、声明和IMA验收 | M | done |
|
||||||
@@ -601,6 +601,7 @@
|
|||||||
- PKG-VAST-01: [记录](baselines/vast-contract.md) [记录](baselines/vast-release.json) [记录](changes/2026-09-12-PKG-VAST-01-contract.md) [记录](baselines/vast-contract-validation.json)
|
- PKG-VAST-01: [记录](baselines/vast-contract.md) [记录](baselines/vast-release.json) [记录](changes/2026-09-12-PKG-VAST-01-contract.md) [记录](baselines/vast-contract-validation.json)
|
||||||
- PKG-VAST-02: [记录](changes/2026-09-12-PKG-VAST-02-tests.md) [记录](baselines/vast-behavior-validation.json) [记录](baselines/vast-core.json) [记录](vast-validation.md)
|
- PKG-VAST-02: [记录](changes/2026-09-12-PKG-VAST-02-tests.md) [记录](baselines/vast-behavior-validation.json) [记录](baselines/vast-core.json) [记录](vast-validation.md)
|
||||||
- PKG-VAST-03: [记录](changes/2026-09-12-PKG-VAST-03-lifecycle.md) [记录](baselines/vast-lifecycle-validation.json) [记录](vast-compatibility-decision.md) [记录](changes/2026-09-14-PKG-VAST-03-compatibility.md) [记录](baselines/vast-compatibility-validation.json)
|
- PKG-VAST-03: [记录](changes/2026-09-12-PKG-VAST-03-lifecycle.md) [记录](baselines/vast-lifecycle-validation.json) [记录](vast-compatibility-decision.md) [记录](changes/2026-09-14-PKG-VAST-03-compatibility.md) [记录](baselines/vast-compatibility-validation.json)
|
||||||
|
- PKG-VAST-04: [记录](changes/2026-09-14-PKG-VAST-04-types.md) [记录](baselines/vast-types-validation.json) [记录](vast-type-decision.md) [记录](vast-validation.md)
|
||||||
- PKG-CAST-01: [记录](baselines/chromecast-release.json) [记录](baselines/chromecast-contract.md) [记录](baselines/chromecast-contract-validation.json) [记录](changes/2026-09-13-PKG-CAST-01-contracts.md)
|
- PKG-CAST-01: [记录](baselines/chromecast-release.json) [记录](baselines/chromecast-contract.md) [记录](baselines/chromecast-contract-validation.json) [记录](changes/2026-09-13-PKG-CAST-01-contracts.md)
|
||||||
- PKG-CAST-02: [记录](changes/2026-09-13-PKG-CAST-02-failures.md) [记录](baselines/chromecast-failures-validation.json)
|
- PKG-CAST-02: [记录](changes/2026-09-13-PKG-CAST-02-failures.md) [记录](baselines/chromecast-failures-validation.json)
|
||||||
- PKG-CAST-03: [记录](changes/2026-09-13-PKG-CAST-03-runtime.md) [记录](baselines/chromecast-runtime-validation.json)
|
- PKG-CAST-03: [记录](changes/2026-09-13-PKG-CAST-03-runtime.md) [记录](baselines/chromecast-runtime-validation.json)
|
||||||
|
|||||||
@@ -1,5 +1,25 @@
|
|||||||
# 进度与证据
|
# 进度与证据
|
||||||
|
|
||||||
|
## PKG-VAST-04 公开类型协调及安装消费者完成
|
||||||
|
|
||||||
|
用户单独确认保留npm1.0.0根类型、工作区TS用法迁移/runtime。根/legacy声明原文
|
||||||
|
保留;准确入口覆盖Promise、SDK字段、两种模式的可空性/可写性、可选callback和
|
||||||
|
default别名。内部Context/Result/配置引用同一准确定义。README/架构/迁移决策同步。
|
||||||
|
|
||||||
|
实际旧包与最终候选在仓库外离线安装并强制frozen重装,14组编译模式全部通过,
|
||||||
|
检查所有安装成员/解析路径;最终核心+VAST共79个成员与当前文件一致。发现并修复
|
||||||
|
VAST打包带入内部tsconfig。编辑器生成器支持旧版内联工厂,保留冻结工作区SDK
|
||||||
|
生成测试;三浏览器Monaco正反例和主片解码均通过,未执行广告SDK。
|
||||||
|
|
||||||
|
20项类型/编辑器/工程、82项VAST运行回归通过,全项目typecheck通过415生产TS
|
||||||
|
文件;正常构建与上一步运行时产物一致。初始生成器/样式/打包错误、历史反例漏计
|
||||||
|
均有失败记录。见[变更](changes/2026-09-14-PKG-VAST-04-types.md)、
|
||||||
|
[证据](baselines/vast-types-validation.json)和[类型决定](vast-type-decision.md)。
|
||||||
|
|
||||||
|
04完成、类型风险按用户明确取舍限定接受;262项为195 done、20 doing、47 todo。
|
||||||
|
VAST剩05真实IMA/组合与06完整分发,LIFE/DIST和SDK风险继续开放。独立本地提交并
|
||||||
|
先核验提交审计,未push/publish;其他包、设备、远端CI及发布复盘不据此标完成。
|
||||||
|
|
||||||
## PKG-VAST-03 已确认初始化策略与运行时资源整理完成
|
## PKG-VAST-03 已确认初始化策略与运行时资源整理完成
|
||||||
|
|
||||||
用户于2026-09-14明确接受npm提前初始化默认、显式workspace-1.2惰性模式。
|
用户于2026-09-14明确接受npm提前初始化默认、显式workspace-1.2惰性模式。
|
||||||
|
|||||||
@@ -148,7 +148,7 @@
|
|||||||
| ADS-MEDIA-01 | open / 已复现 | Ads metadata 与 play 拒绝、隐藏页媒体状态和内容恢复仍缺真实验证 | PKG-ADS-02, PKG-ADS-03, PKG-ADS-05 |
|
| ADS-MEDIA-01 | open / 已复现 | Ads metadata 与 play 拒绝、隐藏页媒体状态和内容恢复仍缺真实验证 | PKG-ADS-02, PKG-ADS-03, PKG-ADS-05 |
|
||||||
| ADS-UI-01 | resolved / 已复现 | Ads 零等待跳过与初始状态不符,全屏图标/外部状态需核验 | PKG-ADS-02, PKG-ADS-03, PKG-ADS-05 |
|
| ADS-UI-01 | resolved / 已复现 | Ads 零等待跳过与初始状态不符,全屏图标/外部状态需核验 | PKG-ADS-02, PKG-ADS-03, PKG-ADS-05 |
|
||||||
| VAST-CONTEXT-01 | accepted-with-scope / 已复现 | Published VAST callback aliases and eager Player differ from the unpublished lazy workspace | PKG-VAST-02, PKG-VAST-03, PKG-VAST-04 |
|
| VAST-CONTEXT-01 | accepted-with-scope / 已复现 | Published VAST callback aliases and eager Player differ from the unpublished lazy workspace | PKG-VAST-02, PKG-VAST-03, PKG-VAST-04 |
|
||||||
| VAST-TYPE-01 | open / 已复现 | VAST declares an async factory as synchronous and imports an unavailable SDK type dependency | PKG-VAST-04, PKG-VAST-06 |
|
| VAST-TYPE-01 | accepted-with-scope / 已复现 | VAST declares an async factory as synchronous and imports an unavailable SDK type dependency | PKG-VAST-04, PKG-VAST-06 |
|
||||||
| VAST-LIFE-01 | open / 已复现 | VAST SDK and container lack core destruction ownership and pending work cancellation | PKG-VAST-02, PKG-VAST-03, PKG-VAST-05 |
|
| VAST-LIFE-01 | open / 已复现 | VAST SDK and container lack core destruction ownership and pending work cancellation | PKG-VAST-02, PKG-VAST-03, PKG-VAST-05 |
|
||||||
| VAST-DIST-01 | open / 已复现 | Published VAST CommonJS default namespace differs from the current callable distribution | PKG-VAST-04, PKG-VAST-06, PKG-VAST-07 |
|
| VAST-DIST-01 | open / 已复现 | Published VAST CommonJS default namespace differs from the current callable distribution | PKG-VAST-04, PKG-VAST-06, PKG-VAST-07 |
|
||||||
| AMBILIGHT-LIFE-01 | open / 已复现 | Ambilight sampling and RAF/DOM ownership lack terminal/error handling | PKG-AMBILIGHT-02, PKG-AMBILIGHT-03, PKG-AMBILIGHT-05 |
|
| AMBILIGHT-LIFE-01 | open / 已复现 | Ambilight sampling and RAF/DOM ownership lack terminal/error handling | PKG-AMBILIGHT-02, PKG-AMBILIGHT-03, PKG-AMBILIGHT-05 |
|
||||||
|
|||||||
+16
-5
@@ -3283,7 +3283,7 @@
|
|||||||
"id": "VAST-TYPE-01",
|
"id": "VAST-TYPE-01",
|
||||||
"title": "VAST declares an async factory as synchronous and imports an unavailable SDK type dependency",
|
"title": "VAST declares an async factory as synchronous and imports an unavailable SDK type dependency",
|
||||||
"confirmation": "reproduced",
|
"confirmation": "reproduced",
|
||||||
"status": "open",
|
"status": "accepted-with-scope",
|
||||||
"owners": [
|
"owners": [
|
||||||
"PKG-VAST-04",
|
"PKG-VAST-04",
|
||||||
"PKG-VAST-06"
|
"PKG-VAST-06"
|
||||||
@@ -3294,11 +3294,20 @@
|
|||||||
"refactor/changes/2026-09-12-PKG-VAST-01-contract.md",
|
"refactor/changes/2026-09-12-PKG-VAST-01-contract.md",
|
||||||
"refactor/baselines/vast-contract-validation.json",
|
"refactor/baselines/vast-contract-validation.json",
|
||||||
"refactor/baselines/vast-lifecycle-validation.json",
|
"refactor/baselines/vast-lifecycle-validation.json",
|
||||||
"refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md"
|
"refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md",
|
||||||
|
"refactor/changes/2026-09-14-PKG-VAST-04-types.md",
|
||||||
|
"refactor/baselines/vast-types-validation.json",
|
||||||
|
"refactor/vast-type-decision.md"
|
||||||
],
|
],
|
||||||
"compatibleResolution": "Provide accurate Promise/context/IMA types and a self-contained installed declaration chain while checking legacy export= and consumers.",
|
"compatibleResolution": "Provide accurate Promise/context/IMA types and a self-contained installed declaration chain while checking legacy export= and consumers.",
|
||||||
"closureCriteria": "Strict isolated package consumers pass without skipLibCheck; synchronous Result inference differences are reproduced and resolved or separately approved. Ads approval does not apply.",
|
"closureCriteria": "Strict isolated package consumers pass without skipLibCheck; synchronous Result inference differences are reproduced and resolved or separately approved. Ads approval does not apply.",
|
||||||
"workspaceState": "Direct @alugha/ima2.1.0 removes the two TS2307 diagnostics in TS5.9.3 and4.3.5; public synchronous Result mismatch and isolated packaged declaration validation remain04/06."
|
"workspaceState": "Task04 complete: root npm bytes and exact factory relationships preserved; CJS/ESM runtime types, editor consumers, old/current compiler positives and per-line negatives pass. Runtime public types share Context/Result/config with implementation. Full media and distribution acceptance remain05/06.",
|
||||||
|
"resolutionEvidence": [
|
||||||
|
"refactor/changes/2026-09-14-PKG-VAST-04-types.md",
|
||||||
|
"refactor/baselines/vast-types-validation.json",
|
||||||
|
"refactor/vast-type-decision.md"
|
||||||
|
],
|
||||||
|
"resolutionRationale": "User separately accepted npm1.0.0 root compatibility types and /runtime accurate Promise/SDK/context types, with unpublished workspace migration. Fourteen actual isolated installation/compiler cases pass without skipLibCheck and enforce SDK dependency resolution; root historical inaccuracy is disclosed, not presented as runtime truth."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "VAST-LIFE-01",
|
"id": "VAST-LIFE-01",
|
||||||
@@ -3345,11 +3354,13 @@
|
|||||||
"refactor/baselines/vast-contract-validation.json",
|
"refactor/baselines/vast-contract-validation.json",
|
||||||
"refactor/changes/2026-09-14-PKG-VAST-07-default-alias.md",
|
"refactor/changes/2026-09-14-PKG-VAST-07-default-alias.md",
|
||||||
"refactor/baselines/vast-alias-validation.json",
|
"refactor/baselines/vast-alias-validation.json",
|
||||||
"test/vast-exports.test.js"
|
"test/vast-exports.test.js",
|
||||||
|
"refactor/changes/2026-09-14-PKG-VAST-04-types.md",
|
||||||
|
"refactor/baselines/vast-types-validation.json"
|
||||||
],
|
],
|
||||||
"compatibleResolution": "Preserve require(pkg).default alongside callable factory, script global and current ESM/legacy paths.",
|
"compatibleResolution": "Preserve require(pkg).default alongside callable factory, script global and current ESM/legacy paths.",
|
||||||
"closureCriteria": "Real packed main/legacy/ESM, historical deep imports, export= consumers and local demo/editor all pass with immutable published comparisons.",
|
"closureCriteria": "Real packed main/legacy/ESM, historical deep imports, export= consumers and local demo/editor all pass with immutable published comparisons.",
|
||||||
"workspaceState": "Task07 restores historical JavaScript .default calls using a callable self-alias. Final four-format tests fail on pre-change main/ESM and pass produced main+ESM and legacy+ESM.65 Node and117 controlled-SDK browser checks pass. Old namespace reflection shape, public declarations, deep paths and installed distribution remain04/06; this risk stays open."
|
"workspaceState": "Task07 preserves old JavaScript default calls. Task04 adds accurate typed default on /runtime, actual isolated root/legacy/runtime imports and native ESM identity checks; preserves npm root types. Historical deep paths, complete browser distribution and old namespace reflection distinction remain task06; risk stays open."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "AMBILIGHT-LIFE-01",
|
"id": "AMBILIGHT-LIFE-01",
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
|
||||||
|
export function vastConsumer(kind, { legacy = false, requireImport = false } = {}) {
|
||||||
|
let source = fs.readFileSync(kind === 'runtime' ? 'test/types/vast-runtime.ts' : 'refactor/fixtures/consumers/vast-published.ts', 'utf8')
|
||||||
|
const entry = kind === 'runtime' ? 'artplayer-plugin-vast/runtime' : legacy ? 'artplayer-plugin-vast/legacy' : 'artplayer-plugin-vast'
|
||||||
|
if (legacy)
|
||||||
|
source = source.replaceAll('\'artplayer-plugin-vast\'', `'${entry}'`)
|
||||||
|
if (requireImport)
|
||||||
|
source = source.replace(`import vast from '${entry}'`, `import vast = require('${entry}')`)
|
||||||
|
return source
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runtimeNegatives(source) {
|
||||||
|
const lines = source.split('\n')
|
||||||
|
const expected = []
|
||||||
|
const invalid = lines.map((line, index) => {
|
||||||
|
if (!/^[ \t]*\/\/ @ts-expect-error/.test(line))
|
||||||
|
return line
|
||||||
|
assert(lines[index + 1]?.trim() && !lines[index + 1].trim().startsWith('//'))
|
||||||
|
expected.push(index + 2)
|
||||||
|
return ''
|
||||||
|
}).join('\n')
|
||||||
|
assert.equal(expected.length, 14, 'Keep every runtime misuse independently observable')
|
||||||
|
return { invalid, expected }
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
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 { hash, readMember } from './releases.mjs'
|
||||||
|
import { runtimeNegatives, vastConsumer } from './vast-consumer.mjs'
|
||||||
|
import { verifyVastContract } from './vast-contract.mjs'
|
||||||
|
|
||||||
|
let output
|
||||||
|
async function main() {
|
||||||
|
assert.equal(process.env.npm_config_user_agent?.split(' ')[0], 'yarn/1.22.22', 'Use yarn test:vast-types-package')
|
||||||
|
const yarn = process.env.npm_execpath
|
||||||
|
assert(yarn && fs.existsSync(yarn))
|
||||||
|
output = fs.mkdtempSync(path.join(workspace, 'refactor/.cache/vast-package-types-'))
|
||||||
|
console.log(`VAST isolated package evidence: ${output}`)
|
||||||
|
const contract = await verifyVastContract()
|
||||||
|
const fixtures = Object.fromEntries(['runtime', 'published'].map(kind => [kind, hash(vastConsumer(kind))]))
|
||||||
|
const packages = []
|
||||||
|
for (const name of ['artplayer', 'artplayer-plugin-vast']) {
|
||||||
|
const archive = path.join(output, `${name}.tgz`)
|
||||||
|
fs.writeFileSync(path.join(output, `${name}-pack.log`), run([yarn, 'pack', '--filename', archive], path.join(workspace, 'packages', name)))
|
||||||
|
const manifest = JSON.parse(readMember(archive, 'package/package.json'))
|
||||||
|
const files = packedFiles(archive)
|
||||||
|
checkFiles(manifest, files, name === 'artplayer-plugin-vast' ? Object.keys(contract.baseline.release.files) : [])
|
||||||
|
packages.push({ name, archive, sha256: hash(fs.readFileSync(archive)), files: Object.fromEntries(files.map(member => [member, hash(readMember(archive, member))])) })
|
||||||
|
}
|
||||||
|
const matrix = []
|
||||||
|
const core = packages[0]
|
||||||
|
const plugins = [{ ...contract.baseline.release, archive: contract.archives.get('artplayer-plugin-vast@1.0.0'), label: 'published' }, { ...packages[1], label: 'candidate' }]
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const consumer = consumerDirectory()
|
||||||
|
try {
|
||||||
|
writeJson(path.join(consumer, 'package.json'), { name: 'vast-isolated-consumer', private: true, dependencies: Object.fromEntries([core, plugin].map(pkg => [pkg.name, `file:${pkg.archive.replaceAll('\\', '/')}`])) })
|
||||||
|
fs.copyFileSync(path.join(workspace, 'yarn.lock'), path.join(consumer, 'yarn.lock'))
|
||||||
|
fs.writeFileSync(path.join(output, `${plugin.label}-install.log`), run([yarn, 'install', '--offline', '--ignore-scripts', '--non-interactive'], consumer))
|
||||||
|
const lock = fs.readFileSync(path.join(consumer, 'yarn.lock'))
|
||||||
|
fs.writeFileSync(path.join(output, `${plugin.label}-frozen-install.log`), run([yarn, 'install', '--offline', '--frozen-lockfile', '--ignore-scripts', '--non-interactive', '--force'], consumer))
|
||||||
|
assert.deepEqual(fs.readFileSync(path.join(consumer, 'yarn.lock')), lock)
|
||||||
|
fs.writeFileSync(path.join(output, `${plugin.label}-yarn.lock`), lock)
|
||||||
|
for (const pkg of [core, plugin]) {
|
||||||
|
const root = path.join(consumer, 'node_modules', pkg.name)
|
||||||
|
assert.equal(fs.realpathSync(root), root, 'Installed package must not be a workspace link')
|
||||||
|
for (const [member, expected] of Object.entries(pkg.files))
|
||||||
|
assert.equal(hash(fs.readFileSync(path.join(root, member.slice(8)))), expected, `Installed bytes differ: ${member}`)
|
||||||
|
}
|
||||||
|
const runtimeFile = path.join(consumer, 'exports.cjs')
|
||||||
|
fs.writeFileSync(runtimeFile, plugin.label === 'published'
|
||||||
|
? `const assert = require('node:assert/strict'); const value = require('artplayer-plugin-vast'); assert.equal(typeof value.default, 'function'); assert.equal(typeof value.default(() => {}), 'function');`
|
||||||
|
: `const assert = require('node:assert/strict');
|
||||||
|
(async () => {
|
||||||
|
for (const name of ['artplayer-plugin-vast','artplayer-plugin-vast/runtime','artplayer-plugin-vast/legacy']) {const factory = require(name); assert.equal(factory.default, factory); assert.equal((await factory()({isDestroy:true})).name,'artplayerPluginVast');}
|
||||||
|
assert.equal(require('artplayer-plugin-vast/runtime'),require('artplayer-plugin-vast'));
|
||||||
|
const [root,runtime] = await Promise.all(['artplayer-plugin-vast','artplayer-plugin-vast/runtime'].map(name=>import(name)));
|
||||||
|
assert.equal(root.default,runtime.default); assert.equal(runtime.default.default,runtime.default); assert.equal((await runtime.default()({isDestroy:true})).name,'artplayerPluginVast');
|
||||||
|
})().catch(error=>{console.error(error);process.exitCode=1;});`)
|
||||||
|
fs.writeFileSync(path.join(output, `${plugin.label}-runtime.log`), run([runtimeFile], consumer))
|
||||||
|
const modes = [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs'], [ts, 'node10-commonjs-no-interop'], [compat, 'node10-commonjs-no-interop']]
|
||||||
|
for (const [compiler, mode] of modes) {
|
||||||
|
const next = mode.startsWith('nodenext')
|
||||||
|
const requireImport = mode.endsWith('-no-interop')
|
||||||
|
const filename = path.join(consumer, next ? `consumer.${mode.endsWith('-cjs') ? 'cts' : 'mts'}` : 'consumer.ts')
|
||||||
|
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], esModuleInterop: !requireImport, target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: next ? compiler.ModuleKind.NodeNext : mode === 'bundler-esm' ? compiler.ModuleKind.ESNext : compiler.ModuleKind.CommonJS, moduleResolution: next ? compiler.ModuleResolutionKind.NodeNext : mode === 'bundler-esm' ? compiler.ModuleResolutionKind.Bundler : compiler.ModuleResolutionKind.NodeJs }
|
||||||
|
function compile(source) {
|
||||||
|
fs.writeFileSync(filename, source)
|
||||||
|
const program = compiler.createProgram([filename], options)
|
||||||
|
const declarations = []
|
||||||
|
for (const file of program.getSourceFiles()) {
|
||||||
|
const actual = fs.realpathSync(file.fileName)
|
||||||
|
assert(actual.startsWith(fs.realpathSync(consumer) + path.sep) || (program.isSourceFileDefaultLibrary(file) && path.dirname(actual) === fs.realpathSync(path.dirname(compiler.sys.getExecutingFilePath()))), `Types escaped installed consumer: ${actual}`)
|
||||||
|
if (!program.isSourceFileDefaultLibrary(file))
|
||||||
|
declarations.push({ file: path.relative(consumer, file.fileName).replaceAll('\\', '/'), sha256: hash(fs.readFileSync(file.fileName)) })
|
||||||
|
}
|
||||||
|
const diagnostics = compiler.getPreEmitDiagnostics(program).map(item => ({ code: item.code, file: item.file && path.relative(consumer, item.file.fileName).replaceAll('\\', '/'), line: item.file && item.start !== undefined ? item.file.getLineAndCharacterOfPosition(item.start).line + 1 : null, message: compiler.flattenDiagnosticMessageText(item.messageText, '\n') }))
|
||||||
|
return { sourceSha256: hash(source), diagnostics, declarations }
|
||||||
|
}
|
||||||
|
const entry = { plugin: plugin.label, compiler: compiler.version, mode }
|
||||||
|
matrix.push(entry)
|
||||||
|
const source = vastConsumer('published', { requireImport })
|
||||||
|
entry.root = compile(source)
|
||||||
|
writeJson(path.join(output, 'matrix-progress.json'), matrix)
|
||||||
|
assert.deepEqual(entry.root.diagnostics, [], `${plugin.label} ${compiler.version} ${mode}`)
|
||||||
|
entry.rootNegative = compile(`${source}\nvast();\nvast(undefined);\nvast.default(() => {});\n`)
|
||||||
|
assert.deepEqual(entry.rootNegative.diagnostics.map(item => item.code), [2554, 2345, 2339])
|
||||||
|
if (plugin.label === 'candidate') {
|
||||||
|
entry.legacy = compile(vastConsumer('published', { requireImport, legacy: true }))
|
||||||
|
assert.deepEqual(entry.legacy.diagnostics, [])
|
||||||
|
const runtime = vastConsumer('runtime', { requireImport })
|
||||||
|
entry.runtime = compile(runtime)
|
||||||
|
writeJson(path.join(output, 'matrix-progress.json'), matrix)
|
||||||
|
assert.deepEqual(entry.runtime.diagnostics, [])
|
||||||
|
assert(entry.runtime.declarations.some(item => item.file.includes('@alugha/ima/')), 'SDK types must resolve through actual installed dependencies')
|
||||||
|
assert(entry.runtime.declarations.some(item => item.file.includes('@glomex/vast-ima-player/')))
|
||||||
|
const { invalid, expected } = runtimeNegatives(runtime)
|
||||||
|
entry.runtimeNegative = compile(invalid)
|
||||||
|
assert.deepEqual(entry.runtimeNegative.diagnostics.map(item => item.line), expected)
|
||||||
|
}
|
||||||
|
writeJson(path.join(output, 'matrix-progress.json'), matrix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally { removeConsumer(consumer) }
|
||||||
|
}
|
||||||
|
assert.deepEqual(Object.fromEntries(['runtime', 'published'].map(kind => [kind, hash(vastConsumer(kind))])), fixtures, 'Fixtures changed during installed validation')
|
||||||
|
writeJson(path.join(output, 'report.json'), { task: 'PKG-VAST-04', node: process.version, fixtures, packages, published: { archive: plugins[0].archive, sha256: hash(fs.readFileSync(plugins[0].archive)) }, matrix, scope: 'Actual published and Yarn-packed candidate installed outside workspace; offline forced frozen reinstall, member hashes and declaration path isolation. No real IMA, live ad SDK registration, device or complete task06 distribution claim.' })
|
||||||
|
console.log(`VAST isolated installed consumers passed ${matrix.length} compiler modes: ${output}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
if (output)
|
||||||
|
writeJson(path.join(output, 'failure.json'), { message: error.message, stack: error.stack })
|
||||||
|
console.error(error)
|
||||||
|
process.exitCode = 1
|
||||||
|
})
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
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 -- Repository baseline 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 { readMember } from './releases.mjs'
|
||||||
|
import { runtimeNegatives } from './vast-consumer.mjs'
|
||||||
|
import { verifyVastContract } from './vast-contract.mjs'
|
||||||
|
|
||||||
|
const modes = [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']]
|
||||||
|
|
||||||
|
test('VAST frozen workspace declaration reproduces the approved npm consumer conflict', async () => {
|
||||||
|
const contract = await verifyVastContract()
|
||||||
|
const historical = contract.sources.get('packages/artplayer-plugin-vast/types/artplayer-plugin-vast.d.ts')
|
||||||
|
const source = fs.readFileSync('refactor/fixtures/consumers/vast-published.ts', 'utf8').replace('from \'artplayer-plugin-vast\'', 'from \'./vast-workspace-history\'')
|
||||||
|
for (const compiler of [ts, compat]) {
|
||||||
|
const filename = path.resolve('test/types/vast-history-consumer.ts')
|
||||||
|
const declaration = path.resolve('test/types/vast-workspace-history.d.ts')
|
||||||
|
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], esModuleInterop: true, target: compiler.ScriptTarget.ES2020, module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs, 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, source, language, true)
|
||||||
|
: path.resolve(file) === declaration ? compiler.createSourceFile(file, historical, 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)
|
||||||
|
const codes = compiler.getPreEmitDiagnostics(program).map(item => item.code)
|
||||||
|
assert.deepEqual(codes, [2344, 2344, 2344, 2322, 2339, 2339, compiler === ts ? 18047 : 2531])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('VAST root retains actual npm declaration bytes and complete factory extraction/replacement', async () => {
|
||||||
|
const contract = await verifyVastContract()
|
||||||
|
const published = readMember(contract.archives.get('artplayer-plugin-vast@1.0.0'), 'package/types/artplayer-plugin-vast.d.ts').toString().replaceAll('\r\n', '\n')
|
||||||
|
assert.equal(fs.readFileSync('packages/artplayer-plugin-vast/types/artplayer-plugin-vast.d.ts', 'utf8').replaceAll('\r\n', '\n'), published)
|
||||||
|
const source = fs.readFileSync('refactor/fixtures/consumers/vast-published.ts', 'utf8')
|
||||||
|
for (const [compiler, mode] of modes) {
|
||||||
|
assert.deepEqual(checkConsumer(compiler, mode, source), [], `${compiler.version} ${mode}`)
|
||||||
|
const invalid = `${source}\nvast();\nvast(undefined);\nvast.default(() => {});\n`
|
||||||
|
assert.deepEqual(checkConsumer(compiler, mode, invalid).map(item => item.code), [2554, 2345, 2339])
|
||||||
|
assert.deepEqual(checkConsumer(compiler, mode, source.replaceAll('\'artplayer-plugin-vast\'', '\'artplayer-plugin-vast/legacy\'')), [])
|
||||||
|
}
|
||||||
|
assert.deepEqual(checkConsumer(ts, 'nodenext-cjs', `import vast = require('artplayer-plugin-vast'); vast(({id}) => id);`), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('VAST runtime checks both initialization modes, SDK fields and async results in current and old compilers', () => {
|
||||||
|
assert.equal(fs.readFileSync('packages/artplayer-plugin-vast/types/runtime.d.ts', 'utf8'), fs.readFileSync('packages/artplayer-plugin-vast/types/runtime.d.cts', 'utf8'))
|
||||||
|
const source = fs.readFileSync('test/types/vast-runtime.ts', 'utf8')
|
||||||
|
for (const [compiler, mode] of modes) {
|
||||||
|
assert.deepEqual(checkConsumer(compiler, mode, source), [], `${compiler.version} ${mode}`)
|
||||||
|
const { invalid, expected } = runtimeNegatives(source)
|
||||||
|
const errors = checkConsumer(compiler, mode, invalid)
|
||||||
|
assert.deepEqual(errors.map(item => item.line), expected, `${compiler.version} ${mode}: every invalid statement must fail on its own line`)
|
||||||
|
}
|
||||||
|
assert.deepEqual(checkConsumer(ts, 'nodenext-cjs', `import vast = require('artplayer-plugin-vast/runtime');
|
||||||
|
const mode: vast.CompatibilityOptions = {compatibility:'workspace-1.2'};
|
||||||
|
vast(({imaPlayer}) => imaPlayer.addEventListener('AdStarted', () => {})); vast.default(undefined, mode);`), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('VAST editor preserves the published global callback and pure synchronous historical factory', async () => {
|
||||||
|
const source = fs.readFileSync('packages/artplayer-plugin-vast/types/artplayer-plugin-vast.d.ts', 'utf8')
|
||||||
|
const generated = generatePluginEditorDeclaration(source, 'artplayerPluginVast')
|
||||||
|
const file = 'docs/assets/ts/artplayer-plugin-vast.d.ts'
|
||||||
|
const [formatted] = await new ESLint({ fix: true, fixTypes: ['layout'] }).lintText(generated, { filePath: file })
|
||||||
|
assert.equal(formatted.errorCount, 0)
|
||||||
|
assert.equal(fs.readFileSync(file, 'utf8').replaceAll('\r\n', '\n'), formatted.output || generated)
|
||||||
|
const core = fs.readFileSync('docs/assets/ts/artplayer.d.ts', 'utf8')
|
||||||
|
const consumer = `declare const art: Artplayer;
|
||||||
|
const factory: typeof artplayerPluginVast = (_option) => (_art) => ({name: 'artplayerPluginVast'});
|
||||||
|
const result: {name: 'artplayerPluginVast'} = artplayerPluginVast(({id, $container, imaPlayer}) => {
|
||||||
|
const idValue: string = id; const node: HTMLDivElement = $container; imaPlayer.addEventListener('AdStarted', () => {}); void [idValue, node]; })(art);
|
||||||
|
// @ts-expect-error Historical callback remains required.
|
||||||
|
artplayerPluginVast();
|
||||||
|
// @ts-expect-error New options and accurate Promise belong to runtime entry.
|
||||||
|
artplayerPluginVast(() => {}, {compatibility:'workspace-1.2'});
|
||||||
|
void [factory, result];`
|
||||||
|
for (const compiler of [ts, compat]) {
|
||||||
|
assert.deepEqual(checkPluginEditorDeclaration(generated, core, consumer, compiler), [])
|
||||||
|
assert.equal(checkPluginEditorDeclaration(generated, core, consumer.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, ''), compiler).length, 2)
|
||||||
|
}
|
||||||
|
})
|
||||||
+7
-2
@@ -3112,11 +3112,16 @@
|
|||||||
"CORE-07",
|
"CORE-07",
|
||||||
"PKG-VAST-07"
|
"PKG-VAST-07"
|
||||||
],
|
],
|
||||||
"status": "todo",
|
"status": "done",
|
||||||
"risk": "H",
|
"risk": "H",
|
||||||
"deliverable": "IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界;修复 @alugha/ima 声明依赖链,保留 export= 和 require.default 消费;同步错误声明的兼容决策单列",
|
"deliverable": "IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界;修复 @alugha/ima 声明依赖链,保留 export= 和 require.default 消费;同步错误声明的兼容决策单列",
|
||||||
"acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容",
|
"acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容",
|
||||||
"evidence": []
|
"evidence": [
|
||||||
|
"changes/2026-09-14-PKG-VAST-04-types.md",
|
||||||
|
"baselines/vast-types-validation.json",
|
||||||
|
"vast-type-decision.md",
|
||||||
|
"vast-validation.md"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "PKG-VAST-05",
|
"id": "PKG-VAST-05",
|
||||||
|
|||||||
@@ -40,3 +40,9 @@ JASSUB 的 PKG-JASSUB-04 保留实际 npm 1.0.0/1.1.0 相同的根声明(忽
|
|||||||
不改变必填资源 URL、旧 resize 参数顺序、Promise 返回声明和扩展索引。新增
|
不改变必填资源 URL、旧 resize 参数顺序、Promise 返回声明和扩展索引。新增
|
||||||
/runtime 描述真实可选参数、同步方法及 Worker 数据,并复用同一运行产物。
|
/runtime 描述真实可选参数、同步方法及 Worker 数据,并复用同一运行产物。
|
||||||
这项实施没有新增旧类型破坏,不声称用户另行批准过 JASSUB 专属类型冲突。
|
这项实施没有新增旧类型破坏,不声称用户另行批准过 JASSUB 专属类型冲突。
|
||||||
|
|
||||||
|
VAST的PKG-VAST-04在2026-09-14取得独立确认:用户接受“保留 npm 根类型,工作区
|
||||||
|
类型迁移到 /runtime”。根/legacy保留实际npm1.0.0的export=、必需callback、any
|
||||||
|
SDK字段及同步历史结果;/runtime提供准确Promise、两种初始化模式及SDK类型。
|
||||||
|
未发布工作区的回调类型、命名类型和根导入形状按[vast-type-decision.md](vast-type-decision.md)
|
||||||
|
迁移。本次批准独立于VAST初始化时机批准,不是将此前四包授权自动扩大。
|
||||||
@@ -60,6 +60,6 @@ art-vast-;两者增加单模块递增后缀修复同毫秒ID碰撞,不恢复
|
|||||||
|
|
||||||
PKG-VAST-03已落实默认模式、显式工作区模式与发布字段,82项Node、162项三浏览器
|
PKG-VAST-03已落实默认模式、显式工作区模式与发布字段,82项Node、162项三浏览器
|
||||||
受控SDK检查通过;初始化风险按本次用户决定限定接受。详见
|
受控SDK检查通过;初始化风险按本次用户决定限定接受。详见
|
||||||
[完成记录](changes/2026-09-14-PKG-VAST-03-compatibility.md)。实际IMA播放和公开声明
|
[完成记录](changes/2026-09-14-PKG-VAST-03-compatibility.md)。公开声明随后按
|
||||||
尚未完成。此前Ads的类型推导批准与本次VAST运行时决定分别记录;未来类型协调
|
[独立类型确认](vast-type-decision.md)恢复npm根类型并提供准确/runtime入口;实际IMA
|
||||||
继续以实际发布声明为基线。
|
播放仍未验收。此前Ads的类型批准、本次运行时决定和随后VAST类型决定分别记录。
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# VAST 公开声明协调:已确认并实施
|
||||||
|
|
||||||
|
2026-09-14用户明确接受:“保留 npm 根类型,工作区类型迁移到 /runtime”。
|
||||||
|
本决定独立于初始化运行时批准;后续不再等待这项类型取舍授权。
|
||||||
|
|
||||||
|
PKG-VAST-04。运行时初始化策略已由用户单独确认,见
|
||||||
|
[运行时决策](vast-compatibility-decision.md);这里不重新询问该决定。
|
||||||
|
|
||||||
|
## 已复现的声明冲突
|
||||||
|
|
||||||
|
实际npm1.0.0根声明采用export=,回调有id/$container/imaPlayer:any,工厂参数必需,
|
||||||
|
第二层错误地声明同步{name}。未发布工作区1.2.0改成default export,回调增加
|
||||||
|
init/选项/getter但丢失id/$container,imaPlayer可空,并导出Option/Instance类型。
|
||||||
|
|
||||||
|
使用实际npm归档声明和当前工作区声明,在TS5.9.3及4.3.5、strict、无skipLibCheck
|
||||||
|
下交叉编译:各自消费者在原声明通过;npm消费者在工作区声明出现4项错误,包括
|
||||||
|
完整工厂类型不等、两个字段缺失、imaPlayer可空。工作区消费者在原npm声明缺少
|
||||||
|
命名类型。临时证据为refactor/.cache/vast04-type-conflict.json;正式测试继续纳入04。
|
||||||
|
补充命名类型可以解决部分导入问题,但无法同时保持两套不同回调Parameters、完整
|
||||||
|
工厂赋值关系、同步Result和准确Promise。增加交叉类型/重载也会改变类型提取结果。
|
||||||
|
|
||||||
|
## 已接受的方案
|
||||||
|
|
||||||
|
1. 根入口/legacy保留实际npm1.0.0的完整工厂类型、必需参数、export=及同步历史声明。
|
||||||
|
旧类型的any和同步误声明只作为历史兼容面保留,不声称它们准确描述运行时。
|
||||||
|
2. 新增/runtime,复用相同JS产物,提供准确Promise、必需destroy、可省略callback、
|
||||||
|
两种初始化模式、SDK类型、配置字段及.default自身别名。
|
||||||
|
3. 依赖未发布工作区回调/命名类型的TS代码转到/runtime,并显式选择workspace-1.2。
|
||||||
|
准确init返回Player|null;核心销毁后可能无法初始化,调用方需要判空。
|
||||||
|
4. 所有已验证的旧JavaScript调用保持上一任务已实现的行为。旧类型与真实行为的
|
||||||
|
差异、TS迁移示例、CJS/ESM导入方式写入包文档,并以隔离安装消费者验收。
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import vast from 'artplayer-plugin-vast/runtime'
|
||||||
|
|
||||||
|
vast((context) => {
|
||||||
|
context.playerOptions.autoResize = false
|
||||||
|
context.init()?.addEventListener('AdStarted', onAdStarted)
|
||||||
|
}, { compatibility: 'workspace-1.2' })
|
||||||
|
```
|
||||||
|
|
||||||
|
这会改变未发布工作区的根类型用法,已由本次用户明确确认。之前Canvas等包的类型
|
||||||
|
授权及VAST初始化授权均不作为此决定的替代依据;仍须实际消费验证才完成04。
|
||||||
|
没有推送或发布授权。
|
||||||
|
|
||||||
|
## 实施结果
|
||||||
|
|
||||||
|
根声明恢复实际npm原文(仅忽略换行格式比较);新增/runtime的CJS/ESM类型门面和
|
||||||
|
共用runtime-api.d.ts,内部Context/Result/配置也引用这份准确定义。两套模式的资源
|
||||||
|
字段可空性/可写性、必需destroy和Promise已建立正反例。实际安装14组编译检查通过,
|
||||||
|
包括不启用interop的require导入;完整结果见
|
||||||
|
[04记录](changes/2026-09-14-PKG-VAST-04-types.md)。真实Google IMA验收仍由05负责。
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
# VAST 测试维护
|
# VAST 测试维护
|
||||||
|
|
||||||
PKG-VAST-03现已落实用户确认的两种初始化模式;公开声明继续由04协调。来源见
|
PKG-VAST-03已落实用户确认的两种初始化模式;04按独立类型确认提供准确/runtime。
|
||||||
|
来源见
|
||||||
[实际契约](baselines/vast-contract.md)、[VAST/SDK归档](baselines/vast-release.json)
|
[实际契约](baselines/vast-contract.md)、[VAST/SDK归档](baselines/vast-release.json)
|
||||||
和 [核心5.1.7归档](baselines/vast-core.json)。工作区1.2.0不是npm发布版本。
|
和 [核心5.1.7归档](baselines/vast-core.json)。工作区1.2.0不是npm发布版本。
|
||||||
|
|
||||||
@@ -14,6 +15,17 @@ PKG-VAST-03现已落实用户确认的两种初始化模式;公开声明继续
|
|||||||
|
|
||||||
## 文件与执行
|
## 文件与执行
|
||||||
|
|
||||||
|
PKG-VAST-04新增`yarn test:vast-types`和`yarn test:vast-types-package`。根声明与
|
||||||
|
实际npm1.0.0原文一致,/runtime与同一JS产物绑定;TS5.9.3/4.3.5、CommonJS、
|
||||||
|
NodeNext、Bundler、关闭interop共14组实际安装消费通过。安装后强制frozen重装、
|
||||||
|
成员哈希与解析路径隔离均检查;14条runtime反例逐行断言错误,不能只统计数量。
|
||||||
|
主项目`yarn typecheck`也接入根/准确消费样例,baseline测试自动发现vast-types。
|
||||||
|
|
||||||
|
编辑器CommonJS生成器补齐旧VAST的内联工厂与局部type;当前global回归npm旧类型,
|
||||||
|
冻结工作区的SDK生成路径仍独立测试。三真实浏览器的Monaco消费生成声明、拒绝
|
||||||
|
错误输入,并运行主片解码样例均通过;不执行广告SDK。正式VAST运行回归82通过,
|
||||||
|
类型/编辑器/工程20通过。见[04记录](changes/2026-09-14-PKG-VAST-04-types.md)。
|
||||||
|
|
||||||
PKG-VAST-07补回工厂`.default`自身别名,不改变初始化决策。当时`yarn test:vast`
|
PKG-VAST-07补回工厂`.default`自身别名,不改变初始化决策。当时`yarn test:vast`
|
||||||
65项通过;实际main/legacy加ESM各4项导出通过。117项三浏览器检查通过,其中候选
|
65项通过;实际main/legacy加ESM各4项导出通过。117项三浏览器检查通过,其中候选
|
||||||
异步注册场景使用`.default`,其他场景保留直接调用。浏览器仍替换SDK边界,实际
|
异步注册场景使用`.default`,其他场景保留直接调用。浏览器仍替换SDK边界,实际
|
||||||
@@ -81,4 +93,4 @@ VAST-LIFE-01由源码观察提升为受控运行复现,问题如下:
|
|||||||
使用精确注入;Node固定Date.now用于同毫秒ID复现,未改变生产时钟。
|
使用精确注入;Node固定Date.now用于同毫秒ID复现,未改变生产时钟。
|
||||||
|
|
||||||
只有实际VAST外部脚本持续因VPN无法加载时,可按用户授权记录并跳过该网络验证;
|
只有实际VAST外部脚本持续因VPN无法加载时,可按用户授权记录并跳过该网络验证;
|
||||||
它不豁免类型、生命周期或其他包。本次未用该例外。04~06和SDK-07继续开放。
|
它不豁免类型、生命周期或其他包。本次未用该例外。05/06和SDK-07继续开放。
|
||||||
@@ -44,13 +44,18 @@ package consumer tests still use them. Core retains its existing bundler and
|
|||||||
private definitions namespace. Plugins preserve callable/default aliases and
|
private definitions namespace. Plugins preserve callable/default aliases and
|
||||||
exported type namespaces. Unsupported imports/re-exports and invalid syntax fail.
|
exported type namespaces. Unsupported imports/re-exports and invalid syntax fail.
|
||||||
|
|
||||||
VAST's `Player` and `PlayerOptions` come from the installed, lockfile-pinned
|
Historical workspace VAST's `Player` and `PlayerOptions` come from the installed, lockfile-pinned
|
||||||
`@glomex/vast-ima-player` 1.21.2 and `@alugha/ima` 2.1.0 declarations. A dedicated
|
`@glomex/vast-ima-player` 1.21.2 and `@alugha/ima` 2.1.0 declarations. A dedicated
|
||||||
type-only SDK entry avoids bundling a second copy of the linked workspace core.
|
type-only SDK entry avoids bundling a second copy of the linked workspace core.
|
||||||
SDK types stay in the plugin's module-private definitions namespace, not global
|
SDK types stay in the plugin's module-private definitions namespace, not global
|
||||||
runtime values. The optional Window hook and required callback remain unchanged.
|
runtime values. The optional Window hook and required callback remain unchanged.
|
||||||
Adjacent generated `artplayer-plugin-vast.LICENSE.txt` preserves upstream notices.
|
Adjacent generated `artplayer-plugin-vast.LICENSE.txt` preserves upstream notices.
|
||||||
This does not settle VAST's runtime default-behavior compatibility decision.
|
PKG-VAST-04 restores the published npm1.0.0 root declaration and editor global under
|
||||||
|
the user's explicit type decision. The CommonJS generator supports its inline factory
|
||||||
|
and module-private aliases, preserving the old required callback and field types.
|
||||||
|
Current root generation does not expose the workspace SDK types or Window augmentation;
|
||||||
|
the historical fixture still verifies that generator path. Accurate module consumers use
|
||||||
|
VAST's `/runtime` declarations. Real IMA verification remains separate.
|
||||||
|
|
||||||
The editor loads 22 declarations: core, 20 ecosystem libraries and i18n. The
|
The editor loads 22 declarations: core, 20 ecosystem libraries and i18n. The
|
||||||
unreferenced legacy `artplayer-plugin-websr.d.ts` asset is not in the canonical
|
unreferenced legacy `artplayer-plugin-websr.d.ts` asset is not in the canonical
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ function generateCommonJSPluginEditor(source: ts.SourceFile, name: string) {
|
|||||||
let exported = false
|
let exported = false
|
||||||
let global = false
|
let global = false
|
||||||
let classExport = false
|
let classExport = false
|
||||||
|
let inlineFactory = false
|
||||||
for (const node of source.statements) {
|
for (const node of source.statements) {
|
||||||
if (ts.isImportDeclaration(node)) {
|
if (ts.isImportDeclaration(node)) {
|
||||||
assert(ts.isStringLiteral(node.moduleSpecifier) && node.importClause?.isTypeOnly && !node.importClause.namedBindings && node.importClause.name?.text === 'Artplayer' && node.moduleSpecifier.text === 'artplayer', 'Unsupported CommonJS plugin editor import')
|
assert(ts.isStringLiteral(node.moduleSpecifier) && node.importClause?.isTypeOnly && !node.importClause.namedBindings && node.importClause.name?.text === 'Artplayer' && node.moduleSpecifier.text === 'artplayer', 'Unsupported CommonJS plugin editor import')
|
||||||
@@ -142,10 +143,14 @@ function generateCommonJSPluginEditor(source: ts.SourceFile, name: string) {
|
|||||||
const definition = definitions[0]
|
const definition = definitions[0]
|
||||||
assert(definition && ts.isIdentifier(definition.name) && definition.type)
|
assert(definition && ts.isIdentifier(definition.name) && definition.type)
|
||||||
assert.equal(definition.name.text, name)
|
assert.equal(definition.name.text, name)
|
||||||
assert(ts.isTypeReferenceNode(definition.type) && ts.isQualifiedName(definition.type.typeName)
|
inlineFactory = ts.isFunctionTypeNode(definition.type)
|
||||||
&& ts.isIdentifier(definition.type.typeName.left) && definition.type.typeName.left.text === name && definition.type.typeName.right.text === 'Factory', 'Editor export must use its public Factory interface')
|
assert(inlineFactory || (ts.isTypeReferenceNode(definition.type) && ts.isQualifiedName(definition.type.typeName)
|
||||||
|
&& ts.isIdentifier(definition.type.typeName.left) && definition.type.typeName.left.text === name && definition.type.typeName.right.text === 'Factory'), 'Editor export must use its public Factory interface or an inline function type')
|
||||||
callable = true
|
callable = true
|
||||||
}
|
}
|
||||||
|
else if (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node)) {
|
||||||
|
assert(!node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword), 'CommonJS local types must remain private')
|
||||||
|
}
|
||||||
else if (ts.isExportAssignment(node)) {
|
else if (ts.isExportAssignment(node)) {
|
||||||
assert(node.isExportEquals && ts.isIdentifier(node.expression) && node.expression.text === name, 'Unexpected CommonJS plugin export')
|
assert(node.isExportEquals && ts.isIdentifier(node.expression) && node.expression.text === name, 'Unexpected CommonJS plugin export')
|
||||||
exported = true
|
exported = true
|
||||||
@@ -159,10 +164,11 @@ function generateCommonJSPluginEditor(source: ts.SourceFile, name: string) {
|
|||||||
}
|
}
|
||||||
statements.push(node)
|
statements.push(node)
|
||||||
}
|
}
|
||||||
assert(namespace && callable && exported && global, 'Incomplete CommonJS plugin editor declaration')
|
assert((namespace || inlineFactory) && callable && exported && global, 'Incomplete CommonJS plugin editor declaration')
|
||||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
||||||
const bridge = classExport ? '' : '/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */\n'
|
const bridge = classExport || !namespace ? '' : '/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */\n'
|
||||||
return `// Generated from the package public declaration by yarn build:ts. Do not edit.\n${bridge}${statements.map(node => printer.printNode(ts.EmitHint.Unspecified, node, source)).join('\n')}\n`
|
const historical = inlineFactory ? '/* eslint-disable ts/no-use-before-define, ts/consistent-type-definitions -- Preserve historical export ordering and private aliases. */\n' : ''
|
||||||
|
return `// Generated from the package public declaration by yarn build:ts. Do not edit.\n${bridge}${historical}${statements.map(node => printer.printNode(ts.EmitHint.Unspecified, node, source)).join('\n')}\n`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkPluginEditorDeclaration(code: string, core: string, consumer = '', compiler: typeof ts = ts) {
|
export function checkPluginEditorDeclaration(code: string, core: string, consumer = '', compiler: typeof ts = ts) {
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ export function runTypechecks() {
|
|||||||
console.log(`Strict project passed: ${relative(config)} (${result.files.length} root files)`)
|
console.log(`Strict project passed: ${relative(config)} (${result.files.length} root files)`)
|
||||||
}
|
}
|
||||||
for (const [compiler, mode] of [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'bundler-esm'], [ts, 'nodenext-esm'], [compat, 'node10-commonjs']]) {
|
for (const [compiler, mode] of [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'bundler-esm'], [ts, 'nodenext-esm'], [compat, 'node10-commonjs']]) {
|
||||||
|
for (const fixture of ['test/types/vast-runtime.ts', 'refactor/fixtures/consumers/vast-published.ts'])
|
||||||
|
assert.deepEqual(checkConsumer(compiler, mode, fs.readFileSync(path.join(root, fixture), 'utf8')), [], `VAST consumer failed: TS ${compiler.version} ${mode}`)
|
||||||
for (const source of [autoThumbnailPublic(mode), autoThumbnailRuntime(mode)])
|
for (const source of [autoThumbnailPublic(mode), autoThumbnailRuntime(mode)])
|
||||||
assert.deepEqual(checkConsumer(compiler, mode, source), [], `Auto Thumbnail consumer failed: TS ${compiler.version} ${mode}`)
|
assert.deepEqual(checkConsumer(compiler, mode, source), [], `Auto Thumbnail consumer failed: TS ${compiler.version} ${mode}`)
|
||||||
for (const fixture of ['test/types/asr-public.ts', mode === 'nodenext-esm' ? 'refactor/fixtures/consumers/asr-esm-namespace.ts' : 'refactor/fixtures/consumers/asr-published.ts']) {
|
for (const fixture of ['test/types/asr-public.ts', mode === 'nodenext-esm' ? 'refactor/fixtures/consumers/asr-esm-namespace.ts' : 'refactor/fixtures/consumers/asr-published.ts']) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { expect, test } from './fixtures.js'
|
import { expect, test } from './fixtures.js'
|
||||||
|
|
||||||
test('docs Monaco worker consumes generated core types and runs a typed player example', async ({ page }) => {
|
test('docs Monaco worker consumes generated core and published VAST types and runs a typed player example', async ({ page }, testInfo) => {
|
||||||
await page.goto('/test/player.html?core=candidate&chapter=published')
|
await page.goto('/test/player.html?core=candidate&chapter=published')
|
||||||
await page.addScriptTag({ url: '/assets/js/vs/loader.js' })
|
await page.addScriptTag({ url: '/assets/js/vs/loader.js' })
|
||||||
const result = await page.evaluate(async () => {
|
const result = await page.evaluate(async () => {
|
||||||
@@ -12,23 +12,36 @@ test('docs Monaco worker consumes generated core types and runs a typed player e
|
|||||||
const source = await (await fetch('/assets/ts/artplayer.d.ts')).text()
|
const source = await (await fetch('/assets/ts/artplayer.d.ts')).text()
|
||||||
const libraryUri = 'file:///artplayer.d.ts'
|
const libraryUri = 'file:///artplayer.d.ts'
|
||||||
const library = types.typescriptDefaults.addExtraLib(source, libraryUri)
|
const library = types.typescriptDefaults.addExtraLib(source, libraryUri)
|
||||||
|
const vastSource = await (await fetch('/assets/ts/artplayer-plugin-vast.d.ts')).text()
|
||||||
|
const vastLibraryUri = 'file:///artplayer-plugin-vast.d.ts'
|
||||||
|
const vastLibrary = types.typescriptDefaults.addExtraLib(vastSource, vastLibraryUri)
|
||||||
const model = api.editor.createModel(`
|
const model = api.editor.createModel(`
|
||||||
const editorOption: Artplayer.OptionInput = { container: '.player', url: '/test/pattern.mp4', muted: true }
|
const editorOption: Artplayer.OptionInput = { container: '.player', url: '/test/pattern.mp4', muted: true }
|
||||||
const editorArt: Artplayer = new Artplayer(editorOption)
|
const editorArt: Artplayer = new Artplayer(editorOption)
|
||||||
const editorEvents: Artplayer.Emitter<{ value: [number] }> = new Artplayer.Emitter()
|
const editorEvents: Artplayer.Emitter<{ value: [number] }> = new Artplayer.Emitter()
|
||||||
editorEvents.emit('value', 1)
|
editorEvents.emit('value', 1)
|
||||||
|
const editorVastCallback: Parameters<typeof artplayerPluginVast>[0] = ({id, $container, imaPlayer}) => {
|
||||||
|
const identifier: string = id
|
||||||
|
const container: HTMLDivElement = $container
|
||||||
|
imaPlayer.addEventListener('AdStarted', () => {})
|
||||||
|
void [identifier, container]
|
||||||
|
}
|
||||||
|
const editorVastFactory: typeof artplayerPluginVast = (_callback) => (_art) => ({name: 'artplayerPluginVast'})
|
||||||
`, 'typescript', api.Uri.parse('file:///consumer.ts'))
|
`, 'typescript', api.Uri.parse('file:///consumer.ts'))
|
||||||
const invalid = api.editor.createModel('new Artplayer({ container: 123, url: "" })', 'typescript', api.Uri.parse('file:///invalid.ts'))
|
const invalid = api.editor.createModel('new Artplayer({ container: 123, url: "" })', 'typescript', api.Uri.parse('file:///invalid.ts'))
|
||||||
|
const vastInvalid = api.editor.createModel('artplayerPluginVast();\nartplayerPluginVast(({id}) => { const wrong: number = id })', 'typescript', api.Uri.parse('file:///vast-invalid.ts'))
|
||||||
try {
|
try {
|
||||||
const getWorker = await types.getTypeScriptWorker()
|
const getWorker = await types.getTypeScriptWorker()
|
||||||
const worker = await getWorker(model.uri, invalid.uri)
|
const worker = await getWorker(model.uri, invalid.uri, vastInvalid.uri)
|
||||||
const syntax = await worker.getSyntacticDiagnostics(model.uri.toString())
|
const syntax = await worker.getSyntacticDiagnostics(model.uri.toString())
|
||||||
const semantic = await worker.getSemanticDiagnostics(model.uri.toString())
|
const semantic = await worker.getSemanticDiagnostics(model.uri.toString())
|
||||||
const declaration = await worker.getSemanticDiagnostics(libraryUri)
|
const declaration = await worker.getSemanticDiagnostics(libraryUri)
|
||||||
|
const vastDeclaration = await worker.getSemanticDiagnostics(vastLibraryUri)
|
||||||
|
const vastBad = (await worker.getSemanticDiagnostics(vastInvalid.uri.toString())).map(item => item.code)
|
||||||
const bad = await worker.getSemanticDiagnostics(invalid.uri.toString())
|
const bad = await worker.getSemanticDiagnostics(invalid.uri.toString())
|
||||||
const output = await worker.getEmitOutput(model.uri.toString())
|
const output = await worker.getEmitOutput(model.uri.toString())
|
||||||
if (syntax.length || semantic.length || declaration.length)
|
if (syntax.length || semantic.length || declaration.length)
|
||||||
return { syntax, semantic, declaration, invalid: bad.map(item => item.code), ready: false }
|
return { syntax, semantic, declaration, vastDeclaration, vastBad, vastSource, invalid: bad.map(item => item.code), ready: false }
|
||||||
const script = output.outputFiles.find(file => file.name.endsWith('.js'))
|
const script = output.outputFiles.find(file => file.name.endsWith('.js'))
|
||||||
if (!script)
|
if (!script)
|
||||||
throw new Error('Monaco did not emit the typed example')
|
throw new Error('Monaco did not emit the typed example')
|
||||||
@@ -37,7 +50,7 @@ editorEvents.emit('value', 1)
|
|||||||
try {
|
try {
|
||||||
if (!art.isReady)
|
if (!art.isReady)
|
||||||
await new Promise(resolve => art.on('ready', resolve))
|
await new Promise(resolve => art.on('ready', resolve))
|
||||||
return { syntax, semantic, declaration, invalid: bad.map(item => item.code), ready: art.isReady && art.video.videoWidth > 0 }
|
return { syntax, semantic, declaration, vastDeclaration, vastBad, vastSource, invalid: bad.map(item => item.code), ready: art.isReady && art.video.videoWidth > 0 }
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
art.destroy()
|
art.destroy()
|
||||||
@@ -46,12 +59,17 @@ editorEvents.emit('value', 1)
|
|||||||
finally {
|
finally {
|
||||||
model.dispose()
|
model.dispose()
|
||||||
invalid.dispose()
|
invalid.dispose()
|
||||||
|
vastInvalid.dispose()
|
||||||
library.dispose()
|
library.dispose()
|
||||||
|
vastLibrary.dispose()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(result.syntax).toEqual([])
|
expect(result.syntax).toEqual([])
|
||||||
expect(result.semantic).toEqual([])
|
expect(result.semantic).toEqual([])
|
||||||
expect(result.declaration).toEqual([])
|
expect(result.declaration).toEqual([])
|
||||||
|
expect(result.vastDeclaration).toEqual([])
|
||||||
|
expect(result.vastBad).toEqual([2554, 2322])
|
||||||
|
await testInfo.attach('vast-editor-declaration', { contentType: 'text/plain', body: result.vastSource })
|
||||||
expect(result.invalid.length).toBeGreaterThan(0)
|
expect(result.invalid.length).toBeGreaterThan(0)
|
||||||
expect(result.ready).toBe(true)
|
expect(result.ready).toBe(true)
|
||||||
})
|
})
|
||||||
@@ -4,6 +4,7 @@ import fs from 'node:fs'
|
|||||||
import { test } from 'node:test'
|
import { test } from 'node:test'
|
||||||
import { ESLint } from 'eslint'
|
import { ESLint } from 'eslint'
|
||||||
import compat from 'typescript-compat'
|
import compat from 'typescript-compat'
|
||||||
|
import { verifyVastContract } from '../refactor/scripts/vast-contract.mjs'
|
||||||
import { vastSdkDeclarations } from '../scripts/editor-declarations/dependencies.ts'
|
import { vastSdkDeclarations } from '../scripts/editor-declarations/dependencies.ts'
|
||||||
import { editorLibUris, generateEditorDeclarations } from '../scripts/editor-declarations/generate.ts'
|
import { editorLibUris, generateEditorDeclarations } from '../scripts/editor-declarations/generate.ts'
|
||||||
import { checkStandaloneDeclarations } from '../scripts/editor-declarations/validation.ts'
|
import { checkStandaloneDeclarations } from '../scripts/editor-declarations/validation.ts'
|
||||||
@@ -24,11 +25,14 @@ test('editor declarations are reproducible, standalone and preserve constructor/
|
|||||||
assert.throws(() => asGlobalDeclaration('export { default } from "./missing"', 'Artplayer'), /unresolved exports/)
|
assert.throws(() => asGlobalDeclaration('export { default } from "./missing"', 'Artplayer'), /unresolved exports/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Chapter and VAST editor consumers preserve SDK types, optional Window hook and named results', () => {
|
test('Chapter and historical workspace VAST editor consumers preserve SDK types, optional Window hook and named results', async () => {
|
||||||
|
const contract = await verifyVastContract()
|
||||||
const core = fs.readFileSync('docs/assets/ts/artplayer.d.ts', 'utf8')
|
const core = fs.readFileSync('docs/assets/ts/artplayer.d.ts', 'utf8')
|
||||||
const generated = new Map([['artplayer.d.ts', core]])
|
const generated = new Map([['artplayer.d.ts', core]])
|
||||||
for (const [suffix, global] of [['chapter', 'artplayerPluginChapter'], ['vast', 'artplayerPluginVast']]) {
|
for (const [suffix, global] of [['chapter', 'artplayerPluginChapter'], ['vast', 'artplayerPluginVast']]) {
|
||||||
const source = fs.readFileSync(`packages/artplayer-plugin-${suffix}/types/artplayer-plugin-${suffix}.d.ts`, 'utf8')
|
const source = suffix === 'vast'
|
||||||
|
? contract.sources.get('packages/artplayer-plugin-vast/types/artplayer-plugin-vast.d.ts')
|
||||||
|
: fs.readFileSync(`packages/artplayer-plugin-${suffix}/types/artplayer-plugin-${suffix}.d.ts`, 'utf8')
|
||||||
const old = `${source.replace(/^import.*$/gim, '')}\nexport = ${global};\nexport as namespace ${global};\n`
|
const old = `${source.replace(/^import.*$/gim, '')}\nexport = ${global};\nexport as namespace ${global};\n`
|
||||||
const diagnostics = checkPluginEditorDeclaration(old, core)
|
const diagnostics = checkPluginEditorDeclaration(old, core)
|
||||||
assert(diagnostics.some(item => item.code === 2309))
|
assert(diagnostics.some(item => item.code === 2309))
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import type { google, ImaSdk } from '@alugha/ima'
|
||||||
|
import type { Player, PlayerOptions } from '@glomex/vast-ima-player'
|
||||||
|
import type Artplayer from 'artplayer'
|
||||||
|
import type { ArtplayerPluginVastInstance, ArtplayerPluginVastOption, CompatibilityOptions, PublishedContext, RuntimeFactory, RuntimeResult, WorkspaceContext } from 'artplayer-plugin-vast/runtime'
|
||||||
|
import vast from 'artplayer-plugin-vast/runtime'
|
||||||
|
|
||||||
|
declare const art: Artplayer
|
||||||
|
declare const options: CompatibilityOptions
|
||||||
|
|
||||||
|
const registration = vast((context) => {
|
||||||
|
const player: Player = context.imaPlayer
|
||||||
|
const container: HTMLDivElement = context.$container
|
||||||
|
const id: string = context.id
|
||||||
|
const sdk: ImaSdk = context.ima
|
||||||
|
const settings: google.ima.AdsRenderingSettings = context.adsRenderingSettings
|
||||||
|
const playerOptions: PlayerOptions = context.playerOptions
|
||||||
|
const self: PublishedContext = context
|
||||||
|
context.id = id
|
||||||
|
context.$container = container
|
||||||
|
context.imaPlayer = player
|
||||||
|
context.init()?.addEventListener('AdStarted', () => {})
|
||||||
|
const urlResult: void = context.playUrl('/ad.xml', { adTagUrl: '/override.xml', custom: true })
|
||||||
|
const responseResult: void = context.playRes('<VAST/>')
|
||||||
|
// @ts-expect-error SDK methods retain actual vendor signatures.
|
||||||
|
context.imaPlayer.playAds(42)
|
||||||
|
// @ts-expect-error SDK settings are typed.
|
||||||
|
context.adsRenderingSettings.enablePreloading = 'yes'
|
||||||
|
// @ts-expect-error The original media element must remain an element.
|
||||||
|
context.$container = 'container'
|
||||||
|
// @ts-expect-error Live container is read-only in both modes.
|
||||||
|
context.container = container
|
||||||
|
// @ts-expect-error Terminal core destruction makes init return null.
|
||||||
|
const initialized: Player = context.init()
|
||||||
|
void [player, container, id, sdk, settings, playerOptions, self, urlResult, responseResult, initialized]
|
||||||
|
})
|
||||||
|
|
||||||
|
const pending: Promise<RuntimeResult> = registration(art)
|
||||||
|
// @ts-expect-error Registration is asynchronous.
|
||||||
|
const synchronous: RuntimeResult = registration(art)
|
||||||
|
pending.then((result) => {
|
||||||
|
const name: 'artplayerPluginVast' = result.name
|
||||||
|
const disposed: void = result.destroy()
|
||||||
|
const migrated: ArtplayerPluginVastInstance = result
|
||||||
|
void [name, disposed, migrated]
|
||||||
|
})
|
||||||
|
vast()
|
||||||
|
vast.default()
|
||||||
|
vast(undefined, { compatibility: 'workspace-1.2' })
|
||||||
|
|
||||||
|
vast(async (context) => {
|
||||||
|
const self: WorkspaceContext = context
|
||||||
|
const player: Player | null = context.imaPlayer
|
||||||
|
const container: HTMLDivElement | null = context.$container
|
||||||
|
const id: string | null = context.id
|
||||||
|
context.playerOptions.autoResize = false
|
||||||
|
context.init()?.addEventListener('AdStarted', () => {})
|
||||||
|
// @ts-expect-error Workspace resource getters may be null.
|
||||||
|
const nonNull: Player = context.imaPlayer
|
||||||
|
// @ts-expect-error Workspace fields are getters without setters.
|
||||||
|
context.imaPlayer = player
|
||||||
|
// @ts-expect-error Workspace identifiers are getters without setters.
|
||||||
|
context.id = 'new-id'
|
||||||
|
// @ts-expect-error Request input remains a string.
|
||||||
|
context.playUrl(123)
|
||||||
|
void [self, player, container, id, nonNull]
|
||||||
|
}, { compatibility: 'workspace-1.2' })
|
||||||
|
|
||||||
|
vast((context) => {
|
||||||
|
const player: Player | null = context.imaPlayer
|
||||||
|
// @ts-expect-error Dynamic mode cannot promise eager allocation.
|
||||||
|
const eager: Player = context.imaPlayer
|
||||||
|
void [player, eager]
|
||||||
|
}, options)
|
||||||
|
const callback: ArtplayerPluginVastOption = context => context.init()
|
||||||
|
vast(callback, { compatibility: 'workspace-1.2' })
|
||||||
|
const factory: RuntimeFactory = vast.default
|
||||||
|
// @ts-expect-error Unknown compatibility mode is rejected at runtime.
|
||||||
|
vast(undefined, { compatibility: 'wrong' })
|
||||||
|
// @ts-expect-error Callback must be callable when supplied.
|
||||||
|
vast(1)
|
||||||
|
// @ts-expect-error A known workspace option cannot provide eager-only context.
|
||||||
|
vast((context: PublishedContext) => context.id, { compatibility: 'workspace-1.2' })
|
||||||
|
void [factory, synchronous]
|
||||||
Reference in new issue
Block a user