mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-09 11:56:15 -08:00
fix(react): [EX-01] verify installed consumers and clean up callback failures
This commit is contained in:
1 parent
3e39fc745f
commit
e0d785662d
25 files changed
+3539
-98
No files matched your search
@@ -131,6 +131,8 @@ jobs:
|
||||
package-manager-cache: false
|
||||
- name: Verify canonical installed consumers
|
||||
run: node scripts/package-runtime.mjs --canonical 2>&1 | tee refactor/.cache/ci/consumer-node-canonical.log
|
||||
- name: Verify React installed consumers
|
||||
run: yarn test:react-consumer 2>&1 | tee refactor/.cache/ci/react-consumer.log
|
||||
- name: Run all three engines
|
||||
run: yarn test:browser 2>&1 | tee refactor/.cache/ci/browser.log
|
||||
- name: Verify iframe cached history and interrupted navigation
|
||||
@@ -146,6 +148,7 @@ jobs:
|
||||
refactor/.cache/ci/
|
||||
refactor/.cache/browser/
|
||||
refactor/.cache/iframe-history/
|
||||
refactor/.cache/react-consumer-*/
|
||||
refactor/.cache/performance/
|
||||
refactor/.cache/packages/latest.json
|
||||
refactor/.cache/packages/run-*/*.json
|
||||
|
||||
@@ -1,12 +1,60 @@
|
||||
# React + Vite
|
||||
# React consumer example
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
Run from the repository root with Node from .node-version and Yarn Classic
|
||||
1.22.22. Install once with yarn install --frozen-lockfile; keep only the root
|
||||
yarn.lock in version control.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
```sh
|
||||
yarn dev:react
|
||||
yarn typecheck:react
|
||||
yarn lint:react
|
||||
yarn build:react
|
||||
yarn test:react-consumer
|
||||
```
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
build:react writes to refactor/.cache/react-example-dist. It uses built
|
||||
workspace package entrypoints. Rebuild a changed library with `yarn build <package>` before testing its integration. The consumer test packs the current
|
||||
core, Danmuku and Document PiP distributions, installs them outside the workspace,
|
||||
verifies their bytes, typechecks and builds the copied example, and exercises it
|
||||
in Chromium, Firefox and WebKit. No package aliases to source files are used.
|
||||
Reports and the consumer lock are in unique refactor/.cache/react-consumer-* folders.
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
## Component contract and ownership
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||
- src/Player.tsx owns one Artplayer instance per effect. Existing props remain
|
||||
option: `Partial<Option>`, optional getInstance(art), and native div attributes.
|
||||
Stable option/callback identities retain the instance. Changing either destroys
|
||||
the old instance before creating one.
|
||||
- getInstance runs after construction, not media readiness. Subscribe to player
|
||||
events for readiness. React StrictMode may call it again during development
|
||||
setup/cleanup. Callback errors destroy the instance before propagating the
|
||||
original error to React, including when cleanup also throws.
|
||||
- Cleanup uses destroy(false): React owns the outer div. Retained player references
|
||||
expose isDestroy; the callback does not receive a new null argument on unmount.
|
||||
- src/player-options.ts retains this example's existing overrides: French language,
|
||||
French/Indonesian dictionaries, and new Danmuku/Document PiP factories per instance.
|
||||
These still override option.lang, i18n and plugins. Other options pass through.
|
||||
React supplies the container. The url assertion preserves the historical Partial
|
||||
input; the core validates it. Missing URLs are not promised to construct successfully.
|
||||
- src/App.tsx supplies stable options and a callback. src/main.tsx mounts StrictMode;
|
||||
index.html loads the TSX entry. tsconfig.json checks the actual TSX and declarations
|
||||
with strict checks and skipLibCheck: false.
|
||||
- Root development dependencies pin React/React DOM 19.1.1, their types
|
||||
19.1.10/19.1.7, Vite 7.3.6, React Vite plugin 5.0.0 and TS 5.9.3.
|
||||
These are example/test tooling, not Artplayer runtime dependencies.
|
||||
|
||||
## Test scope
|
||||
|
||||
Installed development and production builds cover StrictMode, stable/changed
|
||||
props, sibling instances, optional callbacks, unmount/remount, callback exceptions,
|
||||
native play/pause/seek, decoded canvas pixels, plugin registration and the App entry.
|
||||
Video and XML responses are controlled fixtures; CDN availability is not asserted.
|
||||
Window PiP interaction, full Danmuku scheduling, macOS/iOS Safari and device
|
||||
capabilities remain in package/release acceptance tasks.
|
||||
|
||||
yarn test:react-consumer --before substitutes recorded pre-fix Player source
|
||||
against the same installed candidate packages. It must fail at callback exception
|
||||
cleanup. This is a wrapper-source regression control, not an old npm wrapper test:
|
||||
this example is not a published wrapper package.
|
||||
|
||||
Maintenance details and frozen evidence belong to EX-01 in refactor/.
|
||||
@@ -1,29 +1,2 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
reactHooks.configs['recommended-latest'],
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
||||
},
|
||||
},
|
||||
])
|
||||
// Reuse the repository's TypeScript-aware configuration for this TSX example.
|
||||
export { default } from '../../eslint.config.js'
|
||||
@@ -8,6 +8,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,30 +1,29 @@
|
||||
{
|
||||
"name": "artplayer-react",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build": "yarn typecheck && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"artplayer": "^5.3.0-beta.4",
|
||||
"artplayer-plugin-danmuku": "^5.2.0",
|
||||
"artplayer-plugin-document-pip": "^1.0.2",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1"
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@types/react": "^19.1.10",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@vitejs/plugin-react": "^5.0.0",
|
||||
"eslint": "^9.33.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.3.0",
|
||||
"vite": "^7.1.2"
|
||||
"@types/react": "19.1.10",
|
||||
"@types/react-dom": "19.1.7",
|
||||
"@vitejs/plugin-react": "5.0.0",
|
||||
"eslint": "9.39.2",
|
||||
"typescript": "5.9.3",
|
||||
"vite": "7.3.6"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import Artplayer, { type Option } from 'artplayer'
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Option } from 'artplayer'
|
||||
import Player from './Player'
|
||||
|
||||
function getInstance(art: Artplayer) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(art)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import type { Option } from 'artplayer'
|
||||
import type { HTMLAttributes } from 'react'
|
||||
import Artplayer from 'artplayer'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import Artplayer, { type Option } from 'artplayer'
|
||||
import { playerOptions } from './player-options'
|
||||
|
||||
// Test i18n
|
||||
import fr from 'artplayer/i18n/fr'
|
||||
import id from 'artplayer/i18n/id'
|
||||
|
||||
// Test plugins
|
||||
import artplayerPluginDanmuku from 'artplayer-plugin-danmuku'
|
||||
import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip'
|
||||
|
||||
interface PlayerProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
option: Partial<Option>,
|
||||
export interface PlayerProps extends HTMLAttributes<HTMLDivElement> {
|
||||
option: Partial<Option>
|
||||
getInstance?: (art: Artplayer) => void
|
||||
}
|
||||
|
||||
@@ -18,24 +13,25 @@ export default function Player({ option, getInstance, ...rest }: PlayerProps) {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return
|
||||
if (!containerRef.current)
|
||||
return
|
||||
|
||||
const art = new Artplayer({
|
||||
...option,
|
||||
container: containerRef.current,
|
||||
url: option.url as string,
|
||||
i18n: { id, fr },
|
||||
lang: 'fr',
|
||||
plugins: [
|
||||
artplayerPluginDocumentPip({}),
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: 'https://artplayer.org/assets/sample/danmuku.xml',
|
||||
}),
|
||||
],
|
||||
})
|
||||
const art = new Artplayer(playerOptions(option, containerRef.current))
|
||||
|
||||
if (typeof getInstance === 'function') {
|
||||
getInstance(art)
|
||||
try {
|
||||
if (typeof getInstance === 'function') {
|
||||
getInstance(art)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
art.destroy(false)
|
||||
}
|
||||
finally {
|
||||
// Keep the consumer's error even if teardown also fails.
|
||||
// eslint-disable-next-line no-unsafe-finally
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { Option } from 'artplayer'
|
||||
import artplayerPluginDanmuku from 'artplayer-plugin-danmuku'
|
||||
import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip'
|
||||
import fr from 'artplayer/i18n/fr'
|
||||
import id from 'artplayer/i18n/id'
|
||||
|
||||
// Preserve this example's existing overrides and create plugins per instance.
|
||||
export function playerOptions(option: Partial<Option>, container: HTMLDivElement): Option {
|
||||
return {
|
||||
...option,
|
||||
container,
|
||||
// Partial<Option> is the historical wrapper API; Artplayer validates missing URLs.
|
||||
url: option.url as string,
|
||||
i18n: { id, fr },
|
||||
lang: 'fr',
|
||||
plugins: [
|
||||
artplayerPluginDocumentPip({}),
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: 'https://artplayer.org/assets/sample/danmuku.xml',
|
||||
}),
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["react", "react-dom"],
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": false
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
|
||||
+12
-2
@@ -47,7 +47,7 @@
|
||||
"check:plan": "node refactor/scripts/plan.mjs --check",
|
||||
"test:node": "yarn test:unit && node --test test/toolchain.test.js test/build-docs.test.js test/package-check.test.js test/declarations.test.js test/editor-types.test.js test/coverage.test.js test/performance-report.test.js test/media-gate.test.js test/ci-summary.test.js test/package-runtime.test.js test/library-build.test.js",
|
||||
"test:baseline": "node --test refactor/scripts/*.test.mjs",
|
||||
"ci:check": "yarn check:toolchain --strict && yarn check:commits --report && yarn check:impact --report && yarn check:ci && yarn test:contracts && yarn check:contracts --report && yarn check:plan && yarn lint && yarn check:types && yarn typecheck && yarn test",
|
||||
"ci:check": "yarn check:toolchain --strict && yarn check:commits --report && yarn check:impact --report && yarn check:ci && yarn test:contracts && yarn check:contracts --report && yarn check:plan && yarn lint && yarn check:types && yarn typecheck && yarn typecheck:react && yarn lint:react && yarn test",
|
||||
"ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:docs && yarn test:imports",
|
||||
"test:imports": "node --test test/esm.test.js test/i18n.test.js test/ssr.test.js test/asr-distribution.test.js",
|
||||
"typecheck": "node scripts/typecheck.mjs",
|
||||
@@ -108,12 +108,20 @@
|
||||
"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",
|
||||
"probe:auto-thumbnail-rendering": "node refactor/scripts/auto-thumbnail-rendering-probe.mjs"
|
||||
"probe:auto-thumbnail-rendering": "node refactor/scripts/auto-thumbnail-rendering-probe.mjs",
|
||||
"dev:react": "vite example/react.js --config example/react.js/vite.config.js",
|
||||
"typecheck:react": "tsc -p example/react.js/tsconfig.json --noEmit",
|
||||
"build:react": "yarn typecheck:react && vite build example/react.js --config example/react.js/vite.config.js --outDir ../../refactor/.cache/react-example-dist",
|
||||
"test:react-consumer": "node refactor/scripts/react-consumer.mjs",
|
||||
"lint:react": "eslint example/react.js --no-fix"
|
||||
},
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "5.4.1",
|
||||
"@playwright/test": "1.63.0",
|
||||
"@types/react": "19.1.10",
|
||||
"@types/react-dom": "19.1.7",
|
||||
"@vitejs/plugin-react": "5.0.0",
|
||||
"@vue/compiler-sfc": "3.5.28",
|
||||
"@yarnpkg/lockfile": "1.1.0",
|
||||
"c8": "12.0.0",
|
||||
@@ -131,6 +139,8 @@
|
||||
"linkedom": "0.18.13",
|
||||
"pngjs": "7.0.0",
|
||||
"prompts": "2.4.2",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"semver": "7.7.4",
|
||||
"servor": "4.0.2",
|
||||
"svgo": "4.1.0",
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,95 @@
|
||||
# EX-01 React 消费者、异常清理与实际打包验收
|
||||
|
||||
起点 `3e39fc745f4dc98eba678ca081e86c1d3cc965cd`。本任务对应 React 示例,
|
||||
不将其他插件的组合、设备和分发任务一并标为完成。
|
||||
|
||||
## 已复现问题和实现
|
||||
|
||||
1. `index.html` 仍引用不存在的 `/src/main.jsx`,实际入口为 `main.tsx`。
|
||||
改为实际入口,原 App 经 Vite 构建和三引擎实际加载媒体通过。
|
||||
2. 原 Player effect 在调用 `getInstance` 后才返回清理函数。消费者回调抛错时,
|
||||
React 无法取得该清理函数,已创建实例残留。最终 `--before` 控制使用原始
|
||||
Player 源码及相同候选 tarball,在 Chromium 开发模式复现:错误边界已经
|
||||
显示,注册表仍有 1 个播放器。修复在重新抛出原错误前调用 `destroy(false)`;
|
||||
即使清理也抛错,保留最初的消费者异常。六组最终回归均无实例/DOM 残留。
|
||||
3. 原 TSX 示例没有 tsconfig,局部 ESLint 配置仅覆盖 JS/JSX。补充严格 TSX
|
||||
配置,复用仓库的 TS lint 配置,修复实际源码中的类型导入和配置格式。
|
||||
|
||||
文件职责:`Player.tsx` 负责 React effect、引用交付和资源归属;
|
||||
`player-options.ts` 隔离示例特定配置和插件工厂;`App.tsx` 保持调用样例;
|
||||
`main.tsx` 保持 StrictMode;README 说明真实维护入口、行为和验证边界。
|
||||
没有为简单包装增加通用生命周期框架。
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 保留 `option: Partial<Option>`、可选 `getInstance(art)` 和 div 属性。
|
||||
- 保留 `[option, getInstance]` 依赖:同一引用不重建,任一引用改变则先清理后重建。
|
||||
- 保留 callback 在构造之后同步交付实例,不改为等待 ready,不新增 null 回调。
|
||||
- 保留 `destroy(false)`、React 外层容器归属及现有法语/词典/两个插件覆盖规则。
|
||||
这些是示例原有行为;没有借通用化而静默改变用户传入 plugins/lang 的优先级。
|
||||
- `url as string` 仅适配历史 Partial 输入,继续由核心验证无效/缺失 URL;
|
||||
不把可编译的 `option={{}}` 宣称为可成功运行。
|
||||
- 新导出的 PlayerProps 是补充类型入口;核心/插件公开声明和运行产物未修改。
|
||||
|
||||
React 的 [effect 文档](https://react.dev/reference/react/useEffect) 说明开发
|
||||
StrictMode 的额外 setup/cleanup。真实受测 React 19.1.1 的开发模式抛错路径
|
||||
交付两个相同原始错误,生产模式一个,逐模式精确断言;每个创建实例只销毁一次。
|
||||
初版测试错误地统一要求一个异常,已纠正且保留失败报告,未放松清理断言。
|
||||
|
||||
## 工具、测试与 CI
|
||||
|
||||
根 devDependencies 新增固定 React/React DOM 19.1.1、@types/react 19.1.10、
|
||||
@types/react-dom 19.1.7、@vitejs/plugin-react 5.0.0;复用 Vite 7.3.6、TS 5.9.3。
|
||||
用于 TSX 示例、React 模式行为和 Vite 构建,不增加 Artplayer 生产依赖。
|
||||
只更新根 yarn.lock;示例 manifest 同步已验证版本和实际使用的开发工具。
|
||||
|
||||
新增根命令 `dev:react`、`typecheck:react`、`lint:react`、`build:react`、
|
||||
`test:react-consumer`。后者由 `refactor/scripts/react-consumer.mjs` 编排:
|
||||
|
||||
1. Yarn pack 核心/Danmuku/Document PiP,记录 SHA256;仓库外安装,再 frozen、
|
||||
offline、force 安装并逐文件对照 tarball;缓存中的消费者锁是测试证据。
|
||||
2. 复制真实示例及 `test/react/` 夹具,严格编译全部示例、真实浏览器 TSX 夹具和三个 @ts-expect-error
|
||||
反例。检查所有声明只来自隔离消费者和 TS 标准库,禁止工作区类型逃逸。
|
||||
初版 compiler host 使用仓库 cwd 导致 @types/react 逃逸,被验证器正确拒绝;
|
||||
已将 host 的 currentDirectory 设为隔离消费者,保留此隔离检查。
|
||||
3. Vite 构建 development/production,实际使用安装后的包,不 alias 生产源码。
|
||||
4. 三引擎串行执行,每组 12 类检查:StrictMode/插件注册、稳定引用、回调变化、
|
||||
option 变化、真实 play/pause/seek/非黑像素、兄弟实例身份保持、可选回调、
|
||||
卸载清理、重挂载、回调异常、清理次生异常、原 App 媒体加载。
|
||||
5. `--before` 使用固定 Git 版本中的原 Player,预期在回调异常清理处失败。
|
||||
|
||||
在现有 GitHub 三操作系统 browser-smoke 中加入此命令和 always 上传的证据目录;
|
||||
ci:check 加入 React 类型/lint。这里已验证本地配置和 47 项 CI 回归,未执行远端
|
||||
GitHub jobs,不能称远端三操作系统已通过。
|
||||
|
||||
## 验证结果和限制
|
||||
|
||||
最终证据见 [react-consumer-validation.json](../baselines/react-consumer-validation.json)。
|
||||
Windows、Node 24.21.0、Yarn 1.22.22;Chromium 153.0.8010.12、Firefox 155.0、
|
||||
WebKit 26.6:六组全部通过,无 retry/skip。旧包装精确复现 1 个残留实例。
|
||||
严格隔离 TS 5.9.3 无诊断,三个无效输入被拒绝;全仓 typecheck 的 406 个生产
|
||||
TS 文件和历史/准确类型矩阵通过。示例构建、lint、frozen 安装、严格工具链通过。
|
||||
开发 React bundle 的 >500kB Vite 提示保留,没有提高阈值;生产共享 chunk
|
||||
约 477.53kB,整体包体复盘仍属 MOD-03/REVIEW-01。
|
||||
|
||||
前期失败报告保留:`react-consumer-2B2QCR` 是类型逃逸,`dmu7pS` 是开发异常
|
||||
计数断言错误;最终候选 `x9KPB2`,最终旧源码对照 `cgxKhm`。
|
||||
|
||||
这是原包装 API 在实际候选包中的消费验收,不是所有旧核心/旧插件组合验收。
|
||||
受控 MP4/XML 不证明公网 CDN;插件注册不证明 PiP 真窗口或完整弹幕调度。
|
||||
Playwright Windows WebKit 不等于 macOS/iOS Safari,未声称连接 Chrome 或真机。
|
||||
这些包专项和发布复盘门槛继续保留。
|
||||
|
||||
## 回退
|
||||
|
||||
回退 EX-01 提交可恢复包装/HTML/工具配置及根锁;也会恢复已复现的回调泄漏和
|
||||
入口错误。无生产包版本/产物变更,无推送、发布。候选生产内容改变后重跑此消费
|
||||
脚本;不要将本次 tarball 哈希当成未来 npm 候选的免检依据。
|
||||
|
||||
## 扩大检查发现的独立 lint 问题
|
||||
|
||||
本任务受影响的 TSX/脚本 lint 通过,但最后全仓 yarn lint 被未改动的
|
||||
packages/artplayer-plugin-danmuku-mask/package.json 字段排序阻断;已逐字对照
|
||||
HEAD 确认该 manifest 不属于本任务改动。另有旧编辑器声明的 unused-disable
|
||||
警告。全仓 lint 未计为通过;新增 ENG-LINT-01 独立修复,仍接入最终完成门槛。
|
||||
日志 refactor/.cache/react-root-lint.log。
|
||||
+12
-5
@@ -2,9 +2,9 @@
|
||||
|
||||
> 由 tasks.json 生成。请修改数据后运行 `node refactor/scripts/plan.mjs --write`,不要手改本表。
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 237 项,范围 22 个包及工作区/示例。
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 238 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 62 / doing 15 / blocked 0 / done 160 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 62 / doing 15 / blocked 0 / done 161 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
| 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 |
|
||||
| artplayer-plugin-danmuku-mask | 1.1.0 | PKG-MASK-01, PKG-MASK-02, PKG-MASK-03, PKG-MASK-04, PKG-MASK-05, PKG-MASK-06 |
|
||||
| artplayer-plugin-danmuku-mask | 1.1.0 | PKG-MASK-01, PKG-MASK-02, PKG-MASK-03, PKG-MASK-04, PKG-MASK-05, PKG-MASK-06, ENG-LINT-01 |
|
||||
| artplayer-plugin-dash-control | 1.1.0 | PKG-DASH-01, PKG-DASH-02, PKG-DASH-03, PKG-DASH-04, PKG-DASH-05, PKG-DASH-06 |
|
||||
| artplayer-plugin-document-pip | 1.1.0 | PKG-DPIP-01, PKG-DPIP-02, PKG-DPIP-03, PKG-DPIP-04, PKG-DPIP-05, PKG-DPIP-06 |
|
||||
| artplayer-plugin-hls-control | 1.1.0 | PKG-HLS-01, PKG-HLS-02, PKG-HLS-03, PKG-HLS-04, PKG-HLS-SDK-01, PKG-HLS-05, PKG-HLS-06 |
|
||||
@@ -386,7 +386,7 @@
|
||||
| SITE-04 | artplayer-vitepress<br>交叉核对逐包持续维护的文档 | CORE-21, SITE-03, PKG-CHAPTER-04, PKG-AMBILIGHT-04, PKG-AUDIO-04, PKG-AUTO-THUMB-04, PKG-VTT-THUMB-04, PKG-HLS-04, PKG-DASH-04, PKG-MULTI-SUB-04, PKG-JASSUB-04, PKG-MASK-04, PKG-ASR-04, PKG-ADS-04, PKG-VAST-04, PKG-CAST-04, PKG-DPIP-04, PKG-CANVAS-04, PKG-IFRAME-04, PKG-TOOL-THUMB-04, PKG-DANMUKU-06, PKG-MB-08 | 已随实现更新的中文/英文 API、包内实现地图、旧 JS 示例及已知能力限制的全包核对 | 未把缺环境的能力写成已验证,静态核对不等待设备任务;最终 demo 仍由 EX-03 验收 | M | todo |
|
||||
| SITE-05 | artplayer-vitepress<br>构建文档站和验证链接/示例 | SITE-04, EX-01, EX-02 | VitePress 构建、链接与嵌入 demo 检查 | 文档构建、链接、嵌入路径与声明注入通过;真实完整 demo 保留 EX-03 独立门槛;核对 ENG-PM-01 登记的搜索 peer 范围和真实搜索行为 | M | todo |
|
||||
| SITE-06 | artplayer-vitepress<br>文档站交付验收 | SITE-05 | 维护指南和站点变更记录 | 未手改 generated 目录,旧 URL 可用、部署与检查分离 | M | todo |
|
||||
| EX-01 | example/react.js<br>验证 React 消费者与 TS | CORE-22, ENG-07 | React 挂载/卸载/重挂载、引用和插件样例 | 真实 tarball + TS 消费通过,保留既有 React 集成 API | M | todo |
|
||||
| EX-01 | example/react.js, workspace<br>验证 React 消费者与 TS | CORE-22, ENG-07 | React 挂载/卸载/重挂载、引用和插件样例 | 真实 tarball + TS 消费通过,保留既有 React 集成 API | M | done |
|
||||
| EX-02 | example/vue.js<br>验证 Vue 消费者与更新卸载 | CORE-22, ENG-07 | Vue 实例/ref、参数更新、卸载及插件样例 | 旧 JS 组件用法无需修改,重复挂载不泄漏 | M | todo |
|
||||
| EX-03 | workspace<br>验证全部原生 demo 与外部播放集成 | EX-01, EX-02, PKG-CHAPTER-06, PKG-AMBILIGHT-06, PKG-AUDIO-06, PKG-AUTO-THUMB-06, PKG-VTT-THUMB-06, PKG-HLS-06, PKG-DASH-06, PKG-MULTI-SUB-06, PKG-JASSUB-06, PKG-MASK-06, PKG-ASR-06, PKG-ADS-06, PKG-VAST-06, PKG-CAST-06, PKG-DPIP-06, PKG-DANMUKU-09, PKG-CANVAS-06, PKG-MB-10, PKG-IFRAME-06, PKG-TOOL-THUMB-06 | 8082 全 demo、HLS/DASH/FLV/MPEGTS/WebTorrent 集成记录 | 旧 URL/参数/脚本加载保持;网络/SDK 限制明确,不静默跳过;覆盖编辑器重复 Run 和 ESM/i18n/mobile/iframe,记录实际候选脚本及状态隔离证据;依据 BASE-04 路径台账逐项消除 not-run,处理 BASE-DEMO-01 | H | todo |
|
||||
|
||||
@@ -412,7 +412,7 @@
|
||||
| REL-04 | workspace<br>提前演练回退与主线修复同步 | REL-08, ENG-07 | 分包旧版本/tag/依赖回退方案与 master 差异 | 隔离包演练可回退,主线修复同步流程可执行;正式每批再核对其实际回退产物 | H | todo |
|
||||
| REL-05 | workspace<br>经授权发布候选并收集反馈 | REL-03, REL-04, REVIEW-03 | 候选 tag、完整产物 integrity、反馈与复现记录 | 实际发布授权/操作/版本可追溯;本计划不自动执行发布 | H | todo |
|
||||
| REL-06 | workspace<br>经授权分批正式发布 | REL-05 | 正式分包版本/tag/站点文档及兼容公告 | 候选验收通过,安装/浏览器复核和回退入口就绪;候选反馈修复须独立建任务并复验三轮受影响结论,正式内容与最终验证产物一致 | H | todo |
|
||||
| REL-07 | workspace<br>关闭重构里程碑并维护后续队列 | REL-06 | 最终任务/设计/证据归档和维护指南 | 全范围任务有结论、无未解释兼容缺口;遗留项有明确后续责任 | L | todo |
|
||||
| REL-07 | workspace<br>关闭重构里程碑并维护后续队列 | REL-06, ENG-LINT-01 | 最终任务/设计/证据归档和维护指南 | 全范围任务有结论、无未解释兼容缺口;遗留项有明确后续责任 | L | todo |
|
||||
|
||||
## 8.1 多轮复盘
|
||||
|
||||
@@ -434,6 +434,12 @@
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| ENG-12 | workspace, artplayer<br>隔离库构建的 public 源码与分发内容 | ENG-03, CORE-21 | 禁用库的隐式 public 复制,拒绝误入包内的 TS 源码,清理生成污染并验证真实构建 | 三格式真实构建和严格 tarball 检查通过;已有声明和所有剩余成员字节不变;文档站使用独立构建 | M | done |
|
||||
|
||||
## 2 工程基础
|
||||
|
||||
| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| ENG-LINT-01 | artplayer-plugin-danmuku-mask, workspace<br>修复 Mask manifest 排序并恢复全仓 lint | PKG-MASK-04 | 仅调整 manifest 字段顺序,独立验证全仓只读 lint 与元数据语义不变 | 根 lint 通过;解析后的 manifest 深度相等;不改包版本、依赖或公开入口 | L | todo |
|
||||
|
||||
## 完成证据与阻塞
|
||||
|
||||
- DOC-01: [记录](progress.md)
|
||||
@@ -598,6 +604,7 @@
|
||||
- PKG-TOOL-THUMB-02: [记录](baselines/thumbnail-behavior-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-02-behavior.md)
|
||||
- PKG-TOOL-THUMB-03: [记录](changes/2026-09-13-PKG-TOOL-THUMB-03-input-checkpoint.md) [记录](baselines/thumbnail-input-checkpoint.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-03-lifecycle.md) [记录](baselines/thumbnail-lifecycle-validation.json)
|
||||
- PKG-TOOL-THUMB-04: [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-runtime-types.md) [记录](baselines/thumbnail-runtime-types-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-public-types.md) [记录](baselines/thumbnail-public-types-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-emitter.md) [记录](baselines/thumbnail-emitter-validation.json)
|
||||
- EX-01: [记录](changes/2026-09-14-EX-01-react-consumer.md) [记录](baselines/react-consumer-validation.json) [记录](scripts/react-consumer.mjs)
|
||||
- PKG-FACTORY-01: [记录](baselines/factory-assignment-gaps.json) [记录](baselines/factory-compatibility-proposals.json) [记录](factory-compatibility-decision.md) [记录](changes/2026-09-12-PKG-FACTORY-01-decision.md) [记录](type-compatibility-policy.md) [记录](baselines/factory-compatibility-validation.json) [记录](changes/2026-09-13-PKG-FACTORY-01-compatible-types.md)
|
||||
- CORE-25: [记录](changes/2026-09-13-CORE-25-defaults-ssr.md) [记录](baselines/defaults-ssr-validation.json)
|
||||
- ENG-12: [记录](changes/2026-09-13-ENG-12-library-public.md) [记录](baselines/library-public-validation.json)
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# 进度与证据
|
||||
|
||||
## EX-01 React 实际消费者完成
|
||||
|
||||
修复 React HTML 错误入口,以及 getInstance 抛错时实例泄漏;保留 Partial<Option>、
|
||||
可选回调、div 属性、引用变化重建和示例插件/语言覆盖规则。拆出示例配置模块,
|
||||
补齐严格 TSX、维护说明和根 Yarn 命令。实际打包安装核心/Danmuku/Document PiP,
|
||||
逐文件对照并 frozen 重装;类型不允许从工作区补齐。最终开发/生产 × 三引擎六组
|
||||
各 12 类检查通过,包括真实播放/暂停/seek/像素、兄弟实例、卸载重挂载和异常
|
||||
清理。固定旧包装控制复现 1 个残留实例。全仓 406 个生产 TS 文件检查、示例
|
||||
构建/lint、严格工具链和 frozen 安装通过;47 项 CI 回归通过。GitHub 增加消费
|
||||
检查和失败证据上传,远端运行未验证。见[变更](changes/2026-09-14-EX-01-react-consumer.md)
|
||||
和[证据](baselines/react-consumer-validation.json)。另有全仓 lint 被未改动 Mask manifest 排序阻断,已登记独立 ENG-LINT-01。
|
||||
任务现为 238 项:161 done、15 doing、62 todo;未关闭插件专项任务。
|
||||
下一步推进已就绪的 Vue 消费者 EX-02;Auto Thumbnail 首帧与 VAST 兼容选择仍未关闭。
|
||||
|
||||
|
||||
## PKG-AUTO-THUMB-03 渲染/等待诊断检查点(仍 doing)
|
||||
|
||||
新增可重跑的 `yarn probe:auto-thumbnail-rendering`,用固定实际 ESM/时间轴媒体
|
||||
|
||||
@@ -253,3 +253,5 @@
|
||||
| JASSUB-HYBRID-01 | open / 已复现 | Late hybrid frames mutate the new offscreen canvas or throw; terminal track calls recreate transferred canvases | PKG-JASSUB-09, PKG-JASSUB-05 |
|
||||
| JASSUB-FIREFOX-OFFSCREEN-01 | open / 已复现 | Windows Firefox offscreen readback and asynchronous ImageBitmap creation can stall through seek/layout, including a minimal Worker control | PKG-JASSUB-09, PKG-JASSUB-05 |
|
||||
| AUTO-THUMB-CANVAS-01 | resolved / 已复现 | Private thumbnail canvas retains sheet dimensions after completion or cancellation while callbacks retain the element | PKG-AUTO-THUMB-07 |
|
||||
| EX-REACT-LIFE-01 | resolved / 已复现 | React getInstance exception leaks the constructed player | EX-01 |
|
||||
| EX-REACT-ENTRY-01 | resolved / 源码/产物事实 | React HTML references absent main.jsx instead of the existing TSX entry | EX-01 |
|
||||
@@ -5694,6 +5694,48 @@
|
||||
"test/browser/auto-thumbnail-lifecycle.spec.js"
|
||||
],
|
||||
"resolutionRationale": "Six controlled regressions fail before and pass after. The frozen main native complete control fails dimensions; candidate main/legacy native lifecycle checks reset the retained canvas and decode final JPEGs after reset. No public options, types, sample positions or caller URLs changed; WebKit early-frame pixels remain separately open."
|
||||
},
|
||||
{
|
||||
"id": "EX-REACT-LIFE-01",
|
||||
"title": "React getInstance exception leaks the constructed player",
|
||||
"confirmation": "reproduced",
|
||||
"status": "resolved",
|
||||
"owners": [
|
||||
"EX-01"
|
||||
],
|
||||
"evidence": [
|
||||
"refactor/changes/2026-09-14-EX-01-react-consumer.md",
|
||||
"refactor/baselines/react-consumer-validation.json"
|
||||
],
|
||||
"resolutionEvidence": [
|
||||
"refactor/changes/2026-09-14-EX-01-react-consumer.md",
|
||||
"refactor/baselines/react-consumer-validation.json",
|
||||
"refactor/scripts/react-consumer.mjs"
|
||||
],
|
||||
"compatibleResolution": "The old wrapper leaves one active instance after the React error boundary; the candidate cleans each instance exactly once and propagates the original error in six real browser profiles.",
|
||||
"closureCriteria": "Actual installed consumer and original App entry pass without changing the wrapper props, default configuration or effect dependency contract.",
|
||||
"resolutionRationale": "The old wrapper leaves one active instance after the React error boundary; the candidate cleans each instance exactly once and propagates the original error in six real browser profiles."
|
||||
},
|
||||
{
|
||||
"id": "EX-REACT-ENTRY-01",
|
||||
"title": "React HTML references absent main.jsx instead of the existing TSX entry",
|
||||
"confirmation": "source-observed",
|
||||
"status": "resolved",
|
||||
"owners": [
|
||||
"EX-01"
|
||||
],
|
||||
"evidence": [
|
||||
"refactor/changes/2026-09-14-EX-01-react-consumer.md",
|
||||
"refactor/baselines/react-consumer-validation.json"
|
||||
],
|
||||
"resolutionEvidence": [
|
||||
"refactor/changes/2026-09-14-EX-01-react-consumer.md",
|
||||
"refactor/baselines/react-consumer-validation.json",
|
||||
"refactor/scripts/react-consumer.mjs"
|
||||
],
|
||||
"compatibleResolution": "The HTML now loads main.tsx; the unchanged App call builds and loads controlled media in all six installed consumer browser profiles.",
|
||||
"closureCriteria": "Actual installed consumer and original App entry pass without changing the wrapper props, default configuration or effect dependency contract.",
|
||||
"resolutionRationale": "The HTML now loads main.tsx; the unchanged App call builds and loads controlled media in all six installed consumer browser profiles."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -84,6 +84,9 @@ export function validateCIWorkflow(source) {
|
||||
consumerIndex = index + 1
|
||||
}
|
||||
assert(browser.steps.findIndex(step => step.run?.startsWith('yarn test:browser ')) > consumerIndex, 'Browser tools must run after canonical Node restoration')
|
||||
const reactIndex = browser.steps.findIndex(step => step.run === 'yarn test:react-consumer 2>&1 | tee refactor/.cache/ci/react-consumer.log')
|
||||
assert(reactIndex > consumerIndex && !Object.hasOwn(browser.steps[reactIndex], 'if'), 'Run React installed consumers after restoring canonical Node')
|
||||
assert(browser.steps.some(step => step.uses?.startsWith('actions/upload-artifact@') && step.if === 'always()' && step.with.path.split('\n').includes('refactor/.cache/react-consumer-*/')), 'Retain React consumer failure evidence')
|
||||
const pages = workflow.jobs.checks.steps.find(step => step.uses?.startsWith('actions/upload-pages-artifact@'))
|
||||
assert.equal(pages?.if, 'inputs.pages-artifact && github.ref == \'refs/heads/master\' && matrix.os == \'ubuntu-latest\'', 'Only one trusted matrix leg can prepare Pages')
|
||||
return { jobs: requiredJobs, systems, summary: summary.name }
|
||||
|
||||
@@ -34,6 +34,9 @@ for (const [name, mutate] of [
|
||||
['wrong consumer Node version', w => w.jobs['browser-smoke'].steps.find(s => s.id === 'consumer-node-20').with['node-version'] = '24'],
|
||||
['skipped installed consumer', w => w.jobs['browser-smoke'].steps.find(s => s.run?.includes('--expected-node 22.12.0')).if = 'false'],
|
||||
['browser runtime not restored', w => w.jobs['browser-smoke'].steps.find(s => s.id === 'restore-canonical-node').with = { 'node-version': '22.12.0', 'package-manager-cache': false }],
|
||||
['skipped React consumer', w => w.jobs['browser-smoke'].steps.find(s => s.run?.startsWith('yarn test:react-consumer')).if = 'false'],
|
||||
['removed React consumer', w => w.jobs['browser-smoke'].steps = w.jobs['browser-smoke'].steps.filter(s => !s.run?.startsWith('yarn test:react-consumer'))],
|
||||
['missing React evidence', w => w.jobs['browser-smoke'].steps.find(s => s.uses?.startsWith('actions/upload-artifact@')).with.path = 'refactor/.cache/ci/'],
|
||||
['Pages uploaded by both matrix legs', w => w.jobs.checks.steps.find(s => s.uses?.startsWith('actions/upload-pages-artifact@')).if = 'inputs.pages-artifact && github.ref == \'refs/heads/master\''],
|
||||
]) {
|
||||
test(`CI rejects ${name}`, () => {
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { chromium, firefox, webkit } from '@playwright/test'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import ts from 'typescript'
|
||||
import { build, preview } from 'vite'
|
||||
import { packedFiles } from '../../scripts/package-check.mjs'
|
||||
import { consumerDirectory, removeConsumer, run, workspace, writeJson } from '../../scripts/package-consumer.mjs'
|
||||
import { hash, readMember } from './releases.mjs'
|
||||
|
||||
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 before = process.argv.includes('--before')
|
||||
const output = fs.mkdtempSync(path.join(workspace, 'refactor/.cache/react-consumer-'))
|
||||
const consumer = consumerDirectory()
|
||||
const report = { task: 'EX-01', before, node: process.version, source: execFileSync('git', ['rev-parse', 'HEAD'], { cwd: workspace, encoding: 'utf8' }).trim(), packages: [], browsers: [], passed: false }
|
||||
console.log(`React consumer evidence: ${output}`)
|
||||
try {
|
||||
const dependencies = {}
|
||||
for (const name of ['artplayer', 'artplayer-plugin-danmuku', 'artplayer-plugin-document-pip']) {
|
||||
const archive = path.join(output, `${name}.tgz`)
|
||||
fs.writeFileSync(path.join(output, `${name}-pack.log`), run([yarn, 'pack', '--filename', archive], path.join(workspace, 'packages', name)))
|
||||
dependencies[name] = `file:${archive.replaceAll('\\', '/')}`
|
||||
report.packages.push({ name, archive, sha256: hash(fs.readFileSync(archive)) })
|
||||
}
|
||||
const rootManifest = JSON.parse(fs.readFileSync(path.join(workspace, 'package.json'), 'utf8'))
|
||||
for (const name of ['react', 'react-dom', '@types/react', '@types/react-dom']) dependencies[name] = rootManifest.devDependencies[name]
|
||||
writeJson(path.join(consumer, 'package.json'), { name: 'react-artplayer-isolated-consumer', private: true, type: 'module', dependencies })
|
||||
fs.writeFileSync(path.join(output, '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, 'consumer-yarn.lock'), lock)
|
||||
fs.writeFileSync(path.join(output, '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 report.packages) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
const example = path.join(workspace, 'example/react.js')
|
||||
fs.cpSync(path.join(example, 'src'), path.join(consumer, 'src'), { recursive: true })
|
||||
fs.copyFileSync(path.join(example, 'index.html'), path.join(consumer, 'index.html'))
|
||||
fs.copyFileSync(path.join(example, 'tsconfig.json'), path.join(consumer, 'tsconfig.json'))
|
||||
if (before) {
|
||||
const old = execFileSync('git', ['show', '3e39fc745f4dc98eba678ca081e86c1d3cc965cd:example/react.js/src/Player.tsx'], { cwd: workspace })
|
||||
fs.writeFileSync(path.join(consumer, 'src/Player.tsx'), old)
|
||||
report.beforeWrapper = hash(old)
|
||||
}
|
||||
for (const file of ['lifecycle.tsx', 'consumer.tsx']) fs.copyFileSync(path.join(workspace, 'test/react', file), path.join(consumer, file))
|
||||
fs.writeFileSync(path.join(consumer, 'harness.html'), '<!doctype html><html><body><div id="root"></div><script type="module" src="/lifecycle.tsx"></script></body></html>')
|
||||
fs.mkdirSync(path.join(consumer, 'public'))
|
||||
const media = fs.readFileSync(path.join(workspace, 'test/browser/media/pattern.mp4'))
|
||||
fs.writeFileSync(path.join(consumer, 'public/pattern.mp4'), media)
|
||||
fs.copyFileSync(path.join(example, 'public/vite.svg'), path.join(consumer, 'public/vite.svg'))
|
||||
report.media = { file: 'test/browser/media/pattern.mp4', sha256: hash(media) }
|
||||
report.inputs = Object.fromEntries(['src/Player.tsx', 'src/player-options.ts', 'src/App.tsx', 'src/main.tsx', 'index.html', 'lifecycle.tsx', 'consumer.tsx'].map(file => [file, hash(fs.readFileSync(path.join(consumer, file)))]))
|
||||
const config = ts.readConfigFile(path.join(consumer, 'tsconfig.json'), ts.sys.readFile)
|
||||
assert.equal(config.error, undefined)
|
||||
const parsed = ts.parseJsonConfigFileContent({ ...config.config, include: ['src', 'consumer.tsx', 'lifecycle.tsx'] }, ts.sys, consumer)
|
||||
assert.deepEqual(parsed.errors, [])
|
||||
const host = ts.createCompilerHost(parsed.options)
|
||||
host.getCurrentDirectory = () => consumer
|
||||
const program = ts.createProgram(parsed.fileNames, parsed.options, host)
|
||||
const diagnostics = ts.getPreEmitDiagnostics(program).map(d => ({ code: d.code, file: d.file?.fileName, text: ts.flattenDiagnosticMessageText(d.messageText, '\n') }))
|
||||
report.types = { version: ts.version, diagnostics }
|
||||
assert.deepEqual(diagnostics, [])
|
||||
const library = fs.realpathSync(path.dirname(ts.sys.getExecutingFilePath()))
|
||||
for (const file of program.getSourceFiles()) {
|
||||
const actual = fs.realpathSync(file.fileName)
|
||||
assert(actual.startsWith(fs.realpathSync(consumer) + path.sep) || (path.dirname(actual) === library && /^lib\..*\.d\.ts$/.test(path.basename(actual))), `Types escaped consumer: ${actual}`)
|
||||
}
|
||||
for (const mode of ['development', 'production']) {
|
||||
const outDir = path.join(output, mode)
|
||||
await build({ root: consumer, configFile: false, plugins: [react()], mode, define: { 'process.env.NODE_ENV': JSON.stringify(mode) }, build: { outDir, emptyOutDir: false, rollupOptions: { input: { app: path.join(consumer, 'index.html'), harness: path.join(consumer, 'harness.html') } } } })
|
||||
const server = await preview({ root: consumer, configFile: false, build: { outDir }, preview: { host: '127.0.0.1', port: 0, open: false } })
|
||||
const address = server.httpServer.address()
|
||||
const base = `http://127.0.0.1:${address.port}`
|
||||
try {
|
||||
for (const [engine, type] of Object.entries({ chromium, firefox, webkit })) {
|
||||
const browser = await type.launch()
|
||||
const row = { mode, engine, version: browser.version(), checks: [], passed: false }
|
||||
report.browsers.push(row)
|
||||
const page = await browser.newPage()
|
||||
const unexpected = []
|
||||
page.on('pageerror', error => unexpected.push(error.message))
|
||||
await page.route('https://artplayer.org/assets/sample/danmuku.xml', route => route.fulfill({ contentType: 'text/xml', body: '<i><d p="0,1,25,16777215,0,0,0,0">React lifecycle sample</d></i>' }))
|
||||
await page.route('https://artplayer.org/assets/sample/video.mp4', route => route.fulfill({ contentType: 'video/mp4', body: media }))
|
||||
const snapshot = () => page.evaluate(() => window.probe.snapshot())
|
||||
const wait = async (count) => {
|
||||
await page.waitForFunction(count => window.probe?.snapshot().active === count, count)
|
||||
return snapshot()
|
||||
}
|
||||
try {
|
||||
await page.goto(`${base}/harness.html`)
|
||||
let state = await wait(1)
|
||||
assert.equal(state.created, mode === 'development' ? 2 : 1)
|
||||
assert.equal(state.players, 1)
|
||||
assert.equal(await page.locator('#player').getAttribute('data-consumer'), 'preserved')
|
||||
await page.waitForFunction(() => window.probe.current().plugins.artplayerPluginDanmuku && window.probe.current().plugins.artplayerPluginDocumentPip)
|
||||
row.checks.push('strict-mode-and-plugin-registration')
|
||||
const original = state.created
|
||||
await page.evaluate(() => window.probe.render())
|
||||
await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))))
|
||||
assert.equal((await snapshot()).created, original)
|
||||
row.checks.push('stable-props-retain-instance')
|
||||
for (const mode of ['callback', 'option']) {
|
||||
const prior = (await snapshot()).created
|
||||
await page.evaluate(mode => window.probe.render(mode), mode)
|
||||
await page.waitForFunction(prior => window.probe.snapshot().created === prior + 1, prior)
|
||||
state = await wait(1)
|
||||
assert(state.records.slice(0, -1).every(record => record.isDestroy && record.destroyed === 1))
|
||||
assert.equal(state.players, 1)
|
||||
row.checks.push(`${mode}-change-cleans-old-instance`)
|
||||
}
|
||||
await page.waitForFunction(() => window.probe.current().duration > 1)
|
||||
await page.evaluate(() => window.probe.current().play())
|
||||
await page.waitForFunction(() => window.probe.current().currentTime > 0.15)
|
||||
row.media = await page.evaluate(async () => {
|
||||
const art = window.probe.current()
|
||||
art.pause()
|
||||
const time = art.currentTime
|
||||
const seeked = new Promise(resolve => art.video.addEventListener('seeked', resolve, { once: true }))
|
||||
art.currentTime = 1
|
||||
await seeked
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = 8
|
||||
canvas.height = 8
|
||||
const context = canvas.getContext('2d')
|
||||
context.drawImage(art.video, 0, 0, 8, 8)
|
||||
return { time, paused: art.playing === false, seek: art.currentTime, width: art.video.videoWidth, rgba: Array.from(context.getImageData(0, 0, 8, 8).data) }
|
||||
})
|
||||
assert(row.media.time > 0.15 && row.media.paused && Math.abs(row.media.seek - 1) < 0.1 && row.media.width > 0)
|
||||
assert(row.media.rgba.some((value, index) => index % 4 !== 3 && value > 50))
|
||||
row.checks.push('native-play-pause-seek-and-decoded-pixels')
|
||||
await page.evaluate(() => window.probe.render('siblings'))
|
||||
await wait(2)
|
||||
const retainedId = await page.evaluate(() => window.probe.current().id)
|
||||
await page.evaluate(() => window.probe.render())
|
||||
state = await wait(1)
|
||||
assert.equal(await page.evaluate(() => window.probe.current().id), retainedId)
|
||||
assert.equal(state.players, 1)
|
||||
row.checks.push('sibling-unmount-preserves-other-instance')
|
||||
await page.evaluate(() => window.probe.render('optional'))
|
||||
await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))))
|
||||
await wait(1)
|
||||
row.checks.push('optional-getInstance')
|
||||
await page.evaluate(() => window.probe.render('empty'))
|
||||
state = await wait(0)
|
||||
assert.equal(state.players, 0)
|
||||
assert.equal(state.videos, 0)
|
||||
assert(state.records.every(record => record.isDestroy && record.destroyed === 1))
|
||||
row.checks.push('unmount-cleans-recorded-instances-and-dom')
|
||||
await page.evaluate(() => window.probe.render())
|
||||
await wait(1)
|
||||
row.checks.push('remount-after-empty')
|
||||
await page.evaluate(() => window.probe.render('throw'))
|
||||
await page.locator('#caught').waitFor()
|
||||
state = await snapshot()
|
||||
row.callbackFailure = state
|
||||
assert.equal(state.active, 0, 'Throwing getInstance leaked a player')
|
||||
assert(state.records.every(record => record.isDestroy && record.destroyed === 1))
|
||||
assert.equal(state.errors.length, mode === 'development' ? 2 : 1)
|
||||
assert(state.errors.every(error => error.same && error.message === 'react-consumer-callback-failure'))
|
||||
row.checks.push('callback-exception-cleanup-and-original-error')
|
||||
await page.evaluate(() => window.probe.render('throw-cleanup'))
|
||||
await page.waitForFunction(count => window.probe.snapshot().errors.length === count, mode === 'development' ? 4 : 2)
|
||||
state = await snapshot()
|
||||
assert.equal(state.active, 0)
|
||||
assert.equal(state.players, 0)
|
||||
assert(state.records.every(record => record.isDestroy && record.destroyed === 1))
|
||||
assert(state.errors.every(error => error.same && error.message === 'react-consumer-callback-failure'))
|
||||
row.checks.push('cleanup-error-preserves-primary-callback-error')
|
||||
assert.deepEqual(unexpected, [])
|
||||
await page.goto(base)
|
||||
await page.locator('.art-video-player').waitFor()
|
||||
await page.waitForFunction(() => document.querySelector('video')?.readyState >= 2)
|
||||
row.checks.push('original-app-entry-loads-media')
|
||||
assert.deepEqual(unexpected, [])
|
||||
row.passed = true
|
||||
}
|
||||
catch (error) {
|
||||
row.error = error.stack
|
||||
await page.screenshot({ path: path.join(output, `${mode}-${engine}-failure.png`) })
|
||||
throw error
|
||||
}
|
||||
finally {
|
||||
await browser.close()
|
||||
writeJson(path.join(output, 'report.json'), report)
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
await new Promise(resolve => server.httpServer.close(resolve))
|
||||
}
|
||||
}
|
||||
report.passed = true
|
||||
}
|
||||
finally {
|
||||
writeJson(path.join(output, 'report.json'), report)
|
||||
removeConsumer(consumer)
|
||||
}
|
||||
console.log('React installed consumer types and six native browser profiles passed.')
|
||||
+27
-4
@@ -4206,17 +4206,22 @@
|
||||
"phase": "6 文档与消费者",
|
||||
"title": "验证 React 消费者与 TS",
|
||||
"scope": [
|
||||
"example/react.js"
|
||||
"example/react.js",
|
||||
"workspace"
|
||||
],
|
||||
"dependsOn": [
|
||||
"CORE-22",
|
||||
"ENG-07"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"risk": "M",
|
||||
"deliverable": "React 挂载/卸载/重挂载、引用和插件样例",
|
||||
"acceptance": "真实 tarball + TS 消费通过,保留既有 React 集成 API",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-14-EX-01-react-consumer.md",
|
||||
"baselines/react-consumer-validation.json",
|
||||
"scripts/react-consumer.mjs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "EX-02",
|
||||
@@ -4588,7 +4593,8 @@
|
||||
"workspace"
|
||||
],
|
||||
"dependsOn": [
|
||||
"REL-06"
|
||||
"REL-06",
|
||||
"ENG-LINT-01"
|
||||
],
|
||||
"status": "todo",
|
||||
"risk": "L",
|
||||
@@ -4884,6 +4890,23 @@
|
||||
"changes/2026-09-14-PKG-AUTO-THUMB-09-alias.md",
|
||||
"baselines/auto-thumbnail-alias-validation.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ENG-LINT-01",
|
||||
"phase": "2 工程基础",
|
||||
"title": "修复 Mask manifest 排序并恢复全仓 lint",
|
||||
"scope": [
|
||||
"artplayer-plugin-danmuku-mask",
|
||||
"workspace"
|
||||
],
|
||||
"dependsOn": [
|
||||
"PKG-MASK-04"
|
||||
],
|
||||
"status": "todo",
|
||||
"risk": "L",
|
||||
"deliverable": "仅调整 manifest 字段顺序,独立验证全仓只读 lint 与元数据语义不变",
|
||||
"acceptance": "根 lint 通过;解析后的 manifest 深度相等;不改包版本、依赖或公开入口",
|
||||
"evidence": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
Use the pinned Node/Yarn toolchain from `../refactor/toolchain-setup.md`.
|
||||
|
||||
`yarn test:react-consumer` installs packed core/Danmuku/Document PiP outside the
|
||||
workspace and checks the actual React example's strict TSX, development and
|
||||
production builds, and native lifecycle/playback in three engines. Its fixture
|
||||
is in `test/react/`; unique reports and frozen consumer locks are retained under
|
||||
`refactor/.cache/react-consumer-*`. The `--before` control intentionally fails at
|
||||
the recorded old wrapper's callback-exception leak. See the example README for
|
||||
the compatibility contract and the capabilities covered by other package tasks.
|
||||
|
||||
`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`.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Option } from 'artplayer'
|
||||
import type { ComponentProps } from 'react'
|
||||
import Player from './src/Player'
|
||||
|
||||
const option: Partial<Option> = { url: '/pattern.mp4' }
|
||||
const props: ComponentProps<typeof Player> = {
|
||||
option,
|
||||
getInstance(art: Artplayer) { art.pause() },
|
||||
style: { width: 640 },
|
||||
className: 'consumer-container',
|
||||
onClick(event) { event.currentTarget.dataset.clicked = 'yes' },
|
||||
}
|
||||
export const valid = <Player {...props} />
|
||||
export const optional = <Player option={{}} />
|
||||
// @ts-expect-error The historical callback receives a player, not a media element.
|
||||
export const wrongCallback = <Player option={option} getInstance={(video: HTMLVideoElement) => video.pause()} />
|
||||
// @ts-expect-error Native div attributes retain their original types.
|
||||
export const wrongStyle = <Player option={option} style="width: 640px" />
|
||||
// @ts-expect-error Player options still enforce field types.
|
||||
export const wrongOption = <Player option={{ url: 123 }} />
|
||||
@@ -0,0 +1,79 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import Artplayer from 'artplayer'
|
||||
import { Component, StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import Player from './src/Player'
|
||||
|
||||
const records: { art: Artplayer, destroyed: number }[] = []
|
||||
const errors: { message: string, same: boolean }[] = []
|
||||
const container = document.getElementById('root')
|
||||
if (!container)
|
||||
throw new Error('Missing React fixture container')
|
||||
const root = createRoot(container)
|
||||
const option = { url: '/pattern.mp4', muted: true }
|
||||
const changedOption = { ...option, volume: 0.2 }
|
||||
const failure = new Error('react-consumer-callback-failure')
|
||||
function capture(art: Artplayer) {
|
||||
const record = { art, destroyed: 0 }
|
||||
records.push(record)
|
||||
art.on('destroy', () => record.destroyed++)
|
||||
}
|
||||
function changedCapture(art: Artplayer) {
|
||||
capture(art)
|
||||
}
|
||||
function fail(art: Artplayer) {
|
||||
capture(art)
|
||||
throw failure
|
||||
}
|
||||
function failWithCleanupError(art: Artplayer) {
|
||||
const destroy = art.destroy.bind(art)
|
||||
art.destroy = (...args) => {
|
||||
destroy(...args)
|
||||
throw new Error('secondary-cleanup-error')
|
||||
}
|
||||
fail(art)
|
||||
}
|
||||
class Boundary extends Component<{ children: ReactNode }, { failed: boolean }> {
|
||||
state = { failed: false }
|
||||
static getDerivedStateFromError() { return { failed: true } }
|
||||
componentDidCatch(error: Error) { errors.push({ message: error.message, same: error === failure }) }
|
||||
render() { return this.state.failed ? <div id="caught">caught</div> : this.props.children }
|
||||
}
|
||||
function render(mode = 'normal') {
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<Boundary key={mode.startsWith('throw') ? mode : 'healthy'}>
|
||||
{mode !== 'empty' && (
|
||||
<Player
|
||||
key="primary"
|
||||
id="player"
|
||||
className="consumer-container"
|
||||
data-consumer="preserved"
|
||||
style={{ width: 640, height: 360 }}
|
||||
option={mode === 'option' ? changedOption : option}
|
||||
getInstance={mode === 'throw-cleanup' ? failWithCleanupError : mode === 'throw' ? fail : mode === 'callback' ? changedCapture : mode === 'optional' ? undefined : capture}
|
||||
/>
|
||||
)}
|
||||
{mode === 'siblings' && <Player key="sibling" id="sibling" style={{ width: 320, height: 180 }} option={option} getInstance={capture} />}
|
||||
</Boundary>
|
||||
</StrictMode>,
|
||||
)
|
||||
}
|
||||
const probe = {
|
||||
render,
|
||||
snapshot: () => ({
|
||||
active: Artplayer.instances.length,
|
||||
created: records.length,
|
||||
records: records.map(({ art, destroyed }) => ({ id: art.id, isDestroy: art.isDestroy, destroyed })),
|
||||
plugins: Artplayer.instances.map(art => Object.keys(art.plugins)),
|
||||
errors,
|
||||
videos: document.querySelectorAll('video').length,
|
||||
players: document.querySelectorAll('.art-video-player').length,
|
||||
}),
|
||||
current: () => Artplayer.instances[0],
|
||||
}
|
||||
declare global {
|
||||
interface Window { probe: typeof probe }
|
||||
}
|
||||
window.probe = probe
|
||||
render()
|
||||
@@ -219,16 +219,130 @@
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
"@babel/code-frame@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.7.tgz#f2fbbfea87c44a21590ec515b778b2c26d8866e7"
|
||||
integrity sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.29.7"
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
"@babel/compat-data@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629"
|
||||
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
|
||||
|
||||
"@babel/core@^7.28.0":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7"
|
||||
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.29.7"
|
||||
"@babel/generator" "^7.29.7"
|
||||
"@babel/helper-compilation-targets" "^7.29.7"
|
||||
"@babel/helper-module-transforms" "^7.29.7"
|
||||
"@babel/helpers" "^7.29.7"
|
||||
"@babel/parser" "^7.29.7"
|
||||
"@babel/template" "^7.29.7"
|
||||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
"@jridgewell/remapping" "^2.3.5"
|
||||
convert-source-map "^2.0.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
json5 "^2.2.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/generator@^7.29.7", "@babel/generator@^7.29.8":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.8.tgz#4b0b887885422643339e09022148a4c4ebaa4979"
|
||||
integrity sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.29.8"
|
||||
"@babel/types" "^7.29.8"
|
||||
"@jridgewell/gen-mapping" "^0.3.12"
|
||||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz#7a1def704302401c47f64fa85589e974ae217042"
|
||||
integrity sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.29.7"
|
||||
"@babel/helper-validator-option" "^7.29.7"
|
||||
browserslist "^4.24.0"
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-globals@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b"
|
||||
integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==
|
||||
|
||||
"@babel/helper-module-imports@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz#ef25048a518e828d7393fac5882ddd73921d7396"
|
||||
integrity sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/helper-module-transforms@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae"
|
||||
integrity sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.29.7"
|
||||
"@babel/helper-validator-identifier" "^7.29.7"
|
||||
"@babel/traverse" "^7.29.7"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz#c0a0766f1a13617d8a17407d7ab8f9d486225ea4"
|
||||
integrity sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==
|
||||
|
||||
"@babel/helper-string-parser@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz"
|
||||
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
|
||||
|
||||
"@babel/helper-string-parser@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
|
||||
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5":
|
||||
version "7.28.5"
|
||||
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz"
|
||||
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
|
||||
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
|
||||
|
||||
"@babel/helper-validator-option@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a"
|
||||
integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==
|
||||
|
||||
"@babel/helpers@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607"
|
||||
integrity sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==
|
||||
dependencies:
|
||||
"@babel/template" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.29.7", "@babel/parser@^7.29.8":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.8.tgz#9653716a2f10c677b98fbc63d4bfb000c302cf17"
|
||||
integrity sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.29.8"
|
||||
|
||||
"@babel/parser@^7.25.3", "@babel/parser@^7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz"
|
||||
@@ -236,6 +350,50 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.29.0"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.27.1":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz#c24424527858220624fd59a5b1eab4fa413c803a"
|
||||
integrity sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source@^7.27.1":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz#5cf25a3689906b58e2f0a2f2b374789e6627b15f"
|
||||
integrity sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
|
||||
"@babel/template@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700"
|
||||
integrity sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.29.7"
|
||||
"@babel/parser" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/traverse@^7.29.7":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.8.tgz#4111014cdc71a0f95d9471907590baa0b8a6b28a"
|
||||
integrity sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.29.7"
|
||||
"@babel/generator" "^7.29.8"
|
||||
"@babel/helper-globals" "^7.29.7"
|
||||
"@babel/parser" "^7.29.8"
|
||||
"@babel/template" "^7.29.7"
|
||||
"@babel/types" "^7.29.8"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.29.7", "@babel/types@^7.29.8":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.8.tgz#1229eef31d85156d70fa3f4cd859376d0eaf6863"
|
||||
integrity sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.29.7"
|
||||
"@babel/helper-validator-identifier" "^7.29.7"
|
||||
|
||||
"@babel/types@^7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz"
|
||||
@@ -793,7 +951,7 @@
|
||||
dependencies:
|
||||
"@sinclair/typebox" "^0.27.8"
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.5":
|
||||
"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5":
|
||||
version "0.3.13"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f"
|
||||
integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==
|
||||
@@ -801,6 +959,14 @@
|
||||
"@jridgewell/sourcemap-codec" "^1.5.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@jridgewell/remapping@^2.3.5":
|
||||
version "2.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1"
|
||||
integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.1.0":
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
|
||||
@@ -819,7 +985,7 @@
|
||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz"
|
||||
integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
|
||||
"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28":
|
||||
version "0.3.31"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0"
|
||||
integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==
|
||||
@@ -1383,6 +1549,11 @@
|
||||
dependencies:
|
||||
playwright "1.63.0"
|
||||
|
||||
"@rolldown/pluginutils@1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.30.tgz#ac55a2215c78a54ba67276524ac3dc8c195316d0"
|
||||
integrity sha512-whXaSoNUFiyDAjkUF8OBpOm77Szdbk5lGNqFe6CbVbJFrhCCPinCbRA3NjawwlNHla1No7xvXXh+CpSxnPfUEw==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.57.1":
|
||||
version "4.57.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz#add5e608d4e7be55bc3ca3d962490b8b1890e088"
|
||||
@@ -1703,6 +1874,39 @@
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@types/babel__core@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
|
||||
integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.20.7"
|
||||
"@babel/types" "^7.20.7"
|
||||
"@types/babel__generator" "*"
|
||||
"@types/babel__template" "*"
|
||||
"@types/babel__traverse" "*"
|
||||
|
||||
"@types/babel__generator@*":
|
||||
version "7.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9"
|
||||
integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@types/babel__template@*":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f"
|
||||
integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.1.0"
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@types/babel__traverse@*":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74"
|
||||
integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==
|
||||
dependencies:
|
||||
"@babel/types" "^7.28.2"
|
||||
|
||||
"@types/debug@^4.0.0":
|
||||
version "4.1.12"
|
||||
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz"
|
||||
@@ -1819,6 +2023,18 @@
|
||||
resolved "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz"
|
||||
integrity sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==
|
||||
|
||||
"@types/react-dom@19.1.7":
|
||||
version "19.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.7.tgz#2863f2aa89e023592b981204ef92c5221b286410"
|
||||
integrity sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==
|
||||
|
||||
"@types/react@19.1.10":
|
||||
version "19.1.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.10.tgz#a05015952ef328e1b85579c839a71304b07d21d9"
|
||||
integrity sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/seedrandom@^2.4.28":
|
||||
version "2.4.34"
|
||||
resolved "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.34.tgz"
|
||||
@@ -1935,6 +2151,18 @@
|
||||
resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz"
|
||||
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
|
||||
|
||||
"@vitejs/plugin-react@5.0.0":
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.0.0.tgz#5cfe3d3665d3d04b0df7a8356ffd59359f5d0220"
|
||||
integrity sha512-Jx9JfsTa05bYkS9xo0hkofp2dCmp1blrKjw9JONs5BTHOvJCgLbaPSuZLGSVJW6u2qe0tc4eevY0+gSNNi0YCw==
|
||||
dependencies:
|
||||
"@babel/core" "^7.28.0"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.27.1"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.27.1"
|
||||
"@rolldown/pluginutils" "1.0.0-beta.30"
|
||||
"@types/babel__core" "^7.20.5"
|
||||
react-refresh "^0.17.0"
|
||||
|
||||
"@vitejs/plugin-vue@^5.2.1":
|
||||
version "5.2.4"
|
||||
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz"
|
||||
@@ -2392,6 +2620,11 @@ base64-js@^1.3.1:
|
||||
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
||||
baseline-browser-mapping@^2.11.20:
|
||||
version "2.11.23"
|
||||
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.23.tgz#304c980a35de0f460cf12985359d6e11494c1ab4"
|
||||
integrity sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ==
|
||||
|
||||
baseline-browser-mapping@^2.9.0:
|
||||
version "2.9.19"
|
||||
resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz"
|
||||
@@ -2465,6 +2698,17 @@ braces@^3.0.3:
|
||||
dependencies:
|
||||
fill-range "^7.1.1"
|
||||
|
||||
browserslist@^4.24.0:
|
||||
version "4.28.9"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.9.tgz#07ce6b449b90af880eb9bfb7cd39372cc4f71c8c"
|
||||
integrity sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==
|
||||
dependencies:
|
||||
baseline-browser-mapping "^2.11.20"
|
||||
caniuse-lite "^1.0.30001810"
|
||||
electron-to-chromium "^1.5.420"
|
||||
node-releases "^2.0.54"
|
||||
update-browserslist-db "^1.3.2"
|
||||
|
||||
browserslist@^4.28.1:
|
||||
version "4.28.1"
|
||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz"
|
||||
@@ -2571,6 +2815,11 @@ caniuse-lite@^1.0.30001759:
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz"
|
||||
integrity sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==
|
||||
|
||||
caniuse-lite@^1.0.30001810:
|
||||
version "1.0.30001810"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz#4970b477dea3278374de9bc43aa8f5d39fc3cda2"
|
||||
integrity sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==
|
||||
|
||||
ccount@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz"
|
||||
@@ -3028,7 +3277,7 @@ cssom@^0.5.0:
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36"
|
||||
integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==
|
||||
|
||||
csstype@^3.1.3, csstype@^3.2.3:
|
||||
csstype@^3.0.2, csstype@^3.1.3, csstype@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz"
|
||||
integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
|
||||
@@ -3043,7 +3292,7 @@ dateformat@^3.0.3:
|
||||
resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz"
|
||||
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||
|
||||
debug@4, debug@^4.0.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.3:
|
||||
debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.3:
|
||||
version "4.4.3"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
|
||||
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
|
||||
@@ -3252,6 +3501,11 @@ electron-to-chromium@^1.5.263:
|
||||
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz"
|
||||
integrity sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==
|
||||
|
||||
electron-to-chromium@^1.5.420:
|
||||
version "1.5.427"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.427.tgz#f8693d109cf116d4a6efa98bc620b9fc7f265f67"
|
||||
integrity sha512-n14zb3FdsChZ2BNobqNHAJMcP3ifFv4paox2LvCrfVAQcqGiSURgbJl+PfMpHVCNFkStnNc+RRVtPBTVW5PDgw==
|
||||
|
||||
emoji-regex-xs@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz"
|
||||
@@ -4076,6 +4330,11 @@ function-bind@^1.1.2:
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||
|
||||
get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
|
||||
@@ -4831,7 +5090,7 @@ jsdoc-type-pratt-parser@~7.0.0:
|
||||
resolved "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.0.0.tgz"
|
||||
integrity sha512-c7YbokssPOSHmqTbSAmTtnVgAVa/7lumWNYqomgd5KOMyPrRve2anx6lonfOsXEQacqF9FKVUj7bLg4vRSvdYA==
|
||||
|
||||
jsesc@^3.1.0:
|
||||
jsesc@^3.0.2, jsesc@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz"
|
||||
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
|
||||
@@ -4881,7 +5140,7 @@ json-stringify-safe@^5.0.1:
|
||||
resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
|
||||
integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
|
||||
|
||||
json5@^2.2.2:
|
||||
json5@^2.2.2, json5@^2.2.3:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
|
||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||
@@ -5208,6 +5467,13 @@ lru-cache@^11.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.2.tgz#00e16665c90c620fba14a3c368732a976493f760"
|
||||
integrity sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==
|
||||
|
||||
lru-cache@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
|
||||
dependencies:
|
||||
yallist "^3.0.2"
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
|
||||
@@ -6087,6 +6353,11 @@ node-releases@^2.0.27:
|
||||
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz"
|
||||
integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==
|
||||
|
||||
node-releases@^2.0.54:
|
||||
version "2.0.55"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.55.tgz#c52faedb68001dcfe77495b5ed1ac5827a1788fc"
|
||||
integrity sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==
|
||||
|
||||
nopt@^7.0.0, nopt@^7.2.1:
|
||||
version "7.2.1"
|
||||
resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz"
|
||||
@@ -6913,11 +7184,28 @@ quick-lru@^4.0.1:
|
||||
resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz"
|
||||
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
|
||||
|
||||
react-dom@19.1.1:
|
||||
version "19.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.1.tgz#2daa9ff7f3ae384aeb30e76d5ee38c046dc89893"
|
||||
integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==
|
||||
dependencies:
|
||||
scheduler "^0.26.0"
|
||||
|
||||
react-is@^18.0.0:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz"
|
||||
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
||||
|
||||
react-refresh@^0.17.0:
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53"
|
||||
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
|
||||
|
||||
react@19.1.1:
|
||||
version "19.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.1.1.tgz#06d9149ec5e083a67f9a1e39ce97b06a03b644af"
|
||||
integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==
|
||||
|
||||
read-cmd-shim@4.0.0, read-cmd-shim@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz"
|
||||
@@ -7201,6 +7489,11 @@ sax@1.6.1, sax@^1.2.4:
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.6.1.tgz#4c23cf608c0b693ab54b4b5888e92cfe977b9843"
|
||||
integrity sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==
|
||||
|
||||
scheduler@^0.26.0:
|
||||
version "0.26.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337"
|
||||
integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==
|
||||
|
||||
scslre@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz"
|
||||
@@ -7225,6 +7518,11 @@ semver@7.7.4, semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz"
|
||||
integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==
|
||||
|
||||
semver@^6.3.1:
|
||||
version "6.3.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
servor@4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/servor/-/servor-4.0.2.tgz#6d5e5c61fbb3d6f4bde72995dbe6745829395971"
|
||||
@@ -7924,6 +8222,14 @@ update-browserslist-db@^1.2.0:
|
||||
escalade "^3.2.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
update-browserslist-db@^1.3.2:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz#197e21fb2561fa89f8b94fad605a2b296a18993a"
|
||||
integrity sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==
|
||||
dependencies:
|
||||
escalade "^3.2.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
|
||||
@@ -8231,6 +8537,11 @@ y18n@^5.0.5:
|
||||
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
||||
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
||||
|
||||
yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
|
||||
|
||||
Reference in new issue
Block a user