diff --git a/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts b/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts index e6f616aa0..eed4ad608 100644 --- a/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts +++ b/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts @@ -1,17 +1,18 @@ -interface Option { - url?: string - width?: number - number?: number - scale?: 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 artplayerPluginAutoThumbnailDefinitions { + export interface Option { + url?: string + width?: number + number?: number + scale?: number + } + export interface Result { + name: 'artplayerPluginAutoThumbnail' + } + export const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result } - -interface Result { - name: 'artplayerPluginAutoThumbnail' -} - -declare const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result - -export default artplayerPluginAutoThumbnail - +declare const artplayerPluginAutoThumbnail: typeof artplayerPluginAutoThumbnailDefinitions.artplayerPluginAutoThumbnail +declare namespace artplayerPluginAutoThumbnail { } export = artplayerPluginAutoThumbnail export as namespace artplayerPluginAutoThumbnail; diff --git a/package.json b/package.json index 50cd373a7..ba1495427 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "test:iframe-types-package": "node refactor/scripts/iframe-package-types.mjs", "test:thumbnail": "node --test test/thumbnail-emitter.test.js test/thumbnail-runtime.test.js test/thumbnail-vendor.test.js test/thumbnail-lifecycle.test.js test/thumbnail-input.test.js test/thumbnail.test.js refactor/scripts/thumbnail-contract.test.mjs refactor/scripts/thumbnail-types.test.mjs", "test:thumbnail-types-package": "node refactor/scripts/thumbnail-package-types.mjs", - "test:auto-thumbnail": "node --test test/auto-thumbnail-canvas.test.js test/auto-thumbnail-frames.test.js test/auto-thumbnail-lifecycle.test.js test/auto-thumbnail.test.js refactor/scripts/auto-thumbnail-contract.test.mjs", + "test:auto-thumbnail": "node --test test/auto-thumbnail-canvas.test.js test/auto-thumbnail-frames.test.js test/auto-thumbnail-lifecycle.test.js test/auto-thumbnail.test.js refactor/scripts/auto-thumbnail-contract.test.mjs refactor/scripts/auto-thumbnail-types.test.mjs", "test:vtt-thumbnail": "node --test test/vtt-thumbnail-parser.test.js test/vtt-thumbnail-lifecycle.test.js test/vtt-thumbnail.test.js refactor/scripts/vtt-thumbnail-contract.test.mjs refactor/scripts/vtt-thumbnail-types.test.mjs", "test:vtt-thumbnail-types-package": "node refactor/scripts/vtt-thumbnail-package-types.mjs", "test:multiple-subtitles": "node --test test/multiple-subtitles-merge.test.js test/multiple-subtitles-lifecycle.test.js test/multiple-subtitles-failures.test.js test/multiple-subtitles.test.js test/multiple-subtitles-vendor.test.js refactor/scripts/multiple-subtitles-contract.test.mjs refactor/scripts/multiple-subtitles-runtime-types.test.mjs refactor/scripts/multiple-subtitles-types.test.mjs", @@ -105,7 +105,9 @@ "test:danmuku": "node --test test/danmuku-setting.test.js test/danmuku-heatmap.test.js test/danmuku-renderer.test.js test/danmuku-scheduler.test.js test/danmuku-worker-client.test.js test/danmuku-input.test.js test/danmuku-parser.test.js test/danmuku-failures.test.js refactor/scripts/danmuku-contract.test.mjs", "test:danmuku-types": "node --test refactor/scripts/danmuku-types.test.mjs", "test:danmuku-types-package": "node refactor/scripts/danmuku-package-types.mjs", - "test:danmuku-mask-types-package": "node refactor/scripts/danmuku-mask-package-types.mjs" + "test:danmuku-mask-types-package": "node refactor/scripts/danmuku-mask-package-types.mjs", + "test:auto-thumbnail-types": "node --test refactor/scripts/auto-thumbnail-types.test.mjs", + "test:auto-thumbnail-types-package": "node refactor/scripts/auto-thumbnail-package-types.mjs" }, "browserslist": "last 1 Chrome version", "devDependencies": { diff --git a/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md b/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md index b8398255f..76dc5ad2d 100644 --- a/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md +++ b/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md @@ -46,7 +46,17 @@ for video processing. cleanup handles every frame without accumulating per-frame cleanup closures. - `src/types.ts` defines internal configuration, sheet data, the minimal host and guarded extraction-job callbacks. `guard` retains argument/result types and the - inactive undefined result. No public declarations are generated from this file. + inactive undefined result. It shares the opt-in `runtime-api.d.ts` option type; + the entry's Promise result is checked against that public result. No public + declarations are generated from this file. + +The original `types/artplayer-plugin-auto-thumbnail.d.ts` remains byte-equivalent +to npm 1.1.0 after newline normalization. `types/runtime-api.d.ts` owns the precise +option/result/factory contracts; `runtime.d.mts`, `runtime.d.cts`, and `runtime.d.ts` +adapt module resolution without adding runtime code or a factory `.default` alias. +The root editor declaration is generated semantically by `yarn build:ts`; its +historical synchronous callable shape is retained, without mixing default and +export-assignment syntax. See README for the optional accurate import. Only the entry module receives ArtPlayer. Extraction receives a guarded job and a configuration snapshot. These internal modules do not add public player fields, @@ -90,6 +100,8 @@ Use the root Yarn toolchain: ```sh yarn test:auto-thumbnail +yarn test:auto-thumbnail-types +yarn test:auto-thumbnail-types-package yarn exec tsc -p packages/artplayer-plugin-auto-thumbnail/tsconfig.json --noEmit yarn test:browser test/browser/auto-thumbnail-lifecycle.spec.js yarn test:browser test/browser/auto-thumbnail-pixels.spec.js @@ -101,7 +113,10 @@ regression tests. `ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT` selects an actual bundle. Historical contract/failure tests remain separate and continue to reproduce old defects; their passing status does not mean those defects should remain. -This is an intermediate `PKG-AUTO-THUMB-03` implementation. Native lifecycle +The public type entry is tracked independently as `PKG-AUTO-THUMB-08`, split from +04 so that declaration work can proceed without weakening the unfinished 03 +pixel gate. Task04 still depends on both 03 and 08. The source/runtime remains an +intermediate `PKG-AUTO-THUMB-03` implementation. Native lifecycle validation does not prove correct pixels. The attached renderer now has native pixel checks for all five cells when native frame callbacks are available, including the unique first frame, real black content, changing colors, spatial diff --git a/packages/artplayer-plugin-auto-thumbnail/README.md b/packages/artplayer-plugin-auto-thumbnail/README.md index 9e01ce96c..4e6a4a1b9 100644 --- a/packages/artplayer-plugin-auto-thumbnail/README.md +++ b/packages/artplayer-plugin-auto-thumbnail/README.md @@ -9,3 +9,49 @@ Auto thumbnail plugin for ArtPlayer ## License MIT © Harvey Zhao + +## TypeScript + +The root and `/legacy` entries retain the declarations published in 1.1.0, +including the historical synchronous result type. The implementation actually +returns a Promise when registering the plugin. For accurate types, opt into +`/runtime`, which uses the same JavaScript implementation: + +```ts +import Artplayer from 'artplayer' +import autoThumbnail from 'artplayer-plugin-auto-thumbnail/runtime' +import type { Option, Result } from 'artplayer-plugin-auto-thumbnail/runtime' + +const option: Option = { width: 160, number: 100, scale: 1 } +const art = new Artplayer({ + container: '#player', + url: '/video.mp4', + plugins: [autoThumbnail(option)], +}) +``` + +The registrar has type `(art: Artplayer) => Promise`. It resolves with +`{ name: 'artplayerPluginAutoThumbnail' }` after subscribing to player events, +before extraction completes. Generated sheets arrive progressively through the +player's thumbnails configuration. Awaiting registration does not wait for them. +The options object is required; use `{}` for defaults. `height` is accepted by +the runtime type for historical callers but remains ignored: the video aspect +ratio determines sheet height. Numeric strings retain their old JavaScript +coercion behavior but are not advertised as numeric TypeScript options. + +The runtime entry supports default ESM imports and CommonJS +`import autoThumbnail = require('artplayer-plugin-auto-thumbnail/runtime')`. +It exports the `Option`, `Result`, and `Factory` types. The factory has no +`.default` self alias and the result has no extraction-completion or destroy API. +Node10 resolution uses `typesVersions`; modern resolution uses separate ESM/CJS +declarations. The old root's NodeNext namespace behavior is preserved; `/runtime` +provides a direct default-import type without changing that old declaration. + +Versions 1.0.x used `export =` declarations and advertised `height` instead of +`number`; 1.1.0 had already changed these types. This refactor retains the actual +1.1.0 root declaration rather than introducing another conflicting root shape. +Consumers needing the older ignored `height` option can use `/runtime`. + +See [ARCHITECTURE.md](ARCHITECTURE.md) for module ownership, tests, and remaining +browser extraction limitations. This type entry does not resolve the documented +Windows WebKit first-frame issue. diff --git a/packages/artplayer-plugin-auto-thumbnail/package.json b/packages/artplayer-plugin-auto-thumbnail/package.json index cec8e9001..7b85d65c0 100644 --- a/packages/artplayer-plugin-auto-thumbnail/package.json +++ b/packages/artplayer-plugin-auto-thumbnail/package.json @@ -27,11 +27,31 @@ "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", "import": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", "require": "./dist/artplayer-plugin-auto-thumbnail.legacy.js" + }, + "./runtime": { + "import": { + "types": "./types/runtime.d.mts", + "default": "./dist/artplayer-plugin-auto-thumbnail.mjs" + }, + "require": { + "types": "./types/runtime.d.cts", + "default": "./dist/artplayer-plugin-auto-thumbnail.js" + } } }, "main": "./dist/artplayer-plugin-auto-thumbnail.js", "module": "./dist/artplayer-plugin-auto-thumbnail.mjs", "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", "legacy": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", - "browserslist": "last 1 Chrome version" + "browserslist": "last 1 Chrome version", + "typesVersions": { + "*": { + "legacy": [ + "types/artplayer-plugin-auto-thumbnail.d.ts" + ], + "runtime": [ + "types/runtime.d.ts" + ] + } + } } diff --git a/packages/artplayer-plugin-auto-thumbnail/src/index.ts b/packages/artplayer-plugin-auto-thumbnail/src/index.ts index 234db8d38..bd940cf35 100644 --- a/packages/artplayer-plugin-auto-thumbnail/src/index.ts +++ b/packages/artplayer-plugin-auto-thumbnail/src/index.ts @@ -1,10 +1,11 @@ +import type { Result } from '../types/runtime-api' import type { Cleanup, ThumbnailHost, ThumbnailOptions } from './types' import extract from './extraction' import { readOptions } from './options' import createSession, { cleanupAll } from './session' export default function artplayerPluginAutoThumbnail(option: ThumbnailOptions) { - return async (art: ThumbnailHost) => { + return async (art: ThumbnailHost): Promise => { const report = (error: unknown) => console.warn('ArtPlayer auto-thumbnail failed:', error) const session = createSession((config) => { art.thumbnails = config diff --git a/packages/artplayer-plugin-auto-thumbnail/src/types.ts b/packages/artplayer-plugin-auto-thumbnail/src/types.ts index d5154673a..be815127a 100644 --- a/packages/artplayer-plugin-auto-thumbnail/src/types.ts +++ b/packages/artplayer-plugin-auto-thumbnail/src/types.ts @@ -1,11 +1,5 @@ -// Internal contracts only. Public declarations retain their historical entrypoint. -export interface ThumbnailOptions { - url?: string - width?: number - number?: number - scale?: number - height?: number -} +// Root declarations retain their historical shape; the opt-in runtime view is shared. +export type { Option as ThumbnailOptions } from '../types/runtime-api' export interface ExtractionConfig { url: string diff --git a/packages/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts b/packages/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts new file mode 100644 index 000000000..70274eda8 --- /dev/null +++ b/packages/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts @@ -0,0 +1,21 @@ +// Support both the core's ESM/default and CommonJS export= declarations. +type CoreModule = typeof import('artplayer') +type Artplayer = CoreModule extends { default: { prototype: infer Instance } } + ? Instance + : CoreModule extends { prototype: infer Instance } ? Instance : never + +export interface Option { + url?: string + width?: number + number?: number + scale?: number + /** Historical option; sheet height is derived from the video's aspect ratio. */ + height?: number +} + +export interface Result { + name: 'artplayerPluginAutoThumbnail' +} + +/** Registration resolves before frame extraction and progressive sheet updates. */ +export type Factory = (option: Option) => (art: Artplayer) => Promise diff --git a/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.cts b/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.cts new file mode 100644 index 000000000..d99a254d2 --- /dev/null +++ b/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.cts @@ -0,0 +1,10 @@ +import type { Factory } from './runtime-api.js' + +declare const artplayerPluginAutoThumbnail: Factory +// eslint-disable-next-line ts/no-redeclare -- Ambient merge exposes types on the CommonJS factory. +declare namespace artplayerPluginAutoThumbnail { + type Option = import('./runtime-api.js').Option + type Result = import('./runtime-api.js').Result + type Factory = import('./runtime-api.js').Factory +} +export = artplayerPluginAutoThumbnail diff --git a/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.mts b/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.mts new file mode 100644 index 000000000..079d78b49 --- /dev/null +++ b/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.mts @@ -0,0 +1,5 @@ +import type { Factory } from './runtime-api.js' + +declare const artplayerPluginAutoThumbnail: Factory +export default artplayerPluginAutoThumbnail +export type { Factory, Option, Result } from './runtime-api.js' diff --git a/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.ts b/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.ts new file mode 100644 index 000000000..d99a254d2 --- /dev/null +++ b/packages/artplayer-plugin-auto-thumbnail/types/runtime.d.ts @@ -0,0 +1,10 @@ +import type { Factory } from './runtime-api.js' + +declare const artplayerPluginAutoThumbnail: Factory +// eslint-disable-next-line ts/no-redeclare -- Ambient merge exposes types on the CommonJS factory. +declare namespace artplayerPluginAutoThumbnail { + type Option = import('./runtime-api.js').Option + type Result = import('./runtime-api.js').Result + type Factory = import('./runtime-api.js').Factory +} +export = artplayerPluginAutoThumbnail diff --git a/refactor/baselines/auto-thumbnail-types-validation.json b/refactor/baselines/auto-thumbnail-types-validation.json new file mode 100644 index 000000000..f8079be17 --- /dev/null +++ b/refactor/baselines/auto-thumbnail-types-validation.json @@ -0,0 +1,1425 @@ +{ + "task": "PKG-AUTO-THUMB-08", + "capturedAt": "2026-09-13T20:06:59.141Z", + "base": "7be628a98312dbad5d9d9573ae0204e9d79faa01", + "outcome": "passed", + "scope": "Published 1.1.0 and candidate declaration entry task only; package migration remains incomplete", + "installed": { + "task": "PKG-AUTO-THUMB-08", + "node": "v24.21.0", + "packages": [ + { + "name": "artplayer", + "manifest": { + "name": "artplayer", + "version": "5.4.1", + "description": "ArtPlayer.js is a modern and full featured HTML5 video player", + "author": "Harvey Zhao ", + "license": "MIT", + "homepage": "https://artplayer.org", + "repository": { + "type": "git", + "url": "git+https://github.com/zhw2590582/ArtPlayer.git" + }, + "bugs": { + "url": "https://github.com/zhw2590582/ArtPlayer/issues" + }, + "keywords": [ + "html5", + "video", + "player" + ], + "exports": { + ".": { + "import": { + "types": "./types/artplayer.d.mts", + "default": "./dist/artplayer.mjs" + }, + "require": { + "types": "./types/artplayer.d.cts", + "default": "./dist/artplayer.js" + } + }, + "./types": { + "types": "./types/artplayer.d.ts" + }, + "./runtime": { + "import": { + "types": "./types/runtime.d.mts", + "default": "./dist/artplayer.mjs" + }, + "require": { + "types": "./types/runtime.d.cts", + "default": "./dist/artplayer.js" + } + }, + "./runtime/types": { + "types": "./types/runtime.d.ts" + }, + "./runtime/legacy": { + "import": { + "types": "./types/runtime.d.cts", + "default": "./dist/artplayer.legacy.js" + }, + "require": { + "types": "./types/runtime.d.cts", + "default": "./dist/artplayer.legacy.js" + } + }, + "./legacy": { + "import": { + "types": "./types/artplayer.d.cts", + "default": "./dist/artplayer.legacy.js" + }, + "require": { + "types": "./types/artplayer.d.cts", + "default": "./dist/artplayer.legacy.js" + } + }, + "./i18n/*": { + "import": { + "types": "./types/language.d.mts", + "default": "./dist/i18n/*.mjs" + }, + "require": { + "types": "./types/language.d.cts", + "default": "./dist/i18n/*.js" + } + } + }, + "main": "./dist/artplayer.js", + "module": "./dist/artplayer.mjs", + "types": "./types/artplayer.d.ts", + "typesVersions": { + "*": { + "types": [ + "types/artplayer.d.ts" + ], + "runtime": [ + "types/runtime.d.ts" + ], + "runtime/types": [ + "types/runtime.d.ts" + ], + "runtime/legacy": [ + "types/runtime.d.ts" + ], + "i18n/*": [ + "types/legacy/language.d.ts" + ], + "legacy": [ + "types/artplayer.d.ts" + ] + } + }, + "legacy": "./dist/artplayer.legacy.js", + "browserslist": "last 1 Chrome version", + "dependencies": { + "option-validator": "^2.0.6" + } + }, + "archive": "./refactor/.cache/auto-thumbnail-package-types-6JeGsd/artplayer.tgz", + "sha256": "0c0ea52d41575261b836aefac68280733b119c75834ecad6d4bc78edb073f4c1", + "files": { + "package/ARCHITECTURE.md": "bee98fc9d93a3911d58e98ef15f2dbe07e12f2274c444d989094248a22079e46", + "package/README.md": "1e185e65f67fc2081b4182bbc6c4558ea05b6e3fa3acc5dd0c3ac7df1d542b09", + "package/THIRD_PARTY_NOTICES": "b77b5b46b79fa0cda850b0781f78c3b1112c4ed9672fa291956fe8eff53098e7", + "package/dist/artplayer.js": "6dc8ca6d6eb34aa8a056cbc31328efd634530b3c5c60f0014cb7ce719fabc335", + "package/dist/artplayer.legacy.js": "80f74a8a39df4baf64cc00c65d21cd57c011bfcdead0da38eea077fbc67c5c04", + "package/dist/artplayer.mjs": "432e2b0ad92009a09743e020bf7c928c8b8f18a52496622b16259ec9ab20059f", + "package/dist/i18n/ar.js": "bd0bef65f4f7dc3f8ed562904cc6fa9071ff4537fb64c1e0fc3d554141bcd3cb", + "package/dist/i18n/ar.mjs": "59310b7bbeea83bbb7d73aadc5ca82a6ec269c3530d19aa741c94d5c64fc5da8", + "package/dist/i18n/cs.js": "6e2c93daba24c2e48dfa206bcf4f2f2a8a02713b856e404d2e4e4ecd8309ca2f", + "package/dist/i18n/cs.mjs": "c73fba18797d62d7b2581e67fe7340c35fe84510b2250ff1ecaad253d9cabbac", + "package/dist/i18n/es.js": "f4133ac6ea06b69a474b33c4a1809a4066e2376bb9464a3f3aa8330f01f1944a", + "package/dist/i18n/es.mjs": "1390bca3def2be115e811de337df0a0c3f63998e51359f283023246245c552a7", + "package/dist/i18n/fa.js": "8d3ef2e0f0cc0ea480c2167b6fcb87cdf444e90759c3519e8daa139fec576da4", + "package/dist/i18n/fa.mjs": "ab441e8a2d79043b29ceca87c783bf06874bb9d3a149c1604bc167eb481be2a9", + "package/dist/i18n/fr.js": "89dc4194a6c0a962b9ce756b52c90401c1acf3b159f265f3bc0d7d6d7d987f03", + "package/dist/i18n/fr.mjs": "99491878430fb7b6f2b7bf93da0588a831704b412e01116f23ba1d9d45863816", + "package/dist/i18n/id.js": "4c6dc86db741bcc2857df55a9d037e82e91d375fa6fd22e0562809ff621b92db", + "package/dist/i18n/id.mjs": "383e5803a6b6686c6de4e867770241de75b6f517dcca2bdedc6f2004bf6e1fb3", + "package/dist/i18n/pl.js": "3a38828b1c3d719c0aca9906cf6a46c23555a8411f8d57645f0e0ce8147dc664", + "package/dist/i18n/pl.mjs": "079ed96732979035297af387c64a7b99519b5a43107fb86735a654ea4fe8e9b5", + "package/dist/i18n/ru.js": "62fac9dddb302eb16382e6e9301fc4b2c66f5f69d4a358a26b67026a5fa4e787", + "package/dist/i18n/ru.mjs": "a893aeaee1d79409db72e324fbff200e3864f33ed168f04d91d25f7cf2efa765", + "package/dist/i18n/tr.js": "1492c36b069a7d73db4f3913bd18085faff7afd8b3c158138fe264e31600e38c", + "package/dist/i18n/tr.mjs": "a90478cac078836b76c2a98261907610fee07f3e4b28671b8e7dbf533778f918", + "package/dist/i18n/vi.js": "c7216ef7e608a79b7e2c479a07bf310d4ab79577947ac4a62d676faaced0e9cf", + "package/dist/i18n/vi.mjs": "66270fdfa0b5da396322d1769169b7df37a030ba15ac18eb30bd87b3af8074ec", + "package/dist/i18n/zh-tw.js": "11c49857d6d40a5ffd224ffa59c9026e71621b345f63c5a086326db80a22371a", + "package/dist/i18n/zh-tw.mjs": "a38e630cb96de96c15d824686aec750e25cf6c8ada01285a292442a81566314f", + "package/package.json": "82e92699e7c29847f32ac6767ece0401290e7d7a12854722bdbcfd09b90b7954", + "package/types/COMPATIBILITY.md": "a7da9e102a116104b513df4f7451247b7759bc502d3375f30bd5b14a541826e0", + "package/types/README.md": "1bd9868e773610e6312fd48a1c5aa20772d29df0af40c3db66e75b7ab4a1aee0", + "package/types/artplayer.d.cts": "3685065e4263abcfd9d953176e461d5b3eb990b0363b54689a7f55deba770fef", + "package/types/artplayer.d.mts": "b664fec51ee5c5381f2ceab25d99d52aee56feab04a2ee7b4ea5b2145ea5fa0e", + "package/types/artplayer.d.ts": "5d0162adf7ac6d0f2bb9b5cfe361f28657c4d9c540cadbf36eba3cc954ce50f8", + "package/types/component.d.ts": "ae5bc1ddeaa1ee1ebbc62573e32423993727079205c64751a5a314170e588a32", + "package/types/config.d.ts": "36f9a84cd436f17701a0d11d3417fc1fe0414e0c52c80083b94a85dfc329e37e", + "package/types/cssVar.d.ts": "93217860fff2ebf750f606d95ddd22220a58837119e63bdf2f5f78fd7488458b", + "package/types/emitter.d.ts": "7e1f9a2a8ce65feb95734f1ed52d1334e57aa388bbef2a43d8bc53a9b6f6623c", + "package/types/events.d.ts": "f83624c9268a284477e8bd793fe3562a2363b72f2a44d5c64fe8c6a6cede8830", + "package/types/i18n.d.ts": "f4f2f05bdfda73c74fef34767cb18ee8e11b743120b1c4598e9714d7846018e5", + "package/types/icons.d.ts": "326a67ba7bdcf52862c5b2a269e540140aff98d05c7b96196485a77f84fe5960", + "package/types/language.d.cts": "f7928e108cf7b7814c2d75cb0a525333e95873fca6cd6d89a740450656b9c1cd", + "package/types/language.d.mts": "6619a26d604b7cccbe2f596243d87ae37cfaae33b8b52874ec071d9787446f9e", + "package/types/legacy/language.d.ts": "c7abda4d506fd933c350e9030290bf9e64347a921d683a66115da1995ebe0a81", + "package/types/option.d.ts": "ccf2c8ddc537dc65c9682d39f044726e23bff18f476b622512d7e6a4b949b5f6", + "package/types/playback.d.ts": "58705c273df6e76a77a6575e769a9ec6c013785c25080f2551aa22415788d870", + "package/types/player.d.ts": "92b00211b70ac71336e495899df972a0519dd138111846044fe4e0f967966177", + "package/types/plugin.d.ts": "fc3594a41c51d8248713e33c486fb1f6a518ac5c7ce31be6988a6cd8d052c5f3", + "package/types/quality.d.ts": "1ac1a48b4f74ff9ba1ce60443e1463d50d1c6a2e5d87d63dc7d2a8eb7f4c2c34", + "package/types/runtime.d.cts": "7ee988dfea9a0ac71a34a656f96f7b74e78aa92547cfdfab7ff7e1139a77d4a3", + "package/types/runtime.d.mts": "dcb85f59a8b7714918ced0c1d18c2bb24e8b80b56d8c594e019dcbdb5ad88b08", + "package/types/runtime.d.ts": "9c6ccd39a1be293f17ae46dae8ea077053e12635ee79d73a5e3b3a559230fcff", + "package/types/runtime/component.d.ts": "1b4c0cee44568649e80140fe778febfcae88af0ac85515f1cbeff78ab0c6d14f", + "package/types/runtime/construction.d.ts": "7a87bedf6f7ffff0c46078aa5f1551e0077d35574e286516121f5f935e2d9ce4", + "package/types/runtime/events.d.ts": "a1e2f9d387475453eaf95c2a5ee79e228636c0bb859bda3fcc46da46574a0c31", + "package/types/runtime/media.d.ts": "8fc89401be7fe25542c169d07dd5675f10916ed20be8493e19695966cf3864a8", + "package/types/runtime/option.d.ts": "6e334e1a76fdcc40b4665c02523bd31c3994d96078fadeb40e23422aa54c1a1d", + "package/types/runtime/player.d.ts": "8ac6383502e4872e83659838844856903031a81a0adc8e8535feb78453aa042c", + "package/types/runtime/plugin.d.ts": "8528f2b17843149f42f9cc16d6fd70baa238c9dc2c329b67d2c38096799c69bd", + "package/types/runtime/services.d.ts": "604c9f8e4b6c0da818f96576bf9f4b0e96085a9003927b2f7ba30027b1ba237e", + "package/types/runtime/setting.d.ts": "349c1fcb205ad312916bd3ee55e6bf241ea8a569fb2ab6c80822e69fc518f7d7", + "package/types/runtime/subtitle.d.ts": "269ff84678d327b3a9dc2f5bc6cc0d731d1e081b85422e474621d5d792efb153", + "package/types/runtime/template.d.ts": "7a62f968a38b4bf9109a4439557c02074eb1d62ba1f6e21a8eb194e91f0badfe", + "package/types/runtime/utils.d.ts": "6bf731705d86853e066dbaf3b8d4003b6548423fe615b7412b722bd0d3a6e48b", + "package/types/setting.d.ts": "08305a75dff96f06490430e099338b463df471b550c1d0dac3abc8995b39eb09", + "package/types/subtitle.d.ts": "b18314e2d64efdb6045830b6e12f615ae2ed585416130e562329ad3ea337f6ce", + "package/types/template.d.ts": "4792bc0c2cbcb7966e4375118bd34b326166e0831862e94ace4cf6b1bbe6a8c8", + "package/types/utils.d.ts": "fca0d3d814df94a25f9eb067c86fa0cf272e2791bac793b91229d57680797712" + } + }, + { + "name": "artplayer-plugin-auto-thumbnail", + "manifest": { + "name": "artplayer-plugin-auto-thumbnail", + "version": "1.1.0", + "description": "auto-thumbnail plugin for ArtPlayer", + "author": "Harvey Zhao ", + "license": "MIT", + "homepage": "https://artplayer.org", + "repository": { + "type": "git", + "url": "git+https://github.com/zhw2590582/ArtPlayer.git" + }, + "bugs": { + "url": "https://github.com/zhw2590582/ArtPlayer/issues" + }, + "keywords": [ + "html5", + "video", + "player" + ], + "exports": { + ".": { + "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", + "import": "./dist/artplayer-plugin-auto-thumbnail.mjs", + "require": "./dist/artplayer-plugin-auto-thumbnail.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", + "import": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", + "require": "./dist/artplayer-plugin-auto-thumbnail.legacy.js" + }, + "./runtime": { + "import": { + "types": "./types/runtime.d.mts", + "default": "./dist/artplayer-plugin-auto-thumbnail.mjs" + }, + "require": { + "types": "./types/runtime.d.cts", + "default": "./dist/artplayer-plugin-auto-thumbnail.js" + } + } + }, + "main": "./dist/artplayer-plugin-auto-thumbnail.js", + "module": "./dist/artplayer-plugin-auto-thumbnail.mjs", + "types": "./types/artplayer-plugin-auto-thumbnail.d.ts", + "legacy": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", + "browserslist": "last 1 Chrome version", + "typesVersions": { + "*": { + "legacy": [ + "types/artplayer-plugin-auto-thumbnail.d.ts" + ], + "runtime": [ + "types/runtime.d.ts" + ] + } + } + }, + "archive": "./refactor/.cache/auto-thumbnail-package-types-6JeGsd/artplayer-plugin-auto-thumbnail.tgz", + "sha256": "efb27b618c68406011557f873684aeef3ea1746cb59385ac0a93993949be2388", + "files": { + "package/ARCHITECTURE.md": "0ae86fd93061a15d9dac89929c96a199343498120372282008a2f837a80db938", + "package/README.md": "9130497e400eb573d9ebe564a9ba890b3e8b11c72442feb332265c73a346cdab", + "package/dist/artplayer-plugin-auto-thumbnail.js": "23c8a1405077c315a7ebd4700a16d8ac05716464a6601c32a702a30e599727c3", + "package/dist/artplayer-plugin-auto-thumbnail.legacy.js": "32a620523aaccbfa3910232f88f255ebbadc89e20a0cb21dc09c17dff611627d", + "package/dist/artplayer-plugin-auto-thumbnail.mjs": "cf726c7e6c5c08a1afc9b2c080e15150f3b16c0b321779257db662fe83336bf0", + "package/package.json": "dbf644376d50d0ada48e27a1c09c62b036c28cbd5df62db9cc0e47f5e3a074a9", + "package/types/artplayer-plugin-auto-thumbnail.d.ts": "b3fd5197b2d1de81bd80a871103821fc38f5af8faa432265ee1fc04ff3e1e51d", + "package/types/runtime-api.d.ts": "e5ce2db98539ac2d04090c7233af9b022019d2a562d622de3f80223ceae76271", + "package/types/runtime.d.cts": "e98585ae44deafcd60edeb8a55505bb27947862e49854241bf01cf54492cda35", + "package/types/runtime.d.mts": "fd26194f4f48803426b22fe2403d8abe490b8a1326c1da27d53143d46653d297", + "package/types/runtime.d.ts": "e98585ae44deafcd60edeb8a55505bb27947862e49854241bf01cf54492cda35" + } + } + ], + "matrix": [ + { + "plugin": "published-1.1.0", + "compiler": "5.9.3", + "mode": "node10-commonjs", + "public": [ + { + "file": "consumer.ts", + "code": 2307, + "line": 3, + "message": "Cannot find module 'artplayer-plugin-auto-thumbnail/legacy' or its corresponding type declarations.\n There are types at 'C:/Users/laozh/AppData/Local/Temp/artplayer-consumer-2GCcYA/node_modules/artplayer-plugin-auto-thumbnail/types/artplayer-plugin-auto-thumbnail.d.ts', but this result could not be resolved under your current 'moduleResolution' setting. Consider updating to 'node16', 'nodenext', or 'bundler'." + } + ], + "rootOnly": [], + "publicInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2353, + "line": 28, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ] + }, + { + "plugin": "published-1.1.0", + "compiler": "5.9.3", + "mode": "nodenext-cjs", + "public": [], + "publicInvalid": [ + { + "file": "consumer.cts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.cts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.cts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.cts", + "code": 2353, + "line": 28, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.cts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.cts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ] + }, + { + "plugin": "published-1.1.0", + "compiler": "5.9.3", + "mode": "nodenext-esm", + "public": [], + "publicInvalid": [ + { + "file": "consumer.mts", + "code": 2554, + "line": 27, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.mts", + "code": 2345, + "line": 28, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.mts", + "code": 2322, + "line": 29, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.mts", + "code": 2353, + "line": 30, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.mts", + "code": 2739, + "line": 31, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.mts", + "code": 2339, + "line": 32, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ] + }, + { + "plugin": "published-1.1.0", + "compiler": "5.9.3", + "mode": "bundler-esm", + "public": [], + "publicInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2353, + "line": 28, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ] + }, + { + "plugin": "published-1.1.0", + "compiler": "4.3.5", + "mode": "node10-commonjs", + "public": [ + { + "file": "consumer.ts", + "code": 2307, + "line": 3, + "message": "Cannot find module 'artplayer-plugin-auto-thumbnail/legacy' or its corresponding type declarations." + }, + { + "file": "consumer.ts", + "code": 2344, + "line": 13, + "message": "Type 'false' does not satisfy the constraint 'true'." + } + ], + "rootOnly": [], + "publicInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number | undefined'." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 28, + "message": "Argument of type '{ height: number; }' is not assignable to parameter of type 'Option'.\n Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ] + }, + { + "plugin": "candidate", + "compiler": "5.9.3", + "mode": "node10-commonjs", + "public": [], + "publicInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2353, + "line": 28, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ], + "runtime": [], + "runtimeDeclarations": [ + "consumer.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime.d.ts", + "node_modules/artplayer/types/artplayer.d.ts", + "node_modules/artplayer/types/component.d.ts", + "node_modules/artplayer/types/config.d.ts", + "node_modules/artplayer/types/cssVar.d.ts", + "node_modules/artplayer/types/emitter.d.ts", + "node_modules/artplayer/types/events.d.ts", + "node_modules/artplayer/types/i18n.d.ts", + "node_modules/artplayer/types/icons.d.ts", + "node_modules/artplayer/types/option.d.ts", + "node_modules/artplayer/types/playback.d.ts", + "node_modules/artplayer/types/player.d.ts", + "node_modules/artplayer/types/plugin.d.ts", + "node_modules/artplayer/types/quality.d.ts", + "node_modules/artplayer/types/setting.d.ts", + "node_modules/artplayer/types/subtitle.d.ts", + "node_modules/artplayer/types/template.d.ts", + "node_modules/artplayer/types/utils.d.ts" + ], + "runtimeInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 20, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 21, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 22, + "message": "Type 'number' is not assignable to type 'string'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 23, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 24, + "message": "Type 'boolean' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 25, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 26, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2353, + "line": 27, + "message": "Object literal may only specify known properties, and 'unknown' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2554, + "line": 28, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 29, + "message": "Property 'name' does not exist on type 'Promise'." + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type 'Factory'." + }, + { + "file": "consumer.ts", + "code": 2741, + "line": 31, + "message": "Property 'name' is missing in type 'Promise' but required in type 'Result'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 32, + "message": "Type '{ name: string; }' is missing the following properties from type 'Promise': then, catch, finally, [Symbol.toStringTag]" + } + ], + "noInterop": [] + }, + { + "plugin": "candidate", + "compiler": "5.9.3", + "mode": "nodenext-cjs", + "public": [], + "publicInvalid": [ + { + "file": "consumer.cts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.cts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.cts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.cts", + "code": 2353, + "line": 28, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.cts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.cts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ], + "runtime": [], + "runtimeDeclarations": [ + "consumer.cts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime.d.cts", + "node_modules/artplayer/types/artplayer.d.cts", + "node_modules/artplayer/types/artplayer.d.ts", + "node_modules/artplayer/types/component.d.ts", + "node_modules/artplayer/types/config.d.ts", + "node_modules/artplayer/types/cssVar.d.ts", + "node_modules/artplayer/types/emitter.d.ts", + "node_modules/artplayer/types/events.d.ts", + "node_modules/artplayer/types/i18n.d.ts", + "node_modules/artplayer/types/icons.d.ts", + "node_modules/artplayer/types/option.d.ts", + "node_modules/artplayer/types/playback.d.ts", + "node_modules/artplayer/types/player.d.ts", + "node_modules/artplayer/types/plugin.d.ts", + "node_modules/artplayer/types/quality.d.ts", + "node_modules/artplayer/types/setting.d.ts", + "node_modules/artplayer/types/subtitle.d.ts", + "node_modules/artplayer/types/template.d.ts", + "node_modules/artplayer/types/utils.d.ts" + ], + "runtimeInvalid": [ + { + "file": "consumer.cts", + "code": 2554, + "line": 20, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.cts", + "code": 2345, + "line": 21, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.cts", + "code": 2322, + "line": 22, + "message": "Type 'number' is not assignable to type 'string'." + }, + { + "file": "consumer.cts", + "code": 2322, + "line": 23, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.cts", + "code": 2322, + "line": 24, + "message": "Type 'boolean' is not assignable to type 'number'." + }, + { + "file": "consumer.cts", + "code": 2322, + "line": 25, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.cts", + "code": 2322, + "line": 26, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.cts", + "code": 2353, + "line": 27, + "message": "Object literal may only specify known properties, and 'unknown' does not exist in type 'Option'." + }, + { + "file": "consumer.cts", + "code": 2554, + "line": 28, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.cts", + "code": 2339, + "line": 29, + "message": "Property 'name' does not exist on type 'Promise'." + }, + { + "file": "consumer.cts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type 'Factory'." + }, + { + "file": "consumer.cts", + "code": 2741, + "line": 31, + "message": "Property 'name' is missing in type 'Promise' but required in type 'Result'." + }, + { + "file": "consumer.cts", + "code": 2739, + "line": 32, + "message": "Type '{ name: string; }' is missing the following properties from type 'Promise': then, catch, finally, [Symbol.toStringTag]" + } + ], + "noInterop": [] + }, + { + "plugin": "candidate", + "compiler": "5.9.3", + "mode": "nodenext-esm", + "public": [], + "publicInvalid": [ + { + "file": "consumer.mts", + "code": 2554, + "line": 27, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.mts", + "code": 2345, + "line": 28, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.mts", + "code": 2322, + "line": 29, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.mts", + "code": 2353, + "line": 30, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.mts", + "code": 2739, + "line": 31, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.mts", + "code": 2339, + "line": 32, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ], + "runtime": [], + "runtimeDeclarations": [ + "consumer.mts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime.d.mts", + "node_modules/artplayer/types/artplayer.d.cts", + "node_modules/artplayer/types/artplayer.d.mts", + "node_modules/artplayer/types/artplayer.d.ts", + "node_modules/artplayer/types/component.d.ts", + "node_modules/artplayer/types/config.d.ts", + "node_modules/artplayer/types/cssVar.d.ts", + "node_modules/artplayer/types/emitter.d.ts", + "node_modules/artplayer/types/events.d.ts", + "node_modules/artplayer/types/i18n.d.ts", + "node_modules/artplayer/types/icons.d.ts", + "node_modules/artplayer/types/option.d.ts", + "node_modules/artplayer/types/playback.d.ts", + "node_modules/artplayer/types/player.d.ts", + "node_modules/artplayer/types/plugin.d.ts", + "node_modules/artplayer/types/quality.d.ts", + "node_modules/artplayer/types/setting.d.ts", + "node_modules/artplayer/types/subtitle.d.ts", + "node_modules/artplayer/types/template.d.ts", + "node_modules/artplayer/types/utils.d.ts" + ], + "runtimeInvalid": [ + { + "file": "consumer.mts", + "code": 2554, + "line": 20, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.mts", + "code": 2345, + "line": 21, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.mts", + "code": 2322, + "line": 22, + "message": "Type 'number' is not assignable to type 'string'." + }, + { + "file": "consumer.mts", + "code": 2322, + "line": 23, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.mts", + "code": 2322, + "line": 24, + "message": "Type 'boolean' is not assignable to type 'number'." + }, + { + "file": "consumer.mts", + "code": 2322, + "line": 25, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.mts", + "code": 2322, + "line": 26, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.mts", + "code": 2353, + "line": 27, + "message": "Object literal may only specify known properties, and 'unknown' does not exist in type 'Option'." + }, + { + "file": "consumer.mts", + "code": 2554, + "line": 28, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.mts", + "code": 2339, + "line": 29, + "message": "Property 'name' does not exist on type 'Promise'." + }, + { + "file": "consumer.mts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type 'Factory'." + }, + { + "file": "consumer.mts", + "code": 2741, + "line": 31, + "message": "Property 'name' is missing in type 'Promise' but required in type 'Result'." + }, + { + "file": "consumer.mts", + "code": 2739, + "line": 32, + "message": "Type '{ name: string; }' is missing the following properties from type 'Promise': then, catch, finally, [Symbol.toStringTag]" + } + ] + }, + { + "plugin": "candidate", + "compiler": "5.9.3", + "mode": "bundler-esm", + "public": [], + "publicInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2353, + "line": 28, + "message": "Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ], + "runtime": [], + "runtimeDeclarations": [ + "consumer.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime.d.mts", + "node_modules/artplayer/types/artplayer.d.cts", + "node_modules/artplayer/types/artplayer.d.mts", + "node_modules/artplayer/types/artplayer.d.ts", + "node_modules/artplayer/types/component.d.ts", + "node_modules/artplayer/types/config.d.ts", + "node_modules/artplayer/types/cssVar.d.ts", + "node_modules/artplayer/types/emitter.d.ts", + "node_modules/artplayer/types/events.d.ts", + "node_modules/artplayer/types/i18n.d.ts", + "node_modules/artplayer/types/icons.d.ts", + "node_modules/artplayer/types/option.d.ts", + "node_modules/artplayer/types/playback.d.ts", + "node_modules/artplayer/types/player.d.ts", + "node_modules/artplayer/types/plugin.d.ts", + "node_modules/artplayer/types/quality.d.ts", + "node_modules/artplayer/types/setting.d.ts", + "node_modules/artplayer/types/subtitle.d.ts", + "node_modules/artplayer/types/template.d.ts", + "node_modules/artplayer/types/utils.d.ts" + ], + "runtimeInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 20, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 21, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 22, + "message": "Type 'number' is not assignable to type 'string'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 23, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 24, + "message": "Type 'boolean' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 25, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 26, + "message": "Type 'string' is not assignable to type 'number'." + }, + { + "file": "consumer.ts", + "code": 2353, + "line": 27, + "message": "Object literal may only specify known properties, and 'unknown' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2554, + "line": 28, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 29, + "message": "Property 'name' does not exist on type 'Promise'." + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type 'Factory'." + }, + { + "file": "consumer.ts", + "code": 2741, + "line": 31, + "message": "Property 'name' is missing in type 'Promise' but required in type 'Result'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 32, + "message": "Type '{ name: string; }' is missing the following properties from type 'Promise': then, catch, finally, [Symbol.toStringTag]" + } + ] + }, + { + "plugin": "candidate", + "compiler": "4.3.5", + "mode": "node10-commonjs", + "public": [], + "publicInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 25, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 26, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 27, + "message": "Type 'string' is not assignable to type 'number | undefined'." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 28, + "message": "Argument of type '{ height: number; }' is not assignable to parameter of type 'Option'.\n Object literal may only specify known properties, and 'height' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 29, + "message": "Type 'Result' is missing the following properties from type 'Promise<{ name: \"artplayerPluginAutoThumbnail\"; }>': then, catch, finally, [Symbol.toStringTag]" + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type '(option: Option) => (art: Artplayer) => Result'." + } + ], + "runtime": [], + "runtimeDeclarations": [ + "consumer.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts", + "node_modules/artplayer-plugin-auto-thumbnail/types/runtime.d.ts", + "node_modules/artplayer/types/artplayer.d.ts", + "node_modules/artplayer/types/component.d.ts", + "node_modules/artplayer/types/config.d.ts", + "node_modules/artplayer/types/cssVar.d.ts", + "node_modules/artplayer/types/emitter.d.ts", + "node_modules/artplayer/types/events.d.ts", + "node_modules/artplayer/types/i18n.d.ts", + "node_modules/artplayer/types/icons.d.ts", + "node_modules/artplayer/types/option.d.ts", + "node_modules/artplayer/types/playback.d.ts", + "node_modules/artplayer/types/player.d.ts", + "node_modules/artplayer/types/plugin.d.ts", + "node_modules/artplayer/types/quality.d.ts", + "node_modules/artplayer/types/setting.d.ts", + "node_modules/artplayer/types/subtitle.d.ts", + "node_modules/artplayer/types/template.d.ts", + "node_modules/artplayer/types/utils.d.ts" + ], + "runtimeInvalid": [ + { + "file": "consumer.ts", + "code": 2554, + "line": 20, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 21, + "message": "Argument of type 'undefined' is not assignable to parameter of type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 22, + "message": "Type 'number' is not assignable to type 'string | undefined'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 23, + "message": "Type 'string' is not assignable to type 'number | undefined'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 24, + "message": "Type 'false' is not assignable to type 'number | undefined'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 25, + "message": "Type 'string' is not assignable to type 'number | undefined'." + }, + { + "file": "consumer.ts", + "code": 2322, + "line": 26, + "message": "Type 'string' is not assignable to type 'number | undefined'." + }, + { + "file": "consumer.ts", + "code": 2345, + "line": 27, + "message": "Argument of type '{ unknown: boolean; }' is not assignable to parameter of type 'Option'.\n Object literal may only specify known properties, and 'unknown' does not exist in type 'Option'." + }, + { + "file": "consumer.ts", + "code": 2554, + "line": 28, + "message": "Expected 1 arguments, but got 0." + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 29, + "message": "Property 'name' does not exist on type 'Promise'." + }, + { + "file": "consumer.ts", + "code": 2339, + "line": 30, + "message": "Property 'default' does not exist on type 'Factory'." + }, + { + "file": "consumer.ts", + "code": 2741, + "line": 31, + "message": "Property 'name' is missing in type 'Promise' but required in type 'Result'." + }, + { + "file": "consumer.ts", + "code": 2739, + "line": 32, + "message": "Type '{ name: string; }' is missing the following properties from type 'Promise': then, catch, finally, [Symbol.toStringTag]" + } + ], + "noInterop": [] + } + ], + "scope": "Actual npm 1.1.0 and packed candidate installed outside the workspace. Root historical type shape and conditional runtime entry are checked with exact negative lines. Registration and module identities use installed artifacts; no native extraction or device acceptance is implied." + }, + "runtimeChecks": [ + { + "label": "published-1.1.0", + "file": "refactor/.cache/auto-thumbnail-package-types-6JeGsd/published-1.1.0-runtime.log", + "sha256": "b73c2c6cf92036f1c2843adc0dd96a8b7df0b5b878930bae32d590ae2c961467", + "passed": true + }, + { + "label": "candidate", + "file": "refactor/.cache/auto-thumbnail-package-types-6JeGsd/candidate-runtime.log", + "sha256": "b73c2c6cf92036f1c2843adc0dd96a8b7df0b5b878930bae32d590ae2c961467", + "passed": true + } + ], + "artifacts": { + "js": { + "sha256": "23c8a1405077c315a7ebd4700a16d8ac05716464a6601c32a702a30e599727c3", + "normalizedUnchangedFromBase": true, + "docsByteIdentical": true + }, + "legacy.js": { + "sha256": "32a620523aaccbfa3910232f88f255ebbadc89e20a0cb21dc09c17dff611627d", + "normalizedUnchangedFromBase": true, + "docsByteIdentical": true + }, + "mjs": { + "sha256": "cf726c7e6c5c08a1afc9b2c080e15150f3b16c0b321779257db662fe83336bf0", + "normalizedUnchangedFromBase": true, + "docsByteIdentical": true + } + }, + "inputs": [ + { + "file": "packages/artplayer-plugin-auto-thumbnail/package.json", + "sha256": "dbf644376d50d0ada48e27a1c09c62b036c28cbd5df62db9cc0e47f5e3a074a9" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/types/artplayer-plugin-auto-thumbnail.d.ts", + "sha256": "b3fd5197b2d1de81bd80a871103821fc38f5af8faa432265ee1fc04ff3e1e51d" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/types/runtime-api.d.ts", + "sha256": "e5ce2db98539ac2d04090c7233af9b022019d2a562d622de3f80223ceae76271" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/types/runtime.d.cts", + "sha256": "e98585ae44deafcd60edeb8a55505bb27947862e49854241bf01cf54492cda35" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/types/runtime.d.mts", + "sha256": "fd26194f4f48803426b22fe2403d8abe490b8a1326c1da27d53143d46653d297" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/types/runtime.d.ts", + "sha256": "e98585ae44deafcd60edeb8a55505bb27947862e49854241bf01cf54492cda35" + }, + { + "file": "refactor/scripts/auto-thumbnail-consumer.mjs", + "sha256": "5ab5fcc1717656946cca69e18f247416bdefd947f65f47832d008e808c756835" + }, + { + "file": "refactor/scripts/auto-thumbnail-package-types.mjs", + "sha256": "84cce3db5045fbac8f9117b30a0284fc50ec9a90c4bbc3800d89cbde79c77c48" + }, + { + "file": "refactor/scripts/auto-thumbnail-types.test.mjs", + "sha256": "870548041855f6da7fb33b2d907d873490c03f19a3e75c06a8ab2c659455897a" + }, + { + "file": "test/types/auto-thumbnail-public.ts", + "sha256": "5366ad685e9aca758d4698762a83c2f72d470bc96078ef11b034e3899a93e898" + }, + { + "file": "test/types/auto-thumbnail-runtime.ts", + "sha256": "112acc8087aba1480acae0e8c177462a8bc455980d06da60d0671225f4be8591" + }, + { + "file": "refactor/fixtures/implementation/auto-thumbnail.ts", + "sha256": "5028bdc656fbbfa9fde499c12309d669d78942bd67caeaaee5bf04507dec04e8" + } + ], + "logs": [ + { + "file": "refactor/.cache/auto-thumb-types-unit.log", + "sha256": "3939d8cb720f87d1c1456e6c127d9d0c6e6cd9ce7ca67e1e70798bce81ba45ba" + }, + { + "file": "refactor/.cache/auto-thumb-types-package.log", + "sha256": "c72ec199058013fcd94b70580d0eaedca4b295dce189add884e1972c246f141b" + }, + { + "file": "refactor/.cache/auto-thumb-types-package-second.log", + "sha256": "25b9c7a3daa8387eef16b433fab2520547e8b2feb2260ffa003ca7ca7a00c4c5" + }, + { + "file": "refactor/.cache/auto-thumb-types-package-final.log", + "sha256": "0c5bed29cf426ed8b3ebaf32d8cfdd6f67bcacc007ddd153c473b9956976e640" + }, + { + "file": "refactor/.cache/auto-thumb-types-package-verified.log", + "sha256": "12b1831c822a4781efc830bdadd376ce687e4b40d739ee4449aba6273fb41bdb" + }, + { + "file": "refactor/.cache/auto-thumb-types-all.log", + "sha256": "8e5dcb005fb5a215b4da5dd66a3c77304d1ca78017e898ca61c6bb2cfaf155f8" + }, + { + "file": "refactor/.cache/auto-thumb-types-unit-verified.log", + "sha256": "02b64fcfb73b8a77bdc17e80760c40f8c01a129ecf841fd66c497ac04721dbe3" + }, + { + "file": "refactor/.cache/auto-thumb-types-typecheck.log", + "sha256": "01ac9ee9900440b47b52ae4cf673398cb44b33a2b3237fad50668c2294b5ad71" + }, + { + "file": "refactor/.cache/auto-thumb-types-build.log", + "sha256": "357538c3c505f06f106a374d9fc596209e569978982b650b0e337ef50ee2b2f2" + }, + { + "file": "refactor/.cache/auto-thumb-types-lint-final.log", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "file": "refactor/.cache/auto-thumb-types-install.log", + "sha256": "8f75ae5c0dbc77f23dff8b0a121aac52ac5428ba5b9866aa4e220d5cc56d8125" + }, + { + "file": "refactor/.cache/auto-thumb-types-toolchain.log", + "sha256": "6470b90648da412ebe8fb4655977f90d8e683e5fd4c8f0cc0e45f23c7c03165b" + } + ], + "checks": { + "fullAutoThumbnailSuite": { + "pass": 163, + "fail": 0 + }, + "finalTypeSuite": { + "pass": 3, + "fail": 0 + }, + "installedStandardProfiles": 10, + "installedNoInteropProfiles": 3, + "strictWorkspaceTypecheck": { + "passed": true, + "productionFiles": 406 + }, + "targetedLint": true, + "frozenYarnInstall": true, + "strictToolchain": true, + "build": [ + "main", + "legacy", + "esm" + ] + }, + "intermediateFailures": [ + "Editor test requested unexported Option/Result; corrected to historical Parameters/ReturnType instead of changing root exports.", + "Historical Node10 unresolved legacy generates TS2307 in 5.9.3 and TS2307 plus TS2344 in 4.3.5; assertions now preserve each compiler exactly.", + "Installed runtime-api default core import failed with TS1259 when interop was disabled; constructor-prototype extraction fixed the declaration." + ], + "limitations": [ + "No new browser or physical-device test in this type-only task.", + "AUTO-THUMB-PIXEL-01 remains open.", + "1.0.x full isolated type/export compatibility still belongs to 04/06; TYPE-01 and EXPORT-01 are not closed here.", + "No version change, push or publication." + ] +} diff --git a/refactor/changes/2026-09-14-PKG-AUTO-THUMB-08-types.md b/refactor/changes/2026-09-14-PKG-AUTO-THUMB-08-types.md new file mode 100644 index 000000000..339397efe --- /dev/null +++ b/refactor/changes/2026-09-14-PKG-AUTO-THUMB-08-types.md @@ -0,0 +1,59 @@ +# PKG-AUTO-THUMB-08 兼容公开类型与异步入口 + +从尚未开始的 04 中拆出独立声明交付,依赖已完成的契约、测试与类型基础设施。 +04 仍依赖 03 和本任务;03 的 WebKit 首两格像素等门槛没有移走或降低。 +本项不等于整个 Auto Thumbnail 包完成。 + +## 实现与兼容边界 + +实际 npm 1.1.0 的根声明保持原字节(仅允许 checkout 换行格式不同),包括必填 +options、同步 Result、Parameters/ReturnType、普通替代函数和模块 default 形状。 +没有为修正 Promise 返回值给旧工厂追加重载、属性或改变类型提取。 + +新增可选 `/runtime`,通过 package exports 复用根入口的 main/ESM 文件,没有 +另一套运行实现。runtime-api.d.ts 定义 Option/Result/Factory,三个薄声明入口 +分别处理 NodeNext ESM、CommonJS 和旧 Node10 解析。Promise 只代表注册完成, +不代表抽帧完成。工厂实际没有 `.default` 自引用,因此声明也不提供;历史忽略 +的 height 在准确选项类型中保留并注明,number/scale/width 仍有明确数字类型。 +内部 option 与这份声明共用,入口显式返回 Promise,实施 fixture 校验 +真实源码函数可赋给公开 Factory,避免声明与自有源码分离漂移。 + +新增 typesVersions 也补齐 Node10 对旧 `/legacy` 子路径的声明解析。真实 npm +1.1.0 在该路径存在 TS2307,TS4.3.5 另有依赖此 unresolved type 的 TS2344; +保留精确历史诊断,并另用根入口验证旧消费者。未把历史失败吞掉或称为旧包通过。 + +编辑器声明现在走已有语义生成器,避免同时出现 export default 与 export =。 +旧生成方式的 TS2309 有回归;新全局 callable 保留旧同步形状。没有往原根模块 +添加 Option/Result 命名导出;旧类型仍通过 Parameters/ReturnType 提取。 + +README、ARCHITECTURE 与 tests README 同步维护实现地图、使用方式和验证范围。 +没有新依赖、锁文件变更、包版本提升、推送或发布。 + +## 验证与中间失败 + +结果及实际包/文件指纹见 [验证记录](../baselines/auto-thumbnail-types-validation.json)。 +最新 npm 1.1.0 和候选实际 tarball 在仓库外安装,以固定 Yarn 离线强制 frozen +重装并核对每个归档文件字节。TS5.9.3 的 Node10/CJS/ESM/bundler 与 TS4.3.5 +Node10 共十组;候选另验证三组关闭 interop 的 CommonJS 消费。 +正例检查完整工厂、参数元组、结果和普通模块替换;负例逐行匹配,避免 any 或 +未解析模块导致假绿。实际安装 JS 测试 root/legacy/runtime 的 require/import +形状、共享函数身份、Promise 注册、结果及候选订阅清理,不触发视频提取。 + +初次编辑器测试误用未从根模块导出的命名类型,已改为原有类型提取;没有扩大 +根 API 来迁就测试。初次历史诊断断言未区分 TS4.3.5 与 TS5.9.3 的二级错误, +已按实际版本精确记录。真实 no-interop 安装测试发现 runtime-api 的 default +core import 在 NodeNext CJS 下失败,改用核心模块的实际 constructor prototype +类型提取后通过。原失败报告在缓存中保留。最初 Yarn exec 未找到 eslint binary, +改用固定 Node 执行已安装的 ESLint;工具链 frozen 安装和严格检查另行通过。 + +本项类型工作不是首帧修复,也不代表三浏览器重跑。历史 1.0.x 的 export= 与 +1.1.0 的 default、height/number 声明差异已是发布历史的一部分;根保持 1.1.0, +本次没有新增旧类型破坏授权。1.0.x 的完整隔离消费/导出门面仍留在 04/06 与 +AUTO-THUMB-TYPE-01、AUTO-THUMB-EXPORT-01,不能仅凭本项关闭整个历史范围。 + +## 回退与接续 + +本提交可独立 revert:移除新增类型入口、选项共享和语义编辑器生成接入,恢复 +原 manifest、生成文件与测试脚本;原运行算法不变。保留 07 的画布清理修复。 +接续优先处理 03 的抽帧真实像素与资源边界;04 汇总自有源码、全部旧消费范围, +05/06 再执行组合、设备、分发及文档完整验收。 diff --git a/refactor/fixtures/implementation/auto-thumbnail.ts b/refactor/fixtures/implementation/auto-thumbnail.ts index 9796ddaef..aeb5cbf98 100644 --- a/refactor/fixtures/implementation/auto-thumbnail.ts +++ b/refactor/fixtures/implementation/auto-thumbnail.ts @@ -1,6 +1,8 @@ import type Artplayer from 'artplayer' +import type { Factory, Result } from '../../../packages/artplayer-plugin-auto-thumbnail/types/runtime-api' import factory from '../../../packages/artplayer-plugin-auto-thumbnail/src' declare const art: Artplayer -const registration: Promise<{ name: string }> = factory({ width: 80, number: 5 })(art) -export { registration } +const registration: Promise = factory({ width: 80, number: 5 })(art) +const publicFactory: Factory = factory +export { publicFactory, registration } diff --git a/refactor/plan.md b/refactor/plan.md index f5acbc744..7227cb892 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -2,9 +2,9 @@ > 由 tasks.json 生成。请修改数据后运行 `node refactor/scripts/plan.mjs --write`,不要手改本表。 -基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 235 项,范围 22 个包及工作区/示例。 +基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 236 项,范围 22 个包及工作区/示例。 -状态:todo 62 / doing 15 / blocked 0 / done 158 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 62 / doing 15 / blocked 0 / done 159 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -19,7 +19,7 @@ | artplayer-plugin-ambilight | 1.1.0 | PKG-AMBILIGHT-01, PKG-AMBILIGHT-02, PKG-AMBILIGHT-03, PKG-AMBILIGHT-04, PKG-AMBILIGHT-PROXY-01, PKG-AMBILIGHT-05, PKG-AMBILIGHT-06, PKG-FACTORY-01 | | artplayer-plugin-asr | 2.1.0 | PKG-ASR-01, PKG-ASR-02, PKG-ASR-03, PKG-ASR-04, PKG-ASR-05, PKG-ASR-06, PKG-ASR-07, PKG-ASR-08, PKG-ASR-09 | | artplayer-plugin-audio-track | 1.1.0 | PKG-AUDIO-01, PKG-AUDIO-02, PKG-AUDIO-03, PKG-AUDIO-04, PKG-AUDIO-05, PKG-AUDIO-06 | -| artplayer-plugin-auto-thumbnail | 1.1.0 | PKG-AUTO-THUMB-01, PKG-AUTO-THUMB-02, PKG-AUTO-THUMB-03, PKG-AUTO-THUMB-04, PKG-AUTO-THUMB-05, PKG-AUTO-THUMB-06, PKG-AUTO-THUMB-07 | +| artplayer-plugin-auto-thumbnail | 1.1.0 | PKG-AUTO-THUMB-01, PKG-AUTO-THUMB-02, PKG-AUTO-THUMB-03, PKG-AUTO-THUMB-04, PKG-AUTO-THUMB-05, PKG-AUTO-THUMB-06, PKG-AUTO-THUMB-07, PKG-AUTO-THUMB-08 | | artplayer-plugin-chapter | 1.1.0 | PILOT-01, PKG-CHAPTER-01, PKG-CHAPTER-02, PKG-CHAPTER-03, PKG-CHAPTER-04, PKG-CHAPTER-05, PKG-CHAPTER-06 | | artplayer-plugin-chromecast | 1.1.0 | PKG-CAST-01, PKG-CAST-02, PKG-CAST-03, PKG-CAST-04, PKG-CAST-05, PKG-CAST-06 | | artplayer-plugin-danmuku | 5.3.0 | PKG-DANMUKU-01, PKG-DANMUKU-02, PKG-DANMUKU-03, PKG-DANMUKU-04, PKG-DANMUKU-05, PKG-DANMUKU-06, PKG-DANMUKU-07, PKG-DANMUKU-08, PKG-DANMUKU-09, PKG-DANMUKU-10, PKG-DANMUKU-11, PKG-DANMUKU-12 | @@ -175,10 +175,11 @@ | PKG-AUTO-THUMB-01 | artplayer-plugin-auto-thumbnail
核对包契约与历史用法 | BASE-05 | url/width/number/scale、异步工厂和渐进缩略图更新 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done | | PKG-AUTO-THUMB-02 | artplayer-plugin-auto-thumbnail
建立特有行为与错误测试 | PKG-AUTO-THUMB-01, ENG-03, ENG-05 | 抽帧边界、短视频、失败、连续来源和销毁中的抽帧 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done | | PKG-AUTO-THUMB-03 | artplayer-plugin-auto-thumbnail
整理内部职责与资源 | PKG-AUTO-THUMB-02, CORE-09, CORE-19, PKG-AUTO-THUMB-07 | 隐藏 video、seek 队列、canvas 编码与 Blob URL 清理 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | doing | -| PKG-AUTO-THUMB-04 | artplayer-plugin-auto-thumbnail
迁移自有源码和公开类型 | PKG-AUTO-THUMB-03, ENG-04, ENG-06, CORE-07 | 抽帧结果和真实异步插件返回类型兼容 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | +| PKG-AUTO-THUMB-04 | artplayer-plugin-auto-thumbnail
迁移自有源码和公开类型 | PKG-AUTO-THUMB-03, ENG-04, ENG-06, CORE-07, PKG-AUTO-THUMB-08 | 抽帧结果和真实异步插件返回类型兼容 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | | PKG-AUTO-THUMB-05 | artplayer-plugin-auto-thumbnail
验证新旧核心和组合 | PKG-AUTO-THUMB-04, CORE-22 | 旧核心/候选核心预览、多次加载无过期缩略图覆盖 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | | PKG-AUTO-THUMB-06 | artplayer-plugin-auto-thumbnail
验证分发并同步文档 | PKG-AUTO-THUMB-05, ENG-07 | auto.thumbnail.js、三种产物和内存/URL 证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | | PKG-AUTO-THUMB-07 | artplayer-plugin-auto-thumbnail
终止抽帧时清空私有画布像素尺寸 | PKG-AUTO-THUMB-02, CORE-09, CORE-19 | 将私有 canvas 尺寸归入 job 清理;完成、取消、失败及分配重入均有回归,保留已编码 JPEG | 旧红新绿证明保留回调时画布归零,单项清理失败不阻断其他资源;原生取消和完成后 JPEG 仍可解码,原 API/时间公式/类型不变 | M | done | +| PKG-AUTO-THUMB-08 | artplayer-plugin-auto-thumbnail
保留旧声明并提供准确异步类型入口 | PKG-AUTO-THUMB-02, ENG-04, ENG-06, CORE-07 | 保留实际 npm 1.1.0 根声明;新增同实现 /runtime 类型、编辑器声明及隔离安装消费者 | 原 Parameters/ReturnType/替代函数不变;准确 Promise 类型正反例、CJS/ESM 条件入口和声明解析通过;不把像素与设备缺口计为通过 | M | done | ## 5 包迁移:artplayer-plugin-vtt-thumbnail @@ -608,3 +609,4 @@ - PKG-JASSUB-08: [记录](changes/2026-09-14-PKG-JASSUB-08-offscreen.md) [记录](baselines/jassub-offscreen-validation.json) [记录](baselines/jassub-offscreen-patch.json) - PKG-JASSUB-09: [记录](changes/2026-09-14-PKG-JASSUB-09-hybrid.md) [记录](baselines/jassub-hybrid-validation.json) [记录](baselines/jassub-hybrid-patch.json) [记录](changes/2026-09-14-PKG-JASSUB-09-firefox-diagnostics.md) [记录](changes/2026-09-14-PKG-JASSUB-09-display.md) [记录](baselines/jassub-display-validation.json) - PKG-AUTO-THUMB-07: [记录](changes/2026-09-14-PKG-AUTO-THUMB-07-canvas.md) [记录](baselines/auto-thumbnail-canvas-validation.json) +- PKG-AUTO-THUMB-08: [记录](changes/2026-09-14-PKG-AUTO-THUMB-08-types.md) [记录](baselines/auto-thumbnail-types-validation.json) diff --git a/refactor/progress.md b/refactor/progress.md index 8136234b5..32ec70e74 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,21 @@ # 进度与证据 +## PKG-AUTO-THUMB-08 公开类型入口完成 + +保留实际 npm 1.1.0 根声明字节与旧工厂提取/替换形状,新增复用原运行文件的 +`/runtime`,准确声明 Promise 注册、选项和结果;未添加不存在的 default 自引用。 +内部选项与运行类型共用,源码返回值通过公开 Factory 验证。编辑器改用语义 +生成器,修复混合导出声明;Node10 legacy 类型路径已补齐。最新与候选实际安装 +十组编译配置和三组无 interop 验证通过,安装产物 Promise 注册与清理通过。 +联合 163 项、最终三项类型回归、全仓严格类型检查(406 个生产 TS 文件)、lint、 +正常构建、frozen Yarn 安装和严格工具链检查通过;构建运行代码与起点归一化 +换行后完全一致。中间 no-interop 声明失败已修复并留证。没有新增依赖或发布。 +见[变更](changes/2026-09-14-PKG-AUTO-THUMB-08-types.md)与 +[验证](baselines/auto-thumbnail-types-validation.json)。本项从 04 独立拆出,04 +仍依赖 03 与 08;03 首帧、1.0.x 完整历史隔离消费及 05/06 仍未完成,不关闭 +AUTO-THUMB-PIXEL-01/TYPE-01/EXPORT-01。源码和公开类型阶段完全完成的插件仍 +为 14/16;全计划 236 项中 159 done、15 doing、62 todo。 + ## PKG-AUTO-THUMB-07 私有画布清理完成 抽帧 canvas 现由 job 清理宽高;取消、失败和正常完成后归零,单个 reset 抛错 diff --git a/refactor/risk-table.md b/refactor/risk-table.md index 05a6a9a81..245328419 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -183,7 +183,7 @@ | THUMB-MEDIA-01 | open / 已复现 | Windows WebKit native Blob URLs cannot load tested MP4 media despite successful HTTP controls | PKG-TOOL-THUMB-05, PKG-TOOL-THUMB-06 | | VENDOR-09 | resolved / 源码/产物事实 | Thumbnail tiny-emitter 改写来源与最终分发许可 | PKG-TOOL-THUMB-04, PKG-TOOL-THUMB-06 | | THUMB-EVENT-01 | resolved / 已复现 | Thumbnail 原型事件名与嵌套 once 派发缺陷 | PKG-TOOL-THUMB-04 | -| AUTO-THUMB-TYPE-01 | open / 已复现 | Published declarations misdescribe async registration and switch height/number option fields across generations | PKG-AUTO-THUMB-04 | +| AUTO-THUMB-TYPE-01 | open / 已复现 | Published declarations misdescribe async registration and switch height/number option fields across generations | PKG-AUTO-THUMB-04, PKG-AUTO-THUMB-08 | | AUTO-THUMB-EXPORT-01 | open / 已复现 | Published 1.0.1 CommonJS default namespace differs from the direct function exported by 1.1.0 | PKG-AUTO-THUMB-04, PKG-AUTO-THUMB-06 | | AUTO-THUMB-DIST-01 | open / 已复现 | Published 1.0.0 archive lacks declared main and legacy runtimes | PKG-AUTO-THUMB-06 | | AUTO-THUMB-LIFE-01 | open / 已复现 | Extraction tasks, decoder handlers and final object URLs lack source-switch and destroy ownership | PKG-AUTO-THUMB-02, PKG-AUTO-THUMB-03, PKG-AUTO-THUMB-05 | diff --git a/refactor/risks.json b/refactor/risks.json index e10ddd535..be28e1b82 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -4050,14 +4050,17 @@ "confirmation": "reproduced", "status": "open", "owners": [ - "PKG-AUTO-THUMB-04" + "PKG-AUTO-THUMB-04", + "PKG-AUTO-THUMB-08" ], "evidence": [ "refactor/baselines/auto-thumbnail-release.json", "refactor/baselines/auto-thumbnail-contract.md", - "refactor/scripts/auto-thumbnail-contract.test.mjs" + "refactor/scripts/auto-thumbnail-contract.test.mjs", + "refactor/changes/2026-09-14-PKG-AUTO-THUMB-08-types.md", + "refactor/baselines/auto-thumbnail-types-validation.json" ], - "compatibleResolution": "Preserve actual Promise runtime and old valid consumers; explicitly retain the historically ignored height field and verify paired CJS/ESM declarations.", + "compatibleResolution": "Preserve actual Promise runtime and old valid consumers; explicitly retain the historically ignored height field and verify paired CJS/ESM declarations. PKG-AUTO-THUMB-08 retains npm 1.1.0 root bytes and adds tested /runtime types and editor generation; older 1.0.x isolated consumer/export evidence is still pending in 04/06.", "closureCriteria": "Old and current isolated consumers, negative type cases and matching runtime registration pass; any irreconcilable inference change has an explicit user decision." }, { diff --git a/refactor/scripts/auto-thumbnail-consumer.mjs b/refactor/scripts/auto-thumbnail-consumer.mjs new file mode 100644 index 000000000..84737c3d0 --- /dev/null +++ b/refactor/scripts/auto-thumbnail-consumer.mjs @@ -0,0 +1,43 @@ +import fs from 'node:fs' + +export const publicInvalid = [ + 'thumbnail()', + 'thumbnail(undefined)', + 'thumbnail({ width: "80" })', + 'thumbnail({ height: 90 })', + 'const asynchronous: Promise<{name: "artplayerPluginAutoThumbnail"}> = result', + 'thumbnail.default({})', +] + +export const runtimeInvalid = [ + 'runtime()', + 'runtime(undefined)', + 'runtime({ url: 1 })', + 'runtime({ width: "80" })', + 'runtime({ number: false })', + 'runtime({ scale: "1" })', + 'runtime({ height: "90" })', + 'runtime({ unknown: true })', + 'runtime({})()', + 'pending.name', + 'runtime.default({})', + 'const synchronous: Result = pending', + 'const wrong: Factory = (_option) => (_art) => ({name: "artplayerPluginAutoThumbnail"})', +] + +export function publicSource(mode, raw = false) { + let source = fs.readFileSync(new URL('../../test/types/auto-thumbnail-public.ts', import.meta.url), 'utf8') + if (mode === 'nodenext-esm' && !raw) { + source = source.replace('import thumbnail from \'artplayer-plugin-auto-thumbnail\'', 'import thumbnailModule from \'artplayer-plugin-auto-thumbnail\'\nconst thumbnail = thumbnailModule.default') + .replace('import legacy from \'artplayer-plugin-auto-thumbnail/legacy\'', 'import legacyModule from \'artplayer-plugin-auto-thumbnail/legacy\'\nconst legacy = legacyModule.default') + } + return source +} + +export function runtimeSource(mode) { + const source = fs.readFileSync(new URL('../../test/types/auto-thumbnail-runtime.ts', import.meta.url), 'utf8') + return mode.endsWith('-no-interop') + ? source.replace('import runtime from \'artplayer-plugin-auto-thumbnail/runtime\'', 'import runtime = require(\'artplayer-plugin-auto-thumbnail/runtime\')') + .replace('import type Artplayer from \'artplayer\'', 'type Core = typeof import(\'artplayer\'); type Artplayer = Core extends { default: { prototype: infer I } } ? I : Core extends { prototype: infer I } ? I : never') + : source +} diff --git a/refactor/scripts/auto-thumbnail-package-types.mjs b/refactor/scripts/auto-thumbnail-package-types.mjs new file mode 100644 index 000000000..44eacb175 --- /dev/null +++ b/refactor/scripts/auto-thumbnail-package-types.mjs @@ -0,0 +1,150 @@ +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 { publicInvalid, publicSource, runtimeInvalid, runtimeSource } from './auto-thumbnail-consumer.mjs' +import { verifyAutoThumbnailContract } from './auto-thumbnail-contract.mjs' +import { hash, readMember } from './releases.mjs' + +const name = 'artplayer-plugin-auto-thumbnail' +assert.equal(process.version.slice(1), fs.readFileSync(path.join(workspace, '.node-version'), 'utf8').trim()) +assert.equal(process.env.npm_config_user_agent?.split(' ')[0], 'yarn/1.22.22') +const yarn = process.env.npm_execpath +assert(yarn && fs.existsSync(yarn)) +const output = fs.mkdtempSync(path.join(workspace, 'refactor/.cache/auto-thumbnail-package-types-')) +console.log(`Auto Thumbnail installed consumer evidence: ${output}`) +const contract = await verifyAutoThumbnailContract() +const packages = [] +for (const packageName of ['artplayer', name]) { + const archive = path.join(output, `${packageName}.tgz`) + fs.writeFileSync(path.join(output, `${packageName}-pack.log`), run([yarn, 'pack', '--filename', archive], path.join(workspace, 'packages', packageName))) + const manifest = JSON.parse(readMember(archive, 'package/package.json')) + const files = packedFiles(archive) + checkFiles(manifest, files, packageName === name ? Object.keys(contract.baseline.release.files) : []) + packages.push({ name: packageName, manifest, archive, sha256: hash(fs.readFileSync(archive)), files: Object.fromEntries(files.map(member => [member, hash(readMember(archive, member))])) }) +} +const [core, candidate] = packages +const declaration = `package/types/${name}.d.ts` +const normalize = value => value.toString().replaceAll('\r\n', '\n') +assert.equal(normalize(readMember(candidate.archive, declaration)), normalize(readMember(contract.archives.get('1.1.0'), declaration))) +const matrix = [] +function report() { + return writeJson(path.join(output, 'report.json'), { + task: 'PKG-AUTO-THUMB-08', + node: process.version, + packages, + matrix, + scope: 'Actual npm 1.1.0 and packed candidate installed outside the workspace. Root historical type shape and conditional runtime entry are checked with exact negative lines. Registration and module identities use installed artifacts; no native extraction or device acceptance is implied.', + }) +} + +for (const plugin of [{ ...contract.baseline.release, archive: contract.archives.get('1.1.0'), label: 'published-1.1.0' }, { ...candidate, label: 'candidate' }]) { + const consumer = consumerDirectory() + try { + writeJson(path.join(consumer, 'package.json'), { name: 'auto-thumbnail-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.log`), run([yarn, 'install', '--offline', '--frozen-lockfile', '--force', '--ignore-scripts', '--non-interactive'], consumer)) + assert.deepEqual(fs.readFileSync(path.join(consumer, 'yarn.lock')), lock) + for (const pkg of [core, plugin]) { + for (const member of packedFiles(pkg.archive)) { + assert.deepEqual(fs.readFileSync(path.join(consumer, 'node_modules', pkg.name, member.replace(/^package\//, ''))), readMember(pkg.archive, member), member) + } + } + fs.writeFileSync(path.join(output, `${plugin.label}-yarn.lock`), lock) + for (const [compiler, mode] of [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']]) { + const next = mode.startsWith('nodenext') + const filename = path.join(consumer, `consumer.${next ? mode.endsWith('-cjs') ? 'cts' : 'mts' : 'ts'}`) + const options = { + strict: true, + noEmit: true, + skipLibCheck: false, + types: [], + esModuleInterop: true, + 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 declarations = [] + const compile = (source, interop = true) => { + fs.writeFileSync(filename, source) + const program = compiler.createProgram([filename], { ...options, esModuleInterop: interop }) + 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()))), `Type escaped consumer: ${actual}`) + } + declarations = program.getSourceFiles().filter(file => !program.isSourceFileDefaultLibrary(file)).map(file => path.relative(consumer, file.fileName).replaceAll('\\', '/')).sort() + return compiler.getPreEmitDiagnostics(program).map(item => ({ + file: item.file ? path.relative(consumer, item.file.fileName).replaceAll('\\', '/') : null, + code: item.code, + line: item.file && item.start !== undefined ? item.file.getLineAndCharacterOfPosition(item.start).line + 1 : null, + message: compiler.flattenDiagnosticMessageText(item.messageText, '\n'), + })) + } + const entry = { plugin: plugin.label, compiler: compiler.version, mode } + matrix.push(entry) + let source = publicSource(mode) + entry.public = compile(source) + if (plugin.label === 'published-1.1.0' && mode === 'node10-commonjs') { + const lines = source.split('\n') + assert.deepEqual(entry.public.map(item => ({ code: item.code, line: item.line })), [ + { code: 2307, line: lines.findIndex(line => line.includes('from \'artplayer-plugin-auto-thumbnail/legacy\'')) + 1 }, + ...(compiler === compat ? [{ code: 2344, line: lines.findIndex(line => line.startsWith('type ExactLegacy')) + 1 }] : []), + ], 'Preserve the historical Node10 legacy subpath failure') + source = source.replace('from \'artplayer-plugin-auto-thumbnail/legacy\'', 'from \'artplayer-plugin-auto-thumbnail\'') + entry.rootOnly = compile(source) + assert.deepEqual(entry.rootOnly, []) + } + else { + assert.deepEqual(entry.public, [], `${plugin.label} ${compiler.version} ${mode}`) + } + entry.publicInvalid = compile(`${source}\n${publicInvalid.join('\n')}`) + assert.deepEqual(entry.publicInvalid.map(item => item.line), publicInvalid.map((_, index) => source.split('\n').length + 1 + index)) + if (plugin.label === 'candidate') { + const runtime = runtimeSource(mode) + entry.runtime = compile(runtime) + entry.runtimeDeclarations = declarations + assert.deepEqual(entry.runtime, [], `${compiler.version} ${mode}`) + assert(declarations.includes(`node_modules/${name}/types/runtime.${next ? mode.endsWith('-cjs') ? 'd.cts' : 'd.mts' : mode === 'bundler-esm' ? 'd.mts' : 'd.ts'}`)) + entry.runtimeInvalid = compile(`${runtime}\n${runtimeInvalid.join('\n')}`) + assert.deepEqual(entry.runtimeInvalid.map(item => item.line), runtimeInvalid.map((_, index) => runtime.split('\n').length + 1 + index)) + if (mode === 'node10-commonjs' || mode === 'nodenext-cjs') { + entry.noInterop = compile(runtimeSource(`${mode}-no-interop`), false) + assert.deepEqual(entry.noInterop, []) + } + } + report() + } + const probe = path.join(consumer, 'runtime.cjs') + fs.writeFileSync(probe, `const assert = require('node:assert/strict'); +(async () => { + const names = ${JSON.stringify([name, `${name}/legacy`, ...(plugin.label === 'candidate' ? [`${name}/runtime`] : [])])}; + const commonjs = names.map(name => require(name)); + const modules = await Promise.all(names.map(name => import(name))); + for (const factory of [...commonjs, ...modules.map(module => module.default)]) { + assert.equal(typeof factory, 'function'); assert.equal(factory.default, undefined); + const callbacks = new Map(); + const art = { option: {url: '/never-loaded.mp4'}, on(name, callback) { callbacks.set(name, callback); }, off(name, callback) { if (callbacks.get(name) === callback) callbacks.delete(name); } }; + const pending = factory({})(art); + assert(pending instanceof Promise); assert.equal(pending.name, undefined); + assert.deepEqual(await pending, {name: 'artplayerPluginAutoThumbnail'}); + assert(callbacks.has('video:loadedmetadata')); + ${plugin.label === 'candidate' ? 'callbacks.get(\'destroy\')(); assert.equal(callbacks.size, 0);' : ''} + } + ${plugin.label === 'candidate' ? 'assert.equal(commonjs[2], commonjs[0]); assert.equal(modules[2].default, modules[0].default);' : ''} + console.log('Installed root/legacy/runtime module shapes and Promise registration verified; no native extraction.'); +})().catch(error => { console.error(error); process.exitCode = 1; });`) + fs.writeFileSync(path.join(output, `${plugin.label}-runtime.log`), run([probe], consumer)) + } + finally { + report() + removeConsumer(consumer) + } +} +console.log(`Passed ${matrix.length} installed compiler profiles; ${output}`) diff --git a/refactor/scripts/auto-thumbnail-types.test.mjs b/refactor/scripts/auto-thumbnail-types.test.mjs new file mode 100644 index 000000000..9dcfae85a --- /dev/null +++ b/refactor/scripts/auto-thumbnail-types.test.mjs @@ -0,0 +1,63 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +// eslint-disable-next-line test/no-import-node-test -- Repository compatibility 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 { publicInvalid, publicSource, runtimeInvalid, runtimeSource } from './auto-thumbnail-consumer.mjs' +import { verifyAutoThumbnailContract } from './auto-thumbnail-contract.mjs' +import { readMember } from './releases.mjs' + +const modes = [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']] + +test('Auto Thumbnail preserves actual npm 1.1.0 root bytes and historical factory extraction', async () => { + const contract = await verifyAutoThumbnailContract() + const current = fs.readFileSync('packages/artplayer-plugin-auto-thumbnail/types/artplayer-plugin-auto-thumbnail.d.ts', 'utf8') + const previous = readMember(contract.archives.get('1.1.0'), 'package/types/artplayer-plugin-auto-thumbnail.d.ts').toString() + assert.equal(current.replaceAll('\r\n', '\n'), previous.replaceAll('\r\n', '\n')) + for (const [compiler, mode] of modes) { + const source = publicSource(mode) + assert.deepEqual(checkConsumer(compiler, mode, source), [], `${compiler.version} ${mode}`) + const invalid = checkConsumer(compiler, mode, `${source}\n${publicInvalid.join('\n')}`) + assert.deepEqual(invalid.map(item => item.line), publicInvalid.map((_, index) => source.split('\n').length + 1 + index)) + } +}) + +test('Auto Thumbnail runtime types expose only the real asynchronous factory and options', () => { + for (const [compiler, mode] of modes) { + const source = runtimeSource(mode) + assert.deepEqual(checkConsumer(compiler, mode, source), [], `${compiler.version} ${mode}`) + const invalid = checkConsumer(compiler, mode, `${source}\n${runtimeInvalid.join('\n')}`) + assert.deepEqual(invalid.map(item => item.line), runtimeInvalid.map((_, index) => source.split('\n').length + 1 + index)) + } + assert.deepEqual(checkConsumer(ts, 'nodenext-cjs', `import runtime = require('artplayer-plugin-auto-thumbnail/runtime'); +import type Artplayer from 'artplayer'; declare const art: Artplayer; +const option: runtime.Option = {}; const result: Promise = runtime(option)(art); +const factory: runtime.Factory = runtime; void [result, factory];`), []) +}) + +test('Auto Thumbnail generated editor globals replace conflicting export assignments and retain old calls', async () => { + const source = fs.readFileSync('packages/artplayer-plugin-auto-thumbnail/types/artplayer-plugin-auto-thumbnail.d.ts', 'utf8') + const generated = generatePluginEditorDeclaration(source, 'artplayerPluginAutoThumbnail') + const file = 'docs/assets/ts/artplayer-plugin-auto-thumbnail.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; +type Option = Parameters[0]; +type Result = ReturnType>; +const option: Option = { width: 80, number: 12 }; +const result: Result = artplayerPluginAutoThumbnail(option)(art); +const replacement: typeof artplayerPluginAutoThumbnail = _option => _art => result;` + for (const compiler of [ts, compat]) { + assert.deepEqual(checkPluginEditorDeclaration(generated, core, consumer, compiler), []) + const invalid = checkPluginEditorDeclaration(generated, core, `${consumer}\nartplayerPluginAutoThumbnail();\nconst bad: Promise = result;`, compiler) + assert.deepEqual(invalid.map(item => item.code), [2554, 2739]) + const previous = `${source.replace(/^import.*$/gim, '')}\nexport = artplayerPluginAutoThumbnail;\nexport as namespace artplayerPluginAutoThumbnail;\n` + assert(checkPluginEditorDeclaration(previous, core, '', compiler).some(item => item.code === 2309)) + } +}) diff --git a/refactor/tasks.json b/refactor/tasks.json index 8287eb64b..ddefb232c 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -1811,7 +1811,8 @@ "PKG-AUTO-THUMB-03", "ENG-04", "ENG-06", - "CORE-07" + "CORE-07", + "PKG-AUTO-THUMB-08" ], "status": "todo", "risk": "H", @@ -4838,6 +4839,28 @@ "changes/2026-09-14-PKG-AUTO-THUMB-07-canvas.md", "baselines/auto-thumbnail-canvas-validation.json" ] + }, + { + "id": "PKG-AUTO-THUMB-08", + "phase": "5 包迁移:artplayer-plugin-auto-thumbnail", + "title": "保留旧声明并提供准确异步类型入口", + "scope": [ + "artplayer-plugin-auto-thumbnail" + ], + "dependsOn": [ + "PKG-AUTO-THUMB-02", + "ENG-04", + "ENG-06", + "CORE-07" + ], + "status": "done", + "risk": "M", + "deliverable": "保留实际 npm 1.1.0 根声明;新增同实现 /runtime 类型、编辑器声明及隔离安装消费者", + "acceptance": "原 Parameters/ReturnType/替代函数不变;准确 Promise 类型正反例、CJS/ESM 条件入口和声明解析通过;不把像素与设备缺口计为通过", + "evidence": [ + "changes/2026-09-14-PKG-AUTO-THUMB-08-types.md", + "baselines/auto-thumbnail-types-validation.json" + ] } ] } diff --git a/scripts/build-ts.js b/scripts/build-ts.js index f2a5134d7..1b2aeab3b 100644 --- a/scripts/build-ts.js +++ b/scripts/build-ts.js @@ -53,7 +53,7 @@ console.log(`✨ Built ${artplayerTSoutput}`); const type = pluginsTS[index] const { name, file } = parsePluginInfo(type) const source = String(fs.readFileSync(type)) - const semanticPlugin = ['artplayerPluginJassub', 'artplayerPluginDanmukuMask', 'artplayerPluginDanmuku', 'artplayerPluginChromecast', 'artplayerPluginAsr', 'artplayerPluginMultipleSubtitles', 'artplayerPluginVttThumbnail', 'artplayerPluginHlsControl', 'artplayerPluginAudioTrack', 'artplayerPluginDashControl', 'artplayerPluginAds', 'artplayerPluginAmbilight', 'artplayerProxyCanvas', 'artplayerProxyMediabunny', 'artplayerPluginDocumentPip', 'ArtplayerToolIframe', 'ArtplayerToolThumbnail'].includes(name) + const semanticPlugin = ['artplayerPluginAutoThumbnail', 'artplayerPluginJassub', 'artplayerPluginDanmukuMask', 'artplayerPluginDanmuku', 'artplayerPluginChromecast', 'artplayerPluginAsr', 'artplayerPluginMultipleSubtitles', 'artplayerPluginVttThumbnail', 'artplayerPluginHlsControl', 'artplayerPluginAudioTrack', 'artplayerPluginDashControl', 'artplayerPluginAds', 'artplayerPluginAmbilight', 'artplayerProxyCanvas', 'artplayerProxyMediabunny', 'artplayerPluginDocumentPip', 'ArtplayerToolIframe', 'ArtplayerToolThumbnail'].includes(name) const localTypes = name === 'artplayerProxyMediabunny' ? { './media': fs.readFileSync(path.join(path.dirname(type), 'media.d.ts'), 'utf8') } : {} const code = semanticPlugin ? generatePluginEditorDeclaration(source, name, localTypes) diff --git a/scripts/typecheck.mjs b/scripts/typecheck.mjs index 827e264da..7f1e5d537 100644 --- a/scripts/typecheck.mjs +++ b/scripts/typecheck.mjs @@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url' import ts from 'typescript' import compat from 'typescript-compat' import runtimeCompat from 'typescript-runtime-compat' +import { publicSource as autoThumbnailPublic, runtimeSource as autoThumbnailRuntime } from '../refactor/scripts/auto-thumbnail-consumer.mjs' const root = fileURLToPath(new URL('../', import.meta.url)) const relative = name => path.relative(root, name).replaceAll('\\', '/') @@ -73,6 +74,8 @@ export function runTypechecks() { 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 source of [autoThumbnailPublic(mode), autoThumbnailRuntime(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']) { let source = fs.readFileSync(path.join(root, fixture), 'utf8') if (fixture === 'test/types/asr-public.ts' && mode === 'nodenext-esm') { diff --git a/test/README.md b/test/README.md index 86116f04f..2cdbf2ae8 100644 --- a/test/README.md +++ b/test/README.md @@ -2,6 +2,16 @@ Use the pinned Node/Yarn toolchain from `../refactor/toolchain-setup.md`. +`yarn test:auto-thumbnail-types` checks the preserved npm 1.1.0 declaration, +accurate `/runtime` Promise types, exact rejected consumer lines, and generated +editor globals. It also runs in `test:auto-thumbnail` and `test:baseline`. +`yarn test:auto-thumbnail-types-package` packs the candidate and installs it and +the actual npm 1.1.0 archive outside the workspace with a packed core. It verifies +frozen reinstalls, byte identity, conditional declaration resolution, old/current +compiler consumers, no-interop CommonJS, and installed factory registration. +This does not decode video or close the older 1.0.x export-shape, native pixel, +or device acceptance gaps. Candidate entry types use the same runtime files. + `yarn test:danmuku-mask` runs candidate run cancellation/resource ownership plus frozen historical defects and public contracts. Candidate tests also run in `test:unit`; their controlled SDK, RAF and canvas hosts do not prove native model diff --git a/test/types/auto-thumbnail-public.ts b/test/types/auto-thumbnail-public.ts new file mode 100644 index 000000000..a6632b99d --- /dev/null +++ b/test/types/auto-thumbnail-public.ts @@ -0,0 +1,23 @@ +import type Artplayer from 'artplayer' +import thumbnail from 'artplayer-plugin-auto-thumbnail' +import legacy from 'artplayer-plugin-auto-thumbnail/legacy' + +type Equal = (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? true : false +type Assert = T +interface Option { url?: string, width?: number, number?: number, scale?: number } +interface Result { name: 'artplayerPluginAutoThumbnail' } +type HistoricalFactory = (option: Option) => (art: Artplayer) => Result +type ExactFactory = Assert> +type ExactOption = Assert, [option: Option]>> +type ExactResult = Assert>, Result>> +type ExactLegacy = Assert> + +declare const art: Artplayer +const result: Result = thumbnail({ url: '/video.mp4', width: 80, number: 12, scale: 0.5 })(art) +const replacement: typeof thumbnail = (_option: Option) => (_art: Artplayer) => result +const assignBack: HistoricalFactory = thumbnail +const legacyReplacement: typeof legacy = replacement +const moduleReplacement: typeof import('artplayer-plugin-auto-thumbnail') = { default: replacement } +const legacyName: Result['name'] = legacy({})(art).name +void [assignBack, legacyReplacement, moduleReplacement, legacyName] +export type { ExactFactory, ExactLegacy, ExactOption, ExactResult } diff --git a/test/types/auto-thumbnail-runtime.ts b/test/types/auto-thumbnail-runtime.ts new file mode 100644 index 000000000..ceb674776 --- /dev/null +++ b/test/types/auto-thumbnail-runtime.ts @@ -0,0 +1,18 @@ +import type Artplayer from 'artplayer' +import type { Factory, Option, Result } from 'artplayer-plugin-auto-thumbnail/runtime' +import runtime from 'artplayer-plugin-auto-thumbnail/runtime' + +type Equal = (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? true : false +type Assert = T +type ExactFactory = Assert> +type ExactOption = Assert, [option: Option]>> +type ExactResult = Assert>, Promise>> + +declare const art: Artplayer +const option: Option = { url: '/video.mp4', width: 80, number: 12, scale: 0.5, height: 90 } +const pending: Promise = runtime(option)(art) +const name: Promise<'artplayerPluginAutoThumbnail'> = pending.then(value => value.name) +const plugins: NonNullable = [runtime(option)] +const replacement: Factory = _option => async _art => ({ name: 'artplayerPluginAutoThumbnail' }) +void [name, plugins, replacement] +export type { ExactFactory, ExactOption, ExactResult }