From 69b9aa47b4fce6cb503de0b966b8f490b68374b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 02:33:48 +0000 Subject: [PATCH 01/39] chore(deps-dev): bump @cloudflare/workers-types Bumps [@cloudflare/workers-types](https://github.com/cloudflare/workerd) from 4.20260611.1 to 4.20260613.1. - [Release notes](https://github.com/cloudflare/workerd/releases) - [Changelog](https://github.com/cloudflare/workerd/blob/main/RELEASE.md) - [Commits](https://github.com/cloudflare/workerd/commits) --- updated-dependencies: - dependency-name: "@cloudflare/workers-types" dependency-version: 4.20260613.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/player-web-demo/package.json | 2 +- pnpm-lock.yaml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index 4ccdccc0..c5c3c117 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -25,7 +25,7 @@ "lil-gui": "^0.21.0" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20260611.1", + "@cloudflare/workers-types": "^4.20260613.1", "ts-ebml": "^3.0.2", "vite": "^8.0.16", "vite-plugin-node-polyfills": "^0.28.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e4f97cc..8f441962 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -265,8 +265,8 @@ importers: version: 0.21.0 devDependencies: '@cloudflare/workers-types': - specifier: ^4.20260611.1 - version: 4.20260611.1 + specifier: ^4.20260613.1 + version: 4.20260613.1 ts-ebml: specifier: ^3.0.2 version: 3.0.2 @@ -278,7 +278,7 @@ importers: version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4)) wrangler: specifier: ^4.100.0 - version: 4.100.0(@cloudflare/workers-types@4.20260611.1) + version: 4.100.0(@cloudflare/workers-types@4.20260613.1) packages/stringifier: dependencies: @@ -450,8 +450,8 @@ packages: cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20260611.1': - resolution: {integrity: sha512-DLiz8Ol1OIWLigJ+dGvuQ5Nm66D/CHNPasl8YnPiz6fGo10ggYSIVuEDMlFk6oho+piAHstNmZMl088w8xqW6g==} + '@cloudflare/workers-types@4.20260613.1': + resolution: {integrity: sha512-1mrgjE6epolwBhroeGAp5ud5H6Vyi6tl1o/NP0T4rXJ8bmEjmhHnbCzAhHTDHV0PIeip43wcuzHKJarvaGTaUA==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -3840,7 +3840,7 @@ snapshots: '@cloudflare/workerd-windows-64@1.20260611.1': optional: true - '@cloudflare/workers-types@4.20260611.1': {} + '@cloudflare/workers-types@4.20260613.1': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -6522,7 +6522,7 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260611.1 '@cloudflare/workerd-windows-64': 1.20260611.1 - wrangler@4.100.0(@cloudflare/workers-types@4.20260611.1): + wrangler@4.100.0(@cloudflare/workers-types@4.20260613.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260611.1) @@ -6533,7 +6533,7 @@ snapshots: unenv: 2.0.0-rc.24 workerd: 1.20260611.1 optionalDependencies: - '@cloudflare/workers-types': 4.20260611.1 + '@cloudflare/workers-types': 4.20260613.1 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil From 9833c3ce519cd7d307c8737c19e001b6e36a85cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 02:34:10 +0000 Subject: [PATCH 02/39] chore(deps-dev): bump @typescript/native-preview Bumps [@typescript/native-preview](https://github.com/microsoft/typescript-go) from 7.0.0-dev.20260611.2 to 7.0.0-dev.20260613.1. - [Changelog](https://github.com/microsoft/typescript-go/blob/main/CHANGES.md) - [Commits](https://github.com/microsoft/typescript-go/commits) --- updated-dependencies: - dependency-name: "@typescript/native-preview" dependency-version: 7.0.0-dev.20260613.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 76 +++++++++++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 990c06ff..fd228f2b 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "devDependencies": { "@changesets/cli": "^2.31.0", "@types/node": "^25.9.1", - "@typescript/native-preview": "7.0.0-dev.20260611.2", + "@typescript/native-preview": "7.0.0-dev.20260613.1", "@vitest/coverage-v8": "^4.0.18", "oxfmt": "^0.54.0", "oxlint": "^1.69.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e4f97cc..964c7452 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^25.9.1 version: 25.9.1 '@typescript/native-preview': - specifier: 7.0.0-dev.20260611.2 - version: 7.0.0-dev.20260611.2 + specifier: 7.0.0-dev.20260613.1 + version: 7.0.0-dev.20260613.1 '@vitest/coverage-v8': specifier: ^4.0.18 version: 4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4)) @@ -34,7 +34,7 @@ importers: version: 6.0.2 tsdown: specifier: ^0.22.2 - version: 0.22.2(@typescript/native-preview@7.0.0-dev.20260611.2)(tsx@4.22.4)(unrun@0.2.37) + version: 0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(unrun@0.2.37) tsx: specifier: ^4.22.4 version: 4.22.4 @@ -1929,50 +1929,50 @@ packages: '@types/wicg-file-system-access@2020.9.8': resolution: {integrity: sha512-ggMz8nOygG7d/stpH40WVaNvBwuyYLnrg5Mbyf6bmsj/8+gb6Ei4ZZ9/4PNpcPNTT8th9Q8sM8wYmWGjMWLX/A==} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-X6NqNmoTnO1vtcsE4qP571BByPi+i16Ynrp6fffcQ38pbRuy4mwECxA9nKb273gscG0wvcIcGM81B+vy1F4nDw==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-znTFp/M0SpN91/FM3FrsTycdTZr+bLszmHObm2LaR5sgo1c2wiK4qYsMnrhLeP0vSMD2LuiNg5J21501h7Aj6g==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-VeguHC/F7EbxNPCrcwCRH2wif6PZKcdUg2DtMyjxohtcVK3vOoVCYqhJBgJVWQ2gbXk+bXcIz8L2/uNYDksN0w==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-7zXTq3SVw6XCLdm06VRIhMzayG032Ky14xCZ3isnlcm1KD/p4Ev4XL9TN9fZmIV0bVPGMQr4qGS7a2+te8x7lg==} engines: {node: '>=16.20.0'} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-19TXmRxxPUNNDAP/4xBwDNud1NvuNgQJhRm87t7/CSh4FGhWeeEm7AuyEvrCB+vzeeI/ExT+J58U1HOo+kYKzg==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-yYiDEMT4ok7Wd1VtbyB+0YqBdTkU/yzE36edZCbfA/Ljt6L1xZMEn0a7XGlmRtRfwPGHfjtFRFsxrA2nc7jHnw==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-szcSb7sSn3OQZ5UWtToG2RTQeDlokd05pXM+rGctBIctDj6E4j9bvAfp6xLZCzqyDuZJhi3cXCJBdSlBD0NjHw==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-xpA7nXiRE3fwvTUK2ibhkPr7hn6D4i3pB9WjlcX7CSPB2pYGMdHAsL55EAFlR3eNKyNM/geoLfqq4L4PIeOWsQ==} engines: {node: '>=16.20.0'} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-h5Etd2Kc6lvvc+X4MU/EFeYDUZAS4hOqB18piWuy2INHfRvJMOo8jZOwUJRix3NQu75tPbltFCkwFOGqB0fd2Q==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-mZO9hIwXek9VO+N+gs6IKDOf0fPnrQg/SvaOsCDcDwsk7a60yPbacyY7IiXFnxhNgZDLsYqs8j9ojDGl6+Tp5g==} engines: {node: '>=16.20.0'} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-JUUFHNi3asye8iOlVmFEra34LuQ8bw8qvYWp+cW7EXg3mrMxtac/u5chhi8BmICEav2Ff3UFd8ZFL0n+F5EvBA==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-JtMTHRt7auXTCvvOtcn7aX1gdCPByQl4c5vc8e1d+8PcqtMqeSpH1j0Vp06F9vugTA+YMIzFsJQA91sUK1oHeg==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-1ZPtOctecgkUHBIEoTefE34t4CewqxwdzIkRx22fDEC9bHhN8xO4JSfQyL+OSWDxiZaJKuqR9BnfWSl2eAFtmg==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-aCZaFWHDt5n8B++F2FrTK2pF7muAFfkvi8qkUnC0N0SNBGdVnqlO28IbdjScIfI2JFOvgZtUoYWeATGWdrLXBA==} engines: {node: '>=16.20.0'} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260611.2': - resolution: {integrity: sha512-nP/OrQRFTRKHeQiXzMVhQlxSrOPeuDgeGGd9KMlmOFTc/bbQ8Zd6Ep5izsdTkFljd26QUfpm98crp5E5bYAvJg==} + '@typescript/native-preview@7.0.0-dev.20260613.1': + resolution: {integrity: sha512-RJ3YrYNoshFGVY862CwZ/WcICvMW0u9XtezI8AAU81I71Cr3/IJoHPUGsGKUr2gVcPfKRQiaI8YTndFzUGvSug==} engines: {node: '>=16.20.0'} hasBin: true @@ -4699,36 +4699,36 @@ snapshots: '@types/wicg-file-system-access@2020.9.8': {} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260611.2': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260613.1': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260611.2': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260613.1': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260611.2': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260613.1': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260611.2': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260613.1': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260611.2': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260613.1': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260611.2': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260613.1': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260611.2': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260613.1': optional: true - '@typescript/native-preview@7.0.0-dev.20260611.2': + '@typescript/native-preview@7.0.0-dev.20260613.1': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260611.2 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260611.2 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260611.2 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260611.2 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260611.2 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260611.2 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260611.2 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260613.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260613.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260613.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260613.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260613.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260613.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260613.1 '@uwx/libav.js-fat@6.0.0-nightly.29.f420ff.ffmpeg.6.1.1': {} @@ -6000,7 +6000,7 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rolldown-plugin-dts@0.25.2(@typescript/native-preview@7.0.0-dev.20260611.2)(rolldown@1.1.0): + rolldown-plugin-dts@0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0): dependencies: '@babel/generator': 8.0.0-rc.6 '@babel/helper-validator-identifier': 8.0.0-rc.6 @@ -6012,7 +6012,7 @@ snapshots: obug: 2.1.1 rolldown: 1.1.0 optionalDependencies: - '@typescript/native-preview': 7.0.0-dev.20260611.2 + '@typescript/native-preview': 7.0.0-dev.20260613.1 transitivePeerDependencies: - oxc-resolver @@ -6339,7 +6339,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.2(@typescript/native-preview@7.0.0-dev.20260611.2)(tsx@4.22.4)(unrun@0.2.37): + tsdown@0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -6350,7 +6350,7 @@ snapshots: obug: 2.1.1 picomatch: 4.0.4 rolldown: 1.1.0 - rolldown-plugin-dts: 0.25.2(@typescript/native-preview@7.0.0-dev.20260611.2)(rolldown@1.1.0) + rolldown-plugin-dts: 0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0) semver: 7.8.1 tinyexec: 1.2.4 tinyglobby: 0.2.17 From 2b10f2a53b8653e4d5471ea0910e25c0229a892a Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Fri, 19 Jun 2026 03:26:17 +0900 Subject: [PATCH 03/39] chore(deps-dev): replace @typescript/native-preview with typescript 7.0 RC TypeScript 7.0 ships under the `typescript` package on the `rc` tag (7.0.1-rc) instead of the separate `@typescript/native-preview` package, and the binary is the standard `tsc` again rather than `tsgo`. - Swap the root devDependency to `typescript@7.0.1-rc` - Point every package's `typecheck` script at `tsc` - Allow the TS7 RC via `pnpm.peerDependencyRules` so tsdown / rolldown-plugin-dts no longer warn about the optional peer range - Drop the now-unused `tsgo` cSpell entry Verified with lint, typecheck, build, and test. --- .vscode/settings.json | 1 - package.json | 9 +- packages/audio-renderer/package.json | 2 +- packages/beatoraja-skin/package.json | 2 +- packages/chart/package.json | 2 +- packages/editor/package.json | 2 +- packages/json/package.json | 2 +- packages/lr2-skin/package.json | 2 +- packages/parser/package.json | 2 +- packages/player-tui/package.json | 2 +- packages/player-web-demo/package.json | 2 +- packages/player-web/package.json | 2 +- packages/player/package.json | 2 +- packages/stringifier/package.json | 2 +- packages/utils/package.json | 2 +- pnpm-lock.yaml | 225 +++++++++++++++++++++++++- 16 files changed, 238 insertions(+), 23 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5ee2b8f1..3bc5ccf7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -57,7 +57,6 @@ "stringifier", "subartists", "SWBGA", - "tsgo", "Unjudged", "VIDEOFILE", "VOLWAV", diff --git a/package.json b/package.json index fd228f2b..674c0720 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "devDependencies": { "@changesets/cli": "^2.31.0", "@types/node": "^25.9.1", - "@typescript/native-preview": "7.0.0-dev.20260613.1", "@vitest/coverage-v8": "^4.0.18", "oxfmt": "^0.54.0", "oxlint": "^1.69.0", @@ -42,6 +41,7 @@ "tinybench": "^6.0.2", "tsdown": "^0.22.2", "tsx": "^4.22.4", + "typescript": "7.0.1-rc", "vite": "^8.0.16", "vitest": "^4.0.18" }, @@ -52,6 +52,11 @@ "pnpm": { "onlyBuiltDependencies": [ "esbuild" - ] + ], + "peerDependencyRules": { + "allowedVersions": { + "typescript": "7.0.1-rc" + } + } } } diff --git a/packages/audio-renderer/package.json b/packages/audio-renderer/package.json index 12f69479..251b1711 100644 --- a/packages/audio-renderer/package.json +++ b/packages/audio-renderer/package.json @@ -30,7 +30,7 @@ "build:sea": "tsx ../../scripts/build-sea.ts --package audio-renderer", "clean": "rimraf dist tsconfig.tsbuildinfo", "dev": "tsx --tsconfig ../../tsconfig.typecheck.json src/cli.ts", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/beatoraja-skin/package.json b/packages/beatoraja-skin/package.json index f138feb8..38abe6e9 100644 --- a/packages/beatoraja-skin/package.json +++ b/packages/beatoraja-skin/package.json @@ -20,7 +20,7 @@ "build:bundle": "tsdown", "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/chart/package.json b/packages/chart/package.json index 678245ed..46f33d8c 100644 --- a/packages/chart/package.json +++ b/packages/chart/package.json @@ -20,7 +20,7 @@ "build:bundle": "tsdown", "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/editor/package.json b/packages/editor/package.json index 2afbccab..c1f97578 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -24,7 +24,7 @@ "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", "dev": "tsx --tsconfig ../../tsconfig.typecheck.json src/cli.ts", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/json/package.json b/packages/json/package.json index 70aa5d4e..0c56281d 100644 --- a/packages/json/package.json +++ b/packages/json/package.json @@ -20,7 +20,7 @@ "build:bundle": "tsdown", "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/lr2-skin/package.json b/packages/lr2-skin/package.json index 1722a4f9..a069b3c6 100644 --- a/packages/lr2-skin/package.json +++ b/packages/lr2-skin/package.json @@ -20,7 +20,7 @@ "build:bundle": "tsdown", "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/parser/package.json b/packages/parser/package.json index 0e67fffc..553de79a 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -24,7 +24,7 @@ "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", "dev": "tsx --tsconfig ../../tsconfig.typecheck.json src/cli.ts", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/player-tui/package.json b/packages/player-tui/package.json index 4a1d8930..4d09a9bc 100644 --- a/packages/player-tui/package.json +++ b/packages/player-tui/package.json @@ -27,7 +27,7 @@ "dev": "tsx --tsconfig ../../tsconfig.typecheck.json src/cli.ts", "diag:keyboard": "tsx --tsconfig ../../tsconfig.typecheck.json src/keyboard-diagnostic.ts", "diag:gameplay-input": "tsx --tsconfig ../../tsconfig.typecheck.json src/gameplay-input-diagnostic.ts", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index 5ed292aa..2cf65a7d 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -11,7 +11,7 @@ "cf:r2:create": "wrangler r2 bucket create be-music-ffmpeg-core", "cf:r2:push": "pnpm run build:cf && node scripts/sync-ffmpeg-core.mjs --force", "clean": "rimraf dist tsconfig.tsbuildinfo node_modules/.vite", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/player-web/package.json b/packages/player-web/package.json index 53407270..192060a9 100644 --- a/packages/player-web/package.json +++ b/packages/player-web/package.json @@ -44,7 +44,7 @@ "scripts": { "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/player/package.json b/packages/player/package.json index 63d25c7e..7203fc95 100644 --- a/packages/player/package.json +++ b/packages/player/package.json @@ -110,7 +110,7 @@ "build:bundle": "tsdown", "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/stringifier/package.json b/packages/stringifier/package.json index 01645d4a..93bb9698 100644 --- a/packages/stringifier/package.json +++ b/packages/stringifier/package.json @@ -24,7 +24,7 @@ "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", "dev": "tsx --tsconfig ../../tsconfig.typecheck.json src/cli.ts", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/packages/utils/package.json b/packages/utils/package.json index 184700ee..9fd4a2af 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -55,7 +55,7 @@ "build:bundle": "tsdown", "build": "tsdown", "clean": "rimraf dist tsconfig.tsbuildinfo", - "typecheck": "tsgo -p tsconfig.typecheck.json --pretty", + "typecheck": "tsc -p tsconfig.typecheck.json --pretty", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "format": "oxfmt . --write", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8fbe99b..7aec492d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,9 +14,6 @@ importers: '@types/node': specifier: ^25.9.1 version: 25.9.1 - '@typescript/native-preview': - specifier: 7.0.0-dev.20260613.1 - version: 7.0.0-dev.20260613.1 '@vitest/coverage-v8': specifier: ^4.0.18 version: 4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4)) @@ -34,10 +31,13 @@ importers: version: 6.0.2 tsdown: specifier: ^0.22.2 - version: 0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(unrun@0.2.37) + version: 0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(typescript@7.0.1-rc)(unrun@0.2.37) tsx: specifier: ^4.22.4 version: 4.22.4 + typescript: + specifier: 7.0.1-rc + version: 7.0.1-rc vite: specifier: ^8.0.16 version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4) @@ -1976,6 +1976,126 @@ packages: engines: {node: '>=16.20.0'} hasBin: true + '@typescript/typescript-aix-ppc64@7.0.1-rc': + resolution: {integrity: sha512-oqq2ZfEJ7BQuufcC3QBQndZLPNyamYNHLao8lKRBeeSkZKypBqxPSgkzrcFZtbYcIaBvpiyUnQP9MT7DEYHWbw==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.1-rc': + resolution: {integrity: sha512-Slc0yTftT2F/uGDmtPst8ijydneL6uZaLEyr2UjahxZpbhTjHFBJ5agXtVz/TL4A+ldxzjzj+E8QtLZlh/5mXw==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.1-rc': + resolution: {integrity: sha512-h68iFW/LbA1/BsGgSRGFw981/3s1f/rY27YrmeZNuN+ly7dI+fiDduwT9ZT9866x2onoKNRq7PTyxSKyKDzfAQ==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.1-rc': + resolution: {integrity: sha512-DE+ppd8Ix2c6OMuRkKY4PJ4hngMGJ9M95OQUP17p9xL/1IKXof7npIeuusMN/bgL5o5JzMfSGh+N+5scTYRg0Q==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.1-rc': + resolution: {integrity: sha512-ST1ozHMw0u+CLOnWkcTyWDMV4Qn9osZ6fd1V1lnKDM1t0hZIp81mdGpdHxyHJjd7jdGrb6Gb/QXcZ1uqZ0t5zw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.1-rc': + resolution: {integrity: sha512-N46pRihK3t5zD5MUtTQcdmQUqr1WI4U2nxno1gLwOtRSsB4krFkRjPHcQNG7h2DtRkX64rQiReX6WKwg2wprMA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.1-rc': + resolution: {integrity: sha512-gHmHwT5Naq5CKM8g9bbaGeEpnwQEvWCLn3fwP4K2m61VQdDKkPk0Dhab/OoZ4LV2SrMddmclYXTzpyg23YGt5g==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.1-rc': + resolution: {integrity: sha512-G17Sao312rgiPBTh2F4nOpLpa3CcnBSaNhqNghZk2LNhnsp1RaMO5HMq2me21gqu9xLpc6CIgHtOzU6JBgNlfg==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.1-rc': + resolution: {integrity: sha512-0FQspOb5UsQ4tQKvWgUO3pS9OIWkP7/8dPRWq+CRazJUeQZ4LBjtYK52jg5iIOrvItrVl2CwvRtrU3/9OihwJg==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.1-rc': + resolution: {integrity: sha512-SUmwfVBEv6A2Ld0eWfcvW0FqrgemfQL8jFGOmV1qYxsDqumjE5DekHXqbstgmbE4SHr4rrjHjvmuGCY+kTH/vw==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.1-rc': + resolution: {integrity: sha512-rxeqnNnGiYzv/LlPHi/3+4p0ooR1cNJLjRIHXKovtiVmxXGJq6gtw8VSpbHuWPekyFMXgIAoLCZN0SQ51rAALQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.1-rc': + resolution: {integrity: sha512-RYWCHCiPypxajdRHM2CNK/eM22e4Ex5TTjV2pXf7PTtBowGr0xX8i8kIMknyZS0LX2QfleYHouaoMVsFDSle3g==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.1-rc': + resolution: {integrity: sha512-PfLJSu0JzroDkqw2m4nqflPEcn8yev0m/vHFQlY9EzHorzjR6QG0wL8AJHvnD1e6h1s76AZngJ5u+z1K/D/HKw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.1-rc': + resolution: {integrity: sha512-FfbPxH3dTfp8yVIaNM7bdWTixXuyxpzoemluqcqMROSIz+ImpCG3Q9HO9Ptzp9/giv+P9YYEnCMSXh61migj2w==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.1-rc': + resolution: {integrity: sha512-FzdTfSzhRYb6hlav6K3cI5RVgcvCTvNAu/vc+t7B6AmZkThQ+t/1ntnvT5fnHmY1Az2RIBw7/b+qtCEG61HJTQ==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.1-rc': + resolution: {integrity: sha512-PQGhlxfNig+0YQ9Wwzd0USPBkt6w/ZqkBQWsU7G/0JkTzunJel+jSWwhKw4947pak/m7hGSeYiI04xReDLGZww==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.1-rc': + resolution: {integrity: sha512-WJ7NYgO2mHmLUkI/tZ+hl8lFd26QPJqO8ONOHNuYbdsybLvSB6B6sep222JIVrOfPRDGvFinbGGB+l3m1FWRWA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.1-rc': + resolution: {integrity: sha512-UYjDeUxd765V9qcwlUPk4pEXyL0i3G76CJm9baK4i99u1pGO1psf3nXDw4MMmElVOPvGbZag99ZR/O59E2OX6w==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.1-rc': + resolution: {integrity: sha512-KzXzFSXZOm7zvEt2Aw0MsB2LbTL88znAiVqTDNAOHdlEb7brgmUQh/X2wM/8Be+N0fjEqWKl65cBKNwpWEbJiw==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.1-rc': + resolution: {integrity: sha512-98R3+OqDr/r0/PLWEoXu88AE0lGVLNd335Ew8ONgzK1JWkNs4ou/5BGt3Or1ij4iXjH+c7PRL+jFjCbtWze+EA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@uwx/libav.js-fat@6.0.0-nightly.29.f420ff.ffmpeg.6.1.1': resolution: {integrity: sha512-XMUWb4CEKAKZ8ONnBT/U6jwJlH+cvbTPj9ufdQ4H+nIaRDen8tcS2PyPAh2Smrxf6MmkvUqj4kH4/groYlNjOQ==} @@ -3408,6 +3528,11 @@ packages: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} + typescript@7.0.1-rc: + resolution: {integrity: sha512-drEP77wK7CCDlPfXZH4e008UUQOsw1DFmHmZOZjuNA+yoDLLnSNMZRXi90NbV/1LVo7SbNLq1bs3jjvk49TEqQ==} + engines: {node: '>=16.20.0'} + hasBin: true + unconfig-core@7.5.0: resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} @@ -4729,6 +4854,67 @@ snapshots: '@typescript/native-preview-linux-x64': 7.0.0-dev.20260613.1 '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260613.1 '@typescript/native-preview-win32-x64': 7.0.0-dev.20260613.1 + optional: true + + '@typescript/typescript-aix-ppc64@7.0.1-rc': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.1-rc': + optional: true + + '@typescript/typescript-darwin-x64@7.0.1-rc': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.1-rc': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-arm64@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-arm@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-loong64@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-s390x@7.0.1-rc': + optional: true + + '@typescript/typescript-linux-x64@7.0.1-rc': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.1-rc': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.1-rc': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.1-rc': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.1-rc': + optional: true + + '@typescript/typescript-sunos-x64@7.0.1-rc': + optional: true + + '@typescript/typescript-win32-arm64@7.0.1-rc': + optional: true + + '@typescript/typescript-win32-x64@7.0.1-rc': + optional: true '@uwx/libav.js-fat@6.0.0-nightly.29.f420ff.ffmpeg.6.1.1': {} @@ -6000,7 +6186,7 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rolldown-plugin-dts@0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0): + rolldown-plugin-dts@0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0)(typescript@7.0.1-rc): dependencies: '@babel/generator': 8.0.0-rc.6 '@babel/helper-validator-identifier': 8.0.0-rc.6 @@ -6013,6 +6199,7 @@ snapshots: rolldown: 1.1.0 optionalDependencies: '@typescript/native-preview': 7.0.0-dev.20260613.1 + typescript: 7.0.1-rc transitivePeerDependencies: - oxc-resolver @@ -6339,7 +6526,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(unrun@0.2.37): + tsdown@0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(typescript@7.0.1-rc)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -6350,7 +6537,7 @@ snapshots: obug: 2.1.1 picomatch: 4.0.4 rolldown: 1.1.0 - rolldown-plugin-dts: 0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0) + rolldown-plugin-dts: 0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0)(typescript@7.0.1-rc) semver: 7.8.1 tinyexec: 1.2.4 tinyglobby: 0.2.17 @@ -6358,6 +6545,7 @@ snapshots: unconfig-core: 7.5.0 optionalDependencies: tsx: 4.22.4 + typescript: 7.0.1-rc unrun: 0.2.37 transitivePeerDependencies: - '@ts-macro/tsc' @@ -6382,6 +6570,29 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.15 + typescript@7.0.1-rc: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.1-rc + '@typescript/typescript-darwin-arm64': 7.0.1-rc + '@typescript/typescript-darwin-x64': 7.0.1-rc + '@typescript/typescript-freebsd-arm64': 7.0.1-rc + '@typescript/typescript-freebsd-x64': 7.0.1-rc + '@typescript/typescript-linux-arm': 7.0.1-rc + '@typescript/typescript-linux-arm64': 7.0.1-rc + '@typescript/typescript-linux-loong64': 7.0.1-rc + '@typescript/typescript-linux-mips64el': 7.0.1-rc + '@typescript/typescript-linux-ppc64': 7.0.1-rc + '@typescript/typescript-linux-riscv64': 7.0.1-rc + '@typescript/typescript-linux-s390x': 7.0.1-rc + '@typescript/typescript-linux-x64': 7.0.1-rc + '@typescript/typescript-netbsd-arm64': 7.0.1-rc + '@typescript/typescript-netbsd-x64': 7.0.1-rc + '@typescript/typescript-openbsd-arm64': 7.0.1-rc + '@typescript/typescript-openbsd-x64': 7.0.1-rc + '@typescript/typescript-sunos-x64': 7.0.1-rc + '@typescript/typescript-win32-arm64': 7.0.1-rc + '@typescript/typescript-win32-x64': 7.0.1-rc + unconfig-core@7.5.0: dependencies: '@quansync/fs': 1.0.0 From 8aa5985478bd5962291618b645b2dbcfcec25961 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 02:32:09 +0000 Subject: [PATCH 04/39] chore(deps): bump actions/checkout from 6 to 7 Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/release.yml | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58fba925..135591a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 @@ -84,7 +84,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Setup pnpm uses: pnpm/action-setup@v6 @@ -122,7 +122,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.event.pull_request.head.sha }} @@ -183,7 +183,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} @@ -284,7 +284,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.event.pull_request.head.sha }} @@ -386,7 +386,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.sha }} @@ -446,7 +446,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 ref: ${{ github.sha }} @@ -550,7 +550,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.sha }} @@ -652,7 +652,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Setup pnpm uses: pnpm/action-setup@v6 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d8cea77..255c1dfe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,7 +45,7 @@ jobs: steps: - name: Checkout workflow sources - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.sha }} fetch-depth: 0 @@ -110,7 +110,7 @@ jobs: steps: - name: Checkout release target - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ needs.prepare.outputs.release_target }} @@ -295,7 +295,7 @@ jobs: steps: - name: Checkout workflow sources - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.sha }} From ba8ad0cff6302efde1caf5d9128c7fbcd16a1727 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 02:33:38 +0000 Subject: [PATCH 05/39] chore(deps-dev): bump oxlint from 1.69.0 to 1.70.0 Bumps [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) from 1.69.0 to 1.70.0. - [Release notes](https://github.com/oxc-project/oxc/releases) - [Changelog](https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md) - [Commits](https://github.com/oxc-project/oxc/commits/oxlint_v1.70.0/npm/oxlint) --- updated-dependencies: - dependency-name: oxlint dependency-version: 1.70.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 162 ++++++++++++++++++++++++------------------------- 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/package.json b/package.json index 674c0720..aecbdca7 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@types/node": "^25.9.1", "@vitest/coverage-v8": "^4.0.18", "oxfmt": "^0.54.0", - "oxlint": "^1.69.0", + "oxlint": "^1.70.0", "rimraf": "^6.0.1", "tinybench": "^6.0.2", "tsdown": "^0.22.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7aec492d..65123e88 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^0.54.0 version: 0.54.0 oxlint: - specifier: ^1.69.0 - version: 1.69.0 + specifier: ^1.70.0 + version: 1.70.0 rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -1299,124 +1299,124 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.69.0': - resolution: {integrity: sha512-DKQQbD5cZ/MYfDgDI7YGyGD9FSxABlsBsYFo5p26lloob543tP9+4N3guwdXIYJN+7HSZxLe8YJuwcOWw5qnHg==} + '@oxlint/binding-android-arm-eabi@1.70.0': + resolution: {integrity: sha512-zFh0P4cswmRvw6nkyb89dr18rRanuaCPAsEXsFDoQY8WdaquI8Pt4NWFjaMJg6L23cy5NeN8J9cBnREbWzZhaw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.69.0': - resolution: {integrity: sha512-lEhb+I5pr4inux+JFwfCa1HRq3Os7NirEFQ0H1I35SVEHPm6byX0Ah47xmRha3qi6LAkxUcxViL8o/9PivjzBg==} + '@oxlint/binding-android-arm64@1.70.0': + resolution: {integrity: sha512-qI8o4HZjeGiBrWv+pJv4lH0Yi2Gl/JSp/EumBUApezJprIKa5PS4nU0lQsQngtky8k+SplQIOjv6hwu0SSxeyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.69.0': - resolution: {integrity: sha512-GY2YE8lOZW59BW1Ia1y+1gR0XyjrZRvVWHAr8LGeGhYHE0OQJ/7cRKXTkx1P+E9/6awEc3SX8a68SFTjh/E//A==} + '@oxlint/binding-darwin-arm64@1.70.0': + resolution: {integrity: sha512-8KjgVVHI5F9nVwHCRwwA78Ty7zNKP4Wd9OeN5PSv3iu/F/u1RVXoOCgLhWqust6HmwQG6xc8c+RCyaWENy24+w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.69.0': - resolution: {integrity: sha512-ax1oZnOjHX3LB7myQyHEaQkDwfLb6str3/nSP6O7EVUviQGNkEGzGV0EqcBJWK+Ufwx0l4xPgyYayurvhAdl2Q==} + '@oxlint/binding-darwin-x64@1.70.0': + resolution: {integrity: sha512-WVydssv5PSUBXFJTdNBWlmGkbNmvPGaFt/2SUT/EZRB6bq6bEOHmMlbnupZD5jmlEvi9+mZJHi8TCw15lyfSfQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.69.0': - resolution: {integrity: sha512-kHWeHv4g2h8NY+mpCxzCtY4uerMJWTN/TSnNj1CPbakFpHEJ6cTya2wWV0pDSYWOJ2+0UiEbhn3AtXxHtsnKjg==} + '@oxlint/binding-freebsd-x64@1.70.0': + resolution: {integrity: sha512-hJucmUf8OlinHNb1R7fI4Fw6WsAstOz7i8nmkWQfiHoZXtbufNm+MxiDTIMk1ggh2Ro4vLzgQ+bKvRY54MZoRA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.69.0': - resolution: {integrity: sha512-gq84vM1a1oEehXo27YCDzGVcxPsZDI1yswZwz2Da1/cbnWtrL16XZZnz0G/+gIU8edtHpfjxq5c+vWEHqJfWoQ==} + '@oxlint/binding-linux-arm-gnueabihf@1.70.0': + resolution: {integrity: sha512-1BnS7wbCYDSXwWzJJ+mc3NURoha6m6m6RT5c6vgAY3oz7C3OVXP+S0awo2mRq97arrJkVvO3qRQfyAHL+76xtQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.69.0': - resolution: {integrity: sha512-kIqEa98JQ0VRyrcncxA417m2AzasqTlD+FyVT1AksjvjkqQcvm7pBWYvoW3/mpyOP2XYvi5nSCCTIe6De1yu5g==} + '@oxlint/binding-linux-arm-musleabihf@1.70.0': + resolution: {integrity: sha512-yKy/UdbR55+M2yEcuiV5DCNC/gdQAjr/GioUy50QwBzSrKm8ueWADqyRLS9Xk+qjNeCYGg6A8FvUBds56ttfqg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.69.0': - resolution: {integrity: sha512-j+xYiXozxGWx2cpjCrwwGR4awTxPFsRv3JZrv23RCogEPMc4R7UqjHW47p/RG0aRlbWiROCJ8coUfCwy0dvzHA==} + '@oxlint/binding-linux-arm64-gnu@1.70.0': + resolution: {integrity: sha512-0A5XJ4alvmqFUFP/4oYSyaO+qLto/HrKEWTSaegiVl+HOufFngK2BjYw9x4RbwBt/du5QG6l5q1zeWiJYYG5yg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.69.0': - resolution: {integrity: sha512-xEPpNppTfN1l/nM7gYSf9iocscu/as+p/7vxkLeLEKnYU+09Dm+5V6IhDYDh+Uz6FajEupWwCLt5SOG0y1PCKg==} + '@oxlint/binding-linux-arm64-musl@1.70.0': + resolution: {integrity: sha512-JiylyurlB0CLSedNtx1gzv3FvfWPF1h/2Y3BJszPLNt5XQFlBsH5ke0Jle3iJb3uqu5m2e7A/DwzpuCAHdiU+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.69.0': - resolution: {integrity: sha512-Ug0+eU7HJBlek+SjklYH62IlOMirEJsdxpihH0kSqX0XdrDD4NdHpQc10fK1JC35yn6KrrcN+uYzlHD38XAf8Q==} + '@oxlint/binding-linux-ppc64-gnu@1.70.0': + resolution: {integrity: sha512-J8VPG7I3/HmgaU4u8pNU2kFx2+0U+vPLS1dXFxXOaR/2TQ0f8AC7DRz0SRGRI1bfphnX2hVYTTtLuhL4nYKL+Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.69.0': - resolution: {integrity: sha512-iEyI3GIg0l/s3G4qy2TlaaWKdzj4PJJStwtlocpDTC00PY9hZueotf6OKUj9+yfQh0lrpBW/pLMgTztbAHKJEg==} + '@oxlint/binding-linux-riscv64-gnu@1.70.0': + resolution: {integrity: sha512-N2+4lV2KLN+oXTIIIwmWDhwkrnvqf5oX7Hw0zPjk+RuIVgiBQSOlJWF7uQoFx2siEYX0ZQ5cfSbEAHm+J3t7Wg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.69.0': - resolution: {integrity: sha512-NjHjpiI4WIKSMwuoJSZi5VToPeoYOS1FR52HLIDG6lidMdqquusgtODb4iLk0+lb1q3Z0nv2/aPRcC/olmpQGg==} + '@oxlint/binding-linux-riscv64-musl@1.70.0': + resolution: {integrity: sha512-1e2L7cFCvx9QDzq6NPP+0tABKb5z6nWHyddWTNKprEsjO9xNrAtPowuCGpjNXxkTdsMiZ4jc8YQ5SstZd4XK6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.69.0': - resolution: {integrity: sha512-Ai/prDewoItkDXbp38gwGZi41DycZbUTZJ3UidwoHgQC0/DaqC2TGdtBTQLJ6hSD+SAxASzh8+/eSBPmxfOacA==} + '@oxlint/binding-linux-s390x-gnu@1.70.0': + resolution: {integrity: sha512-Kwu/l/8GcYibCWA9m9N5pRXMIKVSsL/YbgpLzYkqDhWTiqdRfnNJ/+nqIKRKQiFbHWsdlHEhzMwruJK+qcEruA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.69.0': - resolution: {integrity: sha512-Gt3KHgp46mRKz4sJeaASmKvD8ayXookRw07RMf+NowhEztGGDZ7VrXpoW96XuKJLjFukWizOFVNjmYb/u7caNQ==} + '@oxlint/binding-linux-x64-gnu@1.70.0': + resolution: {integrity: sha512-tap04CsHYOl0nSAQJfPNIuBxqEPB2HnhQqwaOXLg1jnp2XfRo8Fa814dA4QC4zpvTWXCjAAaCY1W5LOORkEQuQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.69.0': - resolution: {integrity: sha512-7tQhJ2+p/oHv1zcfnjYI7YVzC/7iBaVOfIvFYtxdJ5F45mWgEdrCyXZXZGfiLey5t/5JhOhsaMnnv1kAzckd7g==} + '@oxlint/binding-linux-x64-musl@1.70.0': + resolution: {integrity: sha512-hzJa/WgvtJpbBD9rgfy0qe+MjbxOXNUT0bfR1S6EQQzfTtBFA9xg5q8KSwRrQ2QfSS+TaP4j+4mVPQrfNc6UNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.69.0': - resolution: {integrity: sha512-vmWz6TKp/3hfA4lksR0zHBv/6xuX1jhym6eqOjdH2DXsDDHZWcp2f0KG0VCAnlVbIrjk29G4wAWMXb/Hn1YobA==} + '@oxlint/binding-openharmony-arm64@1.70.0': + resolution: {integrity: sha512-xbsaNSNzVSnaJACCUYr1HQMyY/Q/Q1LkePmHG3UvZPvGCYGNxrsZp9OmtA6ick8xH47ltRRbRrPCM1YXYcyC+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.69.0': - resolution: {integrity: sha512-9RExaLgmaw6IoIkU9cTpT71mLfI0xZ86iZH8x518LVsOkjquJMYqb9P7KpC8lgd1t0Dxs41p2pxynq4XR3Ttzw==} + '@oxlint/binding-win32-arm64-msvc@1.70.0': + resolution: {integrity: sha512-icAEsUI7JbW1TMRdEXV83mVAInhRVQYuuAlPpxdGwJ95chNdnCzjloRW8GglT0WvzOEZSio6fnYSk2DJ2Hv7LQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.69.0': - resolution: {integrity: sha512-1907kRPF8/PrcIw1E7LMs9JbVrpgnt/MvFdss3an8oDkYNAACXzTntV3t3869ZZhMZxb2AzRGbz1pA/jdFatXA==} + '@oxlint/binding-win32-ia32-msvc@1.70.0': + resolution: {integrity: sha512-FHMSWbVsPVs/f+Jcl04ws4JJ2wUnauyTzlpxWRG/lSO/8GpX08Fo2gQZqdA6CrRFI+zvkxl+N/KwJGWfUwYVZA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.69.0': - resolution: {integrity: sha512-w8SOXv3mT9Fi6jY8OXdXCfnvX/3KNLXGNr4HEz2TA7S4Mv/PYAOmpB8y/ge40mxvBMgGNaSaaDwZpAsQn7HtWA==} + '@oxlint/binding-win32-x64-msvc@1.70.0': + resolution: {integrity: sha512-ptOlKwCz7n4AKs5VweMqG6DAg677FmKOK+vBkkL9DMNgFATIQ+upqUYBTOEwRQyRAx1ncGlPlXleV2hIcm3z4g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3002,8 +3002,8 @@ packages: vite-plus: optional: true - oxlint@1.69.0: - resolution: {integrity: sha512-ypZkK/aDc5NQV8zIR6s2H2Tl3aNW8FmJ1m9+2qsaYuRenl8vgnHNCGwTHviWJdUQzglOlHFchgopdtGhSy17Rw==} + oxlint@1.70.0: + resolution: {integrity: sha512-D6JgHtzkhRwvEC+A0Nw5AEc5bk8x5i1pHzvZIEf/a0C4hOzmAACNGtkDGPyFaxxX3ZVGxCPeig3P3rMM8XU3/g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4468,61 +4468,61 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.54.0': optional: true - '@oxlint/binding-android-arm-eabi@1.69.0': + '@oxlint/binding-android-arm-eabi@1.70.0': optional: true - '@oxlint/binding-android-arm64@1.69.0': + '@oxlint/binding-android-arm64@1.70.0': optional: true - '@oxlint/binding-darwin-arm64@1.69.0': + '@oxlint/binding-darwin-arm64@1.70.0': optional: true - '@oxlint/binding-darwin-x64@1.69.0': + '@oxlint/binding-darwin-x64@1.70.0': optional: true - '@oxlint/binding-freebsd-x64@1.69.0': + '@oxlint/binding-freebsd-x64@1.70.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.69.0': + '@oxlint/binding-linux-arm-gnueabihf@1.70.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.69.0': + '@oxlint/binding-linux-arm-musleabihf@1.70.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.69.0': + '@oxlint/binding-linux-arm64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.69.0': + '@oxlint/binding-linux-arm64-musl@1.70.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.69.0': + '@oxlint/binding-linux-ppc64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.69.0': + '@oxlint/binding-linux-riscv64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.69.0': + '@oxlint/binding-linux-riscv64-musl@1.70.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.69.0': + '@oxlint/binding-linux-s390x-gnu@1.70.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.69.0': + '@oxlint/binding-linux-x64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-x64-musl@1.69.0': + '@oxlint/binding-linux-x64-musl@1.70.0': optional: true - '@oxlint/binding-openharmony-arm64@1.69.0': + '@oxlint/binding-openharmony-arm64@1.70.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.69.0': + '@oxlint/binding-win32-arm64-msvc@1.70.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.69.0': + '@oxlint/binding-win32-ia32-msvc@1.70.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.69.0': + '@oxlint/binding-win32-x64-msvc@1.70.0': optional: true '@pinojs/redact@0.4.0': {} @@ -5947,27 +5947,27 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.54.0 '@oxfmt/binding-win32-x64-msvc': 0.54.0 - oxlint@1.69.0: + oxlint@1.70.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.69.0 - '@oxlint/binding-android-arm64': 1.69.0 - '@oxlint/binding-darwin-arm64': 1.69.0 - '@oxlint/binding-darwin-x64': 1.69.0 - '@oxlint/binding-freebsd-x64': 1.69.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.69.0 - '@oxlint/binding-linux-arm-musleabihf': 1.69.0 - '@oxlint/binding-linux-arm64-gnu': 1.69.0 - '@oxlint/binding-linux-arm64-musl': 1.69.0 - '@oxlint/binding-linux-ppc64-gnu': 1.69.0 - '@oxlint/binding-linux-riscv64-gnu': 1.69.0 - '@oxlint/binding-linux-riscv64-musl': 1.69.0 - '@oxlint/binding-linux-s390x-gnu': 1.69.0 - '@oxlint/binding-linux-x64-gnu': 1.69.0 - '@oxlint/binding-linux-x64-musl': 1.69.0 - '@oxlint/binding-openharmony-arm64': 1.69.0 - '@oxlint/binding-win32-arm64-msvc': 1.69.0 - '@oxlint/binding-win32-ia32-msvc': 1.69.0 - '@oxlint/binding-win32-x64-msvc': 1.69.0 + '@oxlint/binding-android-arm-eabi': 1.70.0 + '@oxlint/binding-android-arm64': 1.70.0 + '@oxlint/binding-darwin-arm64': 1.70.0 + '@oxlint/binding-darwin-x64': 1.70.0 + '@oxlint/binding-freebsd-x64': 1.70.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.70.0 + '@oxlint/binding-linux-arm-musleabihf': 1.70.0 + '@oxlint/binding-linux-arm64-gnu': 1.70.0 + '@oxlint/binding-linux-arm64-musl': 1.70.0 + '@oxlint/binding-linux-ppc64-gnu': 1.70.0 + '@oxlint/binding-linux-riscv64-gnu': 1.70.0 + '@oxlint/binding-linux-riscv64-musl': 1.70.0 + '@oxlint/binding-linux-s390x-gnu': 1.70.0 + '@oxlint/binding-linux-x64-gnu': 1.70.0 + '@oxlint/binding-linux-x64-musl': 1.70.0 + '@oxlint/binding-openharmony-arm64': 1.70.0 + '@oxlint/binding-win32-arm64-msvc': 1.70.0 + '@oxlint/binding-win32-ia32-msvc': 1.70.0 + '@oxlint/binding-win32-x64-msvc': 1.70.0 p-filter@2.1.0: dependencies: From 3394f1453b17032cc6ee0115c26a708f0f5927ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 02:35:00 +0000 Subject: [PATCH 06/39] chore(deps-dev): bump wrangler from 4.100.0 to 4.103.0 Bumps [wrangler](https://github.com/cloudflare/workers-sdk/tree/HEAD/packages/wrangler) from 4.100.0 to 4.103.0. - [Release notes](https://github.com/cloudflare/workers-sdk/releases) - [Commits](https://github.com/cloudflare/workers-sdk/commits/wrangler@4.103.0/packages/wrangler) --- updated-dependencies: - dependency-name: wrangler dependency-version: 4.103.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/player-web-demo/package.json | 2 +- pnpm-lock.yaml | 436 +++++++++++++------------- 2 files changed, 219 insertions(+), 219 deletions(-) diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index 2cf65a7d..d313766b 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -29,6 +29,6 @@ "ts-ebml": "^3.0.2", "vite": "^8.0.16", "vite-plugin-node-polyfills": "^0.28.0", - "wrangler": "^4.100.0" + "wrangler": "^4.103.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7aec492d..a7a31505 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: 7.0.1-rc vite: specifier: ^8.0.16 - version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4) + version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4) vitest: specifier: ^4.0.18 version: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4) @@ -272,13 +272,13 @@ importers: version: 3.0.2 vite: specifier: ^8.0.16 - version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4) + version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4) vite-plugin-node-polyfills: specifier: ^0.28.0 - version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4)) + version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4)) wrangler: - specifier: ^4.100.0 - version: 4.100.0(@cloudflare/workers-types@4.20260613.1) + specifier: ^4.103.0 + version: 4.103.0(@cloudflare/workers-types@4.20260613.1) packages/stringifier: dependencies: @@ -420,32 +420,32 @@ packages: workerd: optional: true - '@cloudflare/workerd-darwin-64@1.20260611.1': - resolution: {integrity: sha512-iJICldmi4sBGgi7IrQles8cStOGXM/Tmv95C4OODVs6VIbMsJPqThUM5h3uYVQNULuJ8I/aVvnJ3Eh/wZCKwuA==} + '@cloudflare/workerd-darwin-64@1.20260617.1': + resolution: {integrity: sha512-jWwmgEVVWbsHNrLSNXzwjJaH90VzRxq1cWkQFUidxyeUPnMxemeNE8I9qFAfrpzGgE11e9sKDcE3ettJW08swQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20260611.1': - resolution: {integrity: sha512-yBbVXvbZyltR3I7NJdC4C4ItkItjZSiabcA/3HzEWOUQjLVKFqRh4so6ToHr70VCYh8VGeR8EDZL23igLhXqFQ==} + '@cloudflare/workerd-darwin-arm64@1.20260617.1': + resolution: {integrity: sha512-LHH7b565g9znfCUOkwbec6FG2rmRbsgCy6aJiU9KN662mNheWl5sw/iKleiFSiljPKQQP3HkjnC/NSkdgi/aSA==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20260611.1': - resolution: {integrity: sha512-PfNjpxOlaIgZFYuhD7+neEEewCN2Ud993wEEN0fmbtSOax1AK53LGqmXUDvFhnbkHxJLFAxYCSNISW8QbzaAIg==} + '@cloudflare/workerd-linux-64@1.20260617.1': + resolution: {integrity: sha512-FMnaAKXe4Cfd8TQurCVd9fs2XQVBFRCsP+Id/SRdUv89MlwYu9zXfoyx6BxM+brPTIUK38SHbo8iaxiwzLi9JQ==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20260611.1': - resolution: {integrity: sha512-GEp4XbuIKjlF8pakqXcUDJfKiJosD/Q7S83J0d+r+z9XIlYGfF3ntm08e2aiF5TFTwp3fnG4yMoPUAKNhNJpvQ==} + '@cloudflare/workerd-linux-arm64@1.20260617.1': + resolution: {integrity: sha512-MRoifFYcqbxxIIQy7PqO5tFY/qPFSnjXzakWl0sO93l+HLyG35jRAgOi6jfqa4kBxc7gKKtH861DcewjxUfkjA==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20260611.1': - resolution: {integrity: sha512-S6JkS0kEbcCKs19RGqEPhjCRbP8GBkQwqYLp2fhBJtD/KTlwqLzOJ9E6PQ7gQKgWHtxy1NBG3oXarlNFRNU/dw==} + '@cloudflare/workerd-windows-64@1.20260617.1': + resolution: {integrity: sha512-rgBV9wQrv0OSKgCTTbhFUFY3sLGNANZ88aqaLvtmEn2gmbFVb1J4PDGochVUdB7NSEp4D/ghHva6/8SZmbONpw==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -463,18 +463,12 @@ packages: '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/runtime@1.11.0': - resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.7': resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} @@ -487,11 +481,11 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} - cpu: [arm64] - os: [android] + cpu: [ppc64] + os: [aix] '@esbuild/android-arm64@0.27.7': resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} @@ -505,10 +499,10 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} - cpu: [arm] + cpu: [arm64] os: [android] '@esbuild/android-arm@0.27.7': @@ -523,10 +517,10 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} - cpu: [x64] + cpu: [arm] os: [android] '@esbuild/android-x64@0.27.7': @@ -541,11 +535,11 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] + cpu: [x64] + os: [android] '@esbuild/darwin-arm64@0.27.7': resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} @@ -559,10 +553,10 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} - cpu: [x64] + cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.27.7': @@ -577,11 +571,11 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] + cpu: [x64] + os: [darwin] '@esbuild/freebsd-arm64@0.27.7': resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} @@ -595,10 +589,10 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} - cpu: [x64] + cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.27.7': @@ -613,11 +607,11 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} - cpu: [arm64] - os: [linux] + cpu: [x64] + os: [freebsd] '@esbuild/linux-arm64@0.27.7': resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} @@ -631,10 +625,10 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} - cpu: [arm] + cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.27.7': @@ -649,10 +643,10 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} - cpu: [ia32] + cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.27.7': @@ -667,10 +661,10 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} - cpu: [loong64] + cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.27.7': @@ -685,10 +679,10 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} - cpu: [mips64el] + cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.27.7': @@ -703,10 +697,10 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} - cpu: [ppc64] + cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.27.7': @@ -721,10 +715,10 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} - cpu: [riscv64] + cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.27.7': @@ -739,10 +733,10 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} - cpu: [s390x] + cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.27.7': @@ -757,10 +751,10 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} - cpu: [x64] + cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.27.7': @@ -775,11 +769,11 @@ packages: cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] + cpu: [x64] + os: [linux] '@esbuild/netbsd-arm64@0.27.7': resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} @@ -793,10 +787,10 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} - cpu: [x64] + cpu: [arm64] os: [netbsd] '@esbuild/netbsd-x64@0.27.7': @@ -811,11 +805,11 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] + cpu: [x64] + os: [netbsd] '@esbuild/openbsd-arm64@0.27.7': resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} @@ -829,10 +823,10 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} - cpu: [x64] + cpu: [arm64] os: [openbsd] '@esbuild/openbsd-x64@0.27.7': @@ -847,11 +841,11 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] + cpu: [x64] + os: [openbsd] '@esbuild/openharmony-arm64@0.27.7': resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} @@ -865,11 +859,11 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} - cpu: [x64] - os: [sunos] + cpu: [arm64] + os: [openharmony] '@esbuild/sunos-x64@0.27.7': resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} @@ -883,11 +877,11 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} - cpu: [arm64] - os: [win32] + cpu: [x64] + os: [sunos] '@esbuild/win32-arm64@0.27.7': resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} @@ -901,10 +895,10 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} - cpu: [ia32] + cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.27.7': @@ -919,10 +913,10 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} - cpu: [x64] + cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.27.7': @@ -937,6 +931,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eshaz/web-worker@1.2.2': resolution: {integrity: sha512-WxXiHFmD9u/owrzempiDlBB1ZYqiLnm9s6aPc8AlFQalq2tKmqdmMr9GXOupDgzXtqnBipj8Un0gkIm7Sjf8mw==} @@ -1890,8 +1890,8 @@ packages: resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} engines: {node: '>=18'} - '@speed-highlight/core@1.2.16': - resolution: {integrity: sha512-yNm/fYEcnpRjYduLMaddTK9XKYil6xB88+qFg79ZdZhHu1PadfoQmFW7pVTx7FZqMBNcUuThiAhxhENgtAO2/w==} + '@speed-highlight/core@1.2.17': + resolution: {integrity: sha512-Z92FwKpCtfaW1V0jTU/fh3QzYEZN8wDwrzRIBoADCJfn4mJCNcJN/XegifX7BDrQ8/h9Xh/JnbyMchL0FqXrkg==} '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -2440,11 +2440,6 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} @@ -2455,6 +2450,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -2899,8 +2899,8 @@ packages: resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} hasBin: true - miniflare@4.20260611.0: - resolution: {integrity: sha512-i+JwEo8vN96naz1WL3ntFgFyRluBDYL408zwhHKvR2jefJ464KsZ/gCmJAQ5k+oaWeb5Ug+s7yne5AyiAEswjg==} + miniflare@4.20260617.1: + resolution: {integrity: sha512-Go3/gzStm99QHptsSgU+q1S+xDfLoRgwjJNY80kaTVi0ENhTyqKq+sc4xZiWBSbM7uUcJwmzm8+QFKtcYLJ9nw==} engines: {node: '>=22.0.0'} hasBin: true @@ -3295,8 +3295,8 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.8.4: - resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true @@ -3539,8 +3539,8 @@ packages: undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - undici@7.24.8: - resolution: {integrity: sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==} + undici@7.28.0: + resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} engines: {node: '>=20.18.1'} unenv@2.0.0-rc.24: @@ -3717,23 +3717,23 @@ packages: engines: {node: '>=8'} hasBin: true - workerd@1.20260611.1: - resolution: {integrity: sha512-CS/640T7pIJ2HYX6x2DwKFGbcSckAWN3tgcdq+ptB6SaqjWUhlzIgA/YhPuwIU+/NnMnGpqOFX/hC18Oyge63w==} + workerd@1.20260617.1: + resolution: {integrity: sha512-Re5pl6pdowt3ZmWUzGlOuB7jbRIIPetgKalmo4cYmucQnVhpo7/3e4MfpekbhLi2EhZZz5EY9NWRu8zFzuEZew==} engines: {node: '>=16'} hasBin: true - wrangler@4.100.0: - resolution: {integrity: sha512-dSQO7DO+mD6XDzkVWIWBoGLO3yw+lacWSc/KhFvd7pgfpth+kX98qb5SGRHZN8ACCDhhfwzDLXwB6qHsIHhfBg==} + wrangler@4.103.0: + resolution: {integrity: sha512-3Lv1P5t2xcSEkSTKtG+Lz+3JFryuU7YPLkaCUj7gNe+CJsjZJLtUwqsh1x595QBxkIbCE0GAvDx2DCJUU4+oqw==} engines: {node: '>=22.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20260611.1 + '@cloudflare/workers-types': ^4.20260617.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true - ws@8.20.1: - resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -3944,25 +3944,25 @@ snapshots: '@cloudflare/kv-asset-handler@0.5.0': {} - '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260611.1)': + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260617.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20260611.1 + workerd: 1.20260617.1 - '@cloudflare/workerd-darwin-64@1.20260611.1': + '@cloudflare/workerd-darwin-64@1.20260617.1': optional: true - '@cloudflare/workerd-darwin-arm64@1.20260611.1': + '@cloudflare/workerd-darwin-arm64@1.20260617.1': optional: true - '@cloudflare/workerd-linux-64@1.20260611.1': + '@cloudflare/workerd-linux-64@1.20260617.1': optional: true - '@cloudflare/workerd-linux-arm64@1.20260611.1': + '@cloudflare/workerd-linux-arm64@1.20260617.1': optional: true - '@cloudflare/workerd-windows-64@1.20260611.1': + '@cloudflare/workerd-windows-64@1.20260617.1': optional: true '@cloudflare/workers-types@4.20260613.1': {} @@ -3982,7 +3982,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.11.0': + '@emnapi/runtime@1.11.1': dependencies: tslib: 2.8.1 optional: true @@ -3992,16 +3992,13 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.27.3': - optional: true - '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/aix-ppc64@0.28.0': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/aix-ppc64@0.28.1': optional: true '@esbuild/android-arm64@0.27.7': @@ -4010,7 +4007,7 @@ snapshots: '@esbuild/android-arm64@0.28.0': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/android-arm64@0.28.1': optional: true '@esbuild/android-arm@0.27.7': @@ -4019,7 +4016,7 @@ snapshots: '@esbuild/android-arm@0.28.0': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/android-arm@0.28.1': optional: true '@esbuild/android-x64@0.27.7': @@ -4028,7 +4025,7 @@ snapshots: '@esbuild/android-x64@0.28.0': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/android-x64@0.28.1': optional: true '@esbuild/darwin-arm64@0.27.7': @@ -4037,7 +4034,7 @@ snapshots: '@esbuild/darwin-arm64@0.28.0': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/darwin-arm64@0.28.1': optional: true '@esbuild/darwin-x64@0.27.7': @@ -4046,7 +4043,7 @@ snapshots: '@esbuild/darwin-x64@0.28.0': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/darwin-x64@0.28.1': optional: true '@esbuild/freebsd-arm64@0.27.7': @@ -4055,7 +4052,7 @@ snapshots: '@esbuild/freebsd-arm64@0.28.0': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-arm64@0.28.1': optional: true '@esbuild/freebsd-x64@0.27.7': @@ -4064,7 +4061,7 @@ snapshots: '@esbuild/freebsd-x64@0.28.0': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/freebsd-x64@0.28.1': optional: true '@esbuild/linux-arm64@0.27.7': @@ -4073,7 +4070,7 @@ snapshots: '@esbuild/linux-arm64@0.28.0': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm64@0.28.1': optional: true '@esbuild/linux-arm@0.27.7': @@ -4082,7 +4079,7 @@ snapshots: '@esbuild/linux-arm@0.28.0': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-arm@0.28.1': optional: true '@esbuild/linux-ia32@0.27.7': @@ -4091,7 +4088,7 @@ snapshots: '@esbuild/linux-ia32@0.28.0': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-ia32@0.28.1': optional: true '@esbuild/linux-loong64@0.27.7': @@ -4100,7 +4097,7 @@ snapshots: '@esbuild/linux-loong64@0.28.0': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-loong64@0.28.1': optional: true '@esbuild/linux-mips64el@0.27.7': @@ -4109,7 +4106,7 @@ snapshots: '@esbuild/linux-mips64el@0.28.0': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-mips64el@0.28.1': optional: true '@esbuild/linux-ppc64@0.27.7': @@ -4118,7 +4115,7 @@ snapshots: '@esbuild/linux-ppc64@0.28.0': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-ppc64@0.28.1': optional: true '@esbuild/linux-riscv64@0.27.7': @@ -4127,7 +4124,7 @@ snapshots: '@esbuild/linux-riscv64@0.28.0': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-riscv64@0.28.1': optional: true '@esbuild/linux-s390x@0.27.7': @@ -4136,7 +4133,7 @@ snapshots: '@esbuild/linux-s390x@0.28.0': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-s390x@0.28.1': optional: true '@esbuild/linux-x64@0.27.7': @@ -4145,7 +4142,7 @@ snapshots: '@esbuild/linux-x64@0.28.0': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/linux-x64@0.28.1': optional: true '@esbuild/netbsd-arm64@0.27.7': @@ -4154,7 +4151,7 @@ snapshots: '@esbuild/netbsd-arm64@0.28.0': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/netbsd-arm64@0.28.1': optional: true '@esbuild/netbsd-x64@0.27.7': @@ -4163,7 +4160,7 @@ snapshots: '@esbuild/netbsd-x64@0.28.0': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/netbsd-x64@0.28.1': optional: true '@esbuild/openbsd-arm64@0.27.7': @@ -4172,7 +4169,7 @@ snapshots: '@esbuild/openbsd-arm64@0.28.0': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/openbsd-arm64@0.28.1': optional: true '@esbuild/openbsd-x64@0.27.7': @@ -4181,7 +4178,7 @@ snapshots: '@esbuild/openbsd-x64@0.28.0': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/openbsd-x64@0.28.1': optional: true '@esbuild/openharmony-arm64@0.27.7': @@ -4190,7 +4187,7 @@ snapshots: '@esbuild/openharmony-arm64@0.28.0': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/openharmony-arm64@0.28.1': optional: true '@esbuild/sunos-x64@0.27.7': @@ -4199,7 +4196,7 @@ snapshots: '@esbuild/sunos-x64@0.28.0': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/sunos-x64@0.28.1': optional: true '@esbuild/win32-arm64@0.27.7': @@ -4208,7 +4205,7 @@ snapshots: '@esbuild/win32-arm64@0.28.0': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-arm64@0.28.1': optional: true '@esbuild/win32-ia32@0.27.7': @@ -4217,7 +4214,7 @@ snapshots: '@esbuild/win32-ia32@0.28.0': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/win32-ia32@0.28.1': optional: true '@esbuild/win32-x64@0.27.7': @@ -4226,6 +4223,9 @@ snapshots: '@esbuild/win32-x64@0.28.0': optional: true + '@esbuild/win32-x64@0.28.1': + optional: true + '@eshaz/web-worker@1.2.2': {} '@ffmpeg/core-mt@0.12.10': {} @@ -4324,7 +4324,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.11.0 + '@emnapi/runtime': 1.11.1 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -4790,7 +4790,7 @@ snapshots: '@sindresorhus/is@7.2.0': {} - '@speed-highlight/core@1.2.16': {} + '@speed-highlight/core@1.2.17': {} '@standard-schema/spec@1.1.0': {} @@ -5301,35 +5301,6 @@ snapshots: dependencies: es-errors: 1.3.0 - esbuild@0.27.3: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 - esbuild@0.27.7: optionalDependencies: '@esbuild/aix-ppc64': 0.27.7 @@ -5388,6 +5359,35 @@ snapshots: '@esbuild/win32-ia32': 0.28.0 '@esbuild/win32-x64': 0.28.0 + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + esprima@4.0.1: {} estree-walker@2.0.2: {} @@ -5805,13 +5805,13 @@ snapshots: bn.js: 4.12.3 brorand: 1.1.0 - miniflare@4.20260611.0: + miniflare@4.20260617.1: dependencies: '@cspotcode/source-map-support': 0.8.1 sharp: 0.34.5 - undici: 7.24.8 - workerd: 1.20260611.1 - ws: 8.20.1 + undici: 7.28.0 + workerd: 1.20260617.1 + ws: 8.21.0 youch: 4.1.0-beta.10 transitivePeerDependencies: - bufferutil @@ -6320,7 +6320,7 @@ snapshots: semver@7.8.1: {} - semver@7.8.4: {} + semver@7.8.5: {} set-function-length@1.2.2: dependencies: @@ -6343,7 +6343,7 @@ snapshots: dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.8.4 + semver: 7.8.5 optionalDependencies: '@img/sharp-darwin-arm64': 0.34.5 '@img/sharp-darwin-x64': 0.34.5 @@ -6600,7 +6600,7 @@ snapshots: undici-types@7.24.6: {} - undici@7.24.8: {} + undici@7.28.0: {} unenv@2.0.0-rc.24: dependencies: @@ -6628,11 +6628,11 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.20 - vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4)): + vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) node-stdlib-browser: 1.3.1 - vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4) + vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4) transitivePeerDependencies: - rollup @@ -6650,7 +6650,7 @@ snapshots: lightningcss: 1.32.0 tsx: 4.22.4 - vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(tsx@4.22.4): + vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -6659,7 +6659,7 @@ snapshots: tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.9.1 - esbuild: 0.28.0 + esbuild: 0.28.1 fsevents: 2.3.3 tsx: 4.22.4 @@ -6725,24 +6725,24 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - workerd@1.20260611.1: + workerd@1.20260617.1: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20260611.1 - '@cloudflare/workerd-darwin-arm64': 1.20260611.1 - '@cloudflare/workerd-linux-64': 1.20260611.1 - '@cloudflare/workerd-linux-arm64': 1.20260611.1 - '@cloudflare/workerd-windows-64': 1.20260611.1 + '@cloudflare/workerd-darwin-64': 1.20260617.1 + '@cloudflare/workerd-darwin-arm64': 1.20260617.1 + '@cloudflare/workerd-linux-64': 1.20260617.1 + '@cloudflare/workerd-linux-arm64': 1.20260617.1 + '@cloudflare/workerd-windows-64': 1.20260617.1 - wrangler@4.100.0(@cloudflare/workers-types@4.20260613.1): + wrangler@4.103.0(@cloudflare/workers-types@4.20260613.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 - '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260611.1) + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260617.1) blake3-wasm: 2.1.5 - esbuild: 0.27.3 - miniflare: 4.20260611.0 + esbuild: 0.28.1 + miniflare: 4.20260617.1 path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 - workerd: 1.20260611.1 + workerd: 1.20260617.1 optionalDependencies: '@cloudflare/workers-types': 4.20260613.1 fsevents: 2.3.3 @@ -6750,7 +6750,7 @@ snapshots: - bufferutil - utf-8-validate - ws@8.20.1: {} + ws@8.21.0: {} xtend@4.0.2: {} @@ -6765,6 +6765,6 @@ snapshots: dependencies: '@poppinss/colors': 4.1.6 '@poppinss/dumper': 0.6.5 - '@speed-highlight/core': 1.2.16 + '@speed-highlight/core': 1.2.17 cookie: 1.1.1 youch-core: 0.3.3 From 6febb3668805136022dd82bff6d8caf895d10e59 Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Tue, 30 Jun 2026 20:35:38 +0900 Subject: [PATCH 07/39] docs: add changeset rules to AGENTS.md [ci skip] --- AGENTS.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 8e7b790e..eac0a4ff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,6 +12,20 @@ - Do not prefix pull request titles with `[codex]`. - Use plain, descriptive pull request titles. +# Changeset Rules + +- Base the unreleased set on the diff from the last release: list candidates with `git log --oneline origin/main..origin/devel`. Skip commits already covered by an existing `.changeset/*.md` and only add entries for the uncovered ones. +- One changeset per package. Putting several packages in a single markdown makes Changesets duplicate the same note into every package's CHANGELOG. For a commit that spans multiple packages, split it into one changeset per package and write each note from that package's own perspective. +- Only write entries that are worth landing in a CHANGELOG: + - Include: `fix` / `feat` / `perf`, and bumps of public (runtime `dependencies`) packages (e.g. `fflate`, `node-web-audio-api`). + - Exclude: `devDependencies` dependabot bumps (e.g. `typescript`, `oxlint`, `wrangler`, `@typescript/native-preview`), tooling-only config changes that do not affect consumers (tsconfig paths, build scripts, bench cases), and WIP / in-progress features. +- Bump level: new export / new subpath / new public API → `minor`; bug fix / internal refactor / dependency bump → `patch`. +- Writing style: + - Keep each body paragraph on a single unwrapped line. + - Put each list item on its own line. + - State what changed and why, concisely; lead with the symptom when the change fixes an observable one. +- Releasing: run `pnpm run release:version` on `devel`, commit the generated `packages/*/package.json` and `CHANGELOG.md` together as `chore: version packages`, then merge the `devel -> main` PR to publish. See README "Package Releases". + # Markdown Localization Rules - Keep English as the canonical `.md` document and Japanese as the `.ja.md` counterpart, except for `AGENTS.md` and `.changeset/README.md`, which remain English only. From ee091fa0619b5e38f7244bb9f8ec6fecbcc77ecb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 03:28:23 +0000 Subject: [PATCH 08/39] chore(deps-dev): bump oxfmt from 0.54.0 to 0.57.0 Bumps [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) from 0.54.0 to 0.57.0. - [Release notes](https://github.com/oxc-project/oxc/releases) - [Changelog](https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md) - [Commits](https://github.com/oxc-project/oxc/commits/oxfmt_v0.57.0/npm/oxfmt) --- updated-dependencies: - dependency-name: oxfmt dependency-version: 0.55.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 180 ++++++++++++++++++++++++++----------------------- 2 files changed, 95 insertions(+), 87 deletions(-) diff --git a/package.json b/package.json index aecbdca7..b1a9158b 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@changesets/cli": "^2.31.0", "@types/node": "^25.9.1", "@vitest/coverage-v8": "^4.0.18", - "oxfmt": "^0.54.0", + "oxfmt": "^0.57.0", "oxlint": "^1.70.0", "rimraf": "^6.0.1", "tinybench": "^6.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 94970c3d..f32d0c33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: ^4.0.18 version: 4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4)) oxfmt: - specifier: ^0.54.0 - version: 0.54.0 + specifier: ^0.57.0 + version: 0.57.0 oxlint: specifier: ^1.70.0 version: 1.70.0 @@ -1150,8 +1150,8 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.1.5': - resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 @@ -1177,124 +1177,124 @@ packages: '@oxc-project/types@0.134.0': resolution: {integrity: sha512-T0xuRRKrQFmocH8y+jGfpmSkGcheaJExY9lEihmR1Gm2aH+75B8CzgU2rABRQSzzDxLjZ15Sc0bRVLj5lVeNXQ==} - '@oxfmt/binding-android-arm-eabi@0.54.0': - resolution: {integrity: sha512-NAtpl/SiaeU103e7/OmZw0MvUnsUUopW7hEm/ecegJg7YM0skQaA0IXEZoyTV6NUdiNPupdIUreRqUZTShbn/g==} + '@oxfmt/binding-android-arm-eabi@0.57.0': + resolution: {integrity: sha512-qVBsEO+KugOsCmUHcO8iqNnqc65p7PCKpCs8M66mPZ+Ri+CWbcpoQOEJBg2OTu03+0qu++NK1jj6IzvQVs0Sig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.54.0': - resolution: {integrity: sha512-B4VZfBUlKK1rmMChsssNZbkZjE8+FzG3avMjGgMDwbGxXRoXkoeXiAZ+78Oa+eyDPHvDCiUb4zH/vmCOUSafLQ==} + '@oxfmt/binding-android-arm64@0.57.0': + resolution: {integrity: sha512-mp6PibWbao3aizijcheOeHQaYEhcUAt8pwLniYbtLfHxL/psFF0BykAwCj+s3c6qIpa8yN8keZICWrqtZ70w8g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.54.0': - resolution: {integrity: sha512-i02vF75b+ePsQP3tHqSxVYI5S6b8X/xqdPu7/mDHXtpgXLTYXi3jJmfHU0j+dnZZDKaYTx/ioCK7QYJmtiJR2g==} + '@oxfmt/binding-darwin-arm64@0.57.0': + resolution: {integrity: sha512-T+0stuCBqmUVY+aMIvrgXhzGhHO3sD5tNiiEcYqgSdPsnukskQqn2u5qOVD0sv1l7RLdFS5Z/f5Wi9Ktyjr3Eg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.54.0': - resolution: {integrity: sha512-8VMFvGvooXj7mswkbrhdVZ2/sgiDaBzWpkkbtO+qGDLV4EfJd67nQadHkQC0ZNbaWA9ajXfqI6i7PZLIeDzxEQ==} + '@oxfmt/binding-darwin-x64@0.57.0': + resolution: {integrity: sha512-O+3JbqWs/mCI2oi4xfhRO2IVPFJNDDEBV8Odo+ZpmsUOeKJfjXoNH7nDmBEQcDgK7NfjDIyE7kRgYSZcTLDO0A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.54.0': - resolution: {integrity: sha512-0cRHnp43WN1Jrc5s0BdbdKgR1XirdvHy7TAFi3JEsoEVQVJxTXMbpVd76sxXlgRswNMDhVFSJw+y7Eb8mEavFQ==} + '@oxfmt/binding-freebsd-x64@0.57.0': + resolution: {integrity: sha512-pxwhxVC+JkLX9twOQ/8C/vbuOQcMZyKIDmiRDZfO7yITuVcIdZCiLRqqf4QOxb2+8FWrRXzQpm+1DBKcMpHSSQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.54.0': - resolution: {integrity: sha512-JyQAk3hK/OEtup7Rw6kZwfdzbKqTVD5jXXb8Xpfay29suwZyfBDMVW/bj4RqEPySYWc6zCp198pOluf8n5uYzg==} + '@oxfmt/binding-linux-arm-gnueabihf@0.57.0': + resolution: {integrity: sha512-pxBU4zH2imB/MDBfth2rOMeVxXUMjRQLCazagwLARIFH3hVlxZJBlM4nSnHXaIHJK4/qezoFCIORN6AY8Mra4A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.54.0': - resolution: {integrity: sha512-qnvLatTpM8vtvjOfcckBOzJjk+n6ce/wwpP8OFeUrD5aNLYcKyWAitwj+Rk3PK9jGanbZvKsJnv14JGQ6XqFdw==} + '@oxfmt/binding-linux-arm-musleabihf@0.57.0': + resolution: {integrity: sha512-JAprOzt8tycYou36ZgEw14DlRHTiN8qdtKANdV3VZIRIvTI/lh/cX13c9pJ/EnDk2GT3FASH7KvCgQ2AufAifQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.54.0': - resolution: {integrity: sha512-SMkhnCzIYZYDk9vw3W/80eeYKmrMpGF0Giuxt4HruFlCH7jEtnPeb3SdQKMfgYi/dgtaf+hZAb5XWPYnxqCQ3w==} + '@oxfmt/binding-linux-arm64-gnu@0.57.0': + resolution: {integrity: sha512-ajtjaxSaj9xl4BW7REt+Cef/ttzbAq00Bq4z7JUDZEfgFXdwSjH8K9bF+IcIJzZB9lKqMfQ4eHuSFOvvlvtqOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.54.0': - resolution: {integrity: sha512-QrwJlBFFKnxOd95TAaszpMbZBLzMoYMpGaQTZF8oibacnF5rv8l12IhILhQRPmksWiBqg0YSe2Mnl7ayeJAHSA==} + '@oxfmt/binding-linux-arm64-musl@0.57.0': + resolution: {integrity: sha512-p4Y/+RYk9Bk5WO+zHSUXAClRmZ2fbJCejMuCAsU2HhyME4jqf6Ftt/mJYEwIah1wGCBDYOB7wEGV1x5bCEZ6hA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.54.0': - resolution: {integrity: sha512-WILatiol/TUHTlhod7R09+7Az/XlhKwmY1MHfLZNmewltPWNN/EwxP2rQSHahibZ/cB8gmckEBjBOByD+5bYsQ==} + '@oxfmt/binding-linux-ppc64-gnu@0.57.0': + resolution: {integrity: sha512-By6tRALAZsno0F4zedmtG+wdMvJiJmJoXM4d3+A9zHE4HRXLqXITwRH8mgrlcXc5yJM2g2W3riRPwTYdgemZLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.54.0': - resolution: {integrity: sha512-f05YMG4BH4G8S4ME6UM6fi1MnJ9094mrnvO5Pa4SJlMfWlUM+1/ZWMEF4NnjM7shZAvbHsHRuVYpUo0PHC4P9Q==} + '@oxfmt/binding-linux-riscv64-gnu@0.57.0': + resolution: {integrity: sha512-skYeG+RgvyzspqVEBsEprL90OYYZfoVNqB3HcCNR6QDJyXKOzfDRT3zncnHmUaFluIlBHuY23mU1b5WGgR98hA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.54.0': - resolution: {integrity: sha512-UfL+2hj1ClNqcCRT9s8vBU4axDpjxgVxX96G+9DYAYjoc5b0u15CJtn2jgsi9iM+EbGNc5CW1HVRgwVu76UsSA==} + '@oxfmt/binding-linux-riscv64-musl@0.57.0': + resolution: {integrity: sha512-FFgACrZOXAXUh5KQh2mt1CDOVOZmn+QzHP71wM9QobNwyQvoFfyAeefVUltW83g3sm7LTiH3yfFqLLVUpA5ZFQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.54.0': - resolution: {integrity: sha512-3/XZe931Hka+J6NjnaqJzYpsWWxDTuRdUdwSQHnOuJEgbC+SehIMFJS8hsEjV7LBhVSL2OCnRLvbVW8O97XIyw==} + '@oxfmt/binding-linux-s390x-gnu@0.57.0': + resolution: {integrity: sha512-Nm/BAOfQeFiiKd502mZn/GAVKJwtd0RdCg17G3Wz/WSOIQmDi3+7/SZH4BHn1Ye5KvTVH3ua8WvfwLLycNIuvA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.54.0': - resolution: {integrity: sha512-Ik93RlObtu43GbxApafayFjwYE06L6Xr08cSwpBPYbDrLp2ReZx0Jm1DqwRyYRnukUJy+rK2WaEvUQOxdytU9Q==} + '@oxfmt/binding-linux-x64-gnu@0.57.0': + resolution: {integrity: sha512-BiSy5Ku3mQqyxS6YIqAJgd403wEUWvI7kerfzPxc2l/txZVmZM0pSj7oDM+4bGBExowxOi7o73jEam1W0EDTZg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.54.0': - resolution: {integrity: sha512-yZcakmPlD86CNymknd7KfW+FH+qfbqJH+i0h69CYfV1+KMoVeM9UED+8+TDVoU4haxI0NxY7RPCvRLy3Sqd2Qg==} + '@oxfmt/binding-linux-x64-musl@0.57.0': + resolution: {integrity: sha512-BCRkJiotz5s9afLYD2LuMvzAoDYx9H17E/YbDyu4xK7l4zHDPeny9ErSXL//i/nJyaOwRk08x4b8cgJC00+JDg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.54.0': - resolution: {integrity: sha512-GiVBZNnEZnKu00f1jTg49nomv187d0GQX+O+ocykoLeiaALuEO+swoTehHn9TehTfi7V8H0i0e/yvUjCqnwk1w==} + '@oxfmt/binding-openharmony-arm64@0.57.0': + resolution: {integrity: sha512-4Oaxe1qrGgXfpCJ1C/ERJ2iCtV2rN1R79ga9fsfyVHfSQRu/hVW780u2KDqZWFZ/iGTHODJji0JemxqFZ63eIQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.54.0': - resolution: {integrity: sha512-J0SSB8Z1Fre2sxRolYcW6Rl1RQmKdQ2hnHyq4YJrfBRiXTObLw4DXnIVraM/UyqGqwOi7yTrQA4VT7DPxlHVKA==} + '@oxfmt/binding-win32-arm64-msvc@0.57.0': + resolution: {integrity: sha512-MYLAsDnhdNsSGheLYhWgbk0vfIrlS84iQYun/y21fX6u0jj8iBtYtbpZMdiqYeuf8U12eVPUjVY2xE2NrCfJ0g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.54.0': - resolution: {integrity: sha512-O61UDVj8zz6yXJjkHPf05VaMLOXmEF8P5kf/N0W7AQMmd6bcQogl+KJc7rMutKTL524oE9iH32JXZClBFmEQIg==} + '@oxfmt/binding-win32-ia32-msvc@0.57.0': + resolution: {integrity: sha512-PBwdzZALJY/jcCx2E6is0yu+cuVXeySTDmwuseD+9j0mHqlRNxwlKgsyRTBed/woPeqfVfuXfWjoq4Cx2Zt3Eg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.54.0': - resolution: {integrity: sha512-1MDpqJPiFqxWtIHas8vkb1VZ7f7eKyTffAwmO8isxQYMaG1OFKsH666BWLeXQLO+IWNfiMssLD55hbR1lIPTqg==} + '@oxfmt/binding-win32-x64-msvc@0.57.0': + resolution: {integrity: sha512-bQJdH9i4RRfw55jm7+8/xS7GzHLLTbHx4huhrrDxQJaJtbSDbsyOnODvP1ftT7EG0KFKAYO2S+q6AcioXODx8w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1899,6 +1899,9 @@ packages: '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -2989,8 +2992,8 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - oxfmt@0.54.0: - resolution: {integrity: sha512-DjnMwn7smSLF+Mc2+pRItnuPftm/dkUFpY/d4+33y9TfKrsHZo8GLhmUg9BrOIUEy94Rlom1Q11N6vuhE+e0oQ==} + oxfmt@0.57.0: + resolution: {integrity: sha512-ZB7Bi+rGDSqmVIo9jwcLyFgjxXvQhDdU+jx+ZrVy6VRiVXK2+CHc4hO3J4dUQjHe7V0ymHB+MDuv5z+NhK07HA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4385,11 +4388,11 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true - '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 + '@tybys/wasm-util': 0.10.3 optional: true '@nodelib/fs.scandir@2.1.5': @@ -4411,61 +4414,61 @@ snapshots: '@oxc-project/types@0.134.0': {} - '@oxfmt/binding-android-arm-eabi@0.54.0': + '@oxfmt/binding-android-arm-eabi@0.57.0': optional: true - '@oxfmt/binding-android-arm64@0.54.0': + '@oxfmt/binding-android-arm64@0.57.0': optional: true - '@oxfmt/binding-darwin-arm64@0.54.0': + '@oxfmt/binding-darwin-arm64@0.57.0': optional: true - '@oxfmt/binding-darwin-x64@0.54.0': + '@oxfmt/binding-darwin-x64@0.57.0': optional: true - '@oxfmt/binding-freebsd-x64@0.54.0': + '@oxfmt/binding-freebsd-x64@0.57.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.54.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.57.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.54.0': + '@oxfmt/binding-linux-arm-musleabihf@0.57.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.54.0': + '@oxfmt/binding-linux-arm64-gnu@0.57.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.54.0': + '@oxfmt/binding-linux-arm64-musl@0.57.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.54.0': + '@oxfmt/binding-linux-ppc64-gnu@0.57.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.54.0': + '@oxfmt/binding-linux-riscv64-gnu@0.57.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.54.0': + '@oxfmt/binding-linux-riscv64-musl@0.57.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.54.0': + '@oxfmt/binding-linux-s390x-gnu@0.57.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.54.0': + '@oxfmt/binding-linux-x64-gnu@0.57.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.54.0': + '@oxfmt/binding-linux-x64-musl@0.57.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.54.0': + '@oxfmt/binding-openharmony-arm64@0.57.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.54.0': + '@oxfmt/binding-win32-arm64-msvc@0.57.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.54.0': + '@oxfmt/binding-win32-ia32-msvc@0.57.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.54.0': + '@oxfmt/binding-win32-x64-msvc@0.57.0': optional: true '@oxlint/binding-android-arm-eabi@1.70.0': @@ -4657,7 +4660,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.0.3': @@ -4799,6 +4802,11 @@ snapshots: tslib: 2.8.1 optional: true + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -5923,29 +5931,29 @@ snapshots: outdent@0.5.0: {} - oxfmt@0.54.0: + oxfmt@0.57.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.54.0 - '@oxfmt/binding-android-arm64': 0.54.0 - '@oxfmt/binding-darwin-arm64': 0.54.0 - '@oxfmt/binding-darwin-x64': 0.54.0 - '@oxfmt/binding-freebsd-x64': 0.54.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.54.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.54.0 - '@oxfmt/binding-linux-arm64-gnu': 0.54.0 - '@oxfmt/binding-linux-arm64-musl': 0.54.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.54.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.54.0 - '@oxfmt/binding-linux-riscv64-musl': 0.54.0 - '@oxfmt/binding-linux-s390x-gnu': 0.54.0 - '@oxfmt/binding-linux-x64-gnu': 0.54.0 - '@oxfmt/binding-linux-x64-musl': 0.54.0 - '@oxfmt/binding-openharmony-arm64': 0.54.0 - '@oxfmt/binding-win32-arm64-msvc': 0.54.0 - '@oxfmt/binding-win32-ia32-msvc': 0.54.0 - '@oxfmt/binding-win32-x64-msvc': 0.54.0 + '@oxfmt/binding-android-arm-eabi': 0.57.0 + '@oxfmt/binding-android-arm64': 0.57.0 + '@oxfmt/binding-darwin-arm64': 0.57.0 + '@oxfmt/binding-darwin-x64': 0.57.0 + '@oxfmt/binding-freebsd-x64': 0.57.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.57.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.57.0 + '@oxfmt/binding-linux-arm64-gnu': 0.57.0 + '@oxfmt/binding-linux-arm64-musl': 0.57.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.57.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.57.0 + '@oxfmt/binding-linux-riscv64-musl': 0.57.0 + '@oxfmt/binding-linux-s390x-gnu': 0.57.0 + '@oxfmt/binding-linux-x64-gnu': 0.57.0 + '@oxfmt/binding-linux-x64-musl': 0.57.0 + '@oxfmt/binding-openharmony-arm64': 0.57.0 + '@oxfmt/binding-win32-arm64-msvc': 0.57.0 + '@oxfmt/binding-win32-ia32-msvc': 0.57.0 + '@oxfmt/binding-win32-x64-msvc': 0.57.0 oxlint@1.70.0: optionalDependencies: From da899ca7fd6bae4bc84df8bf6ea5c80b9078c59a Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Wed, 8 Jul 2026 02:00:06 +0900 Subject: [PATCH 09/39] fix(ci): drop per-package dependabot directories that break the pnpm lockfile --- .github/dependabot.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c4668f48..9ab871b9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,9 +1,12 @@ version: 2 updates: - package-ecosystem: "npm" - directories: - - "/" - - "/packages/*" + # The root entry covers every pnpm workspace member: Dependabot bumps + # packages/*/package.json manifests together with the shared root + # pnpm-lock.yaml. Per-package directory entries must not be added back — + # they generate manifest-only PRs that leave pnpm-lock.yaml stale and fail + # CI with ERR_PNPM_OUTDATED_LOCKFILE. + directory: "/" schedule: interval: "weekly" ignore: From 33fa443e93abd1a1d0e7ea59582b9a3849263155 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 17:03:06 +0000 Subject: [PATCH 10/39] chore(deps-dev): bump @cloudflare/workers-types Bumps [@cloudflare/workers-types](https://github.com/cloudflare/workerd) from 4.20260613.1 to 5.20260707.1. - [Release notes](https://github.com/cloudflare/workerd/releases) - [Changelog](https://github.com/cloudflare/workerd/blob/main/RELEASE.md) - [Commits](https://github.com/cloudflare/workerd/commits) --- updated-dependencies: - dependency-name: "@cloudflare/workers-types" dependency-version: 5.20260707.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- packages/player-web-demo/package.json | 2 +- pnpm-lock.yaml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index d313766b..dce23c46 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -25,7 +25,7 @@ "lil-gui": "^0.21.0" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20260613.1", + "@cloudflare/workers-types": "^5.20260707.1", "ts-ebml": "^3.0.2", "vite": "^8.0.16", "vite-plugin-node-polyfills": "^0.28.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f32d0c33..79f665ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -265,8 +265,8 @@ importers: version: 0.21.0 devDependencies: '@cloudflare/workers-types': - specifier: ^4.20260613.1 - version: 4.20260613.1 + specifier: ^5.20260707.1 + version: 5.20260707.1 ts-ebml: specifier: ^3.0.2 version: 3.0.2 @@ -278,7 +278,7 @@ importers: version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4)) wrangler: specifier: ^4.103.0 - version: 4.103.0(@cloudflare/workers-types@4.20260613.1) + version: 4.103.0(@cloudflare/workers-types@5.20260707.1) packages/stringifier: dependencies: @@ -450,8 +450,8 @@ packages: cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20260613.1': - resolution: {integrity: sha512-1mrgjE6epolwBhroeGAp5ud5H6Vyi6tl1o/NP0T4rXJ8bmEjmhHnbCzAhHTDHV0PIeip43wcuzHKJarvaGTaUA==} + '@cloudflare/workers-types@5.20260707.1': + resolution: {integrity: sha512-oTiTTaRNR4mMbuiQo2ijAYMAvjFVWn0uDDfawdT2XS4t6hSa7hNPelDV9aWv/pXuz5ew+HPCabE8TMBy7qLwGQ==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -3968,7 +3968,7 @@ snapshots: '@cloudflare/workerd-windows-64@1.20260617.1': optional: true - '@cloudflare/workers-types@4.20260613.1': {} + '@cloudflare/workers-types@5.20260707.1': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -6741,7 +6741,7 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260617.1 '@cloudflare/workerd-windows-64': 1.20260617.1 - wrangler@4.103.0(@cloudflare/workers-types@4.20260613.1): + wrangler@4.103.0(@cloudflare/workers-types@5.20260707.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260617.1) @@ -6752,7 +6752,7 @@ snapshots: unenv: 2.0.0-rc.24 workerd: 1.20260617.1 optionalDependencies: - '@cloudflare/workers-types': 4.20260613.1 + '@cloudflare/workers-types': 5.20260707.1 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil From 68dd2ee54502de83cd73a2a61c945474ffb0fa5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 17:03:20 +0000 Subject: [PATCH 11/39] chore(deps-dev): bump tsx from 4.22.4 to 4.23.0 Bumps [tsx](https://github.com/privatenumber/tsx) from 4.22.4 to 4.23.0. - [Release notes](https://github.com/privatenumber/tsx/releases) - [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs) - [Commits](https://github.com/privatenumber/tsx/compare/v4.22.4...v4.23.0) --- updated-dependencies: - dependency-name: tsx dependency-version: 4.23.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 322 +++++-------------------------------------------- 2 files changed, 28 insertions(+), 296 deletions(-) diff --git a/package.json b/package.json index b1a9158b..d8c11de1 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "rimraf": "^6.0.1", "tinybench": "^6.0.2", "tsdown": "^0.22.2", - "tsx": "^4.22.4", + "tsx": "^4.23.0", "typescript": "7.0.1-rc", "vite": "^8.0.16", "vitest": "^4.0.18" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f32d0c33..d2221451 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: version: 25.9.1 '@vitest/coverage-v8': specifier: ^4.0.18 - version: 4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4)) + version: 4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0)) oxfmt: specifier: ^0.57.0 version: 0.57.0 @@ -31,19 +31,19 @@ importers: version: 6.0.2 tsdown: specifier: ^0.22.2 - version: 0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(typescript@7.0.1-rc)(unrun@0.2.37) + version: 0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37) tsx: - specifier: ^4.22.4 - version: 4.22.4 + specifier: ^4.23.0 + version: 4.23.0 typescript: specifier: 7.0.1-rc version: 7.0.1-rc vite: specifier: ^8.0.16 - version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4) + version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) vitest: specifier: ^4.0.18 - version: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4) + version: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) packages/audio-renderer: dependencies: @@ -272,10 +272,10 @@ importers: version: 3.0.2 vite: specifier: ^8.0.16 - version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4) + version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) vite-plugin-node-polyfills: specifier: ^0.28.0 - version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4)) + version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) wrangler: specifier: ^4.103.0 version: 4.103.0(@cloudflare/workers-types@4.20260613.1) @@ -475,12 +475,6 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.28.0': - resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} @@ -493,12 +487,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.28.0': - resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.28.1': resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} @@ -511,12 +499,6 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.28.0': - resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.28.1': resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} @@ -529,12 +511,6 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.28.0': - resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.28.1': resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} @@ -547,12 +523,6 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.28.0': - resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.28.1': resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} @@ -565,12 +535,6 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.28.0': - resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.28.1': resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} @@ -583,12 +547,6 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.28.0': - resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.28.1': resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} @@ -601,12 +559,6 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.28.0': - resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.28.1': resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} @@ -619,12 +571,6 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.28.0': - resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.28.1': resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} @@ -637,12 +583,6 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.28.0': - resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.28.1': resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} @@ -655,12 +595,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.28.0': - resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.28.1': resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} @@ -673,12 +607,6 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.28.0': - resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.28.1': resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} @@ -691,12 +619,6 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.28.0': - resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.28.1': resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} @@ -709,12 +631,6 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.28.0': - resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.28.1': resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} @@ -727,12 +643,6 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.28.0': - resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.28.1': resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} @@ -745,12 +655,6 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.28.0': - resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.28.1': resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} @@ -763,12 +667,6 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.28.0': - resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.28.1': resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} @@ -781,12 +679,6 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.28.0': - resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.28.1': resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} @@ -799,12 +691,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.28.0': - resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.28.1': resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} @@ -817,12 +703,6 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.28.0': - resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.28.1': resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} @@ -835,12 +715,6 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.28.0': - resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.28.1': resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} @@ -853,12 +727,6 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.28.0': - resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.28.1': resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} @@ -871,12 +739,6 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.28.0': - resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.28.1': resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} @@ -889,12 +751,6 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.28.0': - resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.28.1': resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} @@ -907,12 +763,6 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.28.0': - resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.28.1': resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} @@ -925,12 +775,6 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.28.0': - resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.28.1': resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} @@ -2448,11 +2292,6 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.28.0: - resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} @@ -3519,8 +3358,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.22.4: - resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==} + tsx@4.23.0: + resolution: {integrity: sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==} engines: {node: '>=18.0.0'} hasBin: true @@ -3998,234 +3837,156 @@ snapshots: '@esbuild/aix-ppc64@0.27.7': optional: true - '@esbuild/aix-ppc64@0.28.0': - optional: true - '@esbuild/aix-ppc64@0.28.1': optional: true '@esbuild/android-arm64@0.27.7': optional: true - '@esbuild/android-arm64@0.28.0': - optional: true - '@esbuild/android-arm64@0.28.1': optional: true '@esbuild/android-arm@0.27.7': optional: true - '@esbuild/android-arm@0.28.0': - optional: true - '@esbuild/android-arm@0.28.1': optional: true '@esbuild/android-x64@0.27.7': optional: true - '@esbuild/android-x64@0.28.0': - optional: true - '@esbuild/android-x64@0.28.1': optional: true '@esbuild/darwin-arm64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.28.0': - optional: true - '@esbuild/darwin-arm64@0.28.1': optional: true '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/darwin-x64@0.28.0': - optional: true - '@esbuild/darwin-x64@0.28.1': optional: true '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.28.0': - optional: true - '@esbuild/freebsd-arm64@0.28.1': optional: true '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/freebsd-x64@0.28.0': - optional: true - '@esbuild/freebsd-x64@0.28.1': optional: true '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/linux-arm64@0.28.0': - optional: true - '@esbuild/linux-arm64@0.28.1': optional: true '@esbuild/linux-arm@0.27.7': optional: true - '@esbuild/linux-arm@0.28.0': - optional: true - '@esbuild/linux-arm@0.28.1': optional: true '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/linux-ia32@0.28.0': - optional: true - '@esbuild/linux-ia32@0.28.1': optional: true '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/linux-loong64@0.28.0': - optional: true - '@esbuild/linux-loong64@0.28.1': optional: true '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/linux-mips64el@0.28.0': - optional: true - '@esbuild/linux-mips64el@0.28.1': optional: true '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/linux-ppc64@0.28.0': - optional: true - '@esbuild/linux-ppc64@0.28.1': optional: true '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.28.0': - optional: true - '@esbuild/linux-riscv64@0.28.1': optional: true '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/linux-s390x@0.28.0': - optional: true - '@esbuild/linux-s390x@0.28.1': optional: true '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/linux-x64@0.28.0': - optional: true - '@esbuild/linux-x64@0.28.1': optional: true '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.28.0': - optional: true - '@esbuild/netbsd-arm64@0.28.1': optional: true '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.28.0': - optional: true - '@esbuild/netbsd-x64@0.28.1': optional: true '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/openbsd-arm64@0.28.0': - optional: true - '@esbuild/openbsd-arm64@0.28.1': optional: true '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.28.0': - optional: true - '@esbuild/openbsd-x64@0.28.1': optional: true '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/openharmony-arm64@0.28.0': - optional: true - '@esbuild/openharmony-arm64@0.28.1': optional: true '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/sunos-x64@0.28.0': - optional: true - '@esbuild/sunos-x64@0.28.1': optional: true '@esbuild/win32-arm64@0.27.7': optional: true - '@esbuild/win32-arm64@0.28.0': - optional: true - '@esbuild/win32-arm64@0.28.1': optional: true '@esbuild/win32-ia32@0.27.7': optional: true - '@esbuild/win32-ia32@0.28.0': - optional: true - '@esbuild/win32-ia32@0.28.1': optional: true '@esbuild/win32-x64@0.27.7': optional: true - '@esbuild/win32-x64@0.28.0': - optional: true - '@esbuild/win32-x64@0.28.1': optional: true @@ -4926,7 +4687,7 @@ snapshots: '@uwx/libav.js-fat@6.0.0-nightly.29.f420ff.ffmpeg.6.1.1': {} - '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4))': + '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.18 @@ -4938,7 +4699,7 @@ snapshots: obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4) + vitest: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) '@vitest/expect@4.0.18': dependencies: @@ -4949,13 +4710,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4))': + '@vitest/mocker@4.0.18(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4) + vite: 7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) '@vitest/pretty-format@4.0.18': dependencies: @@ -5338,35 +5099,6 @@ snapshots: '@esbuild/win32-ia32': 0.27.7 '@esbuild/win32-x64': 0.27.7 - esbuild@0.28.0: - optionalDependencies: - '@esbuild/aix-ppc64': 0.28.0 - '@esbuild/android-arm': 0.28.0 - '@esbuild/android-arm64': 0.28.0 - '@esbuild/android-x64': 0.28.0 - '@esbuild/darwin-arm64': 0.28.0 - '@esbuild/darwin-x64': 0.28.0 - '@esbuild/freebsd-arm64': 0.28.0 - '@esbuild/freebsd-x64': 0.28.0 - '@esbuild/linux-arm': 0.28.0 - '@esbuild/linux-arm64': 0.28.0 - '@esbuild/linux-ia32': 0.28.0 - '@esbuild/linux-loong64': 0.28.0 - '@esbuild/linux-mips64el': 0.28.0 - '@esbuild/linux-ppc64': 0.28.0 - '@esbuild/linux-riscv64': 0.28.0 - '@esbuild/linux-s390x': 0.28.0 - '@esbuild/linux-x64': 0.28.0 - '@esbuild/netbsd-arm64': 0.28.0 - '@esbuild/netbsd-x64': 0.28.0 - '@esbuild/openbsd-arm64': 0.28.0 - '@esbuild/openbsd-x64': 0.28.0 - '@esbuild/openharmony-arm64': 0.28.0 - '@esbuild/sunos-x64': 0.28.0 - '@esbuild/win32-arm64': 0.28.0 - '@esbuild/win32-ia32': 0.28.0 - '@esbuild/win32-x64': 0.28.0 - esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -6534,7 +6266,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.22.4)(typescript@7.0.1-rc)(unrun@0.2.37): + tsdown@0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -6552,7 +6284,7 @@ snapshots: tree-kill: 1.2.2 unconfig-core: 7.5.0 optionalDependencies: - tsx: 4.22.4 + tsx: 4.23.0 typescript: 7.0.1-rc unrun: 0.2.37 transitivePeerDependencies: @@ -6564,9 +6296,9 @@ snapshots: tslib@2.8.1: optional: true - tsx@4.22.4: + tsx@4.23.0: dependencies: - esbuild: 0.28.0 + esbuild: 0.28.1 optionalDependencies: fsevents: 2.3.3 @@ -6636,15 +6368,15 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.20 - vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4)): + vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) node-stdlib-browser: 1.3.1 - vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4) + vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) transitivePeerDependencies: - rollup - vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4): + vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) @@ -6656,9 +6388,9 @@ snapshots: '@types/node': 25.9.1 fsevents: 2.3.3 lightningcss: 1.32.0 - tsx: 4.22.4 + tsx: 4.23.0 - vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.22.4): + vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -6669,12 +6401,12 @@ snapshots: '@types/node': 25.9.1 esbuild: 0.28.1 fsevents: 2.3.3 - tsx: 4.22.4 + tsx: 4.23.0 - vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4): + vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4)) + '@vitest/mocker': 4.0.18(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -6691,7 +6423,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.22.4) + vite: 7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.9.1 From 0f5f996760c2fa24db1274fb3d999802225c16e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 17:03:37 +0000 Subject: [PATCH 12/39] chore(deps-dev): bump oxlint from 1.70.0 to 1.73.0 Bumps [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) from 1.70.0 to 1.73.0. - [Release notes](https://github.com/oxc-project/oxc/releases) - [Changelog](https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md) - [Commits](https://github.com/oxc-project/oxc/commits/oxlint_v1.73.0/npm/oxlint) --- updated-dependencies: - dependency-name: oxlint dependency-version: 1.73.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 164 ++++++++++++++++++++++++------------------------- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/package.json b/package.json index b1a9158b..e93da475 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@types/node": "^25.9.1", "@vitest/coverage-v8": "^4.0.18", "oxfmt": "^0.57.0", - "oxlint": "^1.70.0", + "oxlint": "^1.73.0", "rimraf": "^6.0.1", "tinybench": "^6.0.2", "tsdown": "^0.22.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f32d0c33..31418d8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^0.57.0 version: 0.57.0 oxlint: - specifier: ^1.70.0 - version: 1.70.0 + specifier: ^1.73.0 + version: 1.73.0 rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -1299,124 +1299,124 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.70.0': - resolution: {integrity: sha512-zFh0P4cswmRvw6nkyb89dr18rRanuaCPAsEXsFDoQY8WdaquI8Pt4NWFjaMJg6L23cy5NeN8J9cBnREbWzZhaw==} + '@oxlint/binding-android-arm-eabi@1.73.0': + resolution: {integrity: sha512-HZQRN/UMBu+Ut+/9MiAChkbP4qZqrNOWBcNI45vOT40GVhbGR0JgHB87L48D4iAqFQIdVmeQYtV9RF89AjTKkg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.70.0': - resolution: {integrity: sha512-qI8o4HZjeGiBrWv+pJv4lH0Yi2Gl/JSp/EumBUApezJprIKa5PS4nU0lQsQngtky8k+SplQIOjv6hwu0SSxeyg==} + '@oxlint/binding-android-arm64@1.73.0': + resolution: {integrity: sha512-Gp+KJRylv2aW7thRpG5p1KTxZq4ZJFbWowrKzufNq9d3ssl3r3JviYV45/+p+7CN1Nv0zDd1e8Ex0b/HUDq4TQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.70.0': - resolution: {integrity: sha512-8KjgVVHI5F9nVwHCRwwA78Ty7zNKP4Wd9OeN5PSv3iu/F/u1RVXoOCgLhWqust6HmwQG6xc8c+RCyaWENy24+w==} + '@oxlint/binding-darwin-arm64@1.73.0': + resolution: {integrity: sha512-3de96NdtXhxERMjIz7wsp2HYMY6pMQycGxFWac2mFecAx6VeARF/IqFb1QIaqiCRIdfzBwzTed+pCTCoiS+CYA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.70.0': - resolution: {integrity: sha512-WVydssv5PSUBXFJTdNBWlmGkbNmvPGaFt/2SUT/EZRB6bq6bEOHmMlbnupZD5jmlEvi9+mZJHi8TCw15lyfSfQ==} + '@oxlint/binding-darwin-x64@1.73.0': + resolution: {integrity: sha512-5zx/uPW32TiaOeVY1dQ/H5iOf0K1HOdFKOJhLqGl4o63+i1fpzoqqu/mKtd7OFgFjNCdhlyTGgjVkQTZm1ELcg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.70.0': - resolution: {integrity: sha512-hJucmUf8OlinHNb1R7fI4Fw6WsAstOz7i8nmkWQfiHoZXtbufNm+MxiDTIMk1ggh2Ro4vLzgQ+bKvRY54MZoRA==} + '@oxlint/binding-freebsd-x64@1.73.0': + resolution: {integrity: sha512-qNe4gKHaGnLuZJ8toUg90JAa0S2vTVvDw+0bRi3q1avXZXDT4u5mMeECf3nD4HYrbdn1O7dXqWut4onY/yx/Xg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.70.0': - resolution: {integrity: sha512-1BnS7wbCYDSXwWzJJ+mc3NURoha6m6m6RT5c6vgAY3oz7C3OVXP+S0awo2mRq97arrJkVvO3qRQfyAHL+76xtQ==} + '@oxlint/binding-linux-arm-gnueabihf@1.73.0': + resolution: {integrity: sha512-cCehYh5hTbfShm/fxTD6wwrGUWIpvX+N5OxmAMhFhDeTGXvw+BeNj889tpxsFQ9ZLatQ6wImuY8tsKLZ+FMz7w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.70.0': - resolution: {integrity: sha512-yKy/UdbR55+M2yEcuiV5DCNC/gdQAjr/GioUy50QwBzSrKm8ueWADqyRLS9Xk+qjNeCYGg6A8FvUBds56ttfqg==} + '@oxlint/binding-linux-arm-musleabihf@1.73.0': + resolution: {integrity: sha512-d5j5GDU/2dMgjVhw7TQT9ITrsIr1Y02KEXKyVGIXUkD+KiaxE9TP65FS2ZdgTBemQvoRL+gSBdbrIm3cQIeacg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.70.0': - resolution: {integrity: sha512-0A5XJ4alvmqFUFP/4oYSyaO+qLto/HrKEWTSaegiVl+HOufFngK2BjYw9x4RbwBt/du5QG6l5q1zeWiJYYG5yg==} + '@oxlint/binding-linux-arm64-gnu@1.73.0': + resolution: {integrity: sha512-Eyf1SrP3+yR1DI3OJgOY2Pvrr9dWP9TK37xPaDYycwTtlGlI45erJAVIfH5/m/xosDt6BupJYEFi47bvbTuuyw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.70.0': - resolution: {integrity: sha512-JiylyurlB0CLSedNtx1gzv3FvfWPF1h/2Y3BJszPLNt5XQFlBsH5ke0Jle3iJb3uqu5m2e7A/DwzpuCAHdiU+A==} + '@oxlint/binding-linux-arm64-musl@1.73.0': + resolution: {integrity: sha512-IlT/OJApEDKaMmCooHuncgJZbbCe7T5QIWmTZBEtYscWvzPQuuEinVcid6kwQRVQOUdb7PUCz4jQHnaYXdfJXw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.70.0': - resolution: {integrity: sha512-J8VPG7I3/HmgaU4u8pNU2kFx2+0U+vPLS1dXFxXOaR/2TQ0f8AC7DRz0SRGRI1bfphnX2hVYTTtLuhL4nYKL+Q==} + '@oxlint/binding-linux-ppc64-gnu@1.73.0': + resolution: {integrity: sha512-L+JYcb/vdg5fmcH08V6o0YYLU28cTH1SPNulwJdvK9NK49aXSkYy6oNpKBmddArVOXYqNepriDGiZ04G54kh1Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.70.0': - resolution: {integrity: sha512-N2+4lV2KLN+oXTIIIwmWDhwkrnvqf5oX7Hw0zPjk+RuIVgiBQSOlJWF7uQoFx2siEYX0ZQ5cfSbEAHm+J3t7Wg==} + '@oxlint/binding-linux-riscv64-gnu@1.73.0': + resolution: {integrity: sha512-Qtk0g3bKV6OwWjIm7R8kQN1uOZRKQt/MODK2a8QfkwhTpXBD53ozx5XLVWLGDQAVyp2otLW4D2wB98XfAfMPGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.70.0': - resolution: {integrity: sha512-1e2L7cFCvx9QDzq6NPP+0tABKb5z6nWHyddWTNKprEsjO9xNrAtPowuCGpjNXxkTdsMiZ4jc8YQ5SstZd4XK6g==} + '@oxlint/binding-linux-riscv64-musl@1.73.0': + resolution: {integrity: sha512-wX0NQKZVxltkAOVmzFcpOaMpdaUvsq1Eqpx9tkAfl71UdkTlSo1R4AdAnGccR1Fm2+TzFgZ22CyyGuZ41RDr/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.70.0': - resolution: {integrity: sha512-Kwu/l/8GcYibCWA9m9N5pRXMIKVSsL/YbgpLzYkqDhWTiqdRfnNJ/+nqIKRKQiFbHWsdlHEhzMwruJK+qcEruA==} + '@oxlint/binding-linux-s390x-gnu@1.73.0': + resolution: {integrity: sha512-vPe7UGBMWyiLTtnqS4xxgMQFSFGmtQwhwCxuiw6lXygaO6bVt0D8dFVg8Xv05eaiN3ybC0HXXHUAohFMFvqoCQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.70.0': - resolution: {integrity: sha512-tap04CsHYOl0nSAQJfPNIuBxqEPB2HnhQqwaOXLg1jnp2XfRo8Fa814dA4QC4zpvTWXCjAAaCY1W5LOORkEQuQ==} + '@oxlint/binding-linux-x64-gnu@1.73.0': + resolution: {integrity: sha512-2CwIWr9cemFC/CbRBWZvuk5mffz6ObmfFkfcC/9rTQ7f+icNhYr2kOjf9Rt8lLvugvkdGDOmkoVoFFHh6ClCTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.70.0': - resolution: {integrity: sha512-hzJa/WgvtJpbBD9rgfy0qe+MjbxOXNUT0bfR1S6EQQzfTtBFA9xg5q8KSwRrQ2QfSS+TaP4j+4mVPQrfNc6UNg==} + '@oxlint/binding-linux-x64-musl@1.73.0': + resolution: {integrity: sha512-nDadfJgg7NBBxG0N560wOe7LLX5QiYp6qBaI7viuk5EUORFBktU/NfV0MbTqU3gTqQDCh4VyxKdo5VADxk9w8Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.70.0': - resolution: {integrity: sha512-xbsaNSNzVSnaJACCUYr1HQMyY/Q/Q1LkePmHG3UvZPvGCYGNxrsZp9OmtA6ick8xH47ltRRbRrPCM1YXYcyC+A==} + '@oxlint/binding-openharmony-arm64@1.73.0': + resolution: {integrity: sha512-wGjJC+NLH9xP+IKGn9RDW94ojJR/wPbg5WCnQjj/oReaOtCQthr8ws1zICe77JFmo4ouUdeTHHZL/ESGiF6Pmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.70.0': - resolution: {integrity: sha512-icAEsUI7JbW1TMRdEXV83mVAInhRVQYuuAlPpxdGwJ95chNdnCzjloRW8GglT0WvzOEZSio6fnYSk2DJ2Hv7LQ==} + '@oxlint/binding-win32-arm64-msvc@1.73.0': + resolution: {integrity: sha512-I7X47GPGljw225YUQ5SbC/rb1Kkdrd0yQf0x+hYxeKS6DpfjMbo9ccQPQ6LNY6BoJQ1sHhgDUGuMn5Vg5gHT6w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.70.0': - resolution: {integrity: sha512-FHMSWbVsPVs/f+Jcl04ws4JJ2wUnauyTzlpxWRG/lSO/8GpX08Fo2gQZqdA6CrRFI+zvkxl+N/KwJGWfUwYVZA==} + '@oxlint/binding-win32-ia32-msvc@1.73.0': + resolution: {integrity: sha512-5lWj+3h+74Fm1jYOO9qkJA4xkAlZA099DkXppuXsk7UpnpZLttsefrZU469vChGaG6hcSqrkKXQOvMTZtbjeNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.70.0': - resolution: {integrity: sha512-ptOlKwCz7n4AKs5VweMqG6DAg677FmKOK+vBkkL9DMNgFATIQ+upqUYBTOEwRQyRAx1ncGlPlXleV2hIcm3z4g==} + '@oxlint/binding-win32-x64-msvc@1.73.0': + resolution: {integrity: sha512-WaNRvh4f6zY9CvUQk2YoA1O90ieWrIklI84+HXFr9Isjz9CSESrdqo/RtIYt4Dll/cAchqGDMehfaZd0vqEFZw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3005,12 +3005,12 @@ packages: vite-plus: optional: true - oxlint@1.70.0: - resolution: {integrity: sha512-D6JgHtzkhRwvEC+A0Nw5AEc5bk8x5i1pHzvZIEf/a0C4hOzmAACNGtkDGPyFaxxX3ZVGxCPeig3P3rMM8XU3/g==} + oxlint@1.73.0: + resolution: {integrity: sha512-u91G9TJzU6yqKWNZUYprQB07W7YvntZXaRxQ6CkoytepYhLWUXWsr1M8zUJ34VatNPuUAr3Z8GH+O2A331CluQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.22.1' + oxlint-tsgolint: '>=0.24.0' vite-plus: '*' peerDependenciesMeta: oxlint-tsgolint: @@ -4471,61 +4471,61 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.57.0': optional: true - '@oxlint/binding-android-arm-eabi@1.70.0': + '@oxlint/binding-android-arm-eabi@1.73.0': optional: true - '@oxlint/binding-android-arm64@1.70.0': + '@oxlint/binding-android-arm64@1.73.0': optional: true - '@oxlint/binding-darwin-arm64@1.70.0': + '@oxlint/binding-darwin-arm64@1.73.0': optional: true - '@oxlint/binding-darwin-x64@1.70.0': + '@oxlint/binding-darwin-x64@1.73.0': optional: true - '@oxlint/binding-freebsd-x64@1.70.0': + '@oxlint/binding-freebsd-x64@1.73.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.70.0': + '@oxlint/binding-linux-arm-gnueabihf@1.73.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.70.0': + '@oxlint/binding-linux-arm-musleabihf@1.73.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.70.0': + '@oxlint/binding-linux-arm64-gnu@1.73.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.70.0': + '@oxlint/binding-linux-arm64-musl@1.73.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.70.0': + '@oxlint/binding-linux-ppc64-gnu@1.73.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.70.0': + '@oxlint/binding-linux-riscv64-gnu@1.73.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.70.0': + '@oxlint/binding-linux-riscv64-musl@1.73.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.70.0': + '@oxlint/binding-linux-s390x-gnu@1.73.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.70.0': + '@oxlint/binding-linux-x64-gnu@1.73.0': optional: true - '@oxlint/binding-linux-x64-musl@1.70.0': + '@oxlint/binding-linux-x64-musl@1.73.0': optional: true - '@oxlint/binding-openharmony-arm64@1.70.0': + '@oxlint/binding-openharmony-arm64@1.73.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.70.0': + '@oxlint/binding-win32-arm64-msvc@1.73.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.70.0': + '@oxlint/binding-win32-ia32-msvc@1.73.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.70.0': + '@oxlint/binding-win32-x64-msvc@1.73.0': optional: true '@pinojs/redact@0.4.0': {} @@ -5955,27 +5955,27 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.57.0 '@oxfmt/binding-win32-x64-msvc': 0.57.0 - oxlint@1.70.0: + oxlint@1.73.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.70.0 - '@oxlint/binding-android-arm64': 1.70.0 - '@oxlint/binding-darwin-arm64': 1.70.0 - '@oxlint/binding-darwin-x64': 1.70.0 - '@oxlint/binding-freebsd-x64': 1.70.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.70.0 - '@oxlint/binding-linux-arm-musleabihf': 1.70.0 - '@oxlint/binding-linux-arm64-gnu': 1.70.0 - '@oxlint/binding-linux-arm64-musl': 1.70.0 - '@oxlint/binding-linux-ppc64-gnu': 1.70.0 - '@oxlint/binding-linux-riscv64-gnu': 1.70.0 - '@oxlint/binding-linux-riscv64-musl': 1.70.0 - '@oxlint/binding-linux-s390x-gnu': 1.70.0 - '@oxlint/binding-linux-x64-gnu': 1.70.0 - '@oxlint/binding-linux-x64-musl': 1.70.0 - '@oxlint/binding-openharmony-arm64': 1.70.0 - '@oxlint/binding-win32-arm64-msvc': 1.70.0 - '@oxlint/binding-win32-ia32-msvc': 1.70.0 - '@oxlint/binding-win32-x64-msvc': 1.70.0 + '@oxlint/binding-android-arm-eabi': 1.73.0 + '@oxlint/binding-android-arm64': 1.73.0 + '@oxlint/binding-darwin-arm64': 1.73.0 + '@oxlint/binding-darwin-x64': 1.73.0 + '@oxlint/binding-freebsd-x64': 1.73.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.73.0 + '@oxlint/binding-linux-arm-musleabihf': 1.73.0 + '@oxlint/binding-linux-arm64-gnu': 1.73.0 + '@oxlint/binding-linux-arm64-musl': 1.73.0 + '@oxlint/binding-linux-ppc64-gnu': 1.73.0 + '@oxlint/binding-linux-riscv64-gnu': 1.73.0 + '@oxlint/binding-linux-riscv64-musl': 1.73.0 + '@oxlint/binding-linux-s390x-gnu': 1.73.0 + '@oxlint/binding-linux-x64-gnu': 1.73.0 + '@oxlint/binding-linux-x64-musl': 1.73.0 + '@oxlint/binding-openharmony-arm64': 1.73.0 + '@oxlint/binding-win32-arm64-msvc': 1.73.0 + '@oxlint/binding-win32-ia32-msvc': 1.73.0 + '@oxlint/binding-win32-x64-msvc': 1.73.0 p-filter@2.1.0: dependencies: From 9077abf28eddf2c4ea0bf8b780b533174614bfed Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Wed, 8 Jul 2026 02:04:41 +0900 Subject: [PATCH 13/39] fix(lr2-skin,player-web): make public const types isolated-declarations compatible tsdown 0.22.3 (rolldown-plugin-dts 0.26.0) rejects `as const satisfies ...` on declaration-emitting consts with TS9010 under isolated declarations. Annotate LR2_PLAY_VARIANTS explicitly and keep plain `as const` where the literal types are load-bearing (LR2_SKIN_INFORMATION_TYPE, BEATORAJA_PLAYABLE_VARIANTS). --- packages/lr2-skin/src/paths.ts | 2 +- packages/lr2-skin/src/play-skin.ts | 2 +- packages/player-web/src/skin/beatoraja/theme.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/lr2-skin/src/paths.ts b/packages/lr2-skin/src/paths.ts index 987b6bec..dec2ea6d 100644 --- a/packages/lr2-skin/src/paths.ts +++ b/packages/lr2-skin/src/paths.ts @@ -36,7 +36,7 @@ export const LR2_SKIN_INFORMATION_TYPE = { RESULT: 7, KEY_CONFIG: 8, SKIN_SELECT: 9, -} as const satisfies Record; +} as const; export type Lr2SkinInformationType = (typeof LR2_SKIN_INFORMATION_TYPE)[keyof typeof LR2_SKIN_INFORMATION_TYPE]; diff --git a/packages/lr2-skin/src/play-skin.ts b/packages/lr2-skin/src/play-skin.ts index bf24fb3b..8d9e2828 100644 --- a/packages/lr2-skin/src/play-skin.ts +++ b/packages/lr2-skin/src/play-skin.ts @@ -5,7 +5,7 @@ import { asLoadedBytes, readFilesIntoBytesMap, type Lr2SkinFileEntry } from './f import type { Lr2SkinInputFile } from './file-lookup.ts'; import { loadLr2SkinFromSourceFiles, type Lr2PlayVariant, type Lr2Skin } from './skin.ts'; -export const LR2_PLAY_VARIANTS = ['7', '14', '10', '5', '9'] as const satisfies readonly Lr2PlayVariant[]; +export const LR2_PLAY_VARIANTS: readonly Lr2PlayVariant[] = ['7', '14', '10', '5', '9']; export type Lr2PlaySkinMap = Partial>; diff --git a/packages/player-web/src/skin/beatoraja/theme.ts b/packages/player-web/src/skin/beatoraja/theme.ts index e47f4987..b78cd6ff 100644 --- a/packages/player-web/src/skin/beatoraja/theme.ts +++ b/packages/player-web/src/skin/beatoraja/theme.ts @@ -95,7 +95,7 @@ export function summarizeBeatorajaPlaySkins(playSkins: BeatorajaPlaySkinMap, sep * If the dropped theme only ships a 24-key skin, the host should fall back to the LR2 theme for gameplay. This * matches how `pickLr2PlaySkin` chains through fallbacks for missing variants. */ -const BEATORAJA_PLAYABLE_VARIANTS = ['7', '5', '9', '10', '14'] as const satisfies ReadonlyArray; +const BEATORAJA_PLAYABLE_VARIANTS = ['7', '5', '9', '10', '14'] as const; export type BeatorajaPlayableVariant = (typeof BEATORAJA_PLAYABLE_VARIANTS)[number]; /** From 76d299d72057190c8ceba88302c91ecf49b1f3c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 18:08:42 +0000 Subject: [PATCH 14/39] chore(deps-dev): bump wrangler from 4.103.0 to 4.107.0 Bumps [wrangler](https://github.com/cloudflare/workers-sdk/tree/HEAD/packages/wrangler) from 4.103.0 to 4.107.0. - [Release notes](https://github.com/cloudflare/workers-sdk/releases) - [Commits](https://github.com/cloudflare/workers-sdk/commits/wrangler@4.107.0/packages/wrangler) --- updated-dependencies: - dependency-name: wrangler dependency-version: 4.107.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/player-web-demo/package.json | 2 +- pnpm-lock.yaml | 84 +++++++++++++-------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index dce23c46..038b79d9 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -29,6 +29,6 @@ "ts-ebml": "^3.0.2", "vite": "^8.0.16", "vite-plugin-node-polyfills": "^0.28.0", - "wrangler": "^4.103.0" + "wrangler": "^4.107.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 811a27d3..e9b8fa48 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -277,8 +277,8 @@ importers: specifier: ^0.28.0 version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) wrangler: - specifier: ^4.103.0 - version: 4.103.0(@cloudflare/workers-types@5.20260707.1) + specifier: ^4.107.0 + version: 4.107.0(@cloudflare/workers-types@5.20260707.1) packages/stringifier: dependencies: @@ -420,32 +420,32 @@ packages: workerd: optional: true - '@cloudflare/workerd-darwin-64@1.20260617.1': - resolution: {integrity: sha512-jWwmgEVVWbsHNrLSNXzwjJaH90VzRxq1cWkQFUidxyeUPnMxemeNE8I9qFAfrpzGgE11e9sKDcE3ettJW08swQ==} + '@cloudflare/workerd-darwin-64@1.20260701.1': + resolution: {integrity: sha512-Zd9Y1bah6DwwBN2RW8vJohffQrIUazb8UXnqSNecOxM+jJLhUuvv5IOG8dbHcV83TyZAubea6gsQXo2yH1lDdw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20260617.1': - resolution: {integrity: sha512-LHH7b565g9znfCUOkwbec6FG2rmRbsgCy6aJiU9KN662mNheWl5sw/iKleiFSiljPKQQP3HkjnC/NSkdgi/aSA==} + '@cloudflare/workerd-darwin-arm64@1.20260701.1': + resolution: {integrity: sha512-yBLsjS1qCWqFyCY37qRUrYfzHHvMGvjh8zRKJ6MvUivYDhkZTzqduppK38FoqYvayLJ5KbcxH7zo5rkxGqbsaA==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20260617.1': - resolution: {integrity: sha512-FMnaAKXe4Cfd8TQurCVd9fs2XQVBFRCsP+Id/SRdUv89MlwYu9zXfoyx6BxM+brPTIUK38SHbo8iaxiwzLi9JQ==} + '@cloudflare/workerd-linux-64@1.20260701.1': + resolution: {integrity: sha512-vMfqSIMfoo4xmZXEuUVqLpSFS921YKjiR9q7kDXPi6Vld1PK74UHg9LZuBavT2KSyemHUCTpj9y/4JSYOEyQbQ==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20260617.1': - resolution: {integrity: sha512-MRoifFYcqbxxIIQy7PqO5tFY/qPFSnjXzakWl0sO93l+HLyG35jRAgOi6jfqa4kBxc7gKKtH861DcewjxUfkjA==} + '@cloudflare/workerd-linux-arm64@1.20260701.1': + resolution: {integrity: sha512-HRfwbKU2pK44V2NhoM0+iH0JJSj7nQ9Wv13ifIiGYCmTtDL8/zKtEhX7kQ3D4Vy/Cpjhttl0FkfqXj1aqLDPPg==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20260617.1': - resolution: {integrity: sha512-rgBV9wQrv0OSKgCTTbhFUFY3sLGNANZ88aqaLvtmEn2gmbFVb1J4PDGochVUdB7NSEp4D/ghHva6/8SZmbONpw==} + '@cloudflare/workerd-windows-64@1.20260701.1': + resolution: {integrity: sha512-ngxCiIN9s/fM2o1IBMD0o1/mcXrv2NJVdyznh51UH8sQuvrTrXvV2nM0Uj/qU2wMwF6prgNBcdcd7AZeZGiBQA==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -463,8 +463,8 @@ packages: '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/runtime@1.11.1': - resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + '@emnapi/runtime@1.11.2': + resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} @@ -2741,8 +2741,8 @@ packages: resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} hasBin: true - miniflare@4.20260617.1: - resolution: {integrity: sha512-Go3/gzStm99QHptsSgU+q1S+xDfLoRgwjJNY80kaTVi0ENhTyqKq+sc4xZiWBSbM7uUcJwmzm8+QFKtcYLJ9nw==} + miniflare@4.20260701.0: + resolution: {integrity: sha512-L6eAAi6IKtyb/7J6L+YsH2vb1yBrJWKRXI293JYDiMl70+6nncdAgigex58w6WBd+CwvdMsqOyNyGs95Op5gWQ==} engines: {node: '>=22.0.0'} hasBin: true @@ -3559,17 +3559,17 @@ packages: engines: {node: '>=8'} hasBin: true - workerd@1.20260617.1: - resolution: {integrity: sha512-Re5pl6pdowt3ZmWUzGlOuB7jbRIIPetgKalmo4cYmucQnVhpo7/3e4MfpekbhLi2EhZZz5EY9NWRu8zFzuEZew==} + workerd@1.20260701.1: + resolution: {integrity: sha512-uF813NG09JwNRRUfJ0zBomyTslSPM810dMj9LVvkQ7RAkLrQLzAlPU8Xh/3dIqZDo2bfd7tChbf2PtqLRARRJQ==} engines: {node: '>=16'} hasBin: true - wrangler@4.103.0: - resolution: {integrity: sha512-3Lv1P5t2xcSEkSTKtG+Lz+3JFryuU7YPLkaCUj7gNe+CJsjZJLtUwqsh1x595QBxkIbCE0GAvDx2DCJUU4+oqw==} + wrangler@4.107.0: + resolution: {integrity: sha512-fw69ThymNitZ0oIEBU2yNeq3kK59UKz/jyA3udwRrQIAIsxX57q5qLOpPTN7qc5t8n9pnUeofe0uxtMuhQZW8w==} engines: {node: '>=22.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20260617.1 + '@cloudflare/workers-types': ^4.20260701.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -3786,25 +3786,25 @@ snapshots: '@cloudflare/kv-asset-handler@0.5.0': {} - '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260617.1)': + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260701.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20260617.1 + workerd: 1.20260701.1 - '@cloudflare/workerd-darwin-64@1.20260617.1': + '@cloudflare/workerd-darwin-64@1.20260701.1': optional: true - '@cloudflare/workerd-darwin-arm64@1.20260617.1': + '@cloudflare/workerd-darwin-arm64@1.20260701.1': optional: true - '@cloudflare/workerd-linux-64@1.20260617.1': + '@cloudflare/workerd-linux-64@1.20260701.1': optional: true - '@cloudflare/workerd-linux-arm64@1.20260617.1': + '@cloudflare/workerd-linux-arm64@1.20260701.1': optional: true - '@cloudflare/workerd-windows-64@1.20260617.1': + '@cloudflare/workerd-windows-64@1.20260701.1': optional: true '@cloudflare/workers-types@5.20260707.1': {} @@ -3824,7 +3824,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.11.1': + '@emnapi/runtime@1.11.2': dependencies: tslib: 2.8.1 optional: true @@ -4088,7 +4088,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.11.1 + '@emnapi/runtime': 1.11.2 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -5545,12 +5545,12 @@ snapshots: bn.js: 4.12.3 brorand: 1.1.0 - miniflare@4.20260617.1: + miniflare@4.20260701.0: dependencies: '@cspotcode/source-map-support': 0.8.1 sharp: 0.34.5 undici: 7.28.0 - workerd: 1.20260617.1 + workerd: 1.20260701.1 ws: 8.21.0 youch: 4.1.0-beta.10 transitivePeerDependencies: @@ -6465,24 +6465,24 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - workerd@1.20260617.1: + workerd@1.20260701.1: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20260617.1 - '@cloudflare/workerd-darwin-arm64': 1.20260617.1 - '@cloudflare/workerd-linux-64': 1.20260617.1 - '@cloudflare/workerd-linux-arm64': 1.20260617.1 - '@cloudflare/workerd-windows-64': 1.20260617.1 + '@cloudflare/workerd-darwin-64': 1.20260701.1 + '@cloudflare/workerd-darwin-arm64': 1.20260701.1 + '@cloudflare/workerd-linux-64': 1.20260701.1 + '@cloudflare/workerd-linux-arm64': 1.20260701.1 + '@cloudflare/workerd-windows-64': 1.20260701.1 - wrangler@4.103.0(@cloudflare/workers-types@5.20260707.1): + wrangler@4.107.0(@cloudflare/workers-types@5.20260707.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 - '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260617.1) + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260701.1) blake3-wasm: 2.1.5 esbuild: 0.28.1 - miniflare: 4.20260617.1 + miniflare: 4.20260701.0 path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 - workerd: 1.20260617.1 + workerd: 1.20260701.1 optionalDependencies: '@cloudflare/workers-types': 5.20260707.1 fsevents: 2.3.3 From 5c301ae27131d413ea5ab57ce0be83d74b2e9f74 Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Wed, 8 Jul 2026 03:08:57 +0900 Subject: [PATCH 15/39] chore(deps-dev): bump tsdown from 0.22.2 to 0.22.3 --- package.json | 2 +- pnpm-lock.yaml | 266 +++++++++++++++++++++++++++---------------------- 2 files changed, 149 insertions(+), 119 deletions(-) diff --git a/package.json b/package.json index 5c3f828a..ea4b4f7a 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "oxlint": "^1.73.0", "rimraf": "^6.0.1", "tinybench": "^6.0.2", - "tsdown": "^0.22.2", + "tsdown": "^0.22.3", "tsx": "^4.23.0", "typescript": "7.0.1-rc", "vite": "^8.0.16", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 811a27d3..1f08e6bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ importers: specifier: ^6.0.2 version: 6.0.2 tsdown: - specifier: ^0.22.2 - version: 0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37) + specifier: ^0.22.3 + version: 0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37) tsx: specifier: ^4.23.0 version: 4.23.0 @@ -306,24 +306,24 @@ importers: packages: - '@babel/generator@8.0.0-rc.6': - resolution: {integrity: sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==} + '@babel/generator@8.0.0': + resolution: {integrity: sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==} engines: {node: ^22.18.0 || >=24.11.0} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@8.0.0-rc.6': - resolution: {integrity: sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==} + '@babel/helper-string-parser@8.0.0': + resolution: {integrity: sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==} engines: {node: ^22.18.0 || >=24.11.0} '@babel/helper-validator-identifier@7.29.7': resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@8.0.0-rc.6': - resolution: {integrity: sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==} + '@babel/helper-validator-identifier@8.0.2': + resolution: {integrity: sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==} engines: {node: ^22.18.0 || >=24.11.0} '@babel/parser@7.29.0': @@ -331,8 +331,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@8.0.0-rc.6': - resolution: {integrity: sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==} + '@babel/parser@8.0.0': + resolution: {integrity: sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==} engines: {node: ^22.18.0 || >=24.11.0} hasBin: true @@ -344,8 +344,8 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@8.0.0-rc.6': - resolution: {integrity: sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==} + '@babel/types@8.0.0': + resolution: {integrity: sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==} engines: {node: ^22.18.0 || >=24.11.0} '@bcoe/v8-coverage@1.0.2': @@ -460,6 +460,9 @@ packages: '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} @@ -469,6 +472,9 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@esbuild/aix-ppc64@0.27.7': resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} @@ -1018,8 +1024,8 @@ packages: '@oxc-project/types@0.133.0': resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} - '@oxc-project/types@0.134.0': - resolution: {integrity: sha512-T0xuRRKrQFmocH8y+jGfpmSkGcheaJExY9lEihmR1Gm2aH+75B8CzgU2rABRQSzzDxLjZ15Sc0bRVLj5lVeNXQ==} + '@oxc-project/types@0.138.0': + resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} '@oxfmt/binding-android-arm-eabi@0.57.0': resolution: {integrity: sha512-qVBsEO+KugOsCmUHcO8iqNnqc65p7PCKpCs8M66mPZ+Ri+CWbcpoQOEJBg2OTu03+0qu++NK1jj6IzvQVs0Sig==} @@ -1295,8 +1301,8 @@ packages: cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.1.0': - resolution: {integrity: sha512-gCYzGOSkYY6Z034suzd20euvds7lPzMEEla62DJGE/ZAlR4OMBnNbvnBSsIGUCAr52gaWMsloGxP4tVGtN5aCA==} + '@rolldown/binding-android-arm64@1.1.4': + resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] @@ -1313,8 +1319,8 @@ packages: cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.1.0': - resolution: {integrity: sha512-JQBD77MNgu+4Z6RAyg69acugdrhhVoWesr3l47zohYZ2YV2fwkWMArkN/2p4l6Ei+Sno7W5q+UsKdVWq5Ens0w==} + '@rolldown/binding-darwin-arm64@1.1.4': + resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] @@ -1331,8 +1337,8 @@ packages: cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.1.0': - resolution: {integrity: sha512-p/8cXUTK4Sob604e+xxPhVSbDFf29E6J0l/xESM9rdCfn3aDai3nEs6TnMHUsdD5aNlFz0+gDbiGlozLKGa2YA==} + '@rolldown/binding-darwin-x64@1.1.4': + resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] @@ -1349,8 +1355,8 @@ packages: cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.1.0': - resolution: {integrity: sha512-KbtOSlVv6fElujiZWMcC3aQYhEwLVVf073RcwlSmpGQvIsKZFUqc0ef4sjUuurRwfbiI6JJXji9DQn+86hawmQ==} + '@rolldown/binding-freebsd-x64@1.1.4': + resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] @@ -1367,8 +1373,8 @@ packages: cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.1.0': - resolution: {integrity: sha512-9fZ9i0o0/MQaw7om6Z6TsT7tfCk0jtbEFtC+aPqZL5RNsGWNcHvn6EHgL3dAprjq+AZzPTAQjg2JtpJaMt+6pg==} + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': + resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] @@ -1387,8 +1393,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.1.0': - resolution: {integrity: sha512-+tog7T66i+yFyIuuAnjL6xmW182W/qTBOUt6BtQ6lBIM1Eikh/fSMz4HGgvuCp5uU0zuIVWng7kDYthjCMOHcg==} + '@rolldown/binding-linux-arm64-gnu@1.1.4': + resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -1408,8 +1414,8 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.1.0': - resolution: {integrity: sha512-4b7yruLIIj/oZ3GpcLOvxcLCLDMraohn3IhQfN2hBP4w9UekG0DTIajWguJosRGfySf/+h/NwRUiMKoCpxCrqQ==} + '@rolldown/binding-linux-arm64-musl@1.1.4': + resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -1429,8 +1435,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.1.0': - resolution: {integrity: sha512-QRDOVZd0bhQ5jLsUsCC3dUxDWdTSVY9WMznowZgCGOrZfLLgctWpelhUASEiBwsXfat/JwYnVd1EaxMhqyT+UQ==} + '@rolldown/binding-linux-ppc64-gnu@1.1.4': + resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] @@ -1450,8 +1456,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.1.0': - resolution: {integrity: sha512-ypxT+Hq76NFG7woFbNbySnGEajFuYuIXeKz/jfCU+lXUoxfi3zLE6OG/ZQNeK3RpZSYJlAe2bokpsQ046CaieQ==} + '@rolldown/binding-linux-s390x-gnu@1.1.4': + resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] @@ -1471,8 +1477,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.1.0': - resolution: {integrity: sha512-IdovCmfROFmpTLahdecTDFL74aLERVYN68F/mLZjfVh6LfoplPfI6deyHNMTcVujbokDV5k05XrFO22zfv+qjg==} + '@rolldown/binding-linux-x64-gnu@1.1.4': + resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -1492,8 +1498,8 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-musl@1.1.0': - resolution: {integrity: sha512-pcA8xlFp2tyk9T2R6Fi/rPe3bQ1MA+sSMDNUU5Ogu80GHOatkE4P8YCreGAvZErm5Ho2YRXnyvNrWiRncfVysQ==} + '@rolldown/binding-linux-x64-musl@1.1.4': + resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -1511,8 +1517,8 @@ packages: cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.1.0': - resolution: {integrity: sha512-4+fexHayrLCWpriPh4c6dNvL4an34DEZCG7zOM/FD5QNF6h8DT+bDXzyB/kfC8lDJbaFb7jKShtnjDQFXVQEjg==} + '@rolldown/binding-openharmony-arm64@1.1.4': + resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] @@ -1527,8 +1533,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.1.0': - resolution: {integrity: sha512-SbL++MNmOw6QamrwIGDMSSfM4ceTzFr+RjbOExJSLLBinScU4WI5OdA413h1qwPw2yH7lVF1+H4svQ+6mSXKTQ==} + '@rolldown/binding-wasm32-wasi@1.1.4': + resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] @@ -1544,8 +1550,8 @@ packages: cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.1.0': - resolution: {integrity: sha512-+xTE6XC7wBgk0VKRXGG+QAnyW5S9b8vfsFpiMjf0waQTmSQSU8onsH/beyZ8X4aXVveJnotiy7VDjLOaW8bTrg==} + '@rolldown/binding-win32-arm64-msvc@1.1.4': + resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] @@ -1562,8 +1568,8 @@ packages: cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.1.0': - resolution: {integrity: sha512-Ogji1TQNqH3ACLnYr+1Ns1nyrJ0CO2P585u9Hsh02pXvtFiFpgtgT2b3P4PnCOU86VVCvqtAeCN4OftMT8KU4w==} + '@rolldown/binding-win32-x64-msvc@1.1.4': + resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2035,9 +2041,9 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-kit@3.0.0-beta.1: - resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==} - engines: {node: '>=20.19.0'} + ast-kit@3.0.0: + resolution: {integrity: sha512-8OG92q3R35qjC/4i6BLBMg8IB+fClWu/1PEwg2Z9Rn+BuNaiEgJzpzn+pxWOdHJWDCAwu2JP0wCDTozAM4QirQ==} + engines: {node: ^22.18.0 || >=24.11.0} ast-v8-to-istanbul@0.3.12: resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} @@ -2815,6 +2821,10 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + ogg-opus-decoder@1.7.3: resolution: {integrity: sha512-w47tiZpkLgdkpa+34VzYD8mHUj8I9kfWVZa82mBbNwDvB1byfLXSSzW/HxA4fI3e9kVlICSpXGFwMLV1LPdjwg==} @@ -3068,15 +3078,15 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} - rolldown-plugin-dts@0.25.2: - resolution: {integrity: sha512-nMhN/R+vmR8GM45ZW1FWMSjRTSDDn/6w4GTf8RNrEFCBdl8B1kySWrU1ixPtbwzXoRlcO+R/S88VgXuJQwfdDg==} - engines: {node: ^22.18.0 || >=24.0.0} + rolldown-plugin-dts@0.26.0: + resolution: {integrity: sha512-e+kEPtUiDES0htk5iqkSeF4EzAV7R+vugGB44iPDuw1Kw9E+WyL1VG7PaV0IIjGHLiacztMBcMTyrr8ON9CT1Q==} + engines: {node: ^22.18.0 || >=24.11.0} peerDependencies: '@ts-macro/tsc': ^0.3.6 '@typescript/native-preview': '>=7.0.0-dev.20260325.1' rolldown: ^1.0.0 typescript: ^5.0.0 || ^6.0.0 - vue-tsc: ~3.2.0 + vue-tsc: ~3.2.0 || ~3.3.0 peerDependenciesMeta: '@ts-macro/tsc': optional: true @@ -3097,8 +3107,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.1.0: - resolution: {integrity: sha512-zpMvlJhs5PkXRTtKc0CaLBVI9AR/VDiJFpM+kx//hgToEca7FgMlGjaRIisXBcb19T76LswgmKECSQ96hjWr5A==} + rolldown@1.1.4: + resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3321,14 +3331,14 @@ packages: resolution: {integrity: sha512-Br6DA/YbdpsiSQjc0KaF3ASQtkk3MCiA4q5kIA7ptv6adZa/MdYa2TXAXF2bAzRZIMWfyFEC9Gicr3nb51MgDA==} hasBin: true - tsdown@0.22.2: - resolution: {integrity: sha512-VX9gsyKXsTnBZjnIM4jsHl9aRv+GfgkE/k1hQslilaBfZMlaw3JuGR+6yhiU0QxWBtOCDnTjwOSoXzgB7Rr50g==} - engines: {node: ^22.18.0 || >=24.0.0} + tsdown@0.22.3: + resolution: {integrity: sha512-louqbfA8Qf//B9jTTL0FPtXTNpjCWv1VPkbcmQMph2pTpzs+LnB1tbe4tDDRVpo2BjF5SgUXaTZe45SxB8pWHg==} + engines: {node: ^22.18.0 || >=24.11.0} hasBin: true peerDependencies: '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.22.2 - '@tsdown/exe': 0.22.2 + '@tsdown/css': 0.22.3 + '@tsdown/exe': 0.22.3 '@vitejs/devtools': '*' publint: ^0.3.8 tsx: '*' @@ -3602,10 +3612,10 @@ packages: snapshots: - '@babel/generator@8.0.0-rc.6': + '@babel/generator@8.0.0': dependencies: - '@babel/parser': 8.0.0-rc.6 - '@babel/types': 8.0.0-rc.6 + '@babel/parser': 8.0.0 + '@babel/types': 8.0.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 '@types/jsesc': 2.5.1 @@ -3613,19 +3623,19 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-string-parser@8.0.0-rc.6': {} + '@babel/helper-string-parser@8.0.0': {} '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-identifier@8.0.0-rc.6': {} + '@babel/helper-validator-identifier@8.0.2': {} '@babel/parser@7.29.0': dependencies: '@babel/types': 7.29.0 - '@babel/parser@8.0.0-rc.6': + '@babel/parser@8.0.0': dependencies: - '@babel/types': 8.0.0-rc.6 + '@babel/types': 8.0.0 '@babel/runtime@7.29.2': {} @@ -3634,10 +3644,10 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.29.7 - '@babel/types@8.0.0-rc.6': + '@babel/types@8.0.0': dependencies: - '@babel/helper-string-parser': 8.0.0-rc.6 - '@babel/helper-validator-identifier': 8.0.0-rc.6 + '@babel/helper-string-parser': 8.0.0 + '@babel/helper-validator-identifier': 8.0.2 '@bcoe/v8-coverage@1.0.2': {} @@ -3819,6 +3829,12 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 @@ -3834,6 +3850,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.27.7': optional: true @@ -4156,6 +4177,13 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4173,7 +4201,7 @@ snapshots: '@oxc-project/types@0.133.0': {} - '@oxc-project/types@0.134.0': {} + '@oxc-project/types@0.138.0': {} '@oxfmt/binding-android-arm-eabi@0.57.0': optional: true @@ -4315,7 +4343,7 @@ snapshots: '@rolldown/binding-android-arm64@1.0.3': optional: true - '@rolldown/binding-android-arm64@1.1.0': + '@rolldown/binding-android-arm64@1.1.4': optional: true '@rolldown/binding-darwin-arm64@1.0.0-rc.17': @@ -4324,7 +4352,7 @@ snapshots: '@rolldown/binding-darwin-arm64@1.0.3': optional: true - '@rolldown/binding-darwin-arm64@1.1.0': + '@rolldown/binding-darwin-arm64@1.1.4': optional: true '@rolldown/binding-darwin-x64@1.0.0-rc.17': @@ -4333,7 +4361,7 @@ snapshots: '@rolldown/binding-darwin-x64@1.0.3': optional: true - '@rolldown/binding-darwin-x64@1.1.0': + '@rolldown/binding-darwin-x64@1.1.4': optional: true '@rolldown/binding-freebsd-x64@1.0.0-rc.17': @@ -4342,7 +4370,7 @@ snapshots: '@rolldown/binding-freebsd-x64@1.0.3': optional: true - '@rolldown/binding-freebsd-x64@1.1.0': + '@rolldown/binding-freebsd-x64@1.1.4': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': @@ -4351,7 +4379,7 @@ snapshots: '@rolldown/binding-linux-arm-gnueabihf@1.0.3': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.1.0': + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': @@ -4360,7 +4388,7 @@ snapshots: '@rolldown/binding-linux-arm64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-arm64-gnu@1.1.0': + '@rolldown/binding-linux-arm64-gnu@1.1.4': optional: true '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': @@ -4369,7 +4397,7 @@ snapshots: '@rolldown/binding-linux-arm64-musl@1.0.3': optional: true - '@rolldown/binding-linux-arm64-musl@1.1.0': + '@rolldown/binding-linux-arm64-musl@1.1.4': optional: true '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': @@ -4378,7 +4406,7 @@ snapshots: '@rolldown/binding-linux-ppc64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.1.0': + '@rolldown/binding-linux-ppc64-gnu@1.1.4': optional: true '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': @@ -4387,7 +4415,7 @@ snapshots: '@rolldown/binding-linux-s390x-gnu@1.0.3': optional: true - '@rolldown/binding-linux-s390x-gnu@1.1.0': + '@rolldown/binding-linux-s390x-gnu@1.1.4': optional: true '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': @@ -4396,7 +4424,7 @@ snapshots: '@rolldown/binding-linux-x64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-x64-gnu@1.1.0': + '@rolldown/binding-linux-x64-gnu@1.1.4': optional: true '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': @@ -4405,7 +4433,7 @@ snapshots: '@rolldown/binding-linux-x64-musl@1.0.3': optional: true - '@rolldown/binding-linux-x64-musl@1.1.0': + '@rolldown/binding-linux-x64-musl@1.1.4': optional: true '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': @@ -4414,7 +4442,7 @@ snapshots: '@rolldown/binding-openharmony-arm64@1.0.3': optional: true - '@rolldown/binding-openharmony-arm64@1.1.0': + '@rolldown/binding-openharmony-arm64@1.1.4': optional: true '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': @@ -4431,11 +4459,11 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-wasm32-wasi@1.1.0': + '@rolldown/binding-wasm32-wasi@1.1.4': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) optional: true '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': @@ -4444,7 +4472,7 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.0.3': optional: true - '@rolldown/binding-win32-arm64-msvc@1.1.0': + '@rolldown/binding-win32-arm64-msvc@1.1.4': optional: true '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': @@ -4453,7 +4481,7 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.0.3': optional: true - '@rolldown/binding-win32-x64-msvc@1.1.0': + '@rolldown/binding-win32-x64-msvc@1.1.4': optional: true '@rolldown/pluginutils@1.0.0-rc.17': @@ -4790,9 +4818,9 @@ snapshots: assertion-error@2.0.1: {} - ast-kit@3.0.0-beta.1: + ast-kit@3.0.0: dependencies: - '@babel/parser': 8.0.0-rc.6 + '@babel/parser': 8.0.0 estree-walker: 3.0.3 pathe: 2.0.3 @@ -5646,6 +5674,8 @@ snapshots: obug@2.1.1: {} + obug@2.1.3: {} + ogg-opus-decoder@1.7.3: dependencies: '@wasm-audio-decoders/common': 9.0.7 @@ -5926,17 +5956,17 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rolldown-plugin-dts@0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0)(typescript@7.0.1-rc): + rolldown-plugin-dts@0.26.0(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.4)(typescript@7.0.1-rc): dependencies: - '@babel/generator': 8.0.0-rc.6 - '@babel/helper-validator-identifier': 8.0.0-rc.6 - '@babel/parser': 8.0.0-rc.6 - ast-kit: 3.0.0-beta.1 + '@babel/generator': 8.0.0 + '@babel/helper-validator-identifier': 8.0.2 + '@babel/parser': 8.0.0 + ast-kit: 3.0.0 birpc: 4.0.0 dts-resolver: 3.0.0 get-tsconfig: 5.0.0-beta.5 - obug: 2.1.1 - rolldown: 1.1.0 + obug: 2.1.3 + rolldown: 1.1.4 optionalDependencies: '@typescript/native-preview': 7.0.0-dev.20260613.1 typescript: 7.0.1-rc @@ -5986,26 +6016,26 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.3 '@rolldown/binding-win32-x64-msvc': 1.0.3 - rolldown@1.1.0: + rolldown@1.1.4: dependencies: - '@oxc-project/types': 0.134.0 + '@oxc-project/types': 0.138.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.1.0 - '@rolldown/binding-darwin-arm64': 1.1.0 - '@rolldown/binding-darwin-x64': 1.1.0 - '@rolldown/binding-freebsd-x64': 1.1.0 - '@rolldown/binding-linux-arm-gnueabihf': 1.1.0 - '@rolldown/binding-linux-arm64-gnu': 1.1.0 - '@rolldown/binding-linux-arm64-musl': 1.1.0 - '@rolldown/binding-linux-ppc64-gnu': 1.1.0 - '@rolldown/binding-linux-s390x-gnu': 1.1.0 - '@rolldown/binding-linux-x64-gnu': 1.1.0 - '@rolldown/binding-linux-x64-musl': 1.1.0 - '@rolldown/binding-openharmony-arm64': 1.1.0 - '@rolldown/binding-wasm32-wasi': 1.1.0 - '@rolldown/binding-win32-arm64-msvc': 1.1.0 - '@rolldown/binding-win32-x64-msvc': 1.1.0 + '@rolldown/binding-android-arm64': 1.1.4 + '@rolldown/binding-darwin-arm64': 1.1.4 + '@rolldown/binding-darwin-x64': 1.1.4 + '@rolldown/binding-freebsd-x64': 1.1.4 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.4 + '@rolldown/binding-linux-arm64-gnu': 1.1.4 + '@rolldown/binding-linux-arm64-musl': 1.1.4 + '@rolldown/binding-linux-ppc64-gnu': 1.1.4 + '@rolldown/binding-linux-s390x-gnu': 1.1.4 + '@rolldown/binding-linux-x64-gnu': 1.1.4 + '@rolldown/binding-linux-x64-musl': 1.1.4 + '@rolldown/binding-openharmony-arm64': 1.1.4 + '@rolldown/binding-wasm32-wasi': 1.1.4 + '@rolldown/binding-win32-arm64-msvc': 1.1.4 + '@rolldown/binding-win32-x64-msvc': 1.1.4 rollup@4.59.0: dependencies: @@ -6266,7 +6296,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.2(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37): + tsdown@0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -6274,11 +6304,11 @@ snapshots: empathic: 2.0.1 hookable: 6.1.1 import-without-cache: 0.4.0 - obug: 2.1.1 + obug: 2.1.3 picomatch: 4.0.4 - rolldown: 1.1.0 - rolldown-plugin-dts: 0.25.2(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.0)(typescript@7.0.1-rc) - semver: 7.8.1 + rolldown: 1.1.4 + rolldown-plugin-dts: 0.26.0(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.4)(typescript@7.0.1-rc) + semver: 7.8.5 tinyexec: 1.2.4 tinyglobby: 0.2.17 tree-kill: 1.2.2 From 61d5093cb576ca4ca834aaadf55d98aecb7a38c3 Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Wed, 8 Jul 2026 03:11:14 +0900 Subject: [PATCH 16/39] chore(deps-dev): bump vitest and @vitest/coverage-v8 to 4.1.10 --- package.json | 4 +- pnpm-lock.yaml | 545 +++++++++---------------------------------------- 2 files changed, 100 insertions(+), 449 deletions(-) diff --git a/package.json b/package.json index ea4b4f7a..b08ee660 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "devDependencies": { "@changesets/cli": "^2.31.0", "@types/node": "^25.9.1", - "@vitest/coverage-v8": "^4.0.18", + "@vitest/coverage-v8": "^4.1.10", "oxfmt": "^0.57.0", "oxlint": "^1.73.0", "rimraf": "^6.0.1", @@ -43,7 +43,7 @@ "tsx": "^4.23.0", "typescript": "7.0.1-rc", "vite": "^8.0.16", - "vitest": "^4.0.18" + "vitest": "^4.1.10" }, "engines": { "node": ">=25" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f08e6bb..77096f52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^25.9.1 version: 25.9.1 '@vitest/coverage-v8': - specifier: ^4.0.18 - version: 4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0)) + specifier: ^4.1.10 + version: 4.1.10(vitest@4.1.10) oxfmt: specifier: ^0.57.0 version: 0.57.0 @@ -42,8 +42,8 @@ importers: specifier: ^8.0.16 version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) + specifier: ^4.1.10 + version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) packages/audio-renderer: dependencies: @@ -475,312 +475,156 @@ packages: '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@esbuild/aix-ppc64@0.27.7': - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.7': - resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.28.1': resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.7': - resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.28.1': resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.7': - resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.28.1': resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.7': - resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.28.1': resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.7': - resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.28.1': resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.7': - resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.28.1': resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.7': - resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.28.1': resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.7': - resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.28.1': resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.7': - resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.28.1': resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.7': - resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.28.1': resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.7': - resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.28.1': resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.7': - resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.28.1': resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.7': - resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.28.1': resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.7': - resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.28.1': resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.7': - resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.28.1': resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.7': - resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.28.1': resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.7': - resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.28.1': resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.7': - resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.28.1': resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.7': - resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.28.1': resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.7': - resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.28.1': resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.7': - resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.28.1': resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.7': - resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.28.1': resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.7': - resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.28.1': resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.7': - resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.28.1': resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.7': - resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.28.1': resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} @@ -1952,43 +1796,43 @@ packages: '@uwx/libav.js-fat@6.0.0-nightly.29.f420ff.ffmpeg.6.1.1': resolution: {integrity: sha512-XMUWb4CEKAKZ8ONnBT/U6jwJlH+cvbTPj9ufdQ4H+nIaRDen8tcS2PyPAh2Smrxf6MmkvUqj4kH4/groYlNjOQ==} - '@vitest/coverage-v8@4.0.18': - resolution: {integrity: sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==} + '@vitest/coverage-v8@4.1.10': + resolution: {integrity: sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==} peerDependencies: - '@vitest/browser': 4.0.18 - vitest: 4.0.18 + '@vitest/browser': 4.1.10 + vitest: 4.1.10 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} '@wasm-audio-decoders/common@9.0.7': resolution: {integrity: sha512-WRaUuWSKV7pkttBygml/a6dIEpatq2nnZGFIoPTc5yPLkxL6Wk4YaslPM98OPQvWacvNZ+Py9xROGDtrFBDzag==} @@ -2045,8 +1889,8 @@ packages: resolution: {integrity: sha512-8OG92q3R35qjC/4i6BLBMg8IB+fClWu/1PEwg2Z9Rn+BuNaiEgJzpzn+pxWOdHJWDCAwu2JP0wCDTozAM4QirQ==} engines: {node: ^22.18.0 || >=24.11.0} - ast-v8-to-istanbul@0.3.12: - resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + ast-v8-to-istanbul@1.0.4: + resolution: {integrity: sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==} atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} @@ -2169,6 +2013,9 @@ packages: constants-browserify@1.0.0: resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.1.1: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} @@ -2286,18 +2133,13 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.3.0: + resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} @@ -2818,9 +2660,6 @@ packages: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - obug@2.1.3: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} @@ -2950,10 +2789,6 @@ packages: resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} @@ -3142,11 +2977,6 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.8.1: - resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} - engines: {node: '>=10'} - hasBin: true - semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -3229,8 +3059,8 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} stream-browserify@3.0.0: resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} @@ -3287,18 +3117,10 @@ packages: resolution: {integrity: sha512-FlHoQpcFvCzeXK5kVPvV7IVgW/hs/B36QWTz876iSdeJguBDfdTSRQmYmaHX+fQNt4hp+gEFB2XXw+8hT4/y8A==} engines: {node: '>=20.0.0'} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} - engines: {node: '>=18'} - tinyexec@1.2.4: resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -3307,8 +3129,8 @@ packages: resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} engines: {node: ^20.0.0 || >=22.0.0} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} tmp@0.2.5: @@ -3427,46 +3249,6 @@ packages: peerDependencies: vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - vite@7.3.5: - resolution: {integrity: sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - vite@8.0.16: resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3510,20 +3292,23 @@ packages: yaml: optional: true - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 happy-dom: '*' jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -3537,6 +3322,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -3855,159 +3644,81 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.27.7': - optional: true - '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/android-arm64@0.27.7': - optional: true - '@esbuild/android-arm64@0.28.1': optional: true - '@esbuild/android-arm@0.27.7': - optional: true - '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.27.7': - optional: true - '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/darwin-arm64@0.27.7': - optional: true - '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/darwin-x64@0.27.7': - optional: true - '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/freebsd-arm64@0.27.7': - optional: true - '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/freebsd-x64@0.27.7': - optional: true - '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/linux-arm64@0.27.7': - optional: true - '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/linux-arm@0.27.7': - optional: true - '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/linux-ia32@0.27.7': - optional: true - '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/linux-loong64@0.27.7': - optional: true - '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/linux-mips64el@0.27.7': - optional: true - '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/linux-ppc64@0.27.7': - optional: true - '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.27.7': - optional: true - '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/linux-s390x@0.27.7': - optional: true - '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/linux-x64@0.27.7': - optional: true - '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.27.7': - optional: true - '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/netbsd-x64@0.27.7': - optional: true - '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.27.7': - optional: true - '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.27.7': - optional: true - '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.27.7': - optional: true - '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.27.7': - optional: true - '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.27.7': - optional: true - '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.27.7': - optional: true - '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.27.7': - optional: true - '@esbuild/win32-x64@0.28.1': optional: true @@ -4715,58 +4426,60 @@ snapshots: '@uwx/libav.js-fat@6.0.0-nightly.29.f420ff.ffmpeg.6.1.1': {} - '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0))': + '@vitest/coverage-v8@4.1.10(vitest@4.1.10)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.18 - ast-v8-to-istanbul: 0.3.12 + '@vitest/utils': 4.1.10 + ast-v8-to-istanbul: 1.0.4 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 magicast: 0.5.2 - obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) + obug: 2.1.3 + std-env: 4.1.0 + tinyrainbow: 3.1.0 + vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) - '@vitest/expect@4.0.18': + '@vitest/expect@4.1.10': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 chai: 6.2.2 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/mocker@4.0.18(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0))': + '@vitest/mocker@4.1.10(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) - '@vitest/pretty-format@4.0.18': + '@vitest/pretty-format@4.1.10': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/runner@4.0.18': + '@vitest/runner@4.1.10': dependencies: - '@vitest/utils': 4.0.18 + '@vitest/utils': 4.1.10 pathe: 2.0.3 - '@vitest/snapshot@4.0.18': + '@vitest/snapshot@4.1.10': dependencies: - '@vitest/pretty-format': 4.0.18 + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.18': {} + '@vitest/spy@4.1.10': {} - '@vitest/utils@4.0.18': + '@vitest/utils@4.1.10': dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 + '@vitest/pretty-format': 4.1.10 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 '@wasm-audio-decoders/common@9.0.7': dependencies: @@ -4824,7 +4537,7 @@ snapshots: estree-walker: 3.0.3 pathe: 2.0.3 - ast-v8-to-istanbul@0.3.12: + ast-v8-to-istanbul@1.0.4: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -4960,6 +4673,8 @@ snapshots: constants-browserify@1.0.0: {} + convert-source-map@2.0.0: {} + cookie@1.1.1: {} core-util-is@1.0.3: {} @@ -5092,41 +4807,12 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.3.0: {} es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 - esbuild@0.27.7: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.7 - '@esbuild/android-arm': 0.27.7 - '@esbuild/android-arm64': 0.27.7 - '@esbuild/android-x64': 0.27.7 - '@esbuild/darwin-arm64': 0.27.7 - '@esbuild/darwin-x64': 0.27.7 - '@esbuild/freebsd-arm64': 0.27.7 - '@esbuild/freebsd-x64': 0.27.7 - '@esbuild/linux-arm': 0.27.7 - '@esbuild/linux-arm64': 0.27.7 - '@esbuild/linux-ia32': 0.27.7 - '@esbuild/linux-loong64': 0.27.7 - '@esbuild/linux-mips64el': 0.27.7 - '@esbuild/linux-ppc64': 0.27.7 - '@esbuild/linux-riscv64': 0.27.7 - '@esbuild/linux-s390x': 0.27.7 - '@esbuild/linux-x64': 0.27.7 - '@esbuild/netbsd-arm64': 0.27.7 - '@esbuild/netbsd-x64': 0.27.7 - '@esbuild/openbsd-arm64': 0.27.7 - '@esbuild/openbsd-x64': 0.27.7 - '@esbuild/openharmony-arm64': 0.27.7 - '@esbuild/sunos-x64': 0.27.7 - '@esbuild/win32-arm64': 0.27.7 - '@esbuild/win32-ia32': 0.27.7 - '@esbuild/win32-x64': 0.27.7 - esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -5549,7 +5235,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.8.1 + semver: 7.8.5 math-intrinsics@1.1.0: {} @@ -5672,8 +5358,6 @@ snapshots: has-symbols: 1.1.0 object-keys: 1.1.1 - obug@2.1.1: {} - obug@2.1.3: {} ogg-opus-decoder@1.7.3: @@ -5813,8 +5497,6 @@ snapshots: picomatch@2.3.2: {} - picomatch@4.0.3: {} - picomatch@4.0.4: {} pify@4.0.1: {} @@ -6067,6 +5749,7 @@ snapshots: '@rollup/rollup-win32-x64-gnu': 4.59.0 '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + optional: true run-parallel@1.2.0: dependencies: @@ -6088,8 +5771,6 @@ snapshots: semver@7.7.4: {} - semver@7.8.1: {} - semver@7.8.5: {} set-function-length@1.2.2: @@ -6201,7 +5882,7 @@ snapshots: stackback@0.0.2: {} - std-env@3.10.0: {} + std-env@4.1.0: {} stream-browserify@3.0.0: dependencies: @@ -6253,15 +5934,8 @@ snapshots: tinybench@6.0.2: {} - tinyexec@1.0.2: {} - tinyexec@1.2.4: {} - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -6269,7 +5943,7 @@ snapshots: tinypool@2.1.0: {} - tinyrainbow@3.0.3: {} + tinyrainbow@3.1.0: {} tmp@0.2.5: {} @@ -6406,20 +6080,6 @@ snapshots: transitivePeerDependencies: - rollup - vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0): - dependencies: - esbuild: 0.27.7 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - postcss: 8.5.15 - rollup: 4.59.0 - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 25.9.1 - fsevents: 2.3.3 - lightningcss: 1.32.0 - tsx: 4.23.0 - vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0): dependencies: lightningcss: 1.32.0 @@ -6433,42 +6093,33 @@ snapshots: fsevents: 2.3.3 tsx: 4.23.0 - vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0): + vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.0 expect-type: 1.3.0 magic-string: 0.30.21 - obug: 2.1.1 + obug: 2.1.3 pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 + picomatch: 4.0.4 + std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(tsx@4.23.0) + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.9.1 + '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml vm-browserify@1.1.2: {} From c3a508ffc2664b1e8266fc8cd4697beec21c6a80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 18:13:36 +0000 Subject: [PATCH 17/39] chore(deps-dev): bump vite from 8.0.16 to 8.1.3 Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.16 to 8.1.3. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.1.3/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.1.3 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- packages/player-web-demo/package.json | 2 +- pnpm-lock.yaml | 278 +++++--------------------- 3 files changed, 50 insertions(+), 232 deletions(-) diff --git a/package.json b/package.json index b08ee660..f60ba5bd 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "tsdown": "^0.22.3", "tsx": "^4.23.0", "typescript": "7.0.1-rc", - "vite": "^8.0.16", + "vite": "^8.1.3", "vitest": "^4.1.10" }, "engines": { diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index dce23c46..bf472b3e 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -27,7 +27,7 @@ "devDependencies": { "@cloudflare/workers-types": "^5.20260707.1", "ts-ebml": "^3.0.2", - "vite": "^8.0.16", + "vite": "^8.1.3", "vite-plugin-node-polyfills": "^0.28.0", "wrangler": "^4.103.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 77096f52..58decd09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,11 +39,11 @@ importers: specifier: 7.0.1-rc version: 7.0.1-rc vite: - specifier: ^8.0.16 - version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + specifier: ^8.1.3 + version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) packages/audio-renderer: dependencies: @@ -271,11 +271,11 @@ importers: specifier: ^3.0.2 version: 3.0.2 vite: - specifier: ^8.0.16 - version: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + specifier: ^8.1.3 + version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) vite-plugin-node-polyfills: specifier: ^0.28.0 - version: 0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) wrangler: specifier: ^4.103.0 version: 4.103.0(@cloudflare/workers-types@5.20260707.1) @@ -469,6 +469,9 @@ packages: '@emnapi/runtime@1.11.1': resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + '@emnapi/runtime@1.11.2': + resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} @@ -838,12 +841,6 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.1.6': resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} peerDependencies: @@ -865,9 +862,6 @@ packages: '@oxc-project/types@0.127.0': resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} - '@oxc-project/types@0.133.0': - resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} - '@oxc-project/types@0.138.0': resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} @@ -1139,12 +1133,6 @@ packages: cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.0.3': - resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - '@rolldown/binding-android-arm64@1.1.4': resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1157,12 +1145,6 @@ packages: cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.0.3': - resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - '@rolldown/binding-darwin-arm64@1.1.4': resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1175,12 +1157,6 @@ packages: cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.3': - resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - '@rolldown/binding-darwin-x64@1.1.4': resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1193,12 +1169,6 @@ packages: cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.3': - resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - '@rolldown/binding-freebsd-x64@1.1.4': resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1211,12 +1181,6 @@ packages: cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.1.4': resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1230,13 +1194,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.0.3': - resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.1.4': resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1251,13 +1208,6 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.0.3': - resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.1.4': resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1272,13 +1222,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.1.4': resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1293,13 +1236,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.3': - resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.1.4': resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1314,13 +1250,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.3': - resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.1.4': resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1335,13 +1264,6 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-musl@1.0.3': - resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - '@rolldown/binding-linux-x64-musl@1.1.4': resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1355,12 +1277,6 @@ packages: cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.3': - resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.1.4': resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1372,11 +1288,6 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.3': - resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.1.4': resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1388,12 +1299,6 @@ packages: cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.0.3': - resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.1.4': resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1406,12 +1311,6 @@ packages: cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.3': - resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@rolldown/binding-win32-x64-msvc@1.1.4': resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1590,9 +1489,6 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -2622,8 +2518,8 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2793,6 +2689,10 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -2818,8 +2718,8 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + postcss@8.5.16: + resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} engines: {node: ^10 || ^12 || >=14} prettier@2.8.8: @@ -2937,11 +2837,6 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.0.3: - resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - rolldown@1.1.4: resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3249,13 +3144,13 @@ packages: peerDependencies: vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - vite@8.0.16: - resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + vite@8.1.3: + resolution: {integrity: sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.18 + '@vitejs/devtools': ^0.3.0 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -3634,6 +3529,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.2': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 @@ -3820,7 +3720,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.11.1 + '@emnapi/runtime': 1.11.2 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -3874,13 +3774,6 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 - optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -3910,8 +3803,6 @@ snapshots: '@oxc-project/types@0.127.0': optional: true - '@oxc-project/types@0.133.0': {} - '@oxc-project/types@0.138.0': {} '@oxfmt/binding-android-arm-eabi@0.57.0': @@ -4051,108 +3942,72 @@ snapshots: '@rolldown/binding-android-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-android-arm64@1.0.3': - optional: true - '@rolldown/binding-android-arm64@1.1.4': optional: true '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-arm64@1.0.3': - optional: true - '@rolldown/binding-darwin-arm64@1.1.4': optional: true '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-x64@1.0.3': - optional: true - '@rolldown/binding-darwin-x64@1.1.4': optional: true '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-freebsd-x64@1.0.3': - optional: true - '@rolldown/binding-freebsd-x64@1.1.4': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.1.4': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.3': - optional: true - '@rolldown/binding-linux-arm64-gnu@1.1.4': optional: true '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.3': - optional: true - '@rolldown/binding-linux-arm64-musl@1.1.4': optional: true '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - optional: true - '@rolldown/binding-linux-ppc64-gnu@1.1.4': optional: true '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.3': - optional: true - '@rolldown/binding-linux-s390x-gnu@1.1.4': optional: true '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.3': - optional: true - '@rolldown/binding-linux-x64-gnu@1.1.4': optional: true '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-musl@1.0.3': - optional: true - '@rolldown/binding-linux-x64-musl@1.1.4': optional: true '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-openharmony-arm64@1.0.3': - optional: true - '@rolldown/binding-openharmony-arm64@1.1.4': optional: true @@ -4163,13 +4018,6 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-wasm32-wasi@1.0.3': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - optional: true - '@rolldown/binding-wasm32-wasi@1.1.4': dependencies: '@emnapi/core': 1.11.1 @@ -4180,18 +4028,12 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.3': - optional: true - '@rolldown/binding-win32-arm64-msvc@1.1.4': optional: true '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.3': - optional: true - '@rolldown/binding-win32-x64-msvc@1.1.4': optional: true @@ -4212,7 +4054,7 @@ snapshots: dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 - picomatch: 4.0.4 + picomatch: 4.0.5 optionalDependencies: rollup: 4.59.0 @@ -4297,11 +4139,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@tybys/wasm-util@0.10.2': - dependencies: - tslib: 2.8.1 - optional: true - '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 @@ -4438,7 +4275,7 @@ snapshots: obug: 2.1.3 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) '@vitest/expect@4.1.10': dependencies: @@ -4449,13 +4286,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0))': + '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) '@vitest/pretty-format@4.1.10': dependencies: @@ -4884,9 +4721,9 @@ snapshots: dependencies: reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 fengari-interop@0.1.4(fengari@0.1.5): dependencies: @@ -5294,7 +5131,7 @@ snapshots: ms@2.0.0: {} - nanoid@3.3.12: {} + nanoid@3.3.15: {} node-domexception@1.0.0: {} @@ -5499,6 +5336,8 @@ snapshots: picomatch@4.0.4: {} + picomatch@4.0.5: {} + pify@4.0.1: {} pino-abstract-transport@3.0.0: @@ -5540,9 +5379,9 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss@8.5.15: + postcss@8.5.16: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.15 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -5677,27 +5516,6 @@ snapshots: '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 optional: true - rolldown@1.0.3: - dependencies: - '@oxc-project/types': 0.133.0 - '@rolldown/pluginutils': 1.0.1 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.3 - '@rolldown/binding-darwin-arm64': 1.0.3 - '@rolldown/binding-darwin-x64': 1.0.3 - '@rolldown/binding-freebsd-x64': 1.0.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.3 - '@rolldown/binding-linux-arm64-musl': 1.0.3 - '@rolldown/binding-linux-ppc64-gnu': 1.0.3 - '@rolldown/binding-linux-s390x-gnu': 1.0.3 - '@rolldown/binding-linux-x64-gnu': 1.0.3 - '@rolldown/binding-linux-x64-musl': 1.0.3 - '@rolldown/binding-openharmony-arm64': 1.0.3 - '@rolldown/binding-wasm32-wasi': 1.0.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.3 - '@rolldown/binding-win32-x64-msvc': 1.0.3 - rolldown@1.1.4: dependencies: '@oxc-project/types': 0.138.0 @@ -5938,8 +5756,8 @@ snapshots: tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 tinypool@2.1.0: {} @@ -6072,20 +5890,20 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.20 - vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): + vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) node-stdlib-browser: 1.3.1 - vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) transitivePeerDependencies: - rollup - vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0): + vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0): dependencies: lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.15 - rolldown: 1.0.3 + picomatch: 4.0.5 + postcss: 8.5.16 + rolldown: 1.1.4 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.9.1 @@ -6093,10 +5911,10 @@ snapshots: fsevents: 2.3.3 tsx: 4.23.0 - vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): + vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -6113,7 +5931,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.9.1 From 22b9894cff269577b21b60595dff1fdac0af120e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 02:32:28 +0000 Subject: [PATCH 18/39] chore(deps): bump actions/setup-node from 6 to 7 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 16 ++++++++-------- .github/workflows/release.yml | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 135591a2..51a9633e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,7 +92,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -132,7 +132,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -194,7 +194,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -294,7 +294,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -396,7 +396,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -457,7 +457,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -560,7 +560,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -660,7 +660,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 255c1dfe..e9d3143e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -120,7 +120,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm @@ -305,7 +305,7 @@ jobs: run_install: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version-file: .node-version cache: pnpm From 28a51f0e710ae1afed2957bac09ef269702dd81a Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Tue, 4 Aug 2026 17:37:47 +0900 Subject: [PATCH 19/39] fix(deps): repair lockfile corrupted by auto-merge of #157 and #158 Merging #157 (wrangler 4.107.0) after #158 (vite 8.1.3) let git's three-way merge silently duplicate the @emnapi/runtime@1.11.2 entry and drop @emnapi/runtime@1.11.1, which @napi-rs/wasm-runtime still references. CI failed with ERR_PNPM_BROKEN_LOCKFILE (duplicated mapping key). Restore the 1.11.1 entry and dedupe 1.11.2 in both the packages and snapshots sections; pnpm install --frozen-lockfile now passes. --- pnpm-lock.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad220a44..3c6d360d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -466,8 +466,8 @@ packages: '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/runtime@1.11.2': - resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} '@emnapi/runtime@1.11.2': resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} @@ -3524,7 +3524,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.11.2': + '@emnapi/runtime@1.11.1': dependencies: tslib: 2.8.1 optional: true From e799be21fbd5812fc5a33eda8da82ed701967fa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 02:32:58 +0000 Subject: [PATCH 20/39] chore(deps): bump node-web-audio-api from 2.0.0 to 2.1.0 Bumps [node-web-audio-api](https://github.com/ircam-ismm/node-web-audio-api) from 2.0.0 to 2.1.0. - [Changelog](https://github.com/ircam-ismm/node-web-audio-api/blob/main/CHANGELOG.md) - [Commits](https://github.com/ircam-ismm/node-web-audio-api/compare/v2.0.0...v2.1.0) --- updated-dependencies: - dependency-name: node-web-audio-api dependency-version: 2.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/player/package.json | 2 +- pnpm-lock.yaml | 31 +++++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/player/package.json b/packages/player/package.json index 7203fc95..97c75b41 100644 --- a/packages/player/package.json +++ b/packages/player/package.json @@ -124,6 +124,6 @@ "@be-music/parser": "workspace:*", "@be-music/utils": "workspace:*", "alien-signals": "^3.2.1", - "node-web-audio-api": "^2.0.0" + "node-web-audio-api": "^2.1.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c6d360d..4b21cfae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -156,8 +156,8 @@ importers: specifier: ^3.2.1 version: 3.2.1 node-web-audio-api: - specifier: ^2.0.0 - version: 2.0.0 + specifier: ^2.1.0 + version: 2.1.0 packages/player-tui: dependencies: @@ -847,6 +847,13 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.2.2': + resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2536,8 +2543,8 @@ packages: resolution: {integrity: sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==} engines: {node: '>=10'} - node-web-audio-api@2.0.0: - resolution: {integrity: sha512-I8r10N26N4ssu7KbL70ywWZIVu5F6eSas/DO1wHWwLjiBSo7TKSOXgCVd0mfEvrewDY5vkmqGCUL3ix/iMr4yA==} + node-web-audio-api@2.1.0: + resolution: {integrity: sha512-5aI3ciSs60HlyybHJzPyf8smok8gH9c0Q6n1gjDQGJqcJLafjlPfn78gIkOljVXlS/8l/et3nUQyofsuzf9Tyw==} engines: {node: '>= 22'} object-inspect@1.13.4: @@ -3774,17 +3781,17 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.3 optional: true @@ -4015,7 +4022,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -5171,7 +5178,7 @@ snapshots: util: 0.12.5 vm-browserify: 1.1.2 - node-web-audio-api@2.0.0: + node-web-audio-api@2.1.0: dependencies: caller: 1.1.0 node-fetch: 3.3.2 From 4cdcdcc01ed19bd96e97b0f5bd706bedd0c6b6a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 02:33:11 +0000 Subject: [PATCH 21/39] chore(deps-dev): bump oxlint from 1.73.0 to 1.77.0 Bumps [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) from 1.73.0 to 1.77.0. - [Release notes](https://github.com/oxc-project/oxc/releases) - [Changelog](https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md) - [Commits](https://github.com/oxc-project/oxc/commits/oxlint_v1.77.0/npm/oxlint) --- updated-dependencies: - dependency-name: oxlint dependency-version: 1.77.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 185 +++++++++++++++++++++++++------------------------ 2 files changed, 97 insertions(+), 90 deletions(-) diff --git a/package.json b/package.json index f60ba5bd..ecee0453 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@types/node": "^25.9.1", "@vitest/coverage-v8": "^4.1.10", "oxfmt": "^0.57.0", - "oxlint": "^1.73.0", + "oxlint": "^1.77.0", "rimraf": "^6.0.1", "tinybench": "^6.0.2", "tsdown": "^0.22.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c6d360d..1e027be8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^0.57.0 version: 0.57.0 oxlint: - specifier: ^1.73.0 - version: 1.73.0 + specifier: ^1.77.0 + version: 1.77.0 rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -847,6 +847,13 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.2.2': + resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -987,124 +994,124 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.73.0': - resolution: {integrity: sha512-HZQRN/UMBu+Ut+/9MiAChkbP4qZqrNOWBcNI45vOT40GVhbGR0JgHB87L48D4iAqFQIdVmeQYtV9RF89AjTKkg==} + '@oxlint/binding-android-arm-eabi@1.77.0': + resolution: {integrity: sha512-E06sKWS6PiI6HRxS1wyQg22HvApt01hI7fV+T3wUk3OSbaaP4a3hYGY/MIQDmASqCiRjBdpRQYkgMkqH82cWmQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.73.0': - resolution: {integrity: sha512-Gp+KJRylv2aW7thRpG5p1KTxZq4ZJFbWowrKzufNq9d3ssl3r3JviYV45/+p+7CN1Nv0zDd1e8Ex0b/HUDq4TQ==} + '@oxlint/binding-android-arm64@1.77.0': + resolution: {integrity: sha512-NvsKz0KZxTp9cYWPLf+FXaSZwB3oO3peAjtukpOMBgse2vhQSoIIVqeO1yR0lEo/UcdZIDL18uq+kL0LzQ0ytA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.73.0': - resolution: {integrity: sha512-3de96NdtXhxERMjIz7wsp2HYMY6pMQycGxFWac2mFecAx6VeARF/IqFb1QIaqiCRIdfzBwzTed+pCTCoiS+CYA==} + '@oxlint/binding-darwin-arm64@1.77.0': + resolution: {integrity: sha512-bgjTn6nW4bQCFBvSvuHCpDD+sONvmpo4lGI4PxzMt1quBA+xYxhczk6RiCn3GZ9gY8uhaBbwhj9MdKGfu6T9DA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.73.0': - resolution: {integrity: sha512-5zx/uPW32TiaOeVY1dQ/H5iOf0K1HOdFKOJhLqGl4o63+i1fpzoqqu/mKtd7OFgFjNCdhlyTGgjVkQTZm1ELcg==} + '@oxlint/binding-darwin-x64@1.77.0': + resolution: {integrity: sha512-aotaIttH1R6j1Rwhx0M0htgeZyGtVQqYNTVEYMN/UcgHPquGA6kmk9OyuDc3a2GKUQBC+3C3GVQCcrRPMYqAFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.73.0': - resolution: {integrity: sha512-qNe4gKHaGnLuZJ8toUg90JAa0S2vTVvDw+0bRi3q1avXZXDT4u5mMeECf3nD4HYrbdn1O7dXqWut4onY/yx/Xg==} + '@oxlint/binding-freebsd-x64@1.77.0': + resolution: {integrity: sha512-nNx/wta7ksRAdYvq+l4AWjXkLxEXHALhENxjj2cYbQAIR4ybaA5L+hCbE63HOmft5czQ6ks+hb8vmEAnn7YGPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.73.0': - resolution: {integrity: sha512-cCehYh5hTbfShm/fxTD6wwrGUWIpvX+N5OxmAMhFhDeTGXvw+BeNj889tpxsFQ9ZLatQ6wImuY8tsKLZ+FMz7w==} + '@oxlint/binding-linux-arm-gnueabihf@1.77.0': + resolution: {integrity: sha512-tMLLjM7xXtzXisVCzkOTXNCy9bZVId2wteNwjohlFDR/jY6WagpEDA1c1wu4xRc20Hojaxj+V6DSR7gbKxijWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.73.0': - resolution: {integrity: sha512-d5j5GDU/2dMgjVhw7TQT9ITrsIr1Y02KEXKyVGIXUkD+KiaxE9TP65FS2ZdgTBemQvoRL+gSBdbrIm3cQIeacg==} + '@oxlint/binding-linux-arm-musleabihf@1.77.0': + resolution: {integrity: sha512-MiAFDFaqR0tmHTAyo0YDcZ5hyLREdYw/RQhc2R3cbT+8O3tB+zqPM2th9TTQ+Uo3jn/embS+DO+HyX9ztCPkOQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.73.0': - resolution: {integrity: sha512-Eyf1SrP3+yR1DI3OJgOY2Pvrr9dWP9TK37xPaDYycwTtlGlI45erJAVIfH5/m/xosDt6BupJYEFi47bvbTuuyw==} + '@oxlint/binding-linux-arm64-gnu@1.77.0': + resolution: {integrity: sha512-/xqQ3B16i1T4cyt/9Mn+4CpzhUXoBXp7kVpIwzOXNFLj5JmK1bIjsbSnX296Gg8A/o7oDtKWikFgBx0SLwztkw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.73.0': - resolution: {integrity: sha512-IlT/OJApEDKaMmCooHuncgJZbbCe7T5QIWmTZBEtYscWvzPQuuEinVcid6kwQRVQOUdb7PUCz4jQHnaYXdfJXw==} + '@oxlint/binding-linux-arm64-musl@1.77.0': + resolution: {integrity: sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.73.0': - resolution: {integrity: sha512-L+JYcb/vdg5fmcH08V6o0YYLU28cTH1SPNulwJdvK9NK49aXSkYy6oNpKBmddArVOXYqNepriDGiZ04G54kh1Q==} + '@oxlint/binding-linux-ppc64-gnu@1.77.0': + resolution: {integrity: sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.73.0': - resolution: {integrity: sha512-Qtk0g3bKV6OwWjIm7R8kQN1uOZRKQt/MODK2a8QfkwhTpXBD53ozx5XLVWLGDQAVyp2otLW4D2wB98XfAfMPGA==} + '@oxlint/binding-linux-riscv64-gnu@1.77.0': + resolution: {integrity: sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.73.0': - resolution: {integrity: sha512-wX0NQKZVxltkAOVmzFcpOaMpdaUvsq1Eqpx9tkAfl71UdkTlSo1R4AdAnGccR1Fm2+TzFgZ22CyyGuZ41RDr/A==} + '@oxlint/binding-linux-riscv64-musl@1.77.0': + resolution: {integrity: sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.73.0': - resolution: {integrity: sha512-vPe7UGBMWyiLTtnqS4xxgMQFSFGmtQwhwCxuiw6lXygaO6bVt0D8dFVg8Xv05eaiN3ybC0HXXHUAohFMFvqoCQ==} + '@oxlint/binding-linux-s390x-gnu@1.77.0': + resolution: {integrity: sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.73.0': - resolution: {integrity: sha512-2CwIWr9cemFC/CbRBWZvuk5mffz6ObmfFkfcC/9rTQ7f+icNhYr2kOjf9Rt8lLvugvkdGDOmkoVoFFHh6ClCTw==} + '@oxlint/binding-linux-x64-gnu@1.77.0': + resolution: {integrity: sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.73.0': - resolution: {integrity: sha512-nDadfJgg7NBBxG0N560wOe7LLX5QiYp6qBaI7viuk5EUORFBktU/NfV0MbTqU3gTqQDCh4VyxKdo5VADxk9w8Q==} + '@oxlint/binding-linux-x64-musl@1.77.0': + resolution: {integrity: sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.73.0': - resolution: {integrity: sha512-wGjJC+NLH9xP+IKGn9RDW94ojJR/wPbg5WCnQjj/oReaOtCQthr8ws1zICe77JFmo4ouUdeTHHZL/ESGiF6Pmw==} + '@oxlint/binding-openharmony-arm64@1.77.0': + resolution: {integrity: sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.73.0': - resolution: {integrity: sha512-I7X47GPGljw225YUQ5SbC/rb1Kkdrd0yQf0x+hYxeKS6DpfjMbo9ccQPQ6LNY6BoJQ1sHhgDUGuMn5Vg5gHT6w==} + '@oxlint/binding-win32-arm64-msvc@1.77.0': + resolution: {integrity: sha512-Yh8w+g2Lpx7StrvtYkoz9JJvXjB9wxgFChFNb85nrXm/wj/XTwGWS1hve9+900HL7llrntYB3YP+y32E3tRqzA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.73.0': - resolution: {integrity: sha512-5lWj+3h+74Fm1jYOO9qkJA4xkAlZA099DkXppuXsk7UpnpZLttsefrZU469vChGaG6hcSqrkKXQOvMTZtbjeNg==} + '@oxlint/binding-win32-ia32-msvc@1.77.0': + resolution: {integrity: sha512-zja5b7+6a7UsRFgAQSrnax5vrzliEyNPLCjfXONu/vTWswaIVZGFajJZptaeRvPE4LghtFdAzVFlexTm7MVTGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.73.0': - resolution: {integrity: sha512-WaNRvh4f6zY9CvUQk2YoA1O90ieWrIklI84+HXFr9Isjz9CSESrdqo/RtIYt4Dll/cAchqGDMehfaZd0vqEFZw==} + '@oxlint/binding-win32-x64-msvc@1.77.0': + resolution: {integrity: sha512-+teyvPDZ2RjUvo+SuCqS/UhaJl1QtdW5fWT5NJTV61V5MIuIS90Db9LixmtEGvXixyttiK62P96MSu3UlpviBw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2589,12 +2596,12 @@ packages: vite-plus: optional: true - oxlint@1.73.0: - resolution: {integrity: sha512-u91G9TJzU6yqKWNZUYprQB07W7YvntZXaRxQ6CkoytepYhLWUXWsr1M8zUJ34VatNPuUAr3Z8GH+O2A331CluQ==} + oxlint@1.77.0: + resolution: {integrity: sha512-qnGh8XJHaQ0dprrDXNQZgS0FgjI6v+V3+X8DwmaV++5Aamy6jGKfDdQ1TUvhUxtmKFAbEf4/WeO5QZX+5WSngg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.24.0' + oxlint-tsgolint: '>=7.0.2001' vite-plus: '*' peerDependenciesMeta: oxlint-tsgolint: @@ -3774,17 +3781,17 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.3 optional: true @@ -3862,61 +3869,61 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.57.0': optional: true - '@oxlint/binding-android-arm-eabi@1.73.0': + '@oxlint/binding-android-arm-eabi@1.77.0': optional: true - '@oxlint/binding-android-arm64@1.73.0': + '@oxlint/binding-android-arm64@1.77.0': optional: true - '@oxlint/binding-darwin-arm64@1.73.0': + '@oxlint/binding-darwin-arm64@1.77.0': optional: true - '@oxlint/binding-darwin-x64@1.73.0': + '@oxlint/binding-darwin-x64@1.77.0': optional: true - '@oxlint/binding-freebsd-x64@1.73.0': + '@oxlint/binding-freebsd-x64@1.77.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.73.0': + '@oxlint/binding-linux-arm-gnueabihf@1.77.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.73.0': + '@oxlint/binding-linux-arm-musleabihf@1.77.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.73.0': + '@oxlint/binding-linux-arm64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.73.0': + '@oxlint/binding-linux-arm64-musl@1.77.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.73.0': + '@oxlint/binding-linux-ppc64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.73.0': + '@oxlint/binding-linux-riscv64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.73.0': + '@oxlint/binding-linux-riscv64-musl@1.77.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.73.0': + '@oxlint/binding-linux-s390x-gnu@1.77.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.73.0': + '@oxlint/binding-linux-x64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-x64-musl@1.73.0': + '@oxlint/binding-linux-x64-musl@1.77.0': optional: true - '@oxlint/binding-openharmony-arm64@1.73.0': + '@oxlint/binding-openharmony-arm64@1.77.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.73.0': + '@oxlint/binding-win32-arm64-msvc@1.77.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.73.0': + '@oxlint/binding-win32-ia32-msvc@1.77.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.73.0': + '@oxlint/binding-win32-x64-msvc@1.77.0': optional: true '@pinojs/redact@0.4.0': {} @@ -4015,7 +4022,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -5238,27 +5245,27 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.57.0 '@oxfmt/binding-win32-x64-msvc': 0.57.0 - oxlint@1.73.0: + oxlint@1.77.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.73.0 - '@oxlint/binding-android-arm64': 1.73.0 - '@oxlint/binding-darwin-arm64': 1.73.0 - '@oxlint/binding-darwin-x64': 1.73.0 - '@oxlint/binding-freebsd-x64': 1.73.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.73.0 - '@oxlint/binding-linux-arm-musleabihf': 1.73.0 - '@oxlint/binding-linux-arm64-gnu': 1.73.0 - '@oxlint/binding-linux-arm64-musl': 1.73.0 - '@oxlint/binding-linux-ppc64-gnu': 1.73.0 - '@oxlint/binding-linux-riscv64-gnu': 1.73.0 - '@oxlint/binding-linux-riscv64-musl': 1.73.0 - '@oxlint/binding-linux-s390x-gnu': 1.73.0 - '@oxlint/binding-linux-x64-gnu': 1.73.0 - '@oxlint/binding-linux-x64-musl': 1.73.0 - '@oxlint/binding-openharmony-arm64': 1.73.0 - '@oxlint/binding-win32-arm64-msvc': 1.73.0 - '@oxlint/binding-win32-ia32-msvc': 1.73.0 - '@oxlint/binding-win32-x64-msvc': 1.73.0 + '@oxlint/binding-android-arm-eabi': 1.77.0 + '@oxlint/binding-android-arm64': 1.77.0 + '@oxlint/binding-darwin-arm64': 1.77.0 + '@oxlint/binding-darwin-x64': 1.77.0 + '@oxlint/binding-freebsd-x64': 1.77.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.77.0 + '@oxlint/binding-linux-arm-musleabihf': 1.77.0 + '@oxlint/binding-linux-arm64-gnu': 1.77.0 + '@oxlint/binding-linux-arm64-musl': 1.77.0 + '@oxlint/binding-linux-ppc64-gnu': 1.77.0 + '@oxlint/binding-linux-riscv64-gnu': 1.77.0 + '@oxlint/binding-linux-riscv64-musl': 1.77.0 + '@oxlint/binding-linux-s390x-gnu': 1.77.0 + '@oxlint/binding-linux-x64-gnu': 1.77.0 + '@oxlint/binding-linux-x64-musl': 1.77.0 + '@oxlint/binding-openharmony-arm64': 1.77.0 + '@oxlint/binding-win32-arm64-msvc': 1.77.0 + '@oxlint/binding-win32-ia32-msvc': 1.77.0 + '@oxlint/binding-win32-x64-msvc': 1.77.0 p-filter@2.1.0: dependencies: From ccd80c615482b83fc29f3f0b2ad4f951be3ba76c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 02:33:24 +0000 Subject: [PATCH 22/39] chore(deps-dev): bump @changesets/cli from 2.31.0 to 2.31.1 Bumps [@changesets/cli](https://github.com/changesets/changesets) from 2.31.0 to 2.31.1. - [Release notes](https://github.com/changesets/changesets/releases) - [Commits](https://github.com/changesets/changesets/compare/@changesets/cli@2.31.0...@changesets/cli@2.31.1) --- updated-dependencies: - dependency-name: "@changesets/cli" dependency-version: 2.31.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 96 +++++++++++++++++++++++++------------------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index f60ba5bd..b4ee45f3 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "stringify": "pnpm --filter @be-music/stringifier run dev" }, "devDependencies": { - "@changesets/cli": "^2.31.0", + "@changesets/cli": "^2.31.1", "@types/node": "^25.9.1", "@vitest/coverage-v8": "^4.1.10", "oxfmt": "^0.57.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c6d360d..ff331cd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: devDependencies: '@changesets/cli': - specifier: ^2.31.0 - version: 2.31.0(@types/node@25.9.1) + specifier: ^2.31.1 + version: 2.31.1(@types/node@25.9.1) '@types/node': specifier: ^25.9.1 version: 25.9.1 @@ -336,8 +336,8 @@ packages: engines: {node: ^22.18.0 || >=24.11.0} hasBin: true - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} '@babel/types@7.29.0': @@ -361,8 +361,8 @@ packages: '@changesets/changelog-git@0.2.1': resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} - '@changesets/cli@2.31.0': - resolution: {integrity: sha512-AhI4enNTgHu2IZr6K4WZyf0EPch4XVMn1yOMFmCD9gsfBGqMYaHXls5HyDv6/CL5axVQABz68eG30eCtbr2wFg==} + '@changesets/cli@2.31.1': + resolution: {integrity: sha512-uO05WTcRBwuVOJVSW8Cmpqw6q0WDL53ajGCMyszutvOe5toOnunbpM4jZzf+qxBOz7i0AzopZ8diBuewjmF40w==} hasBin: true '@changesets/config@3.1.4': @@ -847,6 +847,13 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.2.2': + resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1889,8 +1896,8 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chardet@2.1.1: - resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + chardet@2.2.0: + resolution: {integrity: sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==} cipher-base@1.0.7: resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} @@ -2225,12 +2232,12 @@ packages: https-browserify@1.0.0: resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} - human-id@4.1.3: - resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + human-id@4.2.0: + resolution: {integrity: sha512-K3GbkIWqyvvlpfhBPlbEvD97TtqBpAYA4kt+cn2lD2x2HuohzZCibcA2nOlnJT6exqvJLggoB5nv2dNf192nEA==} hasBin: true - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} ieee754@1.2.1: @@ -2341,12 +2348,12 @@ packages: js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + js-yaml@3.15.1: + resolution: {integrity: sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==} hasBin: true - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true jsesc@3.1.0: @@ -2867,11 +2874,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -3321,7 +3323,7 @@ snapshots: dependencies: '@babel/types': 8.0.0 - '@babel/runtime@7.29.2': {} + '@babel/runtime@7.29.7': {} '@babel/types@7.29.0': dependencies: @@ -3349,7 +3351,7 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.5 '@changesets/assemble-release-plan@6.0.10': dependencies: @@ -3358,13 +3360,13 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 - semver: 7.7.4 + semver: 7.8.5 '@changesets/changelog-git@0.2.1': dependencies: '@changesets/types': 6.1.0 - '@changesets/cli@2.31.0(@types/node@25.9.1)': + '@changesets/cli@2.31.1(@types/node@25.9.1)': dependencies: '@changesets/apply-release-plan': 7.1.1 '@changesets/assemble-release-plan': 6.0.10 @@ -3389,7 +3391,7 @@ snapshots: package-manager-detector: 0.2.11 picocolors: 1.1.1 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.5 spawndamnit: 3.0.1 term-size: 2.2.1 transitivePeerDependencies: @@ -3415,7 +3417,7 @@ snapshots: '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.7.4 + semver: 7.8.5 '@changesets/get-release-plan@4.0.16': dependencies: @@ -3443,7 +3445,7 @@ snapshots: '@changesets/parse@0.4.3': dependencies: '@changesets/types': 6.1.0 - js-yaml: 4.1.1 + js-yaml: 4.3.1 '@changesets/pre@2.0.2': dependencies: @@ -3475,7 +3477,7 @@ snapshots: dependencies: '@changesets/types': 6.1.0 fs-extra: 7.0.1 - human-id: 4.1.3 + human-id: 4.2.0 prettier: 2.8.8 '@cloudflare/kv-asset-handler@0.5.0': {} @@ -3734,8 +3736,8 @@ snapshots: '@inquirer/external-editor@1.0.3(@types/node@25.9.1)': dependencies: - chardet: 2.1.1 - iconv-lite: 0.7.2 + chardet: 2.2.0 + iconv-lite: 0.7.3 optionalDependencies: '@types/node': 25.9.1 @@ -3760,31 +3762,31 @@ snapshots: '@manypkg/find-root@1.1.0': dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 '@manypkg/get-packages@1.1.3': dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 globby: 11.1.0 read-yaml-file: 1.1.0 - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.3 optional: true @@ -4015,7 +4017,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -4494,7 +4496,7 @@ snapshots: chai@6.2.2: {} - chardet@2.1.1: {} + chardet@2.2.0: {} cipher-base@1.0.7: dependencies: @@ -4882,9 +4884,9 @@ snapshots: https-browserify@1.0.0: {} - human-id@4.1.3: {} + human-id@4.2.0: {} - iconv-lite@0.7.2: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 @@ -4980,12 +4982,12 @@ snapshots: js-tokens@10.0.0: {} - js-yaml@3.14.2: + js-yaml@3.15.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - js-yaml@4.1.1: + js-yaml@4.3.1: dependencies: argparse: 2.0.1 @@ -5430,7 +5432,7 @@ snapshots: read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 - js-yaml: 3.14.2 + js-yaml: 3.15.1 pify: 4.0.1 strip-bom: 3.0.0 @@ -5587,8 +5589,6 @@ snapshots: safer-buffer@2.1.2: {} - semver@7.7.4: {} - semver@7.8.5: {} set-function-length@1.2.2: From d6f3c7437130c8ca7de8288140c701b9ff2bf773 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 02:33:36 +0000 Subject: [PATCH 23/39] chore(deps-dev): bump tsx from 4.23.0 to 4.23.8 Bumps [tsx](https://github.com/privatenumber/tsx) from 4.23.0 to 4.23.8. - [Release notes](https://github.com/privatenumber/tsx/releases) - [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs) - [Commits](https://github.com/privatenumber/tsx/compare/v4.23.0...v4.23.8) --- updated-dependencies: - dependency-name: tsx dependency-version: 4.23.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 337 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 307 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index f60ba5bd..ccdd0488 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "rimraf": "^6.0.1", "tinybench": "^6.0.2", "tsdown": "^0.22.3", - "tsx": "^4.23.0", + "tsx": "^4.23.8", "typescript": "7.0.1-rc", "vite": "^8.1.3", "vitest": "^4.1.10" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c6d360d..838675f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,19 +31,19 @@ importers: version: 6.0.2 tsdown: specifier: ^0.22.3 - version: 0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37) + version: 0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37) tsx: - specifier: ^4.23.0 - version: 4.23.0 + specifier: ^4.23.8 + version: 4.23.8 typescript: specifier: 7.0.1-rc version: 7.0.1-rc vite: specifier: ^8.1.3 - version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) packages/audio-renderer: dependencies: @@ -272,10 +272,10 @@ importers: version: 3.0.2 vite: specifier: ^8.1.3 - version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) vite-plugin-node-polyfills: specifier: ^0.28.0 - version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) wrangler: specifier: ^4.107.0 version: 4.107.0(@cloudflare/workers-types@5.20260707.1) @@ -484,156 +484,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.28.1': resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.28.1': resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.28.1': resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.28.1': resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.28.1': resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.28.1': resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.28.1': resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.28.1': resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.28.1': resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.28.1': resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.28.1': resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.28.1': resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.28.1': resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.28.1': resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.28.1': resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.28.1': resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.28.1': resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.28.1': resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.28.1': resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.28.1': resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.28.1': resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.28.1': resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.28.1': resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.28.1': resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.28.1': resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eshaz/web-worker@1.2.2': resolution: {integrity: sha512-WxXiHFmD9u/owrzempiDlBB1ZYqiLnm9s6aPc8AlFQalq2tKmqdmMr9GXOupDgzXtqnBipj8Un0gkIm7Sjf8mw==} @@ -847,6 +1003,13 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.2.2': + resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2041,6 +2204,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -3085,8 +3253,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.23.0: - resolution: {integrity: sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==} + tsx@4.23.8: + resolution: {integrity: sha512-8W675THjbzfFmLOQzjDBIBna+WjqMGIxmSZ1mMc1+o9qoVsEuAgQu5j5ueLhau8inOkDu9OslVg0FmfBs1RIHw==} engines: {node: '>=18.0.0'} hasBin: true @@ -3547,81 +3715,159 @@ snapshots: '@esbuild/aix-ppc64@0.28.1': optional: true + '@esbuild/aix-ppc64@0.28.2': + optional: true + '@esbuild/android-arm64@0.28.1': optional: true + '@esbuild/android-arm64@0.28.2': + optional: true + '@esbuild/android-arm@0.28.1': optional: true + '@esbuild/android-arm@0.28.2': + optional: true + '@esbuild/android-x64@0.28.1': optional: true + '@esbuild/android-x64@0.28.2': + optional: true + '@esbuild/darwin-arm64@0.28.1': optional: true + '@esbuild/darwin-arm64@0.28.2': + optional: true + '@esbuild/darwin-x64@0.28.1': optional: true + '@esbuild/darwin-x64@0.28.2': + optional: true + '@esbuild/freebsd-arm64@0.28.1': optional: true + '@esbuild/freebsd-arm64@0.28.2': + optional: true + '@esbuild/freebsd-x64@0.28.1': optional: true + '@esbuild/freebsd-x64@0.28.2': + optional: true + '@esbuild/linux-arm64@0.28.1': optional: true + '@esbuild/linux-arm64@0.28.2': + optional: true + '@esbuild/linux-arm@0.28.1': optional: true + '@esbuild/linux-arm@0.28.2': + optional: true + '@esbuild/linux-ia32@0.28.1': optional: true + '@esbuild/linux-ia32@0.28.2': + optional: true + '@esbuild/linux-loong64@0.28.1': optional: true + '@esbuild/linux-loong64@0.28.2': + optional: true + '@esbuild/linux-mips64el@0.28.1': optional: true + '@esbuild/linux-mips64el@0.28.2': + optional: true + '@esbuild/linux-ppc64@0.28.1': optional: true + '@esbuild/linux-ppc64@0.28.2': + optional: true + '@esbuild/linux-riscv64@0.28.1': optional: true + '@esbuild/linux-riscv64@0.28.2': + optional: true + '@esbuild/linux-s390x@0.28.1': optional: true + '@esbuild/linux-s390x@0.28.2': + optional: true + '@esbuild/linux-x64@0.28.1': optional: true + '@esbuild/linux-x64@0.28.2': + optional: true + '@esbuild/netbsd-arm64@0.28.1': optional: true + '@esbuild/netbsd-arm64@0.28.2': + optional: true + '@esbuild/netbsd-x64@0.28.1': optional: true + '@esbuild/netbsd-x64@0.28.2': + optional: true + '@esbuild/openbsd-arm64@0.28.1': optional: true + '@esbuild/openbsd-arm64@0.28.2': + optional: true + '@esbuild/openbsd-x64@0.28.1': optional: true + '@esbuild/openbsd-x64@0.28.2': + optional: true + '@esbuild/openharmony-arm64@0.28.1': optional: true + '@esbuild/openharmony-arm64@0.28.2': + optional: true + '@esbuild/sunos-x64@0.28.1': optional: true + '@esbuild/sunos-x64@0.28.2': + optional: true + '@esbuild/win32-arm64@0.28.1': optional: true + '@esbuild/win32-arm64@0.28.2': + optional: true + '@esbuild/win32-ia32@0.28.1': optional: true + '@esbuild/win32-ia32@0.28.2': + optional: true + '@esbuild/win32-x64@0.28.1': optional: true + '@esbuild/win32-x64@0.28.2': + optional: true + '@eshaz/web-worker@1.2.2': {} '@ffmpeg/core-mt@0.12.10': {} @@ -3774,17 +4020,17 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.3 optional: true @@ -4015,7 +4261,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -4275,7 +4521,7 @@ snapshots: obug: 2.1.3 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) '@vitest/expect@4.1.10': dependencies: @@ -4286,13 +4532,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0))': + '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) '@vitest/pretty-format@4.1.10': dependencies: @@ -4679,6 +4925,35 @@ snapshots: '@esbuild/win32-ia32': 0.28.1 '@esbuild/win32-x64': 0.28.1 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + esprima@4.0.1: {} estree-walker@2.0.2: {} @@ -5788,7 +6063,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.0)(typescript@7.0.1-rc)(unrun@0.2.37): + tsdown@0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -5806,7 +6081,7 @@ snapshots: tree-kill: 1.2.2 unconfig-core: 7.5.0 optionalDependencies: - tsx: 4.23.0 + tsx: 4.23.8 typescript: 7.0.1-rc unrun: 0.2.37 transitivePeerDependencies: @@ -5818,9 +6093,9 @@ snapshots: tslib@2.8.1: optional: true - tsx@4.23.0: + tsx@4.23.8: dependencies: - esbuild: 0.28.1 + esbuild: 0.28.2 optionalDependencies: fsevents: 2.3.3 @@ -5890,15 +6165,15 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.20 - vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): + vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) node-stdlib-browser: 1.3.1 - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) transitivePeerDependencies: - rollup - vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0): + vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8): dependencies: lightningcss: 1.32.0 picomatch: 4.0.5 @@ -5907,14 +6182,14 @@ snapshots: tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.9.1 - esbuild: 0.28.1 + esbuild: 0.28.2 fsevents: 2.3.3 - tsx: 4.23.0 + tsx: 4.23.8 - vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): + vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -5931,7 +6206,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.9.1 From 0c0950dad57cea396a740893a0aebe5773cbb631 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Aug 2026 07:41:22 +0000 Subject: [PATCH 24/39] chore(deps-dev): bump tsdown from 0.22.3 to 0.22.14 Bumps [tsdown](https://github.com/rolldown/tsdown) from 0.22.3 to 0.22.14. - [Release notes](https://github.com/rolldown/tsdown/releases) - [Commits](https://github.com/rolldown/tsdown/compare/v0.22.3...v0.22.14) --- updated-dependencies: - dependency-name: tsdown dependency-version: 0.22.14 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 653 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 466 insertions(+), 189 deletions(-) diff --git a/package.json b/package.json index 9937c688..54e04a2b 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "oxlint": "^1.77.0", "rimraf": "^6.0.1", "tinybench": "^6.0.2", - "tsdown": "^0.22.3", + "tsdown": "^0.22.14", "tsx": "^4.23.8", "typescript": "7.0.1-rc", "vite": "^8.1.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f88512a..409fd97a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ importers: specifier: ^6.0.2 version: 6.0.2 tsdown: - specifier: ^0.22.3 - version: 0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37) + specifier: ^0.22.14 + version: 0.22.14(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37) tsx: specifier: ^4.23.8 version: 4.23.8 @@ -306,36 +306,19 @@ importers: packages: - '@babel/generator@8.0.0': - resolution: {integrity: sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@8.0.0': - resolution: {integrity: sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-validator-identifier@7.29.7': resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@8.0.2': - resolution: {integrity: sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/parser@7.29.0': resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@8.0.0': - resolution: {integrity: sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==} - engines: {node: ^22.18.0 || >=24.11.0} - hasBin: true - '@babel/runtime@7.29.7': resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} @@ -344,10 +327,6 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@8.0.0': - resolution: {integrity: sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==} - engines: {node: ^22.18.0 || >=24.11.0} - '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -975,9 +954,6 @@ packages: '@types/node': optional: true - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1028,6 +1004,9 @@ packages: '@oxc-project/types@0.138.0': resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} + '@oxc-project/types@0.143.0': + resolution: {integrity: sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==} + '@oxfmt/binding-android-arm-eabi@0.57.0': resolution: {integrity: sha512-qVBsEO+KugOsCmUHcO8iqNnqc65p7PCKpCs8M66mPZ+Ri+CWbcpoQOEJBg2OTu03+0qu++NK1jj6IzvQVs0Sig==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1302,6 +1281,12 @@ packages: cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.2.3': + resolution: {integrity: sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1314,6 +1299,12 @@ packages: cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.2.3': + resolution: {integrity: sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.17': resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1326,6 +1317,12 @@ packages: cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.2.3': + resolution: {integrity: sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1338,6 +1335,12 @@ packages: cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.2.3': + resolution: {integrity: sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1350,6 +1353,12 @@ packages: cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.2.3': + resolution: {integrity: sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1364,6 +1373,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.2.3': + resolution: {integrity: sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1378,6 +1394,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.2.3': + resolution: {integrity: sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1392,6 +1415,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.2.3': + resolution: {integrity: sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1406,6 +1436,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.3': + resolution: {integrity: sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1420,6 +1457,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.3': + resolution: {integrity: sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1434,6 +1478,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.2.3': + resolution: {integrity: sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1446,6 +1497,12 @@ packages: cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.2.3': + resolution: {integrity: sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1468,6 +1525,12 @@ packages: cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.2.3': + resolution: {integrity: sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1480,6 +1543,12 @@ packages: cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.3': + resolution: {integrity: sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} @@ -1673,9 +1742,6 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - '@types/jsesc@2.5.1': - resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} - '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} @@ -1685,53 +1751,6 @@ packages: '@types/wicg-file-system-access@2020.9.8': resolution: {integrity: sha512-ggMz8nOygG7d/stpH40WVaNvBwuyYLnrg5Mbyf6bmsj/8+gb6Ei4ZZ9/4PNpcPNTT8th9Q8sM8wYmWGjMWLX/A==} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-znTFp/M0SpN91/FM3FrsTycdTZr+bLszmHObm2LaR5sgo1c2wiK4qYsMnrhLeP0vSMD2LuiNg5J21501h7Aj6g==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [darwin] - - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-7zXTq3SVw6XCLdm06VRIhMzayG032Ky14xCZ3isnlcm1KD/p4Ev4XL9TN9fZmIV0bVPGMQr4qGS7a2+te8x7lg==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [darwin] - - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-yYiDEMT4ok7Wd1VtbyB+0YqBdTkU/yzE36edZCbfA/Ljt6L1xZMEn0a7XGlmRtRfwPGHfjtFRFsxrA2nc7jHnw==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [linux] - - '@typescript/native-preview-linux-arm@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-xpA7nXiRE3fwvTUK2ibhkPr7hn6D4i3pB9WjlcX7CSPB2pYGMdHAsL55EAFlR3eNKyNM/geoLfqq4L4PIeOWsQ==} - engines: {node: '>=16.20.0'} - cpu: [arm] - os: [linux] - - '@typescript/native-preview-linux-x64@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-mZO9hIwXek9VO+N+gs6IKDOf0fPnrQg/SvaOsCDcDwsk7a60yPbacyY7IiXFnxhNgZDLsYqs8j9ojDGl6+Tp5g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [linux] - - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-JtMTHRt7auXTCvvOtcn7aX1gdCPByQl4c5vc8e1d+8PcqtMqeSpH1j0Vp06F9vugTA+YMIzFsJQA91sUK1oHeg==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [win32] - - '@typescript/native-preview-win32-x64@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-aCZaFWHDt5n8B++F2FrTK2pF7muAFfkvi8qkUnC0N0SNBGdVnqlO28IbdjScIfI2JFOvgZtUoYWeATGWdrLXBA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [win32] - - '@typescript/native-preview@7.0.0-dev.20260613.1': - resolution: {integrity: sha512-RJ3YrYNoshFGVY862CwZ/WcICvMW0u9XtezI8AAU81I71Cr3/IJoHPUGsGKUr2gVcPfKRQiaI8YTndFzUGvSug==} - engines: {node: '>=16.20.0'} - hasBin: true - '@typescript/typescript-aix-ppc64@7.0.1-rc': resolution: {integrity: sha512-oqq2ZfEJ7BQuufcC3QBQndZLPNyamYNHLao8lKRBeeSkZKypBqxPSgkzrcFZtbYcIaBvpiyUnQP9MT7DEYHWbw==} engines: {node: '>=16.20.0'} @@ -1909,6 +1928,141 @@ packages: resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + '@yuku-codegen/binding-android-arm64@0.8.4': + resolution: {integrity: sha512-rsYkGl2kOkDRsh1mxriYnk1qBS78vjlBJ3+T2XwtwKwqOliy2n+2Ae0EDxJ/uX1DZLm3KkBZarGO5isEnmHchA==} + cpu: [arm64] + os: [android] + + '@yuku-codegen/binding-darwin-arm64@0.8.4': + resolution: {integrity: sha512-tNLKzPF3FYmEcHSYvWp/LEpjHHAtDR13hwo6/gdCkYMi9x59CWn2obczKzWNe7kDor4/1AMZuJDEVRpFkTSefw==} + cpu: [arm64] + os: [darwin] + + '@yuku-codegen/binding-darwin-x64@0.8.4': + resolution: {integrity: sha512-tK7LWzXNb5JbZpnoCNHB0nEhPFss/LwwehM6m/f0oYDan+iZgFZXzdoy80JdE7dVxjTZDIhUNPx8X8xbIdaoxA==} + cpu: [x64] + os: [darwin] + + '@yuku-codegen/binding-freebsd-x64@0.8.4': + resolution: {integrity: sha512-5MUV4d7g2p5Hd8GiXW6ynTRgYjm4Dw4eM2gaWRZ4crkGetzNx+HlPxcEfGtVNPqH5Qaa4Z2REtzdsdgvaE6/Ng==} + cpu: [x64] + os: [freebsd] + + '@yuku-codegen/binding-linux-arm-gnu@0.8.4': + resolution: {integrity: sha512-g6LnHrR0Rfqq5cXs7olwR2+LlVDc876pw7Hh7YXbukVSiBxQkaxqsEO/trO25z2g99zWzgXwoYvQZ1TnwA2wEw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-arm-musl@0.8.4': + resolution: {integrity: sha512-7XAPHrROPEFuJWXEGZeLZQN4xR8ENQ65+HSCtCHjSzCwGgnX53GUjM9ExVcHopV0a5g4vu57v2wwtyWIM5iNOQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-linux-arm64-gnu@0.8.4': + resolution: {integrity: sha512-fnBm7NLuuwFXy7F1vRIuyOc+RW9ADUjuCKVGY87Dj8jtr9XgESNrwb+B9VLSFY7nZ0rCdK/Sm1fBqJpI7eLdKQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-arm64-musl@0.8.4': + resolution: {integrity: sha512-6vTw4ZHO9nm4SUkw36uG+UE6/qifZ0E8HIef7Mx/U/c2Zxu3JLBfXtU7U/NN2GMkDmcJkgwjXfpQoYw4Ch5Y1w==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-linux-x64-gnu@0.8.4': + resolution: {integrity: sha512-+vuC3V3Lw+DB4oJgHV9pVDfQZlsZJnxmbdods7HzxgEALU3P5+czwdAcw3wfh7Ebabt0Ny8eLUb1k9RV5OB/+w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-x64-musl@0.8.4': + resolution: {integrity: sha512-QH60PE4eZecmgNGa1/T1cKPhrfxt6ANtu4lrQ1FZ50F9b0GS9WjGmIjrfdSUeQa+f2Iqk3oEFSJdgVHBg1KPNg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-win32-arm64@0.8.4': + resolution: {integrity: sha512-6r68c0nKZPIBRXZIBiD7zjlEukBR+xRxpTOVj4n1Fsjcdh4YbbJfjFfmIzdbo9jXR1xL+dPueDVdsRGOUH5MoQ==} + cpu: [arm64] + os: [win32] + + '@yuku-codegen/binding-win32-x64@0.8.4': + resolution: {integrity: sha512-i+BW77LPjNqe7Apq50J3OeEaVfga3G+eT2bKjb6bj4yO99fil/jnKb4ZDH4JLvby/Q7hRa6VicL2EZ7iS+ifzA==} + cpu: [x64] + os: [win32] + + '@yuku-parser/binding-android-arm64@0.8.4': + resolution: {integrity: sha512-+HIMmv08Zrh9ugIAEMnKBMMePOl7CDxrjc8Vui1+GG2TJHM1yI1+3wo1pnXB6Nj2IiHugDkQw8ycUI6SA2EUkQ==} + cpu: [arm64] + os: [android] + + '@yuku-parser/binding-darwin-arm64@0.8.4': + resolution: {integrity: sha512-Elf/B/2m3OsyvxoQnBk8Dtu+9csHkzBNs5Yv9GbHjT3x0kVKNWjFusyZgm41VwxcPDqdpRi8tWxNX7OqXkmf/A==} + cpu: [arm64] + os: [darwin] + + '@yuku-parser/binding-darwin-x64@0.8.4': + resolution: {integrity: sha512-CjZuMoXnL5XUkVpDqh4WDPwpAw8CwmtHHnTerGkS45So/sNuwkXdyIAEqqIZfaLopi5W/V9NApAT2md9XizjsQ==} + cpu: [x64] + os: [darwin] + + '@yuku-parser/binding-freebsd-x64@0.8.4': + resolution: {integrity: sha512-ibLKORdz71iI4Vs+fyFgvwQ51P5XcxJIyQLa8cSEWqwptRdo+BTcZHIQEcZnFDPUuvmJ19RRH9CoiJdfhr7pZw==} + cpu: [x64] + os: [freebsd] + + '@yuku-parser/binding-linux-arm-gnu@0.8.4': + resolution: {integrity: sha512-Fo3r5fYhGDcFnl+KN+L9PgtiQPS4AIE1n1mG1o5jZ11p7g5yZ/1EjLFmSHAUsoXreun8KjTsFjEL7P1Sb93PZQ==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-arm-musl@0.8.4': + resolution: {integrity: sha512-BEB31vUEgXPWf7WkoMPSzzJhpC/wWCBXyysRCCPsw47BJ/OtbQsvJbxX9fFDuSRLy3kbyIV/WbdUTgbQ9COxiw==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-linux-arm64-gnu@0.8.4': + resolution: {integrity: sha512-xGLCRcHn9xVz7JVNyyKtiNJSf503qtUmih9XVSsghgzOmiKUMnHObs69OMMwXN3788tg1jsl11fNjjQlB8idMA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-arm64-musl@0.8.4': + resolution: {integrity: sha512-3kNRi8NJT2q6FQRVCUFHIQ99+kXdi8cVJEEUi6+xtFqpMgNrZNnbgAj28ILsDC7zmclaU+v47eUCeJoKLSCbww==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-linux-x64-gnu@0.8.4': + resolution: {integrity: sha512-isi62oMy94Z3OXwGs2l2rkqRiRyqLmfHeTRHpA/uWZbsNhnm7IdVvkF7e7wHNKAtd5jwGzOqYSroxKv2fOm7Cw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-x64-musl@0.8.4': + resolution: {integrity: sha512-9RsEw2xYHqU/pjSRBTOupWN3sF8uz9stjJdARfz6o0llvF+yfrj5QHmTiocGGBeAI80fvKmDtr2RIQClUzAPcA==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-win32-arm64@0.8.4': + resolution: {integrity: sha512-VEZHo9rEGOBKR20sA3vCO00aQvwWND5aLu7YxeX+YupMZJh9hd1f17AbClJN37Q2iL1PCHht+wDTOKX6tZYqXg==} + cpu: [arm64] + os: [win32] + + '@yuku-parser/binding-win32-x64@0.8.4': + resolution: {integrity: sha512-PeH3VzN1feGjPtDpVEAqf000fPT+nxtw/696LKp/5Z9RJi/MaXpB636QC+5QtrAPSoEnIkyEe+c+mq2QLZPWBA==} + cpu: [x64] + os: [win32] + + '@yuku-toolchain/types@0.8.4': + resolution: {integrity: sha512-p7JE8flrj7ijZ/qLjHi4UwKqMarMD6zumbKXhrjp2I2iLJOuTYiQyci2U36VlXcUlNyzsY7E/mLnKCHotbzJVw==} + alien-signals@3.2.1: resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} @@ -1944,10 +2098,6 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-kit@3.0.0: - resolution: {integrity: sha512-8OG92q3R35qjC/4i6BLBMg8IB+fClWu/1PEwg2Z9Rn+BuNaiEgJzpzn+pxWOdHJWDCAwu2JP0wCDTozAM4QirQ==} - engines: {node: ^22.18.0 || >=24.11.0} - ast-v8-to-istanbul@1.0.4: resolution: {integrity: sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==} @@ -1970,9 +2120,6 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} - birpc@4.0.0: - resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} - blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} @@ -2517,11 +2664,6 @@ packages: resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -2728,6 +2870,10 @@ packages: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} + engines: {node: '>=12.20.0'} + ogg-opus-decoder@1.7.3: resolution: {integrity: sha512-w47tiZpkLgdkpa+34VzYD8mHUj8I9kfWVZa82mBbNwDvB1byfLXSSzW/HxA4fI3e9kVlICSpXGFwMLV1LPdjwg==} @@ -2981,20 +3127,20 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} - rolldown-plugin-dts@0.26.0: - resolution: {integrity: sha512-e+kEPtUiDES0htk5iqkSeF4EzAV7R+vugGB44iPDuw1Kw9E+WyL1VG7PaV0IIjGHLiacztMBcMTyrr8ON9CT1Q==} + rolldown-plugin-dts@0.27.14: + resolution: {integrity: sha512-ZvuDDwoIpRK9RPxDXratCpklFO9QZZWndf/sd0VBFb4LEj0jj07UcHK9OCh7V4XiFz2Z89ziyBC2K6tJiDjrbw==} engines: {node: ^22.18.0 || >=24.11.0} peerDependencies: - '@ts-macro/tsc': ^0.3.6 - '@typescript/native-preview': '>=7.0.0-dev.20260325.1' + '@typescript/native-preview': '*' + '@volar/typescript': ~2.4.0 rolldown: ^1.0.0 - typescript: ^5.0.0 || ^6.0.0 + typescript: ^5.0.0 || ^6.0.0 || ~7.0.0 vue-tsc: ~3.2.0 || ~3.3.0 peerDependenciesMeta: - '@ts-macro/tsc': - optional: true '@typescript/native-preview': optional: true + '@volar/typescript': + optional: true typescript: optional: true vue-tsc: @@ -3010,6 +3156,11 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rolldown@1.2.3: + resolution: {integrity: sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.59.0: resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -3179,6 +3330,10 @@ packages: resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -3211,18 +3366,18 @@ packages: resolution: {integrity: sha512-Br6DA/YbdpsiSQjc0KaF3ASQtkk3MCiA4q5kIA7ptv6adZa/MdYa2TXAXF2bAzRZIMWfyFEC9Gicr3nb51MgDA==} hasBin: true - tsdown@0.22.3: - resolution: {integrity: sha512-louqbfA8Qf//B9jTTL0FPtXTNpjCWv1VPkbcmQMph2pTpzs+LnB1tbe4tDDRVpo2BjF5SgUXaTZe45SxB8pWHg==} + tsdown@0.22.14: + resolution: {integrity: sha512-ule7Y+fsAN2iZbLDoo7C4KYljFJNJJ+fLshyn+9gozeTspVersWHxwdGB+Dm2hzA38s6muFnUTl0jK3vJm9ifQ==} engines: {node: ^22.18.0 || >=24.11.0} hasBin: true peerDependencies: '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.22.3 - '@tsdown/exe': 0.22.3 + '@tsdown/css': 0.22.14 + '@tsdown/exe': 0.22.14 '@vitejs/devtools': '*' publint: ^0.3.8 tsx: '*' - typescript: ^5.0.0 || ^6.0.0 + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 unplugin-unused: ^0.5.0 unrun: '*' peerDependenciesMeta: @@ -3302,6 +3457,10 @@ packages: util@0.12.5: resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + verkit@0.3.2: + resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==} + engines: {node: '>=18.12.0'} + vite-plugin-node-polyfills@0.28.0: resolution: {integrity: sha512-NXct/ci2ef4fRyCfTb8fk2HmR80Rv7icLd+cRH41TnUugDzdKMFKqFPpZYCFUInZMMem9bkLv5pkq02+7Xu7+w==} peerDependencies: @@ -3457,33 +3616,25 @@ packages: youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} -snapshots: + yuku-ast@0.8.4: + resolution: {integrity: sha512-s7EWfWIQkaGmsGnyr/BU0jli9YTN5TvrKIsSmALyRD9elumDQInuhv0BrVObENKVCxr9W3Ikmnx5u02KvfuUmw==} - '@babel/generator@8.0.0': - dependencies: - '@babel/parser': 8.0.0 - '@babel/types': 8.0.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - '@types/jsesc': 2.5.1 - jsesc: 3.1.0 + yuku-codegen@0.8.4: + resolution: {integrity: sha512-1Rw+NYcmB1xkHAWlsIpbwIv/Fr50idtEbLf7OjDA+90dny6PM4Krz7Fs0TT+w2PBdjaldZpN4ye5wR4Dhlm8vA==} - '@babel/helper-string-parser@7.27.1': {} + yuku-parser@0.8.4: + resolution: {integrity: sha512-sw41wouvT5rUmLIp87hmvm5vtF+MRSI3x6yjq6xqpYmtkQj+Ht6N7xRQ8lMhLv8N7JAzughGj0Rfi0jQRSu9HQ==} - '@babel/helper-string-parser@8.0.0': {} +snapshots: - '@babel/helper-validator-identifier@7.29.7': {} + '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@8.0.2': {} + '@babel/helper-validator-identifier@7.29.7': {} '@babel/parser@7.29.0': dependencies: '@babel/types': 7.29.0 - '@babel/parser@8.0.0': - dependencies: - '@babel/types': 8.0.0 - '@babel/runtime@7.29.7': {} '@babel/types@7.29.0': @@ -3491,11 +3642,6 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.29.7 - '@babel/types@8.0.0': - dependencies: - '@babel/helper-string-parser': 8.0.0 - '@babel/helper-validator-identifier': 8.0.2 - '@bcoe/v8-coverage@1.0.2': {} '@changesets/apply-release-plan@7.1.1': @@ -3980,11 +4126,6 @@ snapshots: optionalDependencies: '@types/node': 25.9.1 - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.5': {} @@ -4046,6 +4187,8 @@ snapshots: '@oxc-project/types@0.138.0': {} + '@oxc-project/types@0.143.0': {} + '@oxfmt/binding-android-arm-eabi@0.57.0': optional: true @@ -4186,72 +4329,108 @@ snapshots: '@rolldown/binding-android-arm64@1.1.4': optional: true + '@rolldown/binding-android-arm64@1.2.3': + optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true '@rolldown/binding-darwin-arm64@1.1.4': optional: true + '@rolldown/binding-darwin-arm64@1.2.3': + optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true '@rolldown/binding-darwin-x64@1.1.4': optional: true + '@rolldown/binding-darwin-x64@1.2.3': + optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true '@rolldown/binding-freebsd-x64@1.1.4': optional: true + '@rolldown/binding-freebsd-x64@1.2.3': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.1.4': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.3': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm64-gnu@1.1.4': optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.3': + optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm64-musl@1.1.4': optional: true + '@rolldown/binding-linux-arm64-musl@1.2.3': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-ppc64-gnu@1.1.4': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.3': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-s390x-gnu@1.1.4': optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.3': + optional: true + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-x64-gnu@1.1.4': optional: true + '@rolldown/binding-linux-x64-gnu@1.2.3': + optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true '@rolldown/binding-linux-x64-musl@1.1.4': optional: true + '@rolldown/binding-linux-x64-musl@1.2.3': + optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true '@rolldown/binding-openharmony-arm64@1.1.4': optional: true + '@rolldown/binding-openharmony-arm64@1.2.3': + optional: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': dependencies: '@emnapi/core': 1.10.0 @@ -4272,12 +4451,18 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.1.4': optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.3': + optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true '@rolldown/binding-win32-x64-msvc@1.1.4': optional: true + '@rolldown/binding-win32-x64-msvc@1.2.3': + optional: true + '@rolldown/pluginutils@1.0.0-rc.17': optional: true @@ -4400,8 +4585,6 @@ snapshots: '@types/estree@1.0.9': {} - '@types/jsesc@2.5.1': {} - '@types/node@12.20.55': {} '@types/node@25.9.1': @@ -4410,38 +4593,6 @@ snapshots: '@types/wicg-file-system-access@2020.9.8': {} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260613.1': - optional: true - - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260613.1': - optional: true - - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260613.1': - optional: true - - '@typescript/native-preview-linux-arm@7.0.0-dev.20260613.1': - optional: true - - '@typescript/native-preview-linux-x64@7.0.0-dev.20260613.1': - optional: true - - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260613.1': - optional: true - - '@typescript/native-preview-win32-x64@7.0.0-dev.20260613.1': - optional: true - - '@typescript/native-preview@7.0.0-dev.20260613.1': - optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260613.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260613.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260613.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260613.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260613.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260613.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260613.1 - optional: true - '@typescript/typescript-aix-ppc64@7.0.1-rc': optional: true @@ -4577,6 +4728,80 @@ snapshots: '@xmldom/xmldom@0.8.13': {} + '@yuku-codegen/binding-android-arm64@0.8.4': + optional: true + + '@yuku-codegen/binding-darwin-arm64@0.8.4': + optional: true + + '@yuku-codegen/binding-darwin-x64@0.8.4': + optional: true + + '@yuku-codegen/binding-freebsd-x64@0.8.4': + optional: true + + '@yuku-codegen/binding-linux-arm-gnu@0.8.4': + optional: true + + '@yuku-codegen/binding-linux-arm-musl@0.8.4': + optional: true + + '@yuku-codegen/binding-linux-arm64-gnu@0.8.4': + optional: true + + '@yuku-codegen/binding-linux-arm64-musl@0.8.4': + optional: true + + '@yuku-codegen/binding-linux-x64-gnu@0.8.4': + optional: true + + '@yuku-codegen/binding-linux-x64-musl@0.8.4': + optional: true + + '@yuku-codegen/binding-win32-arm64@0.8.4': + optional: true + + '@yuku-codegen/binding-win32-x64@0.8.4': + optional: true + + '@yuku-parser/binding-android-arm64@0.8.4': + optional: true + + '@yuku-parser/binding-darwin-arm64@0.8.4': + optional: true + + '@yuku-parser/binding-darwin-x64@0.8.4': + optional: true + + '@yuku-parser/binding-freebsd-x64@0.8.4': + optional: true + + '@yuku-parser/binding-linux-arm-gnu@0.8.4': + optional: true + + '@yuku-parser/binding-linux-arm-musl@0.8.4': + optional: true + + '@yuku-parser/binding-linux-arm64-gnu@0.8.4': + optional: true + + '@yuku-parser/binding-linux-arm64-musl@0.8.4': + optional: true + + '@yuku-parser/binding-linux-x64-gnu@0.8.4': + optional: true + + '@yuku-parser/binding-linux-x64-musl@0.8.4': + optional: true + + '@yuku-parser/binding-win32-arm64@0.8.4': + optional: true + + '@yuku-parser/binding-win32-x64@0.8.4': + optional: true + + '@yuku-toolchain/types@0.8.4': {} + alien-signals@3.2.1: {} ansi-colors@4.1.3: {} @@ -4609,12 +4834,6 @@ snapshots: assertion-error@2.0.1: {} - ast-kit@3.0.0: - dependencies: - '@babel/parser': 8.0.0 - estree-walker: 3.0.3 - pathe: 2.0.3 - ast-v8-to-istanbul@1.0.4: dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -4635,8 +4854,6 @@ snapshots: dependencies: is-windows: 1.0.2 - birpc@4.0.0: {} - blake3-wasm@2.1.5: {} bn.js@4.12.3: {} @@ -5259,8 +5476,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsesc@3.1.0: {} - jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -5467,6 +5682,8 @@ snapshots: obug@2.1.3: {} + obug@2.1.4: {} + ogg-opus-decoder@1.7.3: dependencies: '@wasm-audio-decoders/common': 9.0.7 @@ -5747,19 +5964,16 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rolldown-plugin-dts@0.26.0(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.4)(typescript@7.0.1-rc): + rolldown-plugin-dts@0.27.14(rolldown@1.2.3)(typescript@7.0.1-rc): dependencies: - '@babel/generator': 8.0.0 - '@babel/helper-validator-identifier': 8.0.2 - '@babel/parser': 8.0.0 - ast-kit: 3.0.0 - birpc: 4.0.0 dts-resolver: 3.0.0 get-tsconfig: 5.0.0-beta.5 - obug: 2.1.3 - rolldown: 1.1.4 + obug: 2.1.4 + rolldown: 1.2.3 + yuku-ast: 0.8.4 + yuku-codegen: 0.8.4 + yuku-parser: 0.8.4 optionalDependencies: - '@typescript/native-preview': 7.0.0-dev.20260613.1 typescript: 7.0.1-rc transitivePeerDependencies: - oxc-resolver @@ -5807,6 +6021,26 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.1.4 '@rolldown/binding-win32-x64-msvc': 1.1.4 + rolldown@1.2.3: + dependencies: + '@oxc-project/types': 0.143.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.2.3 + '@rolldown/binding-darwin-arm64': 1.2.3 + '@rolldown/binding-darwin-x64': 1.2.3 + '@rolldown/binding-freebsd-x64': 1.2.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.3 + '@rolldown/binding-linux-arm64-gnu': 1.2.3 + '@rolldown/binding-linux-arm64-musl': 1.2.3 + '@rolldown/binding-linux-ppc64-gnu': 1.2.3 + '@rolldown/binding-linux-s390x-gnu': 1.2.3 + '@rolldown/binding-linux-x64-gnu': 1.2.3 + '@rolldown/binding-linux-x64-musl': 1.2.3 + '@rolldown/binding-openharmony-arm64': 1.2.3 + '@rolldown/binding-win32-arm64-msvc': 1.2.3 + '@rolldown/binding-win32-x64-msvc': 1.2.3 + rollup@4.59.0: dependencies: '@types/estree': 1.0.8 @@ -6022,6 +6256,8 @@ snapshots: tinyexec@1.2.4: {} + tinyexec@1.3.0: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) @@ -6056,7 +6292,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.3(@typescript/native-preview@7.0.0-dev.20260613.1)(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37): + tsdown@0.22.14(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -6064,22 +6300,22 @@ snapshots: empathic: 2.0.1 hookable: 6.1.1 import-without-cache: 0.4.0 - obug: 2.1.3 - picomatch: 4.0.4 - rolldown: 1.1.4 - rolldown-plugin-dts: 0.26.0(@typescript/native-preview@7.0.0-dev.20260613.1)(rolldown@1.1.4)(typescript@7.0.1-rc) - semver: 7.8.5 - tinyexec: 1.2.4 + obug: 2.1.4 + picomatch: 4.0.5 + rolldown: 1.2.3 + rolldown-plugin-dts: 0.27.14(rolldown@1.2.3)(typescript@7.0.1-rc) + tinyexec: 1.3.0 tinyglobby: 0.2.17 tree-kill: 1.2.2 unconfig-core: 7.5.0 + verkit: 0.3.2 optionalDependencies: tsx: 4.23.8 typescript: 7.0.1-rc unrun: 0.2.37 transitivePeerDependencies: - - '@ts-macro/tsc' - '@typescript/native-preview' + - '@volar/typescript' - oxc-resolver - vue-tsc @@ -6158,6 +6394,8 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.20 + verkit@0.3.2: {} + vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) @@ -6275,3 +6513,42 @@ snapshots: '@speed-highlight/core': 1.2.17 cookie: 1.1.1 youch-core: 0.3.3 + + yuku-ast@0.8.4: + dependencies: + '@yuku-toolchain/types': 0.8.4 + + yuku-codegen@0.8.4: + dependencies: + '@yuku-toolchain/types': 0.8.4 + optionalDependencies: + '@yuku-codegen/binding-android-arm64': 0.8.4 + '@yuku-codegen/binding-darwin-arm64': 0.8.4 + '@yuku-codegen/binding-darwin-x64': 0.8.4 + '@yuku-codegen/binding-freebsd-x64': 0.8.4 + '@yuku-codegen/binding-linux-arm-gnu': 0.8.4 + '@yuku-codegen/binding-linux-arm-musl': 0.8.4 + '@yuku-codegen/binding-linux-arm64-gnu': 0.8.4 + '@yuku-codegen/binding-linux-arm64-musl': 0.8.4 + '@yuku-codegen/binding-linux-x64-gnu': 0.8.4 + '@yuku-codegen/binding-linux-x64-musl': 0.8.4 + '@yuku-codegen/binding-win32-arm64': 0.8.4 + '@yuku-codegen/binding-win32-x64': 0.8.4 + + yuku-parser@0.8.4: + dependencies: + '@yuku-toolchain/types': 0.8.4 + yuku-ast: 0.8.4 + optionalDependencies: + '@yuku-parser/binding-android-arm64': 0.8.4 + '@yuku-parser/binding-darwin-arm64': 0.8.4 + '@yuku-parser/binding-darwin-x64': 0.8.4 + '@yuku-parser/binding-freebsd-x64': 0.8.4 + '@yuku-parser/binding-linux-arm-gnu': 0.8.4 + '@yuku-parser/binding-linux-arm-musl': 0.8.4 + '@yuku-parser/binding-linux-arm64-gnu': 0.8.4 + '@yuku-parser/binding-linux-arm64-musl': 0.8.4 + '@yuku-parser/binding-linux-x64-gnu': 0.8.4 + '@yuku-parser/binding-linux-x64-musl': 0.8.4 + '@yuku-parser/binding-win32-arm64': 0.8.4 + '@yuku-parser/binding-win32-x64': 0.8.4 From 4273cb02257b98daf81aac3d1cffee03d0268d15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 02:33:19 +0000 Subject: [PATCH 25/39] chore(deps): bump node-web-audio-api from 2.1.0 to 2.2.0 Bumps [node-web-audio-api](https://github.com/ircam-ismm/node-web-audio-api) from 2.1.0 to 2.2.0. - [Changelog](https://github.com/ircam-ismm/node-web-audio-api/blob/main/CHANGELOG.md) - [Commits](https://github.com/ircam-ismm/node-web-audio-api/compare/v2.1.0...v2.2.0) --- updated-dependencies: - dependency-name: node-web-audio-api dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/player/package.json | 2 +- pnpm-lock.yaml | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/player/package.json b/packages/player/package.json index 97c75b41..8416ec39 100644 --- a/packages/player/package.json +++ b/packages/player/package.json @@ -124,6 +124,6 @@ "@be-music/parser": "workspace:*", "@be-music/utils": "workspace:*", "alien-signals": "^3.2.1", - "node-web-audio-api": "^2.1.0" + "node-web-audio-api": "^2.2.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 409fd97a..4bab9216 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -156,8 +156,8 @@ importers: specifier: ^3.2.1 version: 3.2.1 node-web-audio-api: - specifier: ^2.1.0 - version: 2.1.0 + specifier: ^2.2.0 + version: 2.2.0 packages/player-tui: dependencies: @@ -979,12 +979,12 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.2.2': - resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -1927,6 +1927,7 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@yuku-codegen/binding-android-arm64@0.8.4': resolution: {integrity: sha512-rsYkGl2kOkDRsh1mxriYnk1qBS78vjlBJ3+T2XwtwKwqOliy2n+2Ae0EDxJ/uX1DZLm3KkBZarGO5isEnmHchA==} @@ -2846,8 +2847,8 @@ packages: resolution: {integrity: sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==} engines: {node: '>=10'} - node-web-audio-api@2.1.0: - resolution: {integrity: sha512-5aI3ciSs60HlyybHJzPyf8smok8gH9c0Q6n1gjDQGJqcJLafjlPfn78gIkOljVXlS/8l/et3nUQyofsuzf9Tyw==} + node-web-audio-api@2.2.0: + resolution: {integrity: sha512-qM3dW3Z5HIz+O+++Uiia8x0OSNHcfJGUlexpCTdAkw8JlM17Ru1nV9a94wlxNRXqxT0Lr/ewwEnBXUwGMt24AA==} engines: {node: '>= 22'} object-inspect@1.13.4: @@ -4163,7 +4164,7 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 @@ -4435,7 +4436,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -5656,7 +5657,7 @@ snapshots: util: 0.12.5 vm-browserify: 1.1.2 - node-web-audio-api@2.1.0: + node-web-audio-api@2.2.0: dependencies: caller: 1.1.0 node-fetch: 3.3.2 From 95d3f927fc28ff0a0b4a7d4c439f67a640a59292 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 02:33:45 +0000 Subject: [PATCH 26/39] chore(deps-dev): bump tsx from 4.23.8 to 4.23.12 Bumps [tsx](https://github.com/privatenumber/tsx) from 4.23.8 to 4.23.12. - [Release notes](https://github.com/privatenumber/tsx/releases) - [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs) - [Commits](https://github.com/privatenumber/tsx/compare/v4.23.8...v4.23.12) --- updated-dependencies: - dependency-name: tsx dependency-version: 4.23.12 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 57 +++++++++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 54e04a2b..12a87e9a 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "rimraf": "^6.0.1", "tinybench": "^6.0.2", "tsdown": "^0.22.14", - "tsx": "^4.23.8", + "tsx": "^4.23.12", "typescript": "7.0.1-rc", "vite": "^8.1.3", "vitest": "^4.1.10" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 409fd97a..086eaaff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,19 +31,19 @@ importers: version: 6.0.2 tsdown: specifier: ^0.22.14 - version: 0.22.14(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37) + version: 0.22.14(tsx@4.23.12)(typescript@7.0.1-rc)(unrun@0.2.37) tsx: - specifier: ^4.23.8 - version: 4.23.8 + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: 7.0.1-rc version: 7.0.1-rc vite: specifier: ^8.1.3 - version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) + version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12) vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) + version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12)) packages/audio-renderer: dependencies: @@ -272,10 +272,10 @@ importers: version: 3.0.2 vite: specifier: ^8.1.3 - version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) + version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12) vite-plugin-node-polyfills: specifier: ^0.28.0 - version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) + version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12)) wrangler: specifier: ^4.107.0 version: 4.107.0(@cloudflare/workers-types@5.20260707.1) @@ -979,12 +979,12 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.2.2': - resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -1927,6 +1927,7 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@yuku-codegen/binding-android-arm64@0.8.4': resolution: {integrity: sha512-rsYkGl2kOkDRsh1mxriYnk1qBS78vjlBJ3+T2XwtwKwqOliy2n+2Ae0EDxJ/uX1DZLm3KkBZarGO5isEnmHchA==} @@ -3403,8 +3404,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.23.8: - resolution: {integrity: sha512-8W675THjbzfFmLOQzjDBIBna+WjqMGIxmSZ1mMc1+o9qoVsEuAgQu5j5ueLhau8inOkDu9OslVg0FmfBs1RIHw==} + tsx@4.23.12: + resolution: {integrity: sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==} engines: {node: '>=18.0.0'} hasBin: true @@ -4163,7 +4164,7 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 @@ -4435,7 +4436,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -4667,7 +4668,7 @@ snapshots: obug: 2.1.3 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) + vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12)) '@vitest/expect@4.1.10': dependencies: @@ -4678,13 +4679,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8))': + '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12) '@vitest/pretty-format@4.1.10': dependencies: @@ -6292,7 +6293,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.14(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37): + tsdown@0.22.14(tsx@4.23.12)(typescript@7.0.1-rc)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -6310,7 +6311,7 @@ snapshots: unconfig-core: 7.5.0 verkit: 0.3.2 optionalDependencies: - tsx: 4.23.8 + tsx: 4.23.12 typescript: 7.0.1-rc unrun: 0.2.37 transitivePeerDependencies: @@ -6322,7 +6323,7 @@ snapshots: tslib@2.8.1: optional: true - tsx@4.23.8: + tsx@4.23.12: dependencies: esbuild: 0.28.2 optionalDependencies: @@ -6396,15 +6397,15 @@ snapshots: verkit@0.3.2: {} - vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)): + vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) node-stdlib-browser: 1.3.1 - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12) transitivePeerDependencies: - rollup - vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8): + vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12): dependencies: lightningcss: 1.32.0 picomatch: 4.0.5 @@ -6415,12 +6416,12 @@ snapshots: '@types/node': 25.9.1 esbuild: 0.28.2 fsevents: 2.3.3 - tsx: 4.23.8 + tsx: 4.23.12 - vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)): + vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) + '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -6437,7 +6438,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8) + vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.12) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.9.1 From d5a31166b9f322148cf67b382f7e425fe6e4178f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 02:33:57 +0000 Subject: [PATCH 27/39] chore(deps-dev): bump tinybench from 6.0.2 to 6.1.3 Bumps [tinybench](https://github.com/tinylibs/tinybench) from 6.0.2 to 6.1.3. - [Release notes](https://github.com/tinylibs/tinybench/releases) - [Commits](https://github.com/tinylibs/tinybench/compare/v6.0.2...v6.1.3) --- updated-dependencies: - dependency-name: tinybench dependency-version: 6.1.3 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 54e04a2b..28d97406 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "oxfmt": "^0.57.0", "oxlint": "^1.77.0", "rimraf": "^6.0.1", - "tinybench": "^6.0.2", + "tinybench": "^6.1.3", "tsdown": "^0.22.14", "tsx": "^4.23.8", "typescript": "7.0.1-rc", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 409fd97a..6dd21088 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: ^6.0.1 version: 6.1.3 tinybench: - specifier: ^6.0.2 - version: 6.0.2 + specifier: ^6.1.3 + version: 6.1.3 tsdown: specifier: ^0.22.14 version: 0.22.14(tsx@4.23.8)(typescript@7.0.1-rc)(unrun@0.2.37) @@ -979,12 +979,12 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.2.2': - resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -1927,6 +1927,7 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@yuku-codegen/binding-android-arm64@0.8.4': resolution: {integrity: sha512-rsYkGl2kOkDRsh1mxriYnk1qBS78vjlBJ3+T2XwtwKwqOliy2n+2Ae0EDxJ/uX1DZLm3KkBZarGO5isEnmHchA==} @@ -3322,8 +3323,8 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinybench@6.0.2: - resolution: {integrity: sha512-FlHoQpcFvCzeXK5kVPvV7IVgW/hs/B36QWTz876iSdeJguBDfdTSRQmYmaHX+fQNt4hp+gEFB2XXw+8hT4/y8A==} + tinybench@6.1.3: + resolution: {integrity: sha512-8k25iNSZHnzkjp3nrpEmx6YkrTNs41PzOHYc28DR5Z2l/CId/Nzw+Ume/41jCeDDmCUMPuK5GkQ/VxJaJ2P6Qg==} engines: {node: '>=20.0.0'} tinyexec@1.2.4: @@ -4163,7 +4164,7 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 @@ -4435,7 +4436,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -6252,7 +6253,7 @@ snapshots: tinybench@2.9.0: {} - tinybench@6.0.2: {} + tinybench@6.1.3: {} tinyexec@1.2.4: {} From aeb3185011fd9f69c6dc99884762493d544adcc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 02:34:16 +0000 Subject: [PATCH 28/39] chore(deps-dev): bump @cloudflare/workers-types Bumps [@cloudflare/workers-types](https://github.com/cloudflare/workerd) from 5.20260707.1 to 5.20260813.1. - [Release notes](https://github.com/cloudflare/workerd/releases) - [Changelog](https://github.com/cloudflare/workerd/blob/main/RELEASE.md) - [Commits](https://github.com/cloudflare/workerd/commits) --- updated-dependencies: - dependency-name: "@cloudflare/workers-types" dependency-version: 5.20260813.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/player-web-demo/package.json | 2 +- pnpm-lock.yaml | 29 ++++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index 24fee6c9..2692076a 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -25,7 +25,7 @@ "lil-gui": "^0.21.0" }, "devDependencies": { - "@cloudflare/workers-types": "^5.20260707.1", + "@cloudflare/workers-types": "^5.20260813.1", "ts-ebml": "^3.0.2", "vite": "^8.1.3", "vite-plugin-node-polyfills": "^0.28.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 409fd97a..fbb6a1f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -265,8 +265,8 @@ importers: version: 0.21.0 devDependencies: '@cloudflare/workers-types': - specifier: ^5.20260707.1 - version: 5.20260707.1 + specifier: ^5.20260813.1 + version: 5.20260813.1 ts-ebml: specifier: ^3.0.2 version: 3.0.2 @@ -278,7 +278,7 @@ importers: version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.2)(tsx@4.23.8)) wrangler: specifier: ^4.107.0 - version: 4.107.0(@cloudflare/workers-types@5.20260707.1) + version: 4.107.0(@cloudflare/workers-types@5.20260813.1) packages/stringifier: dependencies: @@ -429,8 +429,8 @@ packages: cpu: [x64] os: [win32] - '@cloudflare/workers-types@5.20260707.1': - resolution: {integrity: sha512-oTiTTaRNR4mMbuiQo2ijAYMAvjFVWn0uDDfawdT2XS4t6hSa7hNPelDV9aWv/pXuz5ew+HPCabE8TMBy7qLwGQ==} + '@cloudflare/workers-types@5.20260813.1': + resolution: {integrity: sha512-RQNfm7xD10hNHEQZFxQPmyGMJ9+aDGPcdFZ0x1LtmjRoLFcgZkGvfaqJAbOMQBAUFSESO3bYJS4p9mOLv28Ihg==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -979,12 +979,12 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@1.2.2': - resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -1927,6 +1927,7 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@yuku-codegen/binding-android-arm64@0.8.4': resolution: {integrity: sha512-rsYkGl2kOkDRsh1mxriYnk1qBS78vjlBJ3+T2XwtwKwqOliy2n+2Ae0EDxJ/uX1DZLm3KkBZarGO5isEnmHchA==} @@ -3810,7 +3811,7 @@ snapshots: '@cloudflare/workerd-windows-64@1.20260701.1': optional: true - '@cloudflare/workers-types@5.20260707.1': {} + '@cloudflare/workers-types@5.20260813.1': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -4163,7 +4164,7 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 @@ -4435,7 +4436,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-wasm32-wasi@1.1.4': @@ -6478,7 +6479,7 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260701.1 '@cloudflare/workerd-windows-64': 1.20260701.1 - wrangler@4.107.0(@cloudflare/workers-types@5.20260707.1): + wrangler@4.107.0(@cloudflare/workers-types@5.20260813.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260701.1) @@ -6489,7 +6490,7 @@ snapshots: unenv: 2.0.0-rc.24 workerd: 1.20260701.1 optionalDependencies: - '@cloudflare/workers-types': 5.20260707.1 + '@cloudflare/workers-types': 5.20260813.1 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil From ab210cbd1735bfa4906f4af993dc0349387d044a Mon Sep 17 00:00:00 2001 From: Seiya KONNO Date: Tue, 18 Aug 2026 00:09:31 +0900 Subject: [PATCH 29/39] feat: add play-log recording and LR2/beatoraja/IIDX replay simulators Record every play as a be-music-playlog input replay (resolved chart, raw press/release stream, play settings) via new PlayerOptions.onPlaylogRecorded / recordPlaylog engine hooks. The @be-music/player/playlog subpath ships the format, defensive parser, recorder, and per-ruleset simulators that re-derive judgments, EX-SCORE, max combo, money score, and groove gauge from the same inputs. The web player exposes the recorded log on both gameplay scenes and the demo auto-downloads it when the result scene mounts (lil-gui toggle, default ON). player-tui gains the bms-playlog CLI for offline re-simulation. --- .changeset/playlog-player-tui.md | 5 + .changeset/playlog-player-web.md | 5 + .changeset/playlog-player.md | 7 + README.ja.md | 1 + README.md | 1 + docs/README.ja.md | 1 + docs/README.md | 1 + docs/player-web.ja.md | 1 + docs/player-web.md | 1 + docs/playlog.ja.md | 100 +++ docs/playlog.md | 107 +++ package.json | 1 + packages/player-tui/package.json | 4 +- packages/player-tui/src/playlog-cli.test.ts | 122 +++ packages/player-tui/src/playlog-cli.ts | 238 ++++++ packages/player-tui/tsdown.config.ts | 1 + packages/player-web-demo/src/main.ts | 46 +- packages/player-web-demo/src/types.ts | 6 + packages/player-web/src/runtime/index.ts | 10 + .../src/scene/beatoraja/gameplay.ts | 26 +- packages/player-web/src/scene/lr2/gameplay.ts | 53 +- packages/player/package.json | 5 + packages/player/scripts/exports-cases.ts | 51 ++ packages/player/src/core/engine.ts | 143 ++-- packages/player/src/core/judge-window.test.ts | 37 + packages/player/src/core/judge-window.ts | 13 +- packages/player/src/core/landmine.test.ts | 46 ++ packages/player/src/core/landmine.ts | 60 ++ packages/player/src/core/scoring.test.ts | 31 + packages/player/src/core/scoring.ts | 6 + packages/player/src/index.test.ts | 77 ++ packages/player/src/playlog/format.test.ts | 243 ++++++ packages/player/src/playlog/format.ts | 456 +++++++++++ packages/player/src/playlog/index.ts | 3 + packages/player/src/playlog/recorder.test.ts | 222 ++++++ packages/player/src/playlog/recorder.ts | 275 +++++++ packages/player/src/playlog/rulesets.ts | 722 ++++++++++++++++++ packages/player/src/playlog/simulate.test.ts | 340 +++++++++ packages/player/src/playlog/simulate.ts | 721 +++++++++++++++++ packages/player/tsdown.config.ts | 1 + scripts/bench/packages/player.ts | 5 + vitest.config.ts | 1 + 42 files changed, 4121 insertions(+), 74 deletions(-) create mode 100644 .changeset/playlog-player-tui.md create mode 100644 .changeset/playlog-player-web.md create mode 100644 .changeset/playlog-player.md create mode 100644 docs/playlog.ja.md create mode 100644 docs/playlog.md create mode 100644 packages/player-tui/src/playlog-cli.test.ts create mode 100644 packages/player-tui/src/playlog-cli.ts create mode 100644 packages/player/src/core/landmine.test.ts create mode 100644 packages/player/src/core/landmine.ts create mode 100644 packages/player/src/playlog/format.test.ts create mode 100644 packages/player/src/playlog/format.ts create mode 100644 packages/player/src/playlog/index.ts create mode 100644 packages/player/src/playlog/recorder.test.ts create mode 100644 packages/player/src/playlog/recorder.ts create mode 100644 packages/player/src/playlog/rulesets.ts create mode 100644 packages/player/src/playlog/simulate.test.ts create mode 100644 packages/player/src/playlog/simulate.ts diff --git a/.changeset/playlog-player-tui.md b/.changeset/playlog-player-tui.md new file mode 100644 index 00000000..20e98359 --- /dev/null +++ b/.changeset/playlog-player-tui.md @@ -0,0 +1,5 @@ +--- +'@be-music/player-tui': minor +--- + +Add the `bms-playlog` CLI: reads recorded play-log files (`*.bmplay.json`) and re-derives LR2 / beatoraja / IIDX judgments, EX-SCORE, DJ LEVEL, max combo, money score, and groove gauge from the raw input replay, printing a per-ruleset comparison table (or `--json`). diff --git a/.changeset/playlog-player-web.md b/.changeset/playlog-player-web.md new file mode 100644 index 00000000..1c160ab5 --- /dev/null +++ b/.changeset/playlog-player-web.md @@ -0,0 +1,5 @@ +--- +'@be-music/player-web': minor +--- + +Record a play log (`*.bmplay.json` input replay) for every gameplay run: the LR2/default gameplay scene exposes it through `PixiGameplayResultData.playlog`, the beatoraja scene through `PixiBeatorajaGameplayView.getPlaylog()`, and the `@be-music/player-web/runtime` subpath re-exports the playlog serializer helpers (`serializePlaylog`, `parsePlaylog`, `resolvePlaylogFilename`) for hosts. diff --git a/.changeset/playlog-player.md b/.changeset/playlog-player.md new file mode 100644 index 00000000..4ff290c4 --- /dev/null +++ b/.changeset/playlog-player.md @@ -0,0 +1,7 @@ +--- +'@be-music/player': minor +--- + +Add the `@be-music/player/playlog` subpath: a play-history ("playlog") format that records the resolved chart, the raw key press/release stream, and the play settings as an input replay, plus LR2 / beatoraja / IIDX ruleset simulators (`simulatePlaylog`) that re-derive judgments, EX-SCORE, max combo, money score, and groove gauge from the same recorded inputs. + +New `PlayerOptions.onPlaylogRecorded` / `PlayerOptions.recordPlaylog` enable engine-side recording for both `manualPlay` and `autoPlay` (including ESC-aborted runs). `ScoreTracker` now latches `maxCombo`, `resolveJudgeRankPercent` exposes the chart's initial judgerank percent, and the landmine gauge-damage rule moved to the shared `core/landmine.ts` helper. diff --git a/README.ja.md b/README.ja.md index 74072d44..32397fb6 100644 --- a/README.ja.md +++ b/README.ja.md @@ -70,6 +70,7 @@ tag は `@be-music/package-name@x.y.z` 形式で作成されます。 - [Player 実装仕様](docs/player-spec.ja.md) - [Terminal player 実装メモ](docs/player-tui.ja.md) - [Browser player 実装メモ](docs/player-web.ja.md) +- [プレイログ(プレイ履歴)仕様](docs/playlog.ja.md) - [LR2 skin 実装メモ](docs/lr2-skin.ja.md) - [beatoraja skin 実装メモ](docs/beatoraja-skin.ja.md) - [BMS/BMSON 中間表現 (`@be-music/json`) 実装仕様](docs/json-spec.ja.md) diff --git a/README.md b/README.md index 0e63a03d..6b8361f5 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ The tag is created in the format `@be-music/package-name@x.y.z`. - [Player implementation specification](./docs/player-spec.md) - [Terminal player implementation notes](./docs/player-tui.md) - [Browser player implementation notes](./docs/player-web.md) +- [Play log (play history) specification](./docs/playlog.md) - [LR2 skin implementation notes](./docs/lr2-skin.md) - [beatoraja skin implementation notes](./docs/beatoraja-skin.md) - [BMS/BMSON intermediate representation (`@be-music/json`) implementation specification](./docs/json-spec.md) diff --git a/docs/README.ja.md b/docs/README.ja.md index 84f2348a..d96f4772 100644 --- a/docs/README.ja.md +++ b/docs/README.ja.md @@ -10,6 +10,7 @@ - [Player 実装仕様](player-spec.ja.md) - [Terminal player 実装メモ](player-tui.ja.md) - [Browser player 実装メモ](player-web.ja.md) +- [プレイログ(プレイ履歴)仕様](playlog.ja.md) - [LR2 skin 実装メモ](lr2-skin.ja.md) - [beatoraja skin 実装メモ](beatoraja-skin.ja.md) - [BMS/BMSON 中間表現 (`@be-music/json`) 実装仕様](json-spec.ja.md) diff --git a/docs/README.md b/docs/README.md index e03313e1..7b9217e5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,6 +10,7 @@ This directory is a Markdown collection of specifications used in the `be-music` - [Player implementation specification](./player-spec.md) - [Terminal player implementation notes](./player-tui.md) - [Browser player implementation notes](./player-web.md) +- [Play log (play history) specification](./playlog.md) - [LR2 skin implementation notes](./lr2-skin.md) - [beatoraja skin implementation notes](./beatoraja-skin.md) - [BMS/BMSON intermediate representation (`@be-music/json`) implementation specification](./json-spec.md) diff --git a/docs/player-web.ja.md b/docs/player-web.ja.md index 05be7fef..45ada74d 100644 --- a/docs/player-web.ja.md +++ b/docs/player-web.ja.md @@ -162,6 +162,7 @@ pnpm bench -- --packages player-web - browser demo は、未対応 video asset を playback 前に ffmpeg.wasm path で transcode できます。 - chart の自然終了時は、短い post-chart delay を置いてから result scene を開きます。視覚的に result へ遷移しても、残っている gameplay audio tail は中断しません。 - gameplay recorder は WebM output を書き出し、active recording が gameplay bus の破棄前に flush されるよう、scene disposal より前に stop / finalization を終えます。 +- 毎プレイでプレイログ(`*.bmplay.json` 入力リプレイ — 解決済み譜面、生の押下/解放列、プレイ設定。[playlog.ja.md](./playlog.ja.md) 参照)を記録します。demo は result scene のマウント時に自動ダウンロードし、Debug Menu の「Auto-save play history」チェックボックス(デフォルト ON)で制御します。`bms-playlog` CLI がこのファイルから LR2 / beatoraja / IIDX のリザルトを再現します。 ## Compatibility boundary diff --git a/docs/player-web.md b/docs/player-web.md index 34ba00cf..7c437963 100644 --- a/docs/player-web.md +++ b/docs/player-web.md @@ -172,6 +172,7 @@ pnpm bench -- --packages player-web - Natural chart completion waits for a short post-chart delay before opening the result scene. The visual transition does not cut off the remaining gameplay audio tail. - The gameplay recorder writes WebM output and coordinates stop/finalization before scene disposal so active recordings are flushed before the gameplay bus is torn down. +- Every play records a play log (`*.bmplay.json` input replay — resolved chart, raw press/release stream, play settings; see [playlog.md](./playlog.md)). The demo auto-downloads it when the result scene mounts, controlled by the Debug Menu's "Auto-save play history" checkbox (ON by default). The `bms-playlog` CLI re-derives LR2 / beatoraja / IIDX results from the file. ## Compatibility boundary diff --git a/docs/playlog.ja.md b/docs/playlog.ja.md new file mode 100644 index 00000000..32ddfc9a --- /dev/null +++ b/docs/playlog.ja.md @@ -0,0 +1,100 @@ +[English version](./playlog.md) + +# プレイログ(プレイ履歴)仕様 + +このドキュメントは be-music のプレイログ(ゲームプレイ中に記録されるプレイ履歴ファイル)と、そこから +LR2 / beatoraja / IIDX のリザルトを再現するツールについて説明します。 + +## 設計原則: 「結果ログ」ではなく「入力リプレイ」 + +プレイログは意図的に**判定結果の列ではありません**。正本となるデータは次の 3 つです。 + +1. **`chart`** — 実際に画面を流れた解決済み譜面。`#RANDOM` 制御構文の解決後、レーンシャッフル + (RANDOM / MIRROR / S-RANDOM)と DP FLIP の適用後の最終配置です。ロングノートは `timeUs` / `endTimeUs` + を持つ 1 オブジェクトとして保存し、地雷は解決済みのゲージダメージを持ち、`#TOTAL` / `#RANK` / + `#DEFEXRANK` は生の値のまま保持します(各ルールセットが自分のデフォルト式を適用できるように)。 +2. **`inputs`** — プレイアブルレーンに届いた全ての生のキー押下・解放 + (`{ seq, timeUs, action: 'down' | 'up', channels }`)。入力は判定へ変換せず、ノート ID への割り当ても + 行わず、空 POOR の原因になる「ノートに対応しない入力」もすべて残します。ソートキーは常に + `(timeUs, seq)` で、`seq` が同時刻イベントの順序を確定します。 +3. **`play`** — スコアに影響する設定。モード(manual / auto)、オートスクラッチ、選択ゲージ、最終配置を + 生んだレーンオプションのラベル、デバッグ用判定幅オーバーライド、ESC 中断フラグです。 + +判定数・EX スコア・コンボ・ゲージ値は **`results`**(ルールセット ID をキーとする再生成可能なキャッシュ。 +`native` は記録時のエンジン自身のサマリ)にのみ存在します。正本が入力列なので、後からルールセットを修正 +しても、過去の全プレイを取り直しなしで再計算できます。 + +時刻は譜面ゼロ基準の整数マイクロ秒です(エンジンのノート時刻と同じ t = 0)。 + +TypeScript 型・シリアライザ・防御的パーサは +[`packages/player/src/playlog/format.ts`](../packages/player/src/playlog/format.ts)(`@be-music/player/playlog`) +にあります。推奨拡張子は `.bmplay.json` です。 + +## 記録 + +記録はエンジン側が担い、全ホスト(ブラウザの LR2 / beatoraja シーン、将来の TUI 採用)が 1 つの実装を共有 +します。`PlayerOptions.onPlaylogRecorded` を設定すると記録が有効になり、エンジンは prepared chart を +スナップショットし、判定対象の押下(`lane-input`)と解放(`kitty-state` release)を `pressedAt` 補正済みの +譜面相対時刻で記録し、空 POOR を native キャッシュ用にカウントし、`autoPlay` / `manualPlay` の解決直前 +(ESC 中断時を含む)に組み上がった `BeMusicPlaylog` をコールバックへ渡します。エンジンが知り得ない +ホスト側設定(選択ゲージ、レーンオプションのラベル、DP FLIP、自由形式の `native` 追加情報)は +`PlayerOptions.recordPlaylog` で渡します。 + +ブラウザプレイヤーでは: + +- LR2 / default ゲームプレイシーンは `PixiGameplayResultData.playlog` として公開します。 +- beatoraja ゲームプレイシーンは `PixiBeatorajaGameplayView.getPlaylog()` として公開します。 +- デモはリザルトシーンのマウント時に `<タイトル>-<タイムスタンプ>.bmplay.json` を自動ダウンロードします。 + Debug Menu の **Auto-save play history** チェックボックス(デフォルト ON)で制御します。 + +## LR2 / beatoraja / IIDX リザルトの再現 + +`@be-music/player/playlog` の `simulatePlaylog(playlog, { ruleset })` が 1 ルールセットで入力列を再生し、 +`simulatePlaylogRulesets(playlog)` が 3 つ全てを実行します。判定幅・ノート選択・ロングノート仕様・ +空 POOR・ゲージ表がルールセットごとに異なります。定数の出典は +[`packages/player/src/playlog/rulesets.ts`](../packages/player/src/playlog/rulesets.ts) に記載しています。 + +| 項目 | LR2 (`lr2/1`) | beatoraja (`beatoraja/1`) | IIDX (`iidx/1`) | +| --- | --- | --- | --- | +| 出典 | lr2oraja / OpenLR2 | beatoraja master | コミュニティ実測 (iidx.org) | +| 判定幅(RANK NORMAL) | ±18/±40/±100/±200 ms | ±15/±45/±112.5/late 210 · early 165 ms(7K, judgerank 75 %) | ±16.67/±33.33/±116.67/±250 ms | +| ランクスケーリング | LR2 アンカー補間、BAD 固定 | judgerank 線形、空 POOR 窓固定 | なし | +| ノート選択 | Lowest + multi-BAD 連鎖 | Combo(デフォルト。duration / lowest / score 選択可) | Lowest | +| ロングノート | 全て LN(終端確定の 1 判定) | ノートごとの LN / CN / HCN | 全て CN(mode 3 は HCN ゲージ) | +| 空 POOR 窓 | 早側のみ 1000 ms | late 150 / early 500 ms(7K) | 未測定 — beatoraja の窓を代用 | +| マネースコア | `(4·PG + 2·GR + GD) × 50000 / notes` | — | —(BISTROVER で廃止) | +| ゲージ | lr2oraja LR2 表(2 % 未満即死、32 % 未満ダメージ ×0.6) | beatoraja ネイティブ表 | iidx.org 表(a 値回復、HARD は 30 % 以下でダメージ半減) | + +EX スコアは全ルールセットで PGREAT × 2 + GREAT × 1、DJ LEVEL は IIDX の 9 分率です。チャージノート系の +ルールセットはロングノートの始点・終端を 2 判定ノートとして数えます(各ルールセットの分母は +`result.noteCount` が報告します)。 + +### 再現度に関する注意 + +- LR2 ルールセットは lr2oraja に従い、OpenLR2 の書き起こしと相互検証しています。両者が食い違う箇所 + (LN 頭の見逃し POOR 閾値、HAZARD 表)は lr2oraja の挙動を採用しています。 +- IIDX の内部仕様は非公開です。判定幅・ゲージ表・DJ LEVEL 境界は現在のコミュニティ実測の合意値であり、 + 空 POOR 窓と CN 終端窓は未測定のため beatoraja の値を代用、HCN のゲージ tick は実測されている + 16 分音符間隔の代わりに固定 200 ms を使用しています。「ほぼ一致」は期待できますが、ビット単位の + 完全一致は保証されません。 +- beatoraja の未モデル化要素: PMS の「1 ノートにつき空 POOR 1 回」規則、PMS の 200 ms チャージ解放 + マージン、SEVENKEYS 以外のモード別ゲージ表(全モードで 7K のゲージ定数を使用)。 +- プレイログは解決済み譜面を保存するため、プレイヤー間の `#RANDOM` やレーンシャッフルの実装差は + 再シミュレーションに影響しません。 + +## CLI + +`@be-music/player-tui` は 2 つ目のバイナリ `bms-playlog` を提供します。 + +```bash +pnpm playlog -- results/Song-2026-08-17T10-00-00-000Z.bmplay.json +``` + +オプション: `--ruleset=lr2,beatoraja,iidx|all`、`--gauge=`(ルールセット固有のゲージ上書き)、 +`--algorithm=combo|duration|lowest|score`(beatoraja のノート選択)、`--json`。 + +## バージョニング + +`format: "be-music-playlog"`、`version: 1`。未知の追加フィールドはパース時に無視されるため、後方互換の +追加は version を変えずに行えます。非互換変更は `version` を上げます。ルールセット結果 ID は独自の +リビジョン(`lr2/1` など)を持ち、ルールセットの修正はリビジョンを上げて既存ファイルを再計算するだけです。 diff --git a/docs/playlog.md b/docs/playlog.md new file mode 100644 index 00000000..110281d3 --- /dev/null +++ b/docs/playlog.md @@ -0,0 +1,107 @@ +[Japanese version](./playlog.ja.md) + +# Play log (play history) specification + +This document describes the be-music play log ("playlog") — the play-history file recorded during gameplay — and +the tools that re-derive LR2 / beatoraja / IIDX results from it. + +## Design principle: an input replay, not a result log + +A playlog is deliberately **not** a list of judgments. Its canonical payload is: + +1. **`chart`** — the resolved chart that actually scrolled past the player: post-`#RANDOM` control flow, post + lane-shuffle (RANDOM / MIRROR / S-RANDOM), post DP-flip. Long notes are stored as single objects with a + `timeUs` / `endTimeUs` pair, mines carry their resolved gauge damage, and the raw `#TOTAL` / `#RANK` / + `#DEFEXRANK` metadata is preserved so each ruleset can apply its own defaults. +2. **`inputs`** — every raw key press / release that reached a playable lane, as + `{ seq, timeUs, action: 'down' | 'up', channels }`. Inputs are never converted into judgments, never assigned + to a note id, and phantom presses (the ones that fire LR2 empty POORs) are kept. The sort key is always + `(timeUs, seq)` — `seq` disambiguates same-microsecond events. +3. **`play`** — the settings that affect scoring: mode (manual / auto), auto scratch, the selected gauge, the + lane-arrangement options that produced the resolved chart, the debug judge-window override, and an ESC flag. + +Judgments, EX-SCORE, combo, and gauge values live only in **`results`** — a regenerable cache keyed by ruleset id +(`native` holds the engine's own summary at record time). Because the canonical data is the input stream, a later +fix to any ruleset re-scores every previously recorded play without re-recording anything. + +Timestamps are integer microseconds relative to chart zero (the same t = 0 the engine's note timing uses). + +The TypeScript types, serializer, and defensive parser live in +[`packages/player/src/playlog/format.ts`](../packages/player/src/playlog/format.ts) (`@be-music/player/playlog`). +The recommended file suffix is `.bmplay.json`. + +## Recording + +Recording is engine-owned so every host (browser LR2 / beatoraja scenes, and any future TUI adoption) shares one +implementation. `PlayerOptions.onPlaylogRecorded` enables it: the engine snapshots its prepared chart, records +every judged press (`lane-input`) and release (`kitty-state` release) with `pressedAt`-corrected chart-relative +timestamps, counts empty POORs for the native cache, and hands the assembled `BeMusicPlaylog` to the callback right +before `autoPlay` / `manualPlay` resolves — including the ESC (aborted) exit. `PlayerOptions.recordPlaylog` carries +the host-declared settings the engine cannot know (selected gauge, lane-shuffle labels, DP flip, freeform +`native` extras). + +In the browser player: + +- The LR2 / default gameplay scene exposes the recorded log through `PixiGameplayResultData.playlog`. +- The beatoraja gameplay scene exposes it through `PixiBeatorajaGameplayView.getPlaylog()`. +- The demo auto-downloads the log as `-<timestamp>.bmplay.json` when the result scene mounts, controlled by + the Debug Menu's **Auto-save play history** checkbox (ON by default). + +## Re-deriving LR2 / beatoraja / IIDX results + +`simulatePlaylog(playlog, { ruleset })` (from `@be-music/player/playlog`) replays the input stream through one +ruleset; `simulatePlaylogRulesets(playlog)` runs all three. Each ruleset differs in judge windows, note selection, +long-note semantics, empty-POOR behavior, and gauge tables — the constants are documented per source in +[`packages/player/src/playlog/rulesets.ts`](../packages/player/src/playlog/rulesets.ts): + +| aspect | LR2 (`lr2/1`) | beatoraja (`beatoraja/1`) | IIDX (`iidx/1`) | +| --- | --- | --- | --- | +| source | lr2oraja / OpenLR2 | beatoraja master | community measurements (iidx.org) | +| windows (NORMAL-rank) | ±18/±40/±100/±200 ms | ±15/±45/±112.5/late 210 · early 165 ms (7K, judgerank 75 %) | ±16.67/±33.33/±116.67/±250 ms | +| rank scaling | LR2 anchor interpolation, BAD fixed | linear × judgerank, MS fixed | none | +| note selection | Lowest + multi-BAD chain | Combo (default; duration / lowest / score selectable) | Lowest | +| long notes | all LN (deferred single judgment) | per-note LN / CN / HCN | all CN (HCN gauge when mode 3) | +| empty POOR window | early-only 1000 ms | late 150 / early 500 ms (7K) | unmeasured — beatoraja window used | +| money score | `(4·PG + 2·GR + GD) × 50000 / notes` | — | — (abolished in BISTROVER) | +| gauges | lr2oraja LR2 tables (death 2 %, guts < 32 % ×0.6) | beatoraja native tables | iidx.org tables (a-value recovery, ≤ 30 % half damage on HARD) | + +EX-SCORE is PGREAT × 2 + GREAT × 1 everywhere; DJ LEVEL uses the IIDX ninths table. Charge-note rulesets count a +long note's head and tail as two judgment notes (`result.noteCount` reports each ruleset's denominator). + +### Fidelity notes + +- The LR2 ruleset follows lr2oraja, cross-checked against the OpenLR2 transcription; where the two disagree + (missed-POOR threshold for LN heads, HAZARD table) the lr2oraja behavior is used. +- IIDX internals are not public. The judge windows, gauge tables, and DJ LEVEL boundaries are current community + consensus; the empty-POOR window and CN release windows are unmeasured and use beatoraja's values as stand-ins, + and the HCN gauge tick uses a fixed 200 ms interval instead of IIDX's measured 16th-note interval. Expect + close — not bit-exact — reproduction. +- beatoraja niceties not modeled: PMS's one-empty-POOR-per-note rule, the PMS 200 ms charge-release margin, and + per-mode gauge tables other than SEVENKEYS (the 7K gauge constants are used for every mode). +- Because the playlog stores the resolved chart, `#RANDOM` and lane-shuffle differences between players never + affect re-simulation. + +## CLI + +`@be-music/player-tui` ships a second binary, `bms-playlog`: + +```bash +pnpm playlog -- results/Song-2026-08-17T10-00-00-000Z.bmplay.json +``` + +``` +RULESET EX RATE DJ PG GR GD BD PR EPR FAST SLOW COMBO SCORE GAUGE +be-music/native 1180 83.10% AA ... +lr2/1 1180 83.10% AA ... ... 140000 96.0% GROOVE CLEAR +beatoraja/1 1174 82.68% AA ... +iidx/1 1102 77.61% AA ... +``` + +Options: `--ruleset=lr2,beatoraja,iidx|all`, `--gauge=<id>` (ruleset-scoped gauge override), +`--algorithm=combo|duration|lowest|score` (beatoraja note selection), `--json`. + +## Versioning + +`format: "be-music-playlog"`, `version: 1`. Unknown extra fields are ignored on parse so minor additions stay +readable; incompatible changes bump `version`. Ruleset result ids carry their own revision (`lr2/1` etc.) — a +corrected ruleset bumps its revision and simply re-simulates existing files. diff --git a/package.json b/package.json index f60ba5bd..0add6369 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "bench:aggregate": "tsx --tsconfig tsconfig.typecheck.json scripts/bench/aggregate-results.ts", "bench:compare": "tsx --tsconfig tsconfig.typecheck.json scripts/bench/compare-results.ts", "player": "pnpm --filter @be-music/player-tui run dev", + "playlog": "pnpm --filter @be-music/player-tui run playlog", "player:web": "pnpm --filter @be-music/player-web-demo run dev", "player:diag:keyboard": "pnpm --filter @be-music/player-tui run diag:keyboard", "player:diag:gameplay-input": "pnpm --filter @be-music/player-tui run diag:gameplay-input", diff --git a/packages/player-tui/package.json b/packages/player-tui/package.json index 4d09a9bc..4e4961f9 100644 --- a/packages/player-tui/package.json +++ b/packages/player-tui/package.json @@ -4,7 +4,8 @@ "description": "Terminal UI and CLI frontend for the be-music player", "license": "MIT", "bin": { - "bms-player": "dist/cli.js" + "bms-player": "dist/cli.js", + "bms-playlog": "dist/playlog-cli.js" }, "files": [ "dist" @@ -25,6 +26,7 @@ "build:sea": "tsx ../../scripts/build-sea.ts --package player", "clean": "rimraf dist tsconfig.tsbuildinfo", "dev": "tsx --tsconfig ../../tsconfig.typecheck.json src/cli.ts", + "playlog": "tsx --tsconfig ../../tsconfig.typecheck.json src/playlog-cli.ts", "diag:keyboard": "tsx --tsconfig ../../tsconfig.typecheck.json src/keyboard-diagnostic.ts", "diag:gameplay-input": "tsx --tsconfig ../../tsconfig.typecheck.json src/gameplay-input-diagnostic.ts", "typecheck": "tsc -p tsconfig.typecheck.json --pretty", diff --git a/packages/player-tui/src/playlog-cli.test.ts b/packages/player-tui/src/playlog-cli.test.ts new file mode 100644 index 00000000..755534f5 --- /dev/null +++ b/packages/player-tui/src/playlog-cli.test.ts @@ -0,0 +1,122 @@ +import { describe, expect, test } from 'vitest'; +import type { BeMusicPlaylog, PlaylogRulesetResult } from '@be-music/player/playlog'; +import { buildPlaylogReport, parsePlaylogCliArgs } from './playlog-cli.ts'; + +function makePlaylog(): BeMusicPlaylog { + return { + format: 'be-music-playlog', + version: 1, + createdAt: '2026-08-17T10:00:00.000Z', + clock: { unit: 'us', origin: 'chart-zero' }, + chart: { + title: 'Sample Song', + artist: 'someone', + sourceFormat: 'bms', + laneMode: '7keys', + total: 300, + lnMode: 1, + judgeRank: { percent: 75, sourceRank: 2 }, + noteCount: 10, + notes: [], + }, + inputs: [], + play: { mode: 'manual', autoScratch: false, gauge: 'GROOVE' }, + }; +} + +function makeResult(overrides: Partial<PlaylogRulesetResult> = {}): PlaylogRulesetResult { + return { + ruleset: 'lr2/1', + judge: { pgreat: 8, great: 1, good: 0, bad: 1, poor: 0, emptyPoor: 2 }, + fast: 1, + slow: 0, + exScore: 17, + noteCount: 10, + maxCombo: 9, + score: 170000, + djLevel: 'AA', + gauge: { type: 'GROOVE', final: 84, cleared: true }, + ...overrides, + }; +} + +describe('playlog-cli', () => { + test('parsePlaylogCliArgs: defaults to all rulesets and collects files', () => { + const args = parsePlaylogCliArgs(['a.bmplay.json', 'b.bmplay.json']); + expect(args.files).toEqual(['a.bmplay.json', 'b.bmplay.json']); + expect(args.rulesets).toEqual(['lr2', 'beatoraja', 'iidx']); + expect(args.json).toBe(false); + expect(args.help).toBe(false); + expect(args.gauge).toBeUndefined(); + expect(args.judgeAlgorithm).toBeUndefined(); + }); + + test('parsePlaylogCliArgs: parses ruleset list, gauge, algorithm, and flags', () => { + const args = parsePlaylogCliArgs([ + '--ruleset=lr2,iidx', + '--gauge=hard', + '--algorithm=lowest', + '--json', + 'file.bmplay.json', + ]); + expect(args.rulesets).toEqual(['lr2', 'iidx']); + expect(args.gauge).toBe('HARD'); + expect(args.judgeAlgorithm).toBe('lowest'); + expect(args.json).toBe(true); + expect(args.files).toEqual(['file.bmplay.json']); + }); + + test('parsePlaylogCliArgs: --ruleset=all restores every simulator', () => { + expect(parsePlaylogCliArgs(['--ruleset=all']).rulesets).toEqual(['lr2', 'beatoraja', 'iidx']); + }); + + test('parsePlaylogCliArgs: rejects unknown rulesets, algorithms, and options', () => { + expect(() => parsePlaylogCliArgs(['--ruleset=osu'])).toThrow(/unknown ruleset 'osu'/); + expect(() => parsePlaylogCliArgs(['--algorithm=psychic'])).toThrow(/unknown judge algorithm/); + expect(() => parsePlaylogCliArgs(['--frobnicate'])).toThrow(/unknown option '--frobnicate'/); + }); + + test('parsePlaylogCliArgs: --help and -h set the help flag', () => { + expect(parsePlaylogCliArgs(['--help']).help).toBe(true); + expect(parsePlaylogCliArgs(['-h']).help).toBe(true); + }); + + test('buildPlaylogReport: renders the chart header and one row per result', () => { + const report = buildPlaylogReport('file.bmplay.json', makePlaylog(), [ + { label: 'lr2/1', result: makeResult() }, + { + label: 'iidx/1', + result: makeResult({ + ruleset: 'iidx/1', + score: undefined, + djLevel: 'A', + gauge: { type: 'HARD', final: 0, cleared: false, failedMidPlay: true }, + }), + }, + ]); + expect(report).toContain('=== file.bmplay.json'); + expect(report).toContain('Sample Song / someone [7keys] notes=10 mode=manual gauge=GROOVE'); + expect(report).toContain('@ 2026-08-17T10:00:00.000Z'); + const lines = report.split('\n'); + const lr2Line = lines.find((line) => line.startsWith('lr2/1')); + expect(lr2Line).toBeDefined(); + // EX 17 / 10 notes → 85.00%, money score printed, gauge cleared. + expect(lr2Line).toContain('17'); + expect(lr2Line).toContain('85.00%'); + expect(lr2Line).toContain('170000'); + expect(lr2Line).toContain('84.0% GROOVE CLEAR'); + const iidxLine = lines.find((line) => line.startsWith('iidx/1')); + expect(iidxLine).toContain('0.0% HARD FAILED(0%)'); + // No money score for IIDX. + expect(iidxLine).toContain(' - '); + }); + + test('buildPlaylogReport: marks aborted plays and auto scratch in the header', () => { + const playlog = makePlaylog(); + playlog.play.autoScratch = true; + playlog.play.aborted = true; + const report = buildPlaylogReport('x', playlog, []); + expect(report).toContain('mode=manual+autoscratch'); + expect(report).toContain('(aborted)'); + }); +}); diff --git a/packages/player-tui/src/playlog-cli.ts b/packages/player-tui/src/playlog-cli.ts new file mode 100644 index 00000000..ad7b3385 --- /dev/null +++ b/packages/player-tui/src/playlog-cli.ts @@ -0,0 +1,238 @@ +import { readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { isMainThread } from 'node:worker_threads'; +import { + parsePlaylog, + simulatePlaylog, + PLAYLOG_SIMULATOR_RULESETS, + type BeMusicPlaylog, + type BeatorajaJudgeAlgorithm, + type PlaylogRulesetId, + type PlaylogRulesetResult, +} from '@be-music/player/playlog'; + +/** + * `bms-playlog` — re-derives LR2 / beatoraja / IIDX scores from a recorded play-log (`*.bmplay.json`). + * + * The playlog is an input replay: the resolved chart, every raw key press / release, and the play settings. Each + * ruleset simulator replays the same input stream through its own judge windows, note-selection algorithm, + * long-note semantics, and gauge tables — so one play yields the score it would have earned in each player. + */ + +export interface PlaylogCliArgs { + files: string[]; + rulesets: PlaylogRulesetId[]; + gauge?: string; + judgeAlgorithm?: BeatorajaJudgeAlgorithm; + json: boolean; + help: boolean; +} + +const USAGE = `Usage: bms-playlog [options] <file.bmplay.json> [...more files] + +Re-derives LR2 / beatoraja / IIDX results from a recorded be-music play-log. + +Options: + --ruleset=<list> Comma-separated rulesets to simulate: lr2, beatoraja, iidx, all (default: all) + --gauge=<id> Override the simulated gauge (ruleset-scoped id, e.g. GROOVE / NORMAL / HARD / EX-HARD) + --algorithm=<name> beatoraja note-selection algorithm: combo (default) / duration / lowest / score + --json Emit the raw result objects as JSON instead of the text table + --help Show this help +`; + +export function parsePlaylogCliArgs(argv: readonly string[]): PlaylogCliArgs { + const args: PlaylogCliArgs = { files: [], rulesets: [...PLAYLOG_SIMULATOR_RULESETS], json: false, help: false }; + for (const arg of argv) { + if (arg === '--help' || arg === '-h') { + args.help = true; + } else if (arg === '--json') { + args.json = true; + } else if (arg.startsWith('--ruleset=')) { + const value = arg.slice('--ruleset='.length).trim().toLowerCase(); + if (value === 'all' || value === '') { + args.rulesets = [...PLAYLOG_SIMULATOR_RULESETS]; + } else { + const parsed: PlaylogRulesetId[] = []; + for (const entry of value.split(',')) { + const id = entry.trim(); + if (id === 'lr2' || id === 'beatoraja' || id === 'iidx') { + parsed.push(id); + } else if (id.length > 0) { + throw new Error(`unknown ruleset '${id}' (expected lr2 / beatoraja / iidx / all)`); + } + } + args.rulesets = parsed; + } + } else if (arg.startsWith('--gauge=')) { + const value = arg.slice('--gauge='.length).trim().toUpperCase(); + if (value.length > 0) { + args.gauge = value; + } + } else if (arg.startsWith('--algorithm=')) { + const value = arg.slice('--algorithm='.length).trim().toLowerCase(); + if (value === 'combo' || value === 'duration' || value === 'lowest' || value === 'score') { + args.judgeAlgorithm = value; + } else { + throw new Error(`unknown judge algorithm '${value}' (expected combo / duration / lowest / score)`); + } + } else if (arg.startsWith('--')) { + throw new Error(`unknown option '${arg}'`); + } else { + args.files.push(arg); + } + } + return args; +} + +function formatRate(exScore: number, noteCount: number): string { + if (noteCount <= 0) return '-'; + return `${((exScore / (noteCount * 2)) * 100).toFixed(2)}%`; +} + +interface ReportRow { + label: string; + result: PlaylogRulesetResult; +} + +/** Builds the human-readable comparison table for one playlog. */ +export function buildPlaylogReport(fileLabel: string, playlog: BeMusicPlaylog, rows: readonly ReportRow[]): string { + const chart = playlog.chart; + const lines: string[] = []; + const title = [chart.title, chart.subtitle].filter((part) => part && part.length > 0).join(' '); + lines.push(`=== ${fileLabel}`); + lines.push( + `${title || '(untitled)'} / ${chart.artist ?? '-'} [${chart.laneMode}] notes=${chart.noteCount}` + + ` mode=${playlog.play.mode}${playlog.play.autoScratch ? '+autoscratch' : ''} gauge=${playlog.play.gauge}` + + `${playlog.play.aborted === true ? ' (aborted)' : ''}${playlog.createdAt ? ` @ ${playlog.createdAt}` : ''}`, + ); + const header = [ + pad('RULESET', 14), + pad('EX', 6), + pad('RATE', 8), + pad('DJ', 4), + pad('PG', 6), + pad('GR', 6), + pad('GD', 5), + pad('BD', 5), + pad('PR', 5), + pad('EPR', 5), + pad('FAST', 6), + pad('SLOW', 6), + pad('COMBO', 6), + pad('SCORE', 7), + 'GAUGE', + ].join(' '); + lines.push(header); + for (const { label, result } of rows) { + const gauge = `${result.gauge.final.toFixed(1)}% ${result.gauge.type} ${ + result.gauge.cleared ? 'CLEAR' : result.gauge.failedMidPlay === true ? 'FAILED(0%)' : 'FAILED' + }`; + lines.push( + [ + pad(label, 14), + pad(String(result.exScore), 6), + pad(formatRate(result.exScore, result.noteCount), 8), + pad(result.djLevel ?? '-', 4), + pad(String(result.judge.pgreat), 6), + pad(String(result.judge.great), 6), + pad(String(result.judge.good), 5), + pad(String(result.judge.bad), 5), + pad(String(result.judge.poor), 5), + pad(String(result.judge.emptyPoor), 5), + pad(String(result.fast), 6), + pad(String(result.slow), 6), + pad(String(result.maxCombo), 6), + pad(result.score !== undefined ? String(result.score) : '-', 7), + gauge, + ].join(' '), + ); + } + return lines.join('\n'); +} + +function pad(value: string, width: number): string { + return value.length >= width ? value : value + ' '.repeat(width - value.length); +} + +export async function runPlaylogCli(argv: readonly string[] = process.argv.slice(2)): Promise<number> { + let args: PlaylogCliArgs; + try { + args = parsePlaylogCliArgs(argv); + } catch (error) { + process.stderr.write(`${(error as Error).message}\n\n${USAGE}`); + return 2; + } + if (args.help || args.files.length === 0) { + process.stdout.write(USAGE); + return args.help ? 0 : 2; + } + + let failures = 0; + const jsonOutput: Record<string, unknown>[] = []; + for (const file of args.files) { + let playlog: BeMusicPlaylog; + try { + playlog = parsePlaylog(await readFile(file, 'utf8')); + } catch (error) { + process.stderr.write(`${file}: ${(error as Error).message}\n`); + failures += 1; + continue; + } + const rows: ReportRow[] = []; + const native = playlog.results?.native; + if (native) { + rows.push({ label: native.ruleset, result: native }); + } + const results: Record<string, PlaylogRulesetResult> = {}; + for (const ruleset of args.rulesets) { + const result = simulatePlaylog(playlog, { + ruleset, + ...(args.gauge !== undefined ? { gauge: args.gauge } : {}), + ...(args.judgeAlgorithm !== undefined ? { judgeAlgorithm: args.judgeAlgorithm } : {}), + }); + results[ruleset] = result; + rows.push({ label: result.ruleset, result }); + } + if (args.json) { + jsonOutput.push({ file, chart: playlog.chart.title, play: playlog.play, native, results }); + } else { + process.stdout.write(`${buildPlaylogReport(file, playlog, rows)}\n\n`); + } + } + if (args.json) { + process.stdout.write(`${JSON.stringify(jsonOutput, null, 2)}\n`); + } + return failures > 0 ? 1 : 0; +} + +function isCliEntryPoint(): boolean { + if (!isMainThread) { + return false; + } + const entry = process.argv[1]; + if (!entry) { + return false; + } + try { + const moduleUrl = (import.meta as { url?: unknown }).url; + if (typeof moduleUrl === 'string' && moduleUrl.length > 0) { + return resolve(entry) === fileURLToPath(moduleUrl); + } + } catch { + // SEA/CJS bundles may not provide import.meta.url. + } + return resolve(entry) === resolve(process.execPath); +} + +if (isCliEntryPoint()) { + void runPlaylogCli() + .then((code) => { + process.exit(code); + }) + .catch((error) => { + const message = error instanceof Error && error.message ? error.message : String(error); + process.stderr.write(`${message}\n`); + process.exit(1); + }); +} diff --git a/packages/player-tui/tsdown.config.ts b/packages/player-tui/tsdown.config.ts index 00cb8536..ab92bf5d 100644 --- a/packages/player-tui/tsdown.config.ts +++ b/packages/player-tui/tsdown.config.ts @@ -9,6 +9,7 @@ export default createPackageTsdownConfig({ entries: { index: 'src/index.ts', cli: 'src/cli.ts', + 'playlog-cli': 'src/playlog-cli.ts', 'bga-video-worker': 'src/bga-video-worker.ts', 'node-gameplay-worker': 'src/node/node-gameplay-worker.ts', 'node-ui-worker': 'src/node/node-ui-worker.ts', diff --git a/packages/player-web-demo/src/main.ts b/packages/player-web-demo/src/main.ts index bda77a2e..779b67d4 100644 --- a/packages/player-web-demo/src/main.ts +++ b/packages/player-web-demo/src/main.ts @@ -48,7 +48,14 @@ import { type BrowserSongCollection, type BrowserSongEntry, } from '@be-music/player-web/collection'; -import { parseCompressorMode, type CompressorMode } from '@be-music/player-web/runtime'; +import { + downloadBlob, + parseCompressorMode, + resolvePlaylogFilename, + serializePlaylog, + type BeMusicPlaylog, + type CompressorMode, +} from '@be-music/player-web/runtime'; import { logger } from '@be-music/player-web'; import { discoverLr2Themes, @@ -415,6 +422,10 @@ class PlayerWebDemoApp { // users coming from those players expect. The dropdown lets users opt into the `'KEEP_SCROLLING'` mode (≈ // beatoraja LANEEFFECT ON) for timing-learning play. judgedNoteDisplay: 'HIDE', + // Play-history auto-save defaults ON: every finished play downloads its play-log (`*.bmplay.json`) when the + // result scene mounts, so the input replay is preserved without the user having to remember anything. The + // Debug Menu checkbox turns the download off for users who don't want per-play files piling up. + autoSavePlaylog: true, // Skin-family routing defaults to `'auto'`: beatoraja > LR2 > default, picked per-scene from what's loaded. // The Debug Menu's "Skin family" dropdown lets users force a specific family; LR2 / beatoraja entries appear // in the dropdown only when their theme is loaded (see {@link rebuildSkinFamilyPicker}). @@ -737,6 +748,15 @@ class PlayerWebDemoApp { this.guiState.judgedNoteDisplay = value; this.gameplayView?.setJudgedNoteDisplay(value); }); + // Play-history auto-save — ON by default. When enabled, every finished play downloads its play-log + // (`*.bmplay.json`, the raw input replay defined in `@be-music/player/playlog`) as soon as the result scene + // mounts. The file feeds the `bms-playlog` CLI, which re-derives LR2 / beatoraja / IIDX scores from the replay. + gui + .add(this.guiState, 'autoSavePlaylog') + .name('Auto-save play history') + .onChange((value: boolean) => { + this.guiState.autoSavePlaylog = value; + }); this.recordController = gui.add(this.guiState, 'record').name('● Record'); // Screenshot button — captures the Pixi stage at its native size (= the renderer's // current screen dimensions; matches what the user sees in the canvas, downloaded as @@ -1513,9 +1533,15 @@ class PlayerWebDemoApp { // `finishBeatorajaGameplayThen` drops the gameplay scene first so the result scene gets a // clean stage; the result scene mounts in the `then` branch. `history` carries the // per-judge score / gauge polyline samples for the result skin's graph elements. + // The play-log is captured HERE (while the gameplay view is guaranteed alive) — the finish + // transition below disposes the scene before the result mounts. + const playlog = this.beatorajaGameplayView?.getPlaylog(); void this.finishBeatorajaGameplayThen(async () => { const mounted = await this.showBeatorajaResult(song, summary, maxCombo, history); if (!mounted) await this.showSelect(); + // Auto-save fires even when the theme ships no result skin — falling back to select + // shouldn't cost the user their replay file. + this.maybeAutoSavePlaylog(playlog); }); }, onError: (error) => { @@ -2954,6 +2980,24 @@ class PlayerWebDemoApp { this.gameplayView?.dispose({ preserveAudioTail: true }); this.gameplayView = undefined; this.setStatus(`Result: ${data.song.title}`); + this.maybeAutoSavePlaylog(data.playlog); + } + + /** + * Downloads the play-log (`*.bmplay.json` input replay) when the "Auto-save play history" toggle is on. Called + * from both result paths (LR2/default `showResult`, beatoraja `onComplete`) the moment the result presentation is + * up. Failures are non-fatal — the result screen must never be blocked by a download hiccup. + */ + private maybeAutoSavePlaylog(playlog: BeMusicPlaylog | undefined): void { + if (!this.guiState.autoSavePlaylog || playlog === undefined) { + return; + } + try { + const blob = new Blob([serializePlaylog(playlog)], { type: 'application/json' }); + downloadBlob(blob, resolvePlaylogFilename(playlog)); + } catch (error) { + gameplayLog.warn('play-log auto-save failed', error); + } } } diff --git a/packages/player-web-demo/src/types.ts b/packages/player-web-demo/src/types.ts index f1f13c80..f258ab23 100644 --- a/packages/player-web-demo/src/types.ts +++ b/packages/player-web-demo/src/types.ts @@ -101,6 +101,12 @@ export interface DemoGuiState { * Long-note bodies are unaffected — they always persist until the tail crosses the line. */ judgedNoteDisplay: 'KEEP_SCROLLING' | 'HIDE'; + /** + * When true (the default), the play-log (`*.bmplay.json` input replay — see `@be-music/player/playlog`) recorded + * during gameplay is automatically downloaded the moment the result scene mounts, for both the LR2/default and + * beatoraja result paths. Toggled from the Debug Menu's "Auto-save play history" checkbox. + */ + autoSavePlaylog: boolean; /** * Explicit skin-family override picked from the Debug Menu dropdown. `'auto'` (default) keeps the legacy * priority — beatoraja if a beatoraja theme is loaded and covers the chart, otherwise LR2 (which itself falls diff --git a/packages/player-web/src/runtime/index.ts b/packages/player-web/src/runtime/index.ts index 9a517266..d558b445 100644 --- a/packages/player-web/src/runtime/index.ts +++ b/packages/player-web/src/runtime/index.ts @@ -10,3 +10,13 @@ export * from './audio-bus.ts'; // Gameplay recorder lives in its own directory but is conceptually a runtime output channel — same scope as the // audio bus that feeds it. export * from '../recording/gameplay-recorder.ts'; + +// Play-log format helpers re-exported for hosts (the demo has no direct `@be-music/player` dependency). The +// gameplay scenes populate a `BeMusicPlaylog` per run; these helpers serialize it for the auto-save download. +export { + serializePlaylog, + parsePlaylog, + resolvePlaylogFilename, + PLAYLOG_FILE_SUFFIX, + type BeMusicPlaylog, +} from '@be-music/player/playlog'; diff --git a/packages/player-web/src/scene/beatoraja/gameplay.ts b/packages/player-web/src/scene/beatoraja/gameplay.ts index 94c726b1..8b98c6f7 100644 --- a/packages/player-web/src/scene/beatoraja/gameplay.ts +++ b/packages/player-web/src/scene/beatoraja/gameplay.ts @@ -54,6 +54,7 @@ import type { BgaCue } from '../lr2/gameplay-bga.ts'; import type { Texture } from 'pixi.js'; import type { BeatorajaFontCache } from '../../skin/beatoraja/fonts.ts'; import type { PlayerOptions, PlayerSummary } from '@be-music/player/core/engine'; +import type { BeMusicPlaylog } from '@be-music/player/playlog'; import type { PlayerInputSignalBus } from '@be-music/player/core/input-signal-bus'; import type { PlayerStateSignals } from '@be-music/player/state-signals'; import type { PlayerUiFramePayload, PlayerUiSignalBus } from '@be-music/player/core/ui-signal-bus'; @@ -247,6 +248,11 @@ export class PixiBeatorajaGameplayView implements PixiScene { private enginePromise?: Promise<EngineDriverResult>; private engineSettled = false; private exitRequested = false; + /** + * Play-log assembled by the shared engine right before its play promise settles (`onPlaylogRecorded`). + * Hosts read it back through {@link getPlaylog} after `onComplete` fires. + */ + private playlog: BeMusicPlaylog | undefined; private disposed = false; /** * Active canvas + audio recorder when the host has called {@link startRecording}. Tied to @@ -483,7 +489,15 @@ export class PixiBeatorajaGameplayView implements PixiScene { // "9 KEY lane 6+ doesn't accept input, AUTO doesn't paint laser/keybeam/judge popup". // Host-provided `engineOptions.laneModeExtension` (if any) wins so callers explicitly // overriding the inference (rare) still take precedence. - engineOptions: composeBeatorajaEngineOptions(this.options), + engineOptions: { + ...composeBeatorajaEngineOptions(this.options), + // Play-log recording — the beatoraja path has no gauge picker yet, so the declared gauge stays the + // engine's GROOVE default. DP flip is a chart transform the host already applied; record the intent. + recordPlaylog: this.options.dpFlip !== undefined ? { dpFlip: this.options.dpFlip } : {}, + onPlaylogRecorded: (playlog) => { + this.playlog = playlog; + }, + }, onInputSignalsReady: ({ inputSignals }) => { this.inputSignals = inputSignals; // The engine input bus is up — stamp the `startinput` timer so chrome gated on it (input-active @@ -613,6 +627,15 @@ export class PixiBeatorajaGameplayView implements PixiScene { return this.enginePromise; } + /** + * Play-log the shared engine recorded for this run (resolved chart + raw input replay + play settings), or + * `undefined` while the run is still in flight. Populated right before `onComplete` fires; survives `dispose()` + * so the host can read it after tearing the scene down. See `@be-music/player/playlog`. + */ + getPlaylog(): BeMusicPlaylog | undefined { + return this.playlog; + } + /** * Begin recording the play scene (canvas video + audio bus mix) into a WebM blob. Same * `GameplayRecorder` infrastructure the LR2 gameplay path uses, just bound to the @@ -997,7 +1020,6 @@ export class PixiBeatorajaGameplayView implements PixiScene { }); this.bgaLayer?.update(this.currentFrame.currentSeconds, ctx, this.adapter.isPoorBgaActive()); } - } private renderContextWithSkinAudio(ctx: BeatorajaRenderContext): BeatorajaRenderContext { diff --git a/packages/player-web/src/scene/lr2/gameplay.ts b/packages/player-web/src/scene/lr2/gameplay.ts index d06af6e7..923e2bc5 100644 --- a/packages/player-web/src/scene/lr2/gameplay.ts +++ b/packages/player-web/src/scene/lr2/gameplay.ts @@ -27,7 +27,11 @@ import type { ChartPlayVariant } from '@be-music/player/core/lane-layout'; import type { PlayerInputSignalBus } from '@be-music/player/core/input-signal-bus'; import type { PlayerJudgeComboSignalState, PlayerStateSignals } from '@be-music/player/state-signals'; import type { PlayerUiCommand, PlayerUiFramePayload, PlayerUiSignalBus } from '@be-music/player/core/ui-signal-bus'; -import { createGrooveGaugeState, isGrooveGaugeCleared, type GrooveGaugeState } from '@be-music/player/core/groove-gauge'; +import { + createGrooveGaugeState, + isGrooveGaugeCleared, + type GrooveGaugeState, +} from '@be-music/player/core/groove-gauge'; import { DEFAULT_POOR_BGA_DISPLAY_SECONDS } from '@be-music/player/core/bga-timeline'; import { createBeatAtSecondsResolverFromTimingResolver, @@ -36,6 +40,7 @@ import { } from '@be-music/player/core/timeline'; import { createScrollDistanceMapper, type ScrollDistanceMapperLike } from '@be-music/player/core/scroll-distance'; import { type TimedLandmineNote, type TimedPlayableNote } from '@be-music/player/playable-notes'; +import type { BeMusicPlaylog } from '@be-music/player/playlog'; import { findFirstIndexAtOrAfter, findFirstIndexNumberAtOrAfter, runWithConcurrency } from '@be-music/utils/core'; import type { BrowserSongAssetSource, BrowserSongEntry } from '../../collection/types.ts'; import { @@ -299,6 +304,11 @@ export interface PixiGameplayResultData { gaugeHistory: GaugeHistorySample[]; /** Per-judge samples of `(progress, exScore)`. Drives `#SRC_SCORECHART`. */ scoreHistory: ScoreHistorySample[]; + /** + * Play-log recorded by the shared engine (resolved chart + raw input replay + play settings). `undefined` for + * legacy paths that finished without the shared engine having produced one. See `@be-music/player/playlog`. + */ + playlog?: BeMusicPlaylog; } export interface PixiGameplayViewOptions { @@ -841,6 +851,11 @@ export class PixiGameplayView { * hit count rather than the longest unbroken streak. */ private maxCombo = 0; + /** + * Play-log assembled by the shared engine right before its play promise settles (`onPlaylogRecorded`). Snapshotted + * into {@link getResultData} so the result host can offer it as a download. + */ + private playlog: BeMusicPlaylog | undefined; /** * Per-play sampled history of `(progress, gauge%)` pairs. Recorded inside `publishJudge` (the single chokepoint for * every judge event) and seeded with a `(0, initialGauge)` entry on `prepareSong` so the polyline starts from the LR2 @@ -3473,6 +3488,7 @@ export class PixiGameplayView { song: this.song, gaugeHistory, scoreHistory, + ...(this.playlog !== undefined ? { playlog: this.playlog } : {}), }; } @@ -5572,6 +5588,24 @@ export class PixiGameplayView { // structurally impossible because there is only one extract. preparedChart: this.preparedChart, signal: (this.sharedEngineAbortController = new AbortController()).signal, + // Play-log recording: the engine snapshots the resolved (post-shuffle) chart and the raw input replay, + // then hands the assembled log here right before the play promise settles. The host reads it back through + // `getResultData().playlog` for the result screen's auto-save. + recordPlaylog: { + gauge: this.options.gauge, + ...(this.options.random1P !== undefined || this.options.random2P !== undefined + ? { + randomLane: { + ...(this.options.random1P !== undefined ? { p1: this.options.random1P } : {}), + ...(this.options.random2P !== undefined ? { p2: this.options.random2P } : {}), + }, + } + : {}), + ...(this.options.dpFlip !== undefined ? { dpFlip: this.options.dpFlip } : {}), + }, + onPlaylogRecorded: (playlog) => { + this.playlog = playlog; + }, }, }) .then((summary) => { @@ -5836,13 +5870,16 @@ export class PixiGameplayView { this.applyFinalComboSummary(finalSummary); } const result = this.getResultData(); - this.beginExitSequence(() => { - if (this.options.onChartFinished && result) { - this.options.onChartFinished(result); - return; - } - this.options.onExit?.(); - }, { fadeAudio: false }); + this.beginExitSequence( + () => { + if (this.options.onChartFinished && result) { + this.options.onChartFinished(result); + return; + } + this.options.onExit?.(); + }, + { fadeAudio: false }, + ); }, delayMs); } } diff --git a/packages/player/package.json b/packages/player/package.json index 7203fc95..25eab4b1 100644 --- a/packages/player/package.json +++ b/packages/player/package.json @@ -20,6 +20,11 @@ "source": "./src/playable-notes.ts", "default": "./dist/playable-notes.js" }, + "./playlog": { + "types": "./dist/playlog.d.ts", + "source": "./src/playlog/index.ts", + "default": "./dist/playlog.js" + }, "./audio-sink": { "types": "./dist/audio-sink.d.ts", "source": "./src/audio-sink.ts", diff --git a/packages/player/scripts/exports-cases.ts b/packages/player/scripts/exports-cases.ts index 8f9c7d30..7e7429bb 100644 --- a/packages/player/scripts/exports-cases.ts +++ b/packages/player/scripts/exports-cases.ts @@ -1,6 +1,8 @@ import * as playerApi from '@be-music/player'; import * as judgingApi from '@be-music/player/judging'; +import * as playlogApi from '@be-music/player/playlog'; import type { PlayerOptions } from '@be-music/player'; +import type { BeMusicPlaylog } from '@be-music/player/playlog'; import type { DefineBenchmarkCase } from '../../../scripts/bench/exports.types.ts'; const BENCH_PLAYER_OPTIONS: PlayerOptions = { @@ -127,8 +129,57 @@ export function registerPlayerExportsCases(define: DefineBenchmarkCase): void { new playerApi.PlayerInterruptedError('escape'); }, }); + define('player.playlog.serializePlaylog', { + run: () => { + playlogApi.serializePlaylog(BENCH_PLAYLOG); + }, + }); + define('player.playlog.parsePlaylog', { + run: () => { + playlogApi.parsePlaylog(BENCH_PLAYLOG_JSON); + }, + }); + define('player.playlog.simulatePlaylog', { + run: () => { + playlogApi.simulatePlaylog(BENCH_PLAYLOG, { ruleset: 'lr2' }); + }, + }); + define('player.playlog.simulatePlaylogRulesets', { + run: () => { + playlogApi.simulatePlaylogRulesets(BENCH_PLAYLOG); + }, + }); } +const BENCH_PLAYLOG: BeMusicPlaylog = { + format: 'be-music-playlog', + version: 1, + clock: { unit: 'us', origin: 'chart-zero' }, + chart: { + title: 'bench', + sourceFormat: 'bms', + laneMode: '7keys', + total: 300, + lnMode: 1, + judgeRank: { percent: 75, sourceRank: 2 }, + noteCount: 64, + notes: Array.from({ length: 64 }, (_, index) => ({ + id: index, + channel: `1${(index % 7) + 1}`, + type: 'normal' as const, + timeUs: 250_000 * (index + 1), + })), + }, + inputs: Array.from({ length: 128 }, (_, index) => ({ + seq: index, + timeUs: 125_000 * (index + 1) + (index % 2 === 0 ? 5_000 : 0), + action: index % 2 === 0 ? ('down' as const) : ('up' as const), + channels: [`1${((index >> 1) % 7) + 1}`], + })), + play: { mode: 'manual', autoScratch: false, gauge: 'GROOVE' }, +}; +const BENCH_PLAYLOG_JSON = JSON.stringify(BENCH_PLAYLOG); + async function runSilently<T>(task: () => Promise<T>): Promise<T> { const stdout = process.stdout as NodeJS.WriteStream & { write: typeof process.stdout.write }; const stderr = process.stderr as NodeJS.WriteStream & { write: typeof process.stderr.write }; diff --git a/packages/player/src/core/engine.ts b/packages/player/src/core/engine.ts index f0e95796..f9d2a6c8 100644 --- a/packages/player/src/core/engine.ts +++ b/packages/player/src/core/engine.ts @@ -76,7 +76,10 @@ import { type JudgeKind, } from './scoring.ts'; import { type GrooveGaugeJudgeKind, type GrooveGaugeType } from './groove-gauge.ts'; +import { resolveLandmineGaugeEffect } from './landmine.ts'; import { resolveBmsJudgeWindowsMsForExRankValue, resolveJudgeWindowsMs } from './judge-window.ts'; +import { createPlaylogRecorder, type PlaylogRecordingOptions } from '../playlog/recorder.ts'; +import type { BeMusicPlaylog } from '../playlog/format.ts'; import { createBeatAtSecondsResolverFromTimingResolver, createBpmTimeline, @@ -244,6 +247,22 @@ export interface PlayerOptions { onResolvedChart?: (json: BeMusicJson) => void; onLog?: (entry: LogEntry) => void; writeOutput?: (text: string) => void; + /** + * Host-declared play settings merged into the recorded play-log (`gauge`, `randomLane`, `dpFlip`, `native`). + * The engine itself knows mode / auto-scratch / judge-window override; everything host-side (which gauge the + * player picked, which lane shuffle produced `preparedChart`, ...) arrives through this bag. Only meaningful + * together with {@link onPlaylogRecorded}. + */ + recordPlaylog?: PlaylogRecordingOptions; + /** + * Enables play-log recording: when set, the engine snapshots the resolved chart it actually played + * (post-`#RANDOM`, post lane-shuffle via `preparedChart`), records every judged key press / release with + * chart-relative timestamps, and hands the assembled {@link BeMusicPlaylog} here right before `autoPlay` / + * `manualPlay` resolves — including the ESC (aborted) exit. The playlog's `results.native` caches this run's + * engine summary; see `@be-music/player/playlog` for the format and the LR2 / beatoraja / IIDX re-simulation + * tools. + */ + onPlaylogRecorded?: (playlog: BeMusicPlaylog) => void; } export interface PlayerSummary { @@ -378,8 +397,6 @@ interface OutputDynamicsConfig { } const LANDMINE_EXPLOSION_SAMPLE_KEY = '00'; -const DEFAULT_LANDMINE_GAUGE_DAMAGE = 4; -const BASE36_OBJECT_KEY_PATTERN = /^[0-9A-Z]{2}$/; interface PlaybackClock { nowMs: () => number; @@ -868,54 +885,8 @@ function resolveLandmineExplosionEvent( }; } -function resolveLandmineGaugeEffect( - landmineEvent: Pick<BeMusicEvent, 'value' | 'bmson'>, - base: 36 | 62 = 36, -): { - objectValue: string; - damage: number; - gaugeDelta: number; -} { - // Mine damage encodes the value in base-36 regardless of the chart's `#BASE` setting (the damage encoding is a - // chart-format constant, not an indexed-resource lookup), so the ID is normalized under the chart's base only to - // keep the returned `objectValue` in sync with the rest of the resource-key reporting. LR2 and beatoraja both - // interpret the value DIRECTLY as the gauge-damage percentage (losak's LR2 mine writeup; jbms-parser passes the raw - // base-36 value into `MineNote`) — the nanasi-era `value / 2` rule in hitkey's memo is a different lineage and is - // NOT what LR2 does. `ZZ` (= 1295) therefore wipes any gauge: survival gauges die instantly, GROOVE / EASY hit - // their 2 % floor. - const objectValue = normalizeObjectKey(landmineEvent.value, base); - // bmson `key_channels[].notes[].damage` is an explicit per-mine gauge percentage; when present it wins over the BMS - // `value / 2` rule because the event value there is the WAV slot, not a damage encoding. `damage: 0` is a valid - // authored value (a no-damage decoration mine), so the guard checks finiteness rather than truthiness. - const bmsonDamage = landmineEvent.bmson?.damage; - if (typeof bmsonDamage === 'number' && Number.isFinite(bmsonDamage) && bmsonDamage >= 0) { - return { - objectValue, - damage: bmsonDamage, - gaugeDelta: -bmsonDamage, - }; - } - if (!BASE36_OBJECT_KEY_PATTERN.test(objectValue)) { - return { - objectValue, - damage: DEFAULT_LANDMINE_GAUGE_DAMAGE, - gaugeDelta: -DEFAULT_LANDMINE_GAUGE_DAMAGE, - }; - } - const parsedDamage = Number.parseInt(objectValue, 36); - if (!Number.isFinite(parsedDamage) || parsedDamage <= 0) { - return { - objectValue, - damage: DEFAULT_LANDMINE_GAUGE_DAMAGE, - gaugeDelta: -DEFAULT_LANDMINE_GAUGE_DAMAGE, - }; - } - return { - objectValue, - damage: parsedDamage, - gaugeDelta: -parsedDamage, - }; -} +// Mine gauge-damage resolution lives in `core/landmine.ts` so the play-log recorder / simulators share the +// exact same value interpretation. Re-imported here for the manual landmine hit path. function writeSampleStopEventLog( writeOutput: (text: string) => void, @@ -1815,6 +1786,22 @@ export async function autoPlay(json: BeMusicJson, options: PlayerOptions = {}): const keyMap = new Map(laneBindings.map((binding) => [binding.channel, binding.keyLabel])); const { summary, applyGaugeJudge } = createInitialPlayerSummary(scorableNotes.length, resolvedJson.metadata.total); const scoreTracker = createScoreTracker(); + // AUTO plays never have manual inputs, but recording still snapshots the resolved chart + play settings so an + // auto run produces a structurally complete playlog (simulators treat an empty input stream as all-miss; the + // cached native result carries the actual AUTO outcome). + const playlogRecorder = options.onPlaylogRecorded + ? createPlaylogRecorder({ + json: resolvedJson, + chart: playbackChart, + dynamicJudgeRankChanges: collectDynamicBmsJudgeRankChanges(resolvedJson, timingResolver), + play: { + mode: 'auto', + autoScratch: false, + judgeWindowOverrideMs: options.judgeWindowMs, + ...options.recordPlaylog, + }, + }) + : undefined; let combo = 0; let interruptedReason: PlayerInterruptReason | undefined; let highSpeed = resolveHighSpeedMultiplier(options.highSpeed); @@ -2339,6 +2326,15 @@ export async function autoPlay(json: BeMusicJson, options: PlayerOptions = {}): summary, }); } + if (playlogRecorder) { + options.onPlaylogRecorded?.( + playlogRecorder.finalize({ + summary, + maxCombo: scoreTracker.maxCombo, + aborted: interruptedReason === 'escape', + }), + ); + } writeOutput(renderSummary(summary)); return summary; } @@ -2419,6 +2415,19 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) resolvedJson.metadata.total, ); const scoreTracker = createScoreTracker(); + const playlogRecorder = options.onPlaylogRecorded + ? createPlaylogRecorder({ + json: resolvedJson, + chart: playbackChart, + dynamicJudgeRankChanges, + play: { + mode: 'manual', + autoScratch: autoScratchEnabled, + judgeWindowOverrideMs: options.judgeWindowMs, + ...options.recordPlaylog, + }, + }) + : undefined; let combo = 0; let highSpeed = resolveHighSpeedMultiplier(options.highSpeed); const stateSignals = createPlayerStateSignals(highSpeed); @@ -3074,6 +3083,10 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) return; } + // Play-log press event — recorded BEFORE any judging so the log stays a raw input replay (recordInput copies + // the shared channel-buffer synchronously). + playlogRecorder?.recordInput('down', nowSec, tokens, candidateChannels); + if (uiEnabled) { for (const mappedChannel of candidateChannels) { uiSignals.pushCommand({ kind: 'flash-lane', channel: mappedChannel }); @@ -3141,6 +3154,7 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) // DEATH -10 — see `applyGrooveGaugeJudge('EMPTY_POOR')`) and fire the POOR BGA, but DO NOT break combo or // increment `summary.poor`. Repeatable per note (LR2's MissCondition.ALWAYS). applyLoggedGaugeJudge(nowSec, 'EMPTY_POOR', 'empty-poor'); + playlogRecorder?.recordEmptyPoor(); uiSignals.pushCommand({ kind: 'trigger-poor-bga', seconds: nowSec }); if (!uiEnabled) { writeRuntimeEventLog(writeOutput, 'judge', [ @@ -3310,6 +3324,15 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) } } const releasedChannels = resolveMappedInputChannels(command.releaseTokens); + if (playlogRecorder && releasedChannels.size > 0) { + const releaseNowMs = resolveJudgeNowMsFromPressedAt(playbackClock.nowMs(), command.pressedAt); + playlogRecorder.recordInput( + 'up', + elapsedMsToGameSeconds(releaseNowMs, speed), + command.releaseTokens, + releasedChannels, + ); + } for (const channel of releasedChannels) { activeKittyPressedChannels.delete(channel); if (uiEnabled) { @@ -3442,19 +3465,11 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) // over the same elapsed duration. Without this branch HCNs were one-shot // gauge sinks — once a player broke a hold, the only recovery path was // through subsequent normal-note PERFECTs. - applyLoggedGaugeDelta( - nowSec, - elapsedSeconds * HELL_CHARGE_GAUGE_GAIN_PER_SECOND, - 'hold-gain', - ); + applyLoggedGaugeDelta(nowSec, elapsedSeconds * HELL_CHARGE_GAUGE_GAIN_PER_SECOND, 'hold-gain'); } else { // HCN DRAIN — hold broken during this frame. Mirrors upstream // `JudgeManager.java:341-344`'s `gauge.update(3, 0.5f)` per 200 ms tick. - applyLoggedGaugeDelta( - nowSec, - -elapsedSeconds * HELL_CHARGE_GAUGE_DRAIN_PER_SECOND, - 'hold-drain', - ); + applyLoggedGaugeDelta(nowSec, -elapsedSeconds * HELL_CHARGE_GAUGE_DRAIN_PER_SECOND, 'hold-drain'); } } hold.gaugeDrainCursorSeconds = accumulateUntilSeconds; @@ -3658,6 +3673,11 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) summary, }); } + if (playlogRecorder) { + options.onPlaylogRecorded?.( + playlogRecorder.finalize({ summary, maxCombo: scoreTracker.maxCombo, aborted: true }), + ); + } writeOutput(renderSummary(summary)); return summary; } @@ -3674,6 +3694,9 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) summary, }); } + if (playlogRecorder) { + options.onPlaylogRecorded?.(playlogRecorder.finalize({ summary, maxCombo: scoreTracker.maxCombo })); + } writeOutput(renderSummary(summary)); return summary; } diff --git a/packages/player/src/core/judge-window.test.ts b/packages/player/src/core/judge-window.test.ts index e8b615cc..27be19e5 100644 --- a/packages/player/src/core/judge-window.test.ts +++ b/packages/player/src/core/judge-window.test.ts @@ -4,6 +4,7 @@ import { bmsExRankValueToJudgeRankPercent, resolveBmsJudgeWindowsMsForExRankValue, resolveBmsJudgeWindowsMsForPercent, + resolveJudgeRankPercent, resolveJudgeWindowsMs, } from './judge-window.ts'; @@ -86,6 +87,42 @@ describe('judge-window', () => { expect(bmsExRankValueToJudgeRankPercent(0)).toBe(0); }); + test('resolveJudgeRankPercent maps #RANK onto the internal percent axis', () => { + const expectations: Array<[number, number]> = [ + [0, 25], // VERY HARD + [1, 50], // HARD + [2, 75], // NORMAL + [3, 100], // EASY + [4, 75], // VERY EASY — LR2 treats #RANK 4 as NORMAL + ]; + for (const [rank, percent] of expectations) { + const json = createEmptyJson('bms'); + json.metadata.rank = rank; + expect(resolveJudgeRankPercent(json), `rank ${rank}`).toBe(percent); + } + }); + + test('resolveJudgeRankPercent: #DEFEXRANK wins over #RANK, and NORMAL is the default', () => { + const json = createEmptyJson('bms'); + json.metadata.rank = 0; + json.bms.defExRank = 120; // 120 × 75 / 100 + expect(resolveJudgeRankPercent(json)).toBeCloseTo(90, 9); + + expect(resolveJudgeRankPercent(createEmptyJson('bms'))).toBe(75); + }); + + test('resolveJudgeRankPercent: bmson prefers info.judge_rank, then metadata, then the spec default', () => { + const json = createEmptyJson('bmson'); + json.bmson.info.judgeRank = 140; + json.metadata.rank = 60; + expect(resolveJudgeRankPercent(json)).toBeCloseTo(105, 9); // 140 × 75 / 100 + + json.bmson.info.judgeRank = 0; // invalid → metadata rank 60 → 45 + expect(resolveJudgeRankPercent(json)).toBeCloseTo(45, 9); + + expect(resolveJudgeRankPercent(createEmptyJson('bmson'))).toBe(75); // judge_rank 100 default + }); + test('resolveBmsJudgeWindowsMsForExRankValue shares the RANK 2 = 100 unit with #DEFEXRANK', () => { const dynamic = resolveBmsJudgeWindowsMsForExRankValue(100); expect(dynamic).toEqual(resolveBmsJudgeWindowsMsForPercent(bmsExRankValueToJudgeRankPercent(100))); diff --git a/packages/player/src/core/judge-window.ts b/packages/player/src/core/judge-window.ts index b7127436..72870fda 100644 --- a/packages/player/src/core/judge-window.ts +++ b/packages/player/src/core/judge-window.ts @@ -98,9 +98,18 @@ export function resolveBmsJudgeWindowsMsForExRankValue(exRankValue: number, debu return resolveBmsJudgeWindowsMsForPercent(bmsExRankValueToJudgeRankPercent(exRankValue), debugBadWindowMs); } +/** + * Resolves the chart's initial judgerank on the internal percent axis (VERY HARD = 25 / HARD = 50 / NORMAL = 75 / + * EASY = 100) — the same value {@link resolveJudgeWindowsMs} scales its windows from. Exposed so consumers that + * persist the resolved rank (e.g. the play-log recorder) share the exact resolution chain (`#DEFEXRANK` → + * `metadata.rank` → default for BMS; `info.judge_rank` → `metadata.rank` → default for bmson). + */ +export function resolveJudgeRankPercent(json: BeMusicJson): number { + return json.sourceFormat === 'bmson' ? resolveBmsonJudgeRankPercent(json) : resolveBmsJudgeRankPercent(json); +} + export function resolveJudgeWindowsMs(json: BeMusicJson, debugBadWindowMs?: number): JudgeWindowsMs { - const judgeRank = json.sourceFormat === 'bmson' ? resolveBmsonJudgeRankPercent(json) : resolveBmsJudgeRankPercent(json); - return scaleJudgeWindowsMs(judgeRank, debugBadWindowMs); + return scaleJudgeWindowsMs(resolveJudgeRankPercent(json), debugBadWindowMs); } function scaleJudgeWindowsMs(judgeRankPercent: number, debugBadWindowMs?: number): JudgeWindowsMs { diff --git a/packages/player/src/core/landmine.test.ts b/packages/player/src/core/landmine.test.ts new file mode 100644 index 00000000..574558e2 --- /dev/null +++ b/packages/player/src/core/landmine.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, test } from 'vitest'; +import { DEFAULT_LANDMINE_GAUGE_DAMAGE, resolveLandmineGaugeEffect } from './landmine.ts'; + +describe('landmine', () => { + test('reads the BMS mine value directly as base-36 gauge damage', () => { + expect(resolveLandmineGaugeEffect({ value: '0A' })).toEqual({ objectValue: '0A', damage: 10, gaugeDelta: -10 }); + expect(resolveLandmineGaugeEffect({ value: '01' })).toEqual({ objectValue: '01', damage: 1, gaugeDelta: -1 }); + // Lowercase input normalizes under base 36 before decoding. + expect(resolveLandmineGaugeEffect({ value: '0a' }).damage).toBe(10); + }); + + test('ZZ decodes to 1295 — enough to wipe any gauge', () => { + expect(resolveLandmineGaugeEffect({ value: 'ZZ' })).toEqual({ + objectValue: 'ZZ', + damage: 1295, + gaugeDelta: -1295, + }); + }); + + test('bmson damage wins over the value rule, including an authored 0', () => { + expect(resolveLandmineGaugeEffect({ value: '0A', bmson: { damage: 25 } })).toEqual({ + objectValue: '0A', + damage: 25, + gaugeDelta: -25, + }); + + const decorative = resolveLandmineGaugeEffect({ value: 'ZZ', bmson: { damage: 0 } }); + expect(decorative.damage).toBe(0); + expect(decorative.gaugeDelta).toBe(-0); + }); + + test('invalid values fall back to the default damage of 4', () => { + expect(DEFAULT_LANDMINE_GAUGE_DAMAGE).toBe(4); + expect(resolveLandmineGaugeEffect({ value: '!!' })).toEqual({ + objectValue: '!!', + damage: DEFAULT_LANDMINE_GAUGE_DAMAGE, + gaugeDelta: -DEFAULT_LANDMINE_GAUGE_DAMAGE, + }); + // Parses fine but decodes to 0 — not a usable damage value. + expect(resolveLandmineGaugeEffect({ value: '00' }).damage).toBe(DEFAULT_LANDMINE_GAUGE_DAMAGE); + // Base-62 keeps lowercase IDs, which are not base-36 damage encodings. + expect(resolveLandmineGaugeEffect({ value: '0a' }, 62).damage).toBe(DEFAULT_LANDMINE_GAUGE_DAMAGE); + // A negative bmson damage is invalid and falls through to the value rule. + expect(resolveLandmineGaugeEffect({ value: '0A', bmson: { damage: -5 } }).damage).toBe(10); + }); +}); diff --git a/packages/player/src/core/landmine.ts b/packages/player/src/core/landmine.ts new file mode 100644 index 00000000..d5aaaf7c --- /dev/null +++ b/packages/player/src/core/landmine.ts @@ -0,0 +1,60 @@ +import { normalizeObjectKey, type BeMusicEvent } from '@be-music/json'; + +export const DEFAULT_LANDMINE_GAUGE_DAMAGE = 4; +const BASE36_OBJECT_KEY_PATTERN = /^[0-9A-Z]{2}$/; + +export interface LandmineGaugeEffect { + objectValue: string; + damage: number; + gaugeDelta: number; +} + +/** + * Resolves the gauge damage a landmine object deals when hit. + * + * Mine damage encodes the value in base-36 regardless of the chart's `#BASE` setting (the damage encoding is a + * chart-format constant, not an indexed-resource lookup), so the ID is normalized under the chart's base only to + * keep the returned `objectValue` in sync with the rest of the resource-key reporting. LR2 and beatoraja both + * interpret the value DIRECTLY as the gauge-damage percentage (losak's LR2 mine writeup; jbms-parser passes the raw + * base-36 value into `MineNote`) — the nanasi-era `value / 2` rule in hitkey's memo is a different lineage and is + * NOT what LR2 does. `ZZ` (= 1295) therefore wipes any gauge: survival gauges die instantly, GROOVE / EASY hit + * their 2 % floor. + * + * bmson `key_channels[].notes[].damage` is an explicit per-mine gauge percentage; when present it wins over the BMS + * value rule because the event value there is the WAV slot, not a damage encoding. `damage: 0` is a valid + * authored value (a no-damage decoration mine), so the guard checks finiteness rather than truthiness. + */ +export function resolveLandmineGaugeEffect( + landmineEvent: Pick<BeMusicEvent, 'value' | 'bmson'>, + base: 36 | 62 = 36, +): LandmineGaugeEffect { + const objectValue = normalizeObjectKey(landmineEvent.value, base); + const bmsonDamage = landmineEvent.bmson?.damage; + if (typeof bmsonDamage === 'number' && Number.isFinite(bmsonDamage) && bmsonDamage >= 0) { + return { + objectValue, + damage: bmsonDamage, + gaugeDelta: -bmsonDamage, + }; + } + if (!BASE36_OBJECT_KEY_PATTERN.test(objectValue)) { + return { + objectValue, + damage: DEFAULT_LANDMINE_GAUGE_DAMAGE, + gaugeDelta: -DEFAULT_LANDMINE_GAUGE_DAMAGE, + }; + } + const parsedDamage = Number.parseInt(objectValue, 36); + if (!Number.isFinite(parsedDamage) || parsedDamage <= 0) { + return { + objectValue, + damage: DEFAULT_LANDMINE_GAUGE_DAMAGE, + gaugeDelta: -DEFAULT_LANDMINE_GAUGE_DAMAGE, + }; + } + return { + objectValue, + damage: parsedDamage, + gaugeDelta: -parsedDamage, + }; +} diff --git a/packages/player/src/core/scoring.test.ts b/packages/player/src/core/scoring.test.ts index 83301d1d..c6dcd930 100644 --- a/packages/player/src/core/scoring.test.ts +++ b/packages/player/src/core/scoring.test.ts @@ -66,4 +66,35 @@ describe('scoring', () => { applyJudgeToSummary(summary, 'GREAT', tracker); expect(summary.score).toBeLessThan(IIDX_SCORE_MAX); }); + + test('latches maxCombo across combo breaks', () => { + const summary = createSummary(20); + const tracker = createScoreTracker(); + + applyJudgeToSummary(summary, 'PERFECT', tracker); + applyJudgeToSummary(summary, 'GREAT', tracker); + applyJudgeToSummary(summary, 'GOOD', tracker); + expect(tracker.combo).toBe(3); + expect(tracker.maxCombo).toBe(3); + + applyJudgeToSummary(summary, 'BAD', tracker); + expect(tracker.combo).toBe(0); + expect(tracker.maxCombo).toBe(3); // BAD breaks the combo but never the latch + + applyJudgeToSummary(summary, 'PERFECT', tracker); + applyJudgeToSummary(summary, 'PERFECT', tracker); + expect(tracker.combo).toBe(2); + expect(tracker.maxCombo).toBe(3); // a shorter rebuild does not move the latch + + applyJudgeToSummary(summary, 'POOR', tracker); + expect(tracker.combo).toBe(0); + expect(tracker.maxCombo).toBe(3); + + applyJudgeToSummary(summary, 'PERFECT', tracker); + applyJudgeToSummary(summary, 'GREAT', tracker); + applyJudgeToSummary(summary, 'GOOD', tracker); + applyJudgeToSummary(summary, 'PERFECT', tracker); + expect(tracker.combo).toBe(4); + expect(tracker.maxCombo).toBe(4); // only a longer streak advances it + }); }); diff --git a/packages/player/src/core/scoring.ts b/packages/player/src/core/scoring.ts index f1ddfa3d..c00946a9 100644 --- a/packages/player/src/core/scoring.ts +++ b/packages/player/src/core/scoring.ts @@ -13,6 +13,8 @@ export interface ScoreSummary { export interface ScoreTracker { combo: number; + /** Highest combo reached so far — latched by {@link applyJudgeToSummary}, never reset by BAD / POOR. */ + maxCombo: number; scoreAccumulator: number; scoreMaxAccumulator: number; } @@ -25,6 +27,7 @@ const IIDX_SCORE_COMBO_BONUS_MAX = 50000; export function createScoreTracker(): ScoreTracker { return { combo: 0, + maxCombo: 0, scoreAccumulator: 0, scoreMaxAccumulator: Number.NaN, }; @@ -91,6 +94,9 @@ export function applyJudgeToSummary(summary: ScoreSummary, judge: JudgeKind, tra if (judge === 'PERFECT' || judge === 'GREAT' || judge === 'GOOD') { tracker.combo += 1; + if (tracker.combo > tracker.maxCombo) { + tracker.maxCombo = tracker.combo; + } } else { tracker.combo = 0; } diff --git a/packages/player/src/index.test.ts b/packages/player/src/index.test.ts index 9af0d814..7d49c4e8 100644 --- a/packages/player/src/index.test.ts +++ b/packages/player/src/index.test.ts @@ -95,6 +95,7 @@ import { } from './index.ts'; import type { PlayerInputCommand } from './core/input-signal-bus.ts'; import { resolveChartVolWavGain, resolveDisplayedJudgeRankLabel, resolveDisplayedJudgeRankValue } from './utils.ts'; +import { simulatePlaylog, type BeMusicPlaylog } from './playlog/index.ts'; const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); const unifiedBmsChartPath = resolve(rootDir, 'examples/test/four-measure-command-combo-test.bms'); @@ -969,6 +970,82 @@ describe('player', () => { expect(output.some((line) => line.includes('result:EMPTY_POOR'))).toBe(false); }); + test('player: onPlaylogRecorded captures the resolved chart, raw inputs, and native result cache', async () => { + // BPM 240 → measure 1 starts at chart 1.0 s. One press near the note, then natural chart end. + const json = createEmptyJson('bms'); + json.metadata.bpm = 240; + json.metadata.title = 'Playlog Test'; + json.metadata.total = 300; + json.events = [{ measure: 1, channel: '11', position: [0, 1], value: '01' }]; + + let playlog: BeMusicPlaylog | undefined; + const summary = await manualPlay(json, { + speed: 1, + leadInMs: 0, + audio: false, + tui: false, + recordPlaylog: { gauge: 'GROOVE', randomLane: { p1: 'MIRROR' } }, + onPlaylogRecorded: (recorded) => { + playlog = recorded; + }, + createInputRuntime: createScheduledInputRuntime([ + { delayMs: 1000, command: { kind: 'lane-input', tokens: ['z'] } }, + ]), + }); + + expect(playlog).toBeDefined(); + expect(playlog!.format).toBe('be-music-playlog'); + expect(playlog!.version).toBe(1); + expect(playlog!.clock).toEqual({ unit: 'us', origin: 'chart-zero' }); + expect(playlog!.chart.title).toBe('Playlog Test'); + expect(playlog!.chart.total).toBe(300); + expect(playlog!.chart.noteCount).toBe(1); + expect(playlog!.chart.notes).toHaveLength(1); + expect(playlog!.chart.notes[0]).toMatchObject({ id: 0, channel: '11', type: 'normal', timeUs: 1_000_000 }); + expect(playlog!.play).toMatchObject({ mode: 'manual', autoScratch: false, gauge: 'GROOVE' }); + expect(playlog!.play.randomLane).toEqual({ p1: 'MIRROR' }); + expect(playlog!.play.aborted).toBeUndefined(); + // The single scheduled press resolves against lane channel 11 with a chart-relative µs timestamp near the note. + expect(playlog!.inputs).toHaveLength(1); + expect(playlog!.inputs[0]).toMatchObject({ seq: 0, action: 'down', channels: ['11'] }); + expect(Math.abs(playlog!.inputs[0]!.timeUs - 1_000_000)).toBeLessThan(250_000); + // The native cache mirrors the engine's own summary. + const native = playlog!.results?.native; + expect(native).toBeDefined(); + expect(native!.exScore).toBe(summary.exScore); + expect(native!.judge.pgreat).toBe(summary.perfect); + expect(native!.judge.poor).toBe(summary.poor); + expect(native!.gauge.final).toBeCloseTo(summary.gauge?.current ?? -1, 6); + // The recorded log feeds the ruleset simulators without further conversion. + const lr2 = simulatePlaylog(playlog!, { ruleset: 'lr2' }); + expect(lr2.noteCount).toBe(1); + expect(lr2.judge.pgreat + lr2.judge.great + lr2.judge.good + lr2.judge.bad + lr2.judge.poor).toBe(1); + }); + + test('player: ESC-interrupted play records an aborted playlog', async () => { + const json = createEmptyJson('bms'); + json.metadata.bpm = 240; + json.events = [{ measure: 1, channel: '11', position: [0, 1], value: '01' }]; + + let playlog: BeMusicPlaylog | undefined; + await manualPlay(json, { + speed: 1, + leadInMs: 0, + audio: false, + tui: false, + onPlaylogRecorded: (recorded) => { + playlog = recorded; + }, + createInputRuntime: createScheduledInputRuntime([ + { delayMs: 100, command: { kind: 'interrupt', reason: 'escape' } }, + ]), + }); + + expect(playlog).toBeDefined(); + expect(playlog!.play.aborted).toBe(true); + expect(playlog!.inputs).toHaveLength(0); + }); + test('player: blank press between same-lane notes plays the previous keysound, not the next pending keysound', async () => { const json = createEmptyJson('bms'); json.metadata.bpm = 240; diff --git a/packages/player/src/playlog/format.test.ts b/packages/player/src/playlog/format.test.ts new file mode 100644 index 00000000..a6eb00b9 --- /dev/null +++ b/packages/player/src/playlog/format.test.ts @@ -0,0 +1,243 @@ +import { describe, expect, test } from 'vitest'; +import { + BE_MUSIC_PLAYLOG_FORMAT, + BE_MUSIC_PLAYLOG_VERSION, + parsePlaylog, + PLAYLOG_FILE_SUFFIX, + PlaylogParseError, + resolvePlaylogFilename, + serializePlaylog, + type BeMusicPlaylog, +} from './format.ts'; + +function makePlaylog(): BeMusicPlaylog { + return { + format: BE_MUSIC_PLAYLOG_FORMAT, + version: BE_MUSIC_PLAYLOG_VERSION, + createdAt: '2026-08-17T01:02:03.456Z', + clock: { unit: 'us', origin: 'chart-zero' }, + chart: { + title: 'Song / Title: Test', + subtitle: 'ANOTHER', + artist: 'composer', + genre: 'genre', + sourceFormat: 'bms', + laneMode: '7keys', + total: 300, + lnMode: 2, + judgeRank: { + percent: 75, + sourceRank: 2, + sourceExRank: 100, + timeline: [{ timeUs: 4_000_000, exRankValue: 48 }], + }, + noteCount: 3, + notes: [ + { id: 0, channel: '11', type: 'normal', timeUs: 500_000 }, + { id: 1, channel: '12', type: 'long', timeUs: 1_000_000, endTimeUs: 2_000_000, lnMode: 2 }, + { id: 2, channel: '13', type: 'mine', timeUs: 1_500_000, damage: 10 }, + { id: 3, channel: '14', type: 'invisible', timeUs: 1_600_000 }, + { id: 4, channel: '17', type: 'freezone', timeUs: 1_700_000, endTimeUs: 1_900_000 }, + ], + }, + inputs: [ + { seq: 0, timeUs: 499_000, action: 'down', channels: ['11'], tokens: ['z'] }, + { seq: 1, timeUs: 520_000, action: 'up', channels: ['11', '12'] }, + ], + play: { + mode: 'manual', + autoScratch: true, + gauge: 'HARD', + randomLane: { p1: 'MIRROR', p2: 'RANDOM' }, + dpFlip: true, + judgeWindowOverrideMs: 500, + aborted: true, + native: { hiSpeed: 2.5, skin: 'default', assist: false, memo: null }, + }, + results: { + native: { + ruleset: 'be-music/native', + judge: { pgreat: 1, great: 1, good: 0, bad: 0, poor: 1, emptyPoor: 2 }, + fast: 1, + slow: 0, + exScore: 3, + noteCount: 3, + maxCombo: 2, + score: 100000, + djLevel: 'AA', + gauge: { type: 'HARD', final: 0, cleared: false, failedMidPlay: true }, + }, + }, + }; +} + +function corrupt(mutate: (value: any) => void): unknown { + const value = JSON.parse(serializePlaylog(makePlaylog())); + mutate(value); + return value; +} + +describe('playlog format', () => { + test('serializePlaylog → parsePlaylog round-trips every field', () => { + const playlog = makePlaylog(); + expect(parsePlaylog(serializePlaylog(playlog))).toEqual(playlog); + // An already-parsed value is accepted too. + expect(parsePlaylog(JSON.parse(serializePlaylog(playlog)))).toEqual(playlog); + }); + + test('round-trips a minimal playlog without any optional field', () => { + const minimal: BeMusicPlaylog = { + format: BE_MUSIC_PLAYLOG_FORMAT, + version: BE_MUSIC_PLAYLOG_VERSION, + clock: { unit: 'us', origin: 'chart-zero' }, + chart: { + sourceFormat: 'bmson', + laneMode: '7keys', + lnMode: 1, + judgeRank: { percent: 75 }, + noteCount: 0, + notes: [], + }, + inputs: [], + play: { mode: 'auto', autoScratch: false, gauge: 'GROOVE' }, + }; + const parsed = parsePlaylog(serializePlaylog(minimal)); + expect(parsed).toEqual(minimal); + expect(parsed.results).toBeUndefined(); + }); + + test('rejects invalid JSON and wrong format / version / clock markers', () => { + expect(() => parsePlaylog('{oops')).toThrow(PlaylogParseError); + expect(() => parsePlaylog('{oops')).toThrow(/invalid JSON/); + expect(() => + parsePlaylog( + corrupt((value) => { + value.format = 'other-format'; + }), + ), + ).toThrow(/^format:/); + expect(() => + parsePlaylog( + corrupt((value) => { + value.version = 2; + }), + ), + ).toThrow(/^version:/); + expect(() => + parsePlaylog( + corrupt((value) => { + value.clock.unit = 'ms'; + }), + ), + ).toThrow(/^clock:/); + }); + + test('reports the field path of structural problems', () => { + expect(() => + parsePlaylog( + corrupt((value) => { + value.inputs = {}; + }), + ), + ).toThrow('inputs: expected an array'); + expect(() => + parsePlaylog( + corrupt((value) => { + value.inputs[0].action = 'press'; + }), + ), + ).toThrow("inputs[0].action: expected 'down' | 'up'"); + expect(() => + parsePlaylog( + corrupt((value) => { + value.inputs[0].channels = [11]; + }), + ), + ).toThrow('inputs[0].channels: expected string[]'); + expect(() => + parsePlaylog( + corrupt((value) => { + value.chart.notes[1].type = 'weird'; + }), + ), + ).toThrow(/chart\.notes\[1\]\.type/); + expect(() => + parsePlaylog( + corrupt((value) => { + delete value.chart.notes[0].timeUs; + }), + ), + ).toThrow('chart.notes[0].timeUs: expected a finite number'); + expect(() => + parsePlaylog( + corrupt((value) => { + delete value.chart.judgeRank.percent; + }), + ), + ).toThrow('chart.judgeRank.percent: expected a finite number'); + expect(() => + parsePlaylog( + corrupt((value) => { + value.chart.lnMode = 5; + }), + ), + ).toThrow('chart.lnMode: expected 1 | 2 | 3'); + expect(() => + parsePlaylog( + corrupt((value) => { + value.play.gauge = 'SUPER'; + }), + ), + ).toThrow(/play\.gauge/); + expect(() => + parsePlaylog( + corrupt((value) => { + delete value.results.native.judge.pgreat; + }), + ), + ).toThrow('results.native.judge.pgreat: expected a finite number'); + }); + + test('ignores unknown fields for forward compatibility', () => { + const parsed = parsePlaylog( + corrupt((value) => { + value.futureRootField = true; + value.chart.futureChartField = 'x'; + value.chart.notes[0].futureNoteField = 1; + value.inputs[0].futureInputField = 1; + value.play.futurePlayField = 1; + value.results.native.futureResultField = 1; + }), + ); + expect(parsed).toEqual(makePlaylog()); + expect(parsed).not.toHaveProperty('futureRootField'); + expect(parsed.chart.notes[0]).not.toHaveProperty('futureNoteField'); + }); + + test('resolvePlaylogFilename sanitizes the title and stamps createdAt', () => { + const playlog = makePlaylog(); + expect(resolvePlaylogFilename(playlog)).toBe('Song Title Test-2026-08-17T01-02-03-456Z.bmplay.json'); + // An explicit `when` wins over the playlog's own createdAt. + expect(resolvePlaylogFilename(playlog, new Date('2027-02-03T04:05:06.007Z'))).toBe( + 'Song Title Test-2027-02-03T04-05-06-007Z.bmplay.json', + ); + }); + + test("resolvePlaylogFilename falls back to 'play' / 'unknown-time'", () => { + const playlog = makePlaylog(); + delete playlog.chart.title; + delete playlog.createdAt; + expect(resolvePlaylogFilename(playlog)).toBe(`play-unknown-time${PLAYLOG_FILE_SUFFIX}`); + + // A title made entirely of filesystem-hostile characters sanitizes to nothing → 'play'. + const hostile = makePlaylog(); + hostile.chart.title = '<>:"/\\|?*'; + expect(resolvePlaylogFilename(hostile)).toBe('play-2026-08-17T01-02-03-456Z.bmplay.json'); + + // A createdAt that does not parse as a date is reported as unknown-time. + const badDate = makePlaylog(); + badDate.createdAt = 'not-a-date'; + expect(resolvePlaylogFilename(badDate)).toBe(`Song Title Test-unknown-time${PLAYLOG_FILE_SUFFIX}`); + expect(resolvePlaylogFilename(badDate).endsWith('.bmplay.json')).toBe(true); + }); +}); diff --git a/packages/player/src/playlog/format.ts b/packages/player/src/playlog/format.ts new file mode 100644 index 00000000..a7d167e4 --- /dev/null +++ b/packages/player/src/playlog/format.ts @@ -0,0 +1,456 @@ +import type { GrooveGaugeType } from '../core/groove-gauge.ts'; +import type { LongNoteMode } from '../playable-notes.ts'; + +/** + * be-music play-log ("playlog") format. + * + * A playlog is an INPUT REPLAY, not a result log: the canonical payload is the resolved chart that actually + * scrolled past the player (post `#RANDOM`, post lane-shuffle / DP-flip), the raw key press / release stream, and + * the play settings. Judgments, EX-SCORE, combo, and gauge values are deliberately NOT part of the canonical data — + * they are re-derived by ruleset simulators (`simulate.ts`), so a later fix to a ruleset re-scores every past play + * without re-recording anything. `results` is a regenerable cache, never the source of truth. + * + * Times are integer microseconds relative to chart zero (the same t=0 the engine's note `seconds` axis uses). + * Events that share a timestamp are ordered by `seq` — sort key is always `(timeUs, seq)`. + */ +export const BE_MUSIC_PLAYLOG_FORMAT = 'be-music-playlog'; +export const BE_MUSIC_PLAYLOG_VERSION = 1; + +/** Recommended file suffix for serialized playlogs (JSON payload). */ +export const PLAYLOG_FILE_SUFFIX = '.bmplay.json'; + +export type PlaylogNoteType = 'normal' | 'long' | 'mine' | 'invisible' | 'freezone'; + +export interface PlaylogNote { + /** Stable note id — index into the chart's note array at record time. */ + id: number; + /** Normalized playable channel AFTER every lane transform (`11`..`19` / `21`..`29`), i.e. the lane the player saw. */ + channel: string; + type: PlaylogNoteType; + timeUs: number; + /** Long-note / freezone tail. Present only when `type` is `'long'` or `'freezone'`. */ + endTimeUs?: number; + /** `#LNMODE`-resolved mode for `type: 'long'` notes (1: LN / 2: CN / 3: HCN). */ + lnMode?: LongNoteMode; + /** Gauge damage percentage for `type: 'mine'` notes (base-36 value / bmson `damage`, already resolved). */ + damage?: number; +} + +export type PlaylogInputAction = 'down' | 'up'; + +export interface PlaylogInputEvent { + /** Monotonic sequence number — tie-breaker for events that share `timeUs`. */ + seq: number; + timeUs: number; + action: PlaylogInputAction; + /** + * Playable channels the physical input resolved to under the play session's lane bindings (auto-scratch lanes + * already filtered out). One press can cover several channels (e.g. a token bound to multiple lanes); simulators + * search all of them for a judgable note, mirroring the live engine. + */ + channels: string[]; + /** Raw input tokens (`'z'`, `'shift-left'`, ...) — diagnostic only; simulators use `channels`. */ + tokens?: string[]; +} + +export interface PlaylogJudgeRank { + /** + * Initial judgerank on the internal LR2 percent axis (VERY HARD = 25 / HARD = 50 / NORMAL = 75 / EASY = 100), + * resolved through `resolveJudgeRankPercent` at record time. + */ + percent: number; + /** Raw `#RANK` (`metadata.rank`) when the chart specified one. */ + sourceRank?: number; + /** Raw `#DEFEXRANK` (BMS) / `info.judge_rank` (bmson) when specified (`100 = NORMAL` unit). */ + sourceExRank?: number; + /** Dynamic `#EXRANKxx` changes (channel `A0`), in chart order. Values share the `100 = NORMAL` unit. */ + timeline?: Array<{ timeUs: number; exRankValue: number }>; +} + +export interface PlaylogChart { + title?: string; + subtitle?: string; + artist?: string; + genre?: string; + sourceFormat: 'bms' | 'bmson'; + /** Engine lane display mode (`'7keys'` / `'14keys'` / ... — `resolveLaneDisplayMode` output). */ + laneMode: string; + /** Raw `#TOTAL` / bmson `info.total`. Omitted when the chart did not specify one — each ruleset applies its own default. */ + total?: number; + /** Chart-level long-note mode (1: LN / 2: CN / 3: HCN) after `#LNMODE` / `info.ln_type` resolution. */ + lnMode: LongNoteMode; + judgeRank: PlaylogJudgeRank; + /** Number of scorable notes (TOTAL / EX-SCORE denominator — mines / invisibles / freezones excluded). */ + noteCount: number; + notes: PlaylogNote[]; +} + +export interface PlaylogPlay { + mode: 'manual' | 'auto'; + autoScratch: boolean; + /** Gauge the player selected for the session (declared by the host; LR2-family gauge id). */ + gauge: GrooveGaugeType; + /** Lane-arrangement option per side, when the host applied one (`'OFF'` / `'MIRROR'` / `'RANDOM'` / ...). */ + randomLane?: { p1?: string; p2?: string }; + dpFlip?: boolean; + /** Debug BAD-window override (`PlayerOptions.judgeWindowMs`) — simulations of such plays are non-standard. */ + judgeWindowOverrideMs?: number; + /** True when the play ended early (ESC). The input stream stops at the abort point. */ + aborted?: boolean; + /** Lossless bag for host-specific settings that don't affect simulation (hi-speed, skin, ...). */ + native?: Record<string, string | number | boolean | null>; +} + +export interface PlaylogJudgeCounts { + pgreat: number; + great: number; + good: number; + bad: number; + poor: number; + /** LR2-style empty POOR count — never part of the judge counters above. */ + emptyPoor: number; +} + +export interface PlaylogGaugeResult { + /** Ruleset-scoped gauge id (`'GROOVE'`, `'HARD'`, `'NORMAL'`, `'EX-HARD'`, ...). */ + type: string; + /** Final gauge value in percent. */ + final: number; + cleared: boolean; + /** True when a survival gauge bottomed out mid-play (the simulator keeps judging to the end regardless). */ + failedMidPlay?: boolean; +} + +export interface PlaylogRulesetResult { + /** Ruleset identifier + revision (e.g. `'lr2/1'`, `'beatoraja/1'`, `'iidx/1'`, `'be-music/native'`). */ + ruleset: string; + judge: PlaylogJudgeCounts; + fast: number; + slow: number; + exScore: number; + /** + * The ruleset's judgment-note count (EX-SCORE denominator ÷ 2). Differs per ruleset: charge-note styles + * (beatoraja CN/HCN, IIDX CN) count a long note's head and tail as two judgments, LN styles as one. + */ + noteCount: number; + maxCombo: number; + /** 200000-max money score where the ruleset defines one. */ + score?: number; + /** IIDX DJ LEVEL label (`'AAA'`..`'F'`) where the ruleset defines one. */ + djLevel?: string; + gauge: PlaylogGaugeResult; +} + +export interface BeMusicPlaylog { + format: typeof BE_MUSIC_PLAYLOG_FORMAT; + version: typeof BE_MUSIC_PLAYLOG_VERSION; + /** ISO 8601 timestamp of the recording, when the recorder had a clock available. */ + createdAt?: string; + clock: { unit: 'us'; origin: 'chart-zero' }; + chart: PlaylogChart; + inputs: PlaylogInputEvent[]; + play: PlaylogPlay; + /** Regenerable result cache keyed by ruleset id. Never authoritative — delete freely. */ + results?: Record<string, PlaylogRulesetResult>; +} + +export function serializePlaylog(playlog: BeMusicPlaylog): string { + return JSON.stringify(playlog); +} + +/** + * Suggested download / save filename for a playlog: `<title>-<timestamp>.bmplay.json` with + * filesystem-hostile characters stripped. `when` defaults to the playlog's own `createdAt`. + */ +export function resolvePlaylogFilename(playlog: BeMusicPlaylog, when?: Date): string { + const stemSource = playlog.chart.title ?? 'play'; + const stem = + stemSource + .normalize('NFKC') + .replace(/[\\/:*?"<>|]+/g, ' ') + .replace(/\s+/g, ' ') + .trim() + .slice(0, 60) || 'play'; + const timestampSource = when ?? (playlog.createdAt !== undefined ? new Date(playlog.createdAt) : undefined); + const timestamp = + timestampSource !== undefined && Number.isFinite(timestampSource.getTime()) + ? timestampSource.toISOString().replace(/[:.]/g, '-') + : 'unknown-time'; + return `${stem}-${timestamp}${PLAYLOG_FILE_SUFFIX}`; +} + +export class PlaylogParseError extends Error { + constructor(message: string) { + super(message); + this.name = 'PlaylogParseError'; + } +} + +/** + * Parses (and defensively validates) a serialized playlog. Accepts either the JSON text or an already-parsed + * value. Throws {@link PlaylogParseError} with a field-path message on structural problems; unknown extra fields + * are preserved-by-ignoring so future minor additions stay readable. + */ +export function parsePlaylog(source: string | unknown): BeMusicPlaylog { + let value: unknown = source; + if (typeof source === 'string') { + try { + value = JSON.parse(source); + } catch (error) { + throw new PlaylogParseError(`invalid JSON: ${(error as Error).message}`); + } + } + const root = expectRecord(value, 'playlog'); + if (root.format !== BE_MUSIC_PLAYLOG_FORMAT) { + throw new PlaylogParseError(`format: expected '${BE_MUSIC_PLAYLOG_FORMAT}', got ${JSON.stringify(root.format)}`); + } + if (root.version !== BE_MUSIC_PLAYLOG_VERSION) { + throw new PlaylogParseError(`version: unsupported version ${JSON.stringify(root.version)}`); + } + const clock = expectRecord(root.clock, 'clock'); + if (clock.unit !== 'us' || clock.origin !== 'chart-zero') { + throw new PlaylogParseError(`clock: expected { unit: 'us', origin: 'chart-zero' }`); + } + + const chart = parseChart(expectRecord(root.chart, 'chart')); + const inputs = parseInputs(root.inputs); + const play = parsePlay(expectRecord(root.play, 'play')); + const results = root.results === undefined ? undefined : parseResults(expectRecord(root.results, 'results')); + + return { + format: BE_MUSIC_PLAYLOG_FORMAT, + version: BE_MUSIC_PLAYLOG_VERSION, + createdAt: optionalString(root.createdAt, 'createdAt'), + clock: { unit: 'us', origin: 'chart-zero' }, + chart, + inputs, + play, + ...(results !== undefined ? { results } : {}), + }; +} + +function parseChart(chart: Record<string, unknown>): PlaylogChart { + const sourceFormat = chart.sourceFormat; + if (sourceFormat !== 'bms' && sourceFormat !== 'bmson') { + throw new PlaylogParseError(`chart.sourceFormat: expected 'bms' | 'bmson'`); + } + const judgeRankRaw = expectRecord(chart.judgeRank, 'chart.judgeRank'); + const judgeRank: PlaylogJudgeRank = { + percent: expectFiniteNumber(judgeRankRaw.percent, 'chart.judgeRank.percent'), + sourceRank: optionalFiniteNumber(judgeRankRaw.sourceRank, 'chart.judgeRank.sourceRank'), + sourceExRank: optionalFiniteNumber(judgeRankRaw.sourceExRank, 'chart.judgeRank.sourceExRank'), + timeline: parseJudgeRankTimeline(judgeRankRaw.timeline), + }; + if (judgeRank.sourceRank === undefined) delete judgeRank.sourceRank; + if (judgeRank.sourceExRank === undefined) delete judgeRank.sourceExRank; + if (judgeRank.timeline === undefined) delete judgeRank.timeline; + + const notesRaw = chart.notes; + if (!Array.isArray(notesRaw)) { + throw new PlaylogParseError('chart.notes: expected an array'); + } + const notes = notesRaw.map((note, index) => parseNote(note, index)); + + const lnMode = chart.lnMode; + if (lnMode !== 1 && lnMode !== 2 && lnMode !== 3) { + throw new PlaylogParseError('chart.lnMode: expected 1 | 2 | 3'); + } + + const parsed: PlaylogChart = { + title: optionalString(chart.title, 'chart.title'), + subtitle: optionalString(chart.subtitle, 'chart.subtitle'), + artist: optionalString(chart.artist, 'chart.artist'), + genre: optionalString(chart.genre, 'chart.genre'), + sourceFormat, + laneMode: expectString(chart.laneMode, 'chart.laneMode'), + total: optionalFiniteNumber(chart.total, 'chart.total'), + lnMode, + judgeRank, + noteCount: expectFiniteNumber(chart.noteCount, 'chart.noteCount'), + notes, + }; + for (const key of ['title', 'subtitle', 'artist', 'genre', 'total'] as const) { + if (parsed[key] === undefined) delete parsed[key]; + } + return parsed; +} + +function parseJudgeRankTimeline(value: unknown): PlaylogJudgeRank['timeline'] { + if (value === undefined) return undefined; + if (!Array.isArray(value)) { + throw new PlaylogParseError('chart.judgeRank.timeline: expected an array'); + } + return value.map((entry, index) => { + const record = expectRecord(entry, `chart.judgeRank.timeline[${index}]`); + return { + timeUs: expectFiniteNumber(record.timeUs, `chart.judgeRank.timeline[${index}].timeUs`), + exRankValue: expectFiniteNumber(record.exRankValue, `chart.judgeRank.timeline[${index}].exRankValue`), + }; + }); +} + +const PLAYLOG_NOTE_TYPES: ReadonlySet<string> = new Set(['normal', 'long', 'mine', 'invisible', 'freezone']); + +function parseNote(value: unknown, index: number): PlaylogNote { + const record = expectRecord(value, `chart.notes[${index}]`); + const type = record.type; + if (typeof type !== 'string' || !PLAYLOG_NOTE_TYPES.has(type)) { + throw new PlaylogParseError(`chart.notes[${index}].type: expected one of ${[...PLAYLOG_NOTE_TYPES].join(' | ')}`); + } + const note: PlaylogNote = { + id: expectFiniteNumber(record.id, `chart.notes[${index}].id`), + channel: expectString(record.channel, `chart.notes[${index}].channel`), + type: type as PlaylogNoteType, + timeUs: expectFiniteNumber(record.timeUs, `chart.notes[${index}].timeUs`), + }; + const endTimeUs = optionalFiniteNumber(record.endTimeUs, `chart.notes[${index}].endTimeUs`); + if (endTimeUs !== undefined) note.endTimeUs = endTimeUs; + if (record.lnMode !== undefined) { + if (record.lnMode !== 1 && record.lnMode !== 2 && record.lnMode !== 3) { + throw new PlaylogParseError(`chart.notes[${index}].lnMode: expected 1 | 2 | 3`); + } + note.lnMode = record.lnMode; + } + const damage = optionalFiniteNumber(record.damage, `chart.notes[${index}].damage`); + if (damage !== undefined) note.damage = damage; + return note; +} + +function parseInputs(value: unknown): PlaylogInputEvent[] { + if (!Array.isArray(value)) { + throw new PlaylogParseError('inputs: expected an array'); + } + return value.map((entry, index) => { + const record = expectRecord(entry, `inputs[${index}]`); + const action = record.action; + if (action !== 'down' && action !== 'up') { + throw new PlaylogParseError(`inputs[${index}].action: expected 'down' | 'up'`); + } + const channelsRaw = record.channels; + if (!Array.isArray(channelsRaw) || channelsRaw.some((channel) => typeof channel !== 'string')) { + throw new PlaylogParseError(`inputs[${index}].channels: expected string[]`); + } + const event: PlaylogInputEvent = { + seq: expectFiniteNumber(record.seq, `inputs[${index}].seq`), + timeUs: expectFiniteNumber(record.timeUs, `inputs[${index}].timeUs`), + action, + channels: channelsRaw as string[], + }; + if (record.tokens !== undefined) { + if (!Array.isArray(record.tokens) || record.tokens.some((token) => typeof token !== 'string')) { + throw new PlaylogParseError(`inputs[${index}].tokens: expected string[]`); + } + event.tokens = record.tokens as string[]; + } + return event; + }); +} + +const GAUGE_TYPES: ReadonlySet<string> = new Set(['GROOVE', 'HARD', 'DEATH', 'EASY']); + +function parsePlay(play: Record<string, unknown>): PlaylogPlay { + const mode = play.mode; + if (mode !== 'manual' && mode !== 'auto') { + throw new PlaylogParseError(`play.mode: expected 'manual' | 'auto'`); + } + const gauge = play.gauge; + if (typeof gauge !== 'string' || !GAUGE_TYPES.has(gauge)) { + throw new PlaylogParseError(`play.gauge: expected one of ${[...GAUGE_TYPES].join(' | ')}`); + } + const parsed: PlaylogPlay = { + mode, + autoScratch: play.autoScratch === true, + gauge: gauge as GrooveGaugeType, + }; + if (play.randomLane !== undefined) { + const randomLane = expectRecord(play.randomLane, 'play.randomLane'); + parsed.randomLane = {}; + const p1 = optionalString(randomLane.p1, 'play.randomLane.p1'); + const p2 = optionalString(randomLane.p2, 'play.randomLane.p2'); + if (p1 !== undefined) parsed.randomLane.p1 = p1; + if (p2 !== undefined) parsed.randomLane.p2 = p2; + } + if (play.dpFlip !== undefined) parsed.dpFlip = play.dpFlip === true; + const judgeWindowOverrideMs = optionalFiniteNumber(play.judgeWindowOverrideMs, 'play.judgeWindowOverrideMs'); + if (judgeWindowOverrideMs !== undefined) parsed.judgeWindowOverrideMs = judgeWindowOverrideMs; + if (play.aborted !== undefined) parsed.aborted = play.aborted === true; + if (play.native !== undefined) { + const native = expectRecord(play.native, 'play.native'); + const copied: Record<string, string | number | boolean | null> = {}; + for (const [key, raw] of Object.entries(native)) { + if (raw === null || typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') { + copied[key] = raw; + } + } + parsed.native = copied; + } + return parsed; +} + +function parseResults(results: Record<string, unknown>): Record<string, PlaylogRulesetResult> { + const parsed: Record<string, PlaylogRulesetResult> = {}; + for (const [key, raw] of Object.entries(results)) { + const record = expectRecord(raw, `results.${key}`); + const judge = expectRecord(record.judge, `results.${key}.judge`); + const gauge = expectRecord(record.gauge, `results.${key}.gauge`); + const result: PlaylogRulesetResult = { + ruleset: expectString(record.ruleset, `results.${key}.ruleset`), + judge: { + pgreat: expectFiniteNumber(judge.pgreat, `results.${key}.judge.pgreat`), + great: expectFiniteNumber(judge.great, `results.${key}.judge.great`), + good: expectFiniteNumber(judge.good, `results.${key}.judge.good`), + bad: expectFiniteNumber(judge.bad, `results.${key}.judge.bad`), + poor: expectFiniteNumber(judge.poor, `results.${key}.judge.poor`), + emptyPoor: expectFiniteNumber(judge.emptyPoor, `results.${key}.judge.emptyPoor`), + }, + fast: expectFiniteNumber(record.fast, `results.${key}.fast`), + slow: expectFiniteNumber(record.slow, `results.${key}.slow`), + exScore: expectFiniteNumber(record.exScore, `results.${key}.exScore`), + noteCount: expectFiniteNumber(record.noteCount, `results.${key}.noteCount`), + maxCombo: expectFiniteNumber(record.maxCombo, `results.${key}.maxCombo`), + gauge: { + type: expectString(gauge.type, `results.${key}.gauge.type`), + final: expectFiniteNumber(gauge.final, `results.${key}.gauge.final`), + cleared: gauge.cleared === true, + }, + }; + if (gauge.failedMidPlay !== undefined) result.gauge.failedMidPlay = gauge.failedMidPlay === true; + const score = optionalFiniteNumber(record.score, `results.${key}.score`); + if (score !== undefined) result.score = score; + const djLevel = optionalString(record.djLevel, `results.${key}.djLevel`); + if (djLevel !== undefined) result.djLevel = djLevel; + parsed[key] = result; + } + return parsed; +} + +function expectRecord(value: unknown, path: string): Record<string, unknown> { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new PlaylogParseError(`${path}: expected an object`); + } + return value as Record<string, unknown>; +} + +function expectString(value: unknown, path: string): string { + if (typeof value !== 'string') { + throw new PlaylogParseError(`${path}: expected a string`); + } + return value; +} + +function optionalString(value: unknown, path: string): string | undefined { + if (value === undefined) return undefined; + return expectString(value, path); +} + +function expectFiniteNumber(value: unknown, path: string): number { + if (typeof value !== 'number' || !Number.isFinite(value)) { + throw new PlaylogParseError(`${path}: expected a finite number`); + } + return value; +} + +function optionalFiniteNumber(value: unknown, path: string): number | undefined { + if (value === undefined) return undefined; + return expectFiniteNumber(value, path); +} diff --git a/packages/player/src/playlog/index.ts b/packages/player/src/playlog/index.ts new file mode 100644 index 00000000..e2373602 --- /dev/null +++ b/packages/player/src/playlog/index.ts @@ -0,0 +1,3 @@ +export * from './format.ts'; +export * from './recorder.ts'; +export * from './simulate.ts'; diff --git a/packages/player/src/playlog/recorder.test.ts b/packages/player/src/playlog/recorder.test.ts new file mode 100644 index 00000000..5b1e3286 --- /dev/null +++ b/packages/player/src/playlog/recorder.test.ts @@ -0,0 +1,222 @@ +import { createEmptyJson, type BeMusicEvent, type BeMusicJson } from '@be-music/json'; +import { describe, expect, test } from 'vitest'; +import type { PlayerSummary } from '../core/engine.ts'; +import { resolveLandmineGaugeEffect } from '../core/landmine.ts'; +import type { TimedLandmineNote, TimedPlayableNote } from '../playable-notes.ts'; +import { BE_MUSIC_PLAYLOG_FORMAT, BE_MUSIC_PLAYLOG_VERSION } from './format.ts'; +import { + createPlaylogRecorder, + PLAYLOG_NATIVE_RULESET_ID, + type PlaylogRecorderChartData, + type PlaylogRecorderOptions, +} from './recorder.ts'; + +function makeEvent(channel: string, value = '01'): BeMusicEvent { + return { measure: 0, channel, position: [0, 1], value }; +} + +function playable(channel: string, seconds: number, overrides: Partial<TimedPlayableNote> = {}): TimedPlayableNote { + return { event: makeEvent(channel), channel, beat: 0, seconds, judged: false, ...overrides }; +} + +function landmine(channel: string, seconds: number, value: string): TimedLandmineNote { + return { event: makeEvent(channel, value), channel, beat: 0, seconds, judged: false, mine: true }; +} + +function makeJson(): BeMusicJson { + const json = createEmptyJson('bms'); + json.metadata.title = 'My Song'; + json.metadata.artist = 'composer'; + json.metadata.total = 300; + json.metadata.rank = 2; + json.bms.lnMode = 2; + return json; +} + +function makeChartData(): PlaylogRecorderChartData { + const scorable = [ + playable('13', 0.25), + playable('11', 0.5), + playable('12', 1, { endSeconds: 2 }), + playable('18', 3, { endSeconds: 4, longNoteMode: 3 }), + ]; + return { + notes: [...scorable, playable('17', 1.5, { endSeconds: 2.5 })], + landmineNotes: [landmine('14', 0.75, '0A')], + invisibleNotes: [playable('15', 0.5, { invisible: true })], + activeFreeZoneChannels: new Set(['17']), + scorableNotes: scorable, + laneDisplayMode: '7keys', + }; +} + +function makeSummary(overrides: Partial<PlayerSummary> = {}): PlayerSummary { + return { + total: 4, + perfect: 2, + fast: 1, + slow: 1, + great: 1, + good: 1, + bad: 0, + poor: 0, + exScore: 5, + score: 123456, + ...overrides, + }; +} + +function makeRecorderOptions(overrides: Partial<PlaylogRecorderOptions> = {}): PlaylogRecorderOptions { + return { + json: makeJson(), + chart: makeChartData(), + play: { mode: 'manual', autoScratch: false }, + now: () => new Date('2026-08-17T00:00:00.000Z'), + ...overrides, + }; +} + +describe('playlog recorder', () => { + test('snapshots chart notes in (timeUs, channel, type) order with stable ids and resolved types', () => { + const recorder = createPlaylogRecorder(makeRecorderOptions()); + const playlog = recorder.finalize({ summary: makeSummary() }); + + expect(playlog.format).toBe(BE_MUSIC_PLAYLOG_FORMAT); + expect(playlog.version).toBe(BE_MUSIC_PLAYLOG_VERSION); + expect(playlog.createdAt).toBe('2026-08-17T00:00:00.000Z'); + expect(playlog.clock).toEqual({ unit: 'us', origin: 'chart-zero' }); + + expect(playlog.chart.notes).toEqual([ + { id: 0, channel: '13', type: 'normal', timeUs: 250_000 }, + { id: 1, channel: '11', type: 'normal', timeUs: 500_000 }, + { id: 2, channel: '15', type: 'invisible', timeUs: 500_000 }, + { id: 3, channel: '14', type: 'mine', timeUs: 750_000, damage: 10 }, + // The chart-level #LNMODE 2 fills in when the note has no own long-note mode. + { id: 4, channel: '12', type: 'long', timeUs: 1_000_000, endTimeUs: 2_000_000, lnMode: 2 }, + // Free-zone notes keep their tail but never carry an lnMode. + { id: 5, channel: '17', type: 'freezone', timeUs: 1_500_000, endTimeUs: 2_500_000 }, + { id: 6, channel: '18', type: 'long', timeUs: 3_000_000, endTimeUs: 4_000_000, lnMode: 3 }, + ]); + + const mineNote = playlog.chart.notes.find((note) => note.type === 'mine'); + expect(mineNote?.damage).toBe(resolveLandmineGaugeEffect({ value: '0A' }).damage); + }); + + test('captures chart metadata, noteCount, TOTAL, judge rank, and lnMode from the JSON', () => { + const recorder = createPlaylogRecorder(makeRecorderOptions()); + const playlog = recorder.finalize({ summary: makeSummary() }); + + expect(playlog.chart.sourceFormat).toBe('bms'); + expect(playlog.chart.laneMode).toBe('7keys'); + expect(playlog.chart.title).toBe('My Song'); + expect(playlog.chart.artist).toBe('composer'); + expect(playlog.chart.subtitle).toBeUndefined(); + expect(playlog.chart.total).toBe(300); + expect(playlog.chart.lnMode).toBe(2); + expect(playlog.chart.noteCount).toBe(4); // scorableNotes.length — mines / invisibles / freezones excluded + expect(playlog.chart.judgeRank).toEqual({ percent: 75, sourceRank: 2 }); + }); + + test('captures #DEFEXRANK and dynamic #EXRANK changes into judgeRank', () => { + const json = makeJson(); + json.metadata.rank = 1; + json.bms.defExRank = 120; + const recorder = createPlaylogRecorder( + makeRecorderOptions({ + json, + dynamicJudgeRankChanges: [{ seconds: 12.5, exRankValue: 48 }], + }), + ); + const playlog = recorder.finalize({ summary: makeSummary() }); + + expect(playlog.chart.judgeRank).toEqual({ + percent: 90, // #DEFEXRANK 120 × 75 / 100 — wins over #RANK 1 + sourceRank: 1, + sourceExRank: 120, + timeline: [{ timeUs: 12_500_000, exRankValue: 48 }], + }); + }); + + test('records inputs with microsecond timestamps, sequential seq, and copied channels', () => { + const recorder = createPlaylogRecorder(makeRecorderOptions()); + + // Inputs that resolve to no playable channel are not recorded (and consume no seq). + recorder.recordInput('down', 0.5, ['q'], new Set()); + + const sourceChannels = ['11']; + recorder.recordInput('down', 1.234567, ['z'], sourceChannels); + sourceChannels.push('19'); // later mutation must not leak into the recorded event + recorder.recordInput('up', 1.3, [], new Set(['11', '12'])); + + const playlog = recorder.finalize({ summary: makeSummary() }); + expect(playlog.inputs).toEqual([ + { seq: 0, timeUs: 1_234_567, action: 'down', channels: ['11'], tokens: ['z'] }, + { seq: 1, timeUs: 1_300_000, action: 'up', channels: ['11', '12'] }, + ]); + }); + + test('finalize caches the native result with judge counts, empty POORs, maxCombo, and gauge', () => { + const recorder = createPlaylogRecorder( + makeRecorderOptions({ + play: { + mode: 'manual', + autoScratch: true, + gauge: 'HARD', + randomLane: { p1: 'MIRROR' }, + dpFlip: true, + native: { hiSpeed: 2 }, + }, + }), + ); + recorder.recordEmptyPoor(); + recorder.recordEmptyPoor(); + + const summary = makeSummary({ + gauge: { + current: 88.5, + max: 100, + clearThreshold: 80, + initial: 20, + effectiveTotal: 300, + cleared: true, + type: 'GROOVE', + }, + }); + const playlog = recorder.finalize({ summary, maxCombo: 5, aborted: true }); + + expect(playlog.play).toEqual({ + mode: 'manual', + autoScratch: true, + gauge: 'HARD', + randomLane: { p1: 'MIRROR' }, + dpFlip: true, + aborted: true, + native: { hiSpeed: 2 }, + }); + expect(playlog.results).toEqual({ + native: { + ruleset: PLAYLOG_NATIVE_RULESET_ID, + judge: { pgreat: 2, great: 1, good: 1, bad: 0, poor: 0, emptyPoor: 2 }, + fast: 1, + slow: 1, + exScore: 5, + noteCount: 4, + maxCombo: 5, + score: 123456, + gauge: { type: 'GROOVE', final: 88.5, cleared: true }, + }, + }); + }); + + test('finalize defaults: GROOVE gauge, maxCombo 0, declared gauge when the summary has none', () => { + const recorder = createPlaylogRecorder(makeRecorderOptions()); + const playlog = recorder.finalize({ summary: makeSummary() }); + + expect(playlog.play).toEqual({ mode: 'manual', autoScratch: false, gauge: 'GROOVE' }); + expect(playlog.play.aborted).toBeUndefined(); + expect(playlog.results?.native).toMatchObject({ + maxCombo: 0, + gauge: { type: 'GROOVE', final: 0, cleared: false }, + }); + }); +}); diff --git a/packages/player/src/playlog/recorder.ts b/packages/player/src/playlog/recorder.ts new file mode 100644 index 00000000..9706cc66 --- /dev/null +++ b/packages/player/src/playlog/recorder.ts @@ -0,0 +1,275 @@ +import { resolveBmsBase, type BeMusicJson } from '@be-music/json'; +import type { PlayerSummary } from '../core/engine.ts'; +import type { PreparedPlaybackChartData } from '../core/bootstrap.ts'; +import { resolveJudgeRankPercent } from '../core/judge-window.ts'; +import { resolveLandmineGaugeEffect } from '../core/landmine.ts'; +import type { GrooveGaugeType } from '../core/groove-gauge.ts'; +import type { LongNoteMode } from '../playable-notes.ts'; +import { + BE_MUSIC_PLAYLOG_FORMAT, + BE_MUSIC_PLAYLOG_VERSION, + type BeMusicPlaylog, + type PlaylogChart, + type PlaylogInputAction, + type PlaylogInputEvent, + type PlaylogNote, + type PlaylogPlay, + type PlaylogRulesetResult, +} from './format.ts'; + +/** Ruleset id used for the engine's own summary cached into `results` at record time. */ +export const PLAYLOG_NATIVE_RULESET_ID = 'be-music/native'; + +/** + * Chart data the recorder snapshots — structurally a subset of the engine's `PreparedPlaybackChartData`, so the + * engine can hand its prepared bundle over verbatim. + */ +export type PlaylogRecorderChartData = Pick< + PreparedPlaybackChartData, + 'notes' | 'landmineNotes' | 'invisibleNotes' | 'activeFreeZoneChannels' | 'scorableNotes' | 'laneDisplayMode' +>; + +export interface PlaylogRecorderPlaySettings { + mode: 'manual' | 'auto'; + autoScratch: boolean; + /** Selected gauge — declared by the host (the engine's own summary path always runs GROOVE today). */ + gauge?: GrooveGaugeType; + randomLane?: { p1?: string; p2?: string }; + dpFlip?: boolean; + judgeWindowOverrideMs?: number; + native?: Record<string, string | number | boolean | null>; +} + +/** + * Host-declared subset of the play settings — the fields the engine cannot know by itself. Passed through + * `PlayerOptions.recordPlaylog`. + */ +export type PlaylogRecordingOptions = Pick<PlaylogRecorderPlaySettings, 'gauge' | 'randomLane' | 'dpFlip' | 'native'>; + +export interface PlaylogRecorderOptions { + /** Resolved chart JSON (post `#RANDOM` control flow) — metadata source. */ + json: BeMusicJson; + chart: PlaylogRecorderChartData; + play: PlaylogRecorderPlaySettings; + /** Dynamic `#EXRANKxx` changes the engine collected (chart order). */ + dynamicJudgeRankChanges?: ReadonlyArray<{ seconds: number; exRankValue: number }>; + /** Clock source for `createdAt` — injectable for tests. Defaults to `Date`. */ + now?: () => Date; +} + +export interface PlaylogRecorderFinalizeInput { + summary: PlayerSummary; + maxCombo?: number; + aborted?: boolean; +} + +export interface PlaylogRecorder { + recordInput( + action: PlaylogInputAction, + timeSeconds: number, + tokens: readonly string[], + channels: Iterable<string>, + ): void; + /** Counts an LR2-style empty POOR — cached into the native result for diagnostics. */ + recordEmptyPoor(): void; + finalize(input: PlaylogRecorderFinalizeInput): BeMusicPlaylog; +} + +export function createPlaylogRecorder(options: PlaylogRecorderOptions): PlaylogRecorder { + const chart = buildPlaylogChart(options); + const inputs: PlaylogInputEvent[] = []; + let seq = 0; + let emptyPoorCount = 0; + + return { + recordInput: (action, timeSeconds, tokens, channels): void => { + const channelList = [...channels]; + if (channelList.length === 0) { + return; + } + const event: PlaylogInputEvent = { + seq: seq++, + timeUs: secondsToMicroseconds(timeSeconds), + action, + channels: channelList, + }; + if (tokens.length > 0) { + event.tokens = [...tokens]; + } + inputs.push(event); + }, + recordEmptyPoor: (): void => { + emptyPoorCount += 1; + }, + finalize: ({ summary, maxCombo, aborted }): BeMusicPlaylog => { + const play: PlaylogPlay = { + mode: options.play.mode, + autoScratch: options.play.autoScratch, + gauge: options.play.gauge ?? 'GROOVE', + }; + if (options.play.randomLane !== undefined) play.randomLane = options.play.randomLane; + if (options.play.dpFlip !== undefined) play.dpFlip = options.play.dpFlip; + if (options.play.judgeWindowOverrideMs !== undefined) { + play.judgeWindowOverrideMs = options.play.judgeWindowOverrideMs; + } + if (aborted === true) play.aborted = true; + if (options.play.native !== undefined) play.native = options.play.native; + + const createdAt = (options.now?.() ?? new Date()).toISOString(); + return { + format: BE_MUSIC_PLAYLOG_FORMAT, + version: BE_MUSIC_PLAYLOG_VERSION, + createdAt, + clock: { unit: 'us', origin: 'chart-zero' }, + chart, + inputs, + play, + results: { + native: buildNativeResult(summary, maxCombo, emptyPoorCount, play.gauge, chart.noteCount), + }, + }; + }, + }; +} + +function buildPlaylogChart(options: PlaylogRecorderOptions): PlaylogChart { + const { json, chart } = options; + const idBase = resolveBmsBase(json); + const chartLnMode = resolveChartLongNoteMode(json); + const notes: PlaylogNote[] = []; + + for (const note of chart.notes) { + const isFreeZone = chart.activeFreeZoneChannels.has(note.channel); + const hasTail = + typeof note.endSeconds === 'number' && Number.isFinite(note.endSeconds) && note.endSeconds > note.seconds; + const entry: PlaylogNote = { + id: 0, + channel: note.channel, + type: isFreeZone ? 'freezone' : hasTail ? 'long' : 'normal', + timeUs: secondsToMicroseconds(note.seconds), + }; + if (hasTail) { + entry.endTimeUs = secondsToMicroseconds(note.endSeconds!); + if (!isFreeZone) { + entry.lnMode = note.longNoteMode ?? chartLnMode; + } + } + notes.push(entry); + } + for (const mine of chart.landmineNotes) { + notes.push({ + id: 0, + channel: mine.channel, + type: 'mine', + timeUs: secondsToMicroseconds(mine.seconds), + damage: resolveLandmineGaugeEffect(mine.event, idBase).damage, + }); + } + for (const invisible of chart.invisibleNotes) { + notes.push({ + id: 0, + channel: invisible.channel, + type: 'invisible', + timeUs: secondsToMicroseconds(invisible.seconds), + }); + } + notes.sort(comparePlaylogNotes); + for (let index = 0; index < notes.length; index += 1) { + notes[index]!.id = index; + } + + const judgeRank: PlaylogChart['judgeRank'] = { + percent: resolveJudgeRankPercent(json), + }; + const sourceRank = json.metadata.rank; + if (typeof sourceRank === 'number' && Number.isFinite(sourceRank)) { + judgeRank.sourceRank = sourceRank; + } + const sourceExRank = json.sourceFormat === 'bmson' ? json.bmson.info.judgeRank : json.bms.defExRank; + if (typeof sourceExRank === 'number' && Number.isFinite(sourceExRank)) { + judgeRank.sourceExRank = sourceExRank; + } + const timelineSource = options.dynamicJudgeRankChanges ?? []; + if (timelineSource.length > 0) { + judgeRank.timeline = timelineSource.map((change) => ({ + timeUs: secondsToMicroseconds(change.seconds), + exRankValue: change.exRankValue, + })); + } + + const result: PlaylogChart = { + sourceFormat: json.sourceFormat === 'bmson' ? 'bmson' : 'bms', + laneMode: chart.laneDisplayMode, + lnMode: chartLnMode, + judgeRank, + noteCount: chart.scorableNotes.length, + notes, + }; + if (typeof json.metadata.title === 'string' && json.metadata.title.length > 0) result.title = json.metadata.title; + if (typeof json.metadata.subtitle === 'string' && json.metadata.subtitle.length > 0) { + result.subtitle = json.metadata.subtitle; + } + if (typeof json.metadata.artist === 'string' && json.metadata.artist.length > 0) result.artist = json.metadata.artist; + if (typeof json.metadata.genre === 'string' && json.metadata.genre.length > 0) result.genre = json.metadata.genre; + if (typeof json.metadata.total === 'number' && Number.isFinite(json.metadata.total)) { + result.total = json.metadata.total; + } + return result; +} + +function buildNativeResult( + summary: PlayerSummary, + maxCombo: number | undefined, + emptyPoorCount: number, + declaredGauge: GrooveGaugeType, + noteCount: number, +): PlaylogRulesetResult { + const result: PlaylogRulesetResult = { + ruleset: PLAYLOG_NATIVE_RULESET_ID, + judge: { + pgreat: summary.perfect, + great: summary.great, + good: summary.good, + bad: summary.bad, + poor: summary.poor, + emptyPoor: emptyPoorCount, + }, + fast: summary.fast, + slow: summary.slow, + exScore: summary.exScore, + noteCount, + maxCombo: maxCombo ?? 0, + score: summary.score, + gauge: { + type: summary.gauge?.type ?? declaredGauge, + final: summary.gauge?.current ?? 0, + cleared: summary.gauge?.cleared ?? false, + }, + }; + return result; +} + +function resolveChartLongNoteMode(json: BeMusicJson): LongNoteMode { + if (json.sourceFormat === 'bms') { + return json.bms.lnMode === 2 || json.bms.lnMode === 3 ? json.bms.lnMode : 1; + } + const lnType = json.bmson.info.lnType; + return lnType === 2 || lnType === 3 ? lnType : 1; +} + +function comparePlaylogNotes(left: PlaylogNote, right: PlaylogNote): number { + if (left.timeUs !== right.timeUs) { + return left.timeUs - right.timeUs; + } + if (left.channel !== right.channel) { + return left.channel < right.channel ? -1 : 1; + } + if (left.type !== right.type) { + return left.type < right.type ? -1 : 1; + } + return 0; +} + +function secondsToMicroseconds(seconds: number): number { + return Math.round(seconds * 1_000_000); +} diff --git a/packages/player/src/playlog/rulesets.ts b/packages/player/src/playlog/rulesets.ts new file mode 100644 index 00000000..dd6b8673 --- /dev/null +++ b/packages/player/src/playlog/rulesets.ts @@ -0,0 +1,722 @@ +import { resolveBmsJudgeWindowsMsForPercent, bmsExRankValueToJudgeRankPercent } from '../core/judge-window.ts'; +import type { BeMusicPlaylog, PlaylogChart } from './format.ts'; + +/** + * Ruleset tables for the playlog simulators. + * + * Every numeric constant here was read from primary sources (2026-08 HEAD): + * - beatoraja: `exch-bms2/beatoraja` — `play/JudgeProperty.java`, `play/JudgeAlgorithm.java`, + * `play/JudgeManager.java`, `play/GaugeProperty.java`, `play/GrooveGauge.java`, `play/BMSPlayerRule.java`. + * - LR2: `wcko87/lr2oraja` / `seraxis/lr2oraja-endlessdream` (`JudgeProperty.LR2`, `JudgeWindowRule.LR2`, + * `GaugeProperty` LR2 variants with `death = 2` / guts `{32, 0.6}`, `MultiBadCollector`) cross-checked against + * the OpenLR2 transcription (`GOMazk/OpenLR2` — `Scene04_Play.cpp`, `LR2_bmsload.cpp`). + * - IIDX: community measurements (iidx.org compendium; dbm_capture / leisurely1 measurements). IIDX internals are + * not public — those values are the current community consensus, not vendor data. + * + * Window convention (borrowed from beatoraja): `dmTimeUs = noteTimeUs - inputTimeUs`, so POSITIVE deltas are + * EARLY (FAST) presses. A window is a `[lateBoundUs, earlyBoundUs]` pair with `lateBoundUs <= 0 <= earlyBoundUs` + * (except the LR2 empty-POOR window, which is early-only). + */ + +export type WindowPairUs = readonly [number, number]; + +export interface JudgeWindowSetUs { + /** PGREAT / GREAT / GOOD / BAD windows, inner to outer. */ + judges: readonly [WindowPairUs, WindowPairUs, WindowPairUs, WindowPairUs]; + /** Empty-POOR (空POOR) window, or undefined when the context has none (long-note ends). */ + ms?: WindowPairUs; +} + +export interface RulesetWindowTables { + note: JudgeWindowSetUs; + scratch: JudgeWindowSetUs; + longNoteEnd: JudgeWindowSetUs; + longScratchEnd: JudgeWindowSetUs; +} + +export type PlaylogRulesetId = 'lr2' | 'beatoraja' | 'iidx'; + +export type BeatorajaJudgeAlgorithm = 'combo' | 'duration' | 'lowest' | 'score'; + +/** How a ruleset plays the chart's long notes. */ +export type LongNoteStyle = + /** LR2: every long note is an LN — one deferred judgment, early release = BAD. */ + | 'ln' + /** beatoraja: per-note lnMode decides LN (1) vs CN (2) vs HCN (3). */ + | 'per-note' + /** IIDX: every long note is a CN (HCN when the chart says mode 3) — head and tail judged separately. */ + | 'charge'; + +export interface GaugeGutsStep { + /** Gauge value below (or at, when `inclusive`) which the damage multiplier applies. */ + threshold: number; + multiplier: number; + inclusive?: boolean; +} + +export interface GaugeSpec { + /** Ruleset-scoped gauge label reported in the result. */ + id: string; + min: number; + max: number; + initial: number; + /** Clear border; survival gauges use 0 (clear = survive). */ + border: number; + /** Survival gauges fail the moment they reach 0. */ + survival: boolean; + /** LR2 survival gauges: values below this collapse to 0 (death border). */ + death?: number; + /** Per-judge deltas in percent, `[PG, GR, GD, BD, missPOOR, emptyPOOR]`, AFTER TOTAL modifiers. */ + values: readonly [number, number, number, number, number, number]; + /** Low-gauge damage reduction steps (first match wins). */ + guts: readonly GaugeGutsStep[]; +} + +export interface RulesetConfig { + /** Versioned ruleset id written into the result (`'lr2/1'` etc.). */ + id: string; + rulesetId: PlaylogRulesetId; + windows: RulesetWindowTables; + /** + * LR2 dynamic `#EXRANKxx` support: returns the window tables active at `timeUs`. Rulesets without dynamic + * rank support return the static tables. + */ + windowsAt: (timeUs: number) => RulesetWindowTables; + selection: BeatorajaJudgeAlgorithm; + /** LR2 multi-BAD: one press BADs every other in-BAD-window (but out-of-GOOD-window) note on the lane. */ + multiBad: boolean; + /** LR2: a long-note head is never judged as a LATE bad — the press is ignored instead. */ + ignoreLateBadOnLnHead: boolean; + longNoteStyle: LongNoteStyle; + /** IIDX: a BAD / POOR on a charge-note head skips the tail judgment entirely. */ + headBadSkipsTail: boolean; + comboBreaksOnEmptyPoor: boolean; + /** HCN hold-state gauge tick interval (µs). */ + hcnTickUs: number; + /** HCN tick deltas as `[heldJudgeIndex, heldRate, releasedJudgeIndex, releasedRate]` (beatoraja model). */ + hcnTick: { heldJudge: number; heldRate: number; releasedJudge: number; releasedRate: number }; + gauge: GaugeSpec; + /** EX-SCORE denominator note count (longs count 1 for LN styles, 2 for charge styles). */ + noteCount: number; + /** Effective TOTAL after the ruleset's default formula. */ + effectiveTotal: number; + /** LR2 money score (`(4PG + 2GR + GD) × 50000 / notes`, floored). */ + moneyScore: boolean; +} + +export interface ResolveRulesetOptions { + /** Overrides the gauge picked from `playlog.play.gauge`. Ruleset-scoped id (see gauge tables). */ + gauge?: string; + /** beatoraja note-selection algorithm (default `'combo'`, beatoraja's own default). */ + judgeAlgorithm?: BeatorajaJudgeAlgorithm; +} + +const scale = (windows: { pgreat: number; great: number; good: number; bad: number }): JudgeWindowSetUs => ({ + judges: [ + [-windows.pgreat * 1000, windows.pgreat * 1000], + [-windows.great * 1000, windows.great * 1000], + [-windows.good * 1000, windows.good * 1000], + [-windows.bad * 1000, windows.bad * 1000], + ], + ms: [0, 1_000_000], +}); + +/** LR2 long-note end tolerance is the (rank-scaled) GOOD window on both ends (OpenLR2 `ProcLongnote`). */ +const lr2LongNoteEnd = (windows: { good: number; bad: number }): JudgeWindowSetUs => ({ + judges: [ + [-windows.good * 1000, windows.good * 1000], + [-windows.good * 1000, windows.good * 1000], + [-windows.good * 1000, windows.good * 1000], + [-windows.bad * 1000, windows.bad * 1000], + ], +}); + +function resolveLr2WindowTables(percent: number, overrideBadMs: number | undefined): RulesetWindowTables { + const windows = resolveBmsJudgeWindowsMsForPercent(percent, overrideBadMs); + const note = scale(windows); + const longEnd = lr2LongNoteEnd(windows); + return { note, scratch: note, longNoteEnd: longEnd, longScratchEnd: longEnd }; +} + +/** beatoraja judgerank percent per `BMSPlayerRule.validate` (NORMAL window rule). */ +function resolveBeatorajaJudgeRank(chart: PlaylogChart, rankTable: readonly number[]): number { + const exRank = chart.judgeRank.sourceExRank; + if (typeof exRank === 'number' && exRank > 0) { + if (chart.sourceFormat === 'bmson') { + return exRank; + } + // BMS #DEFEXRANK: value × (NORMAL-rule rank-2 percent) / 100. + return (exRank * rankTable[2]!) / 100; + } + const rank = chart.judgeRank.sourceRank; + if (typeof rank === 'number' && Number.isInteger(rank) && rank >= 0 && rank < rankTable.length) { + return rankTable[rank]!; + } + return rankTable[2]!; +} + +interface BeatorajaModeWindows { + note: readonly number[]; + scratch?: readonly number[]; + longNoteEnd: readonly number[]; + longScratchEnd?: readonly number[]; + rankTable: readonly number[]; + /** Which judge windows scale with judgerank (`[PG, GR, GD, BD]`; MS is always fixed). */ + scaled: readonly [boolean, boolean, boolean, boolean]; +} + +// beatoraja JudgeProperty flat tables: {PG late, PG early, GR..., GD..., BD..., MS late, MS early} in µs. +const BEATORAJA_MODES: Record<'FIVEKEYS' | 'SEVENKEYS' | 'PMS' | 'KEYBOARD', BeatorajaModeWindows> = { + FIVEKEYS: { + note: [-20000, 20000, -50000, 50000, -100000, 100000, -150000, 150000, -150000, 500000], + scratch: [-30000, 30000, -60000, 60000, -110000, 110000, -160000, 160000, -160000, 500000], + longNoteEnd: [-120000, 120000, -150000, 150000, -200000, 200000, -250000, 250000], + longScratchEnd: [-130000, 130000, -160000, 160000, -110000, 110000, -260000, 260000], + rankTable: [25, 50, 75, 100, 125], + scaled: [true, true, true, true], + }, + SEVENKEYS: { + note: [-20000, 20000, -60000, 60000, -150000, 150000, -280000, 220000, -150000, 500000], + scratch: [-30000, 30000, -70000, 70000, -160000, 160000, -290000, 230000, -160000, 500000], + longNoteEnd: [-120000, 120000, -160000, 160000, -200000, 200000, -280000, 220000], + longScratchEnd: [-130000, 130000, -170000, 170000, -210000, 210000, -290000, 230000], + rankTable: [25, 50, 75, 100, 125], + scaled: [true, true, true, true], + }, + PMS: { + note: [-20000, 20000, -50000, 50000, -117000, 117000, -183000, 183000, -175000, 500000], + longNoteEnd: [-120000, 120000, -150000, 150000, -217000, 217000, -283000, 283000], + rankTable: [33, 50, 70, 100, 133], + scaled: [false, true, true, false], + }, + KEYBOARD: { + note: [-30000, 30000, -90000, 90000, -200000, 200000, -320000, 240000, -200000, 650000], + longNoteEnd: [-160000, 25000, -200000, 75000, -260000, 140000, -320000, 240000], + rankTable: [25, 50, 75, 100, 125], + scaled: [true, true, true, true], + }, +}; + +function resolveBeatorajaMode(laneMode: string): BeatorajaModeWindows { + if (laneMode.startsWith('5') || laneMode.startsWith('10')) return BEATORAJA_MODES.FIVEKEYS; + if (laneMode.startsWith('9')) return BEATORAJA_MODES.PMS; + if (laneMode.startsWith('24') || laneMode.startsWith('48')) return BEATORAJA_MODES.KEYBOARD; + return BEATORAJA_MODES.SEVENKEYS; +} + +/** + * Applies beatoraja's `JudgeWindowRule.create` to one flat window table: scale the non-fixed judges by + * `judgerank / 100`, clamp every leg to the BAD leg, then enforce inner-to-outer monotonicity. + */ +function scaleBeatorajaWindows( + flat: readonly number[], + judgeRank: number, + scaled: readonly [boolean, boolean, boolean, boolean], +): JudgeWindowSetUs { + const judgeCount = flat.length >= 10 ? 5 : 4; + const legs: number[] = []; + for (let judge = 0; judge < 4; judge += 1) { + for (let side = 0; side < 2; side += 1) { + let value = flat[judge * 2 + side]!; + if (scaled[judge]) { + value = (value * judgeRank) / 100; + } + const badLeg = flat[3 * 2 + side]!; + if (Math.abs(value) > Math.abs(badLeg)) { + value = badLeg; + } + if (judge > 0 && Math.abs(value) < Math.abs(legs[(judge - 1) * 2 + side]!)) { + value = legs[(judge - 1) * 2 + side]!; + } + legs.push(Math.round(value)); + } + } + const set: JudgeWindowSetUs = { + judges: [ + [legs[0]!, legs[1]!], + [legs[2]!, legs[3]!], + [legs[4]!, legs[5]!], + [legs[6]!, legs[7]!], + ], + ...(judgeCount === 5 ? { ms: [flat[8]!, flat[9]!] as WindowPairUs } : {}), + }; + return set; +} + +function resolveBeatorajaWindowTables(chart: PlaylogChart): RulesetWindowTables { + const mode = resolveBeatorajaMode(chart.laneMode); + const judgeRank = resolveBeatorajaJudgeRank(chart, mode.rankTable); + const note = scaleBeatorajaWindows(mode.note, judgeRank, mode.scaled); + const scratch = mode.scratch ? scaleBeatorajaWindows(mode.scratch, judgeRank, mode.scaled) : note; + const longNoteEnd = scaleBeatorajaWindows(mode.longNoteEnd, judgeRank, mode.scaled); + const longScratchEnd = mode.longScratchEnd + ? scaleBeatorajaWindows(mode.longScratchEnd, judgeRank, mode.scaled) + : longNoteEnd; + return { note, scratch, longNoteEnd, longScratchEnd }; +} + +// IIDX community-consensus windows (iidx.org): PG ±1F / GR ±2F / GD ±7F / BD ±15F at 60 fps. +const IIDX_NOTE: JudgeWindowSetUs = { + judges: [ + [-16667, 16667], + [-33333, 33333], + [-116667, 116667], + [-250000, 250000], + ], + // The IIDX empty-POOR window has never been measured precisely; beatoraja's MS window (late 150 ms / + // early 500 ms) is used as the stand-in. + ms: [-150000, 500000], +}; +// IIDX CN release windows are "significantly wider" but unmeasured — beatoraja's SEVENKEYS long-note end +// windows are used as the stand-in. +const IIDX_LN_END: JudgeWindowSetUs = { + judges: [ + [-120000, 120000], + [-160000, 160000], + [-200000, 200000], + [-280000, 220000], + ], +}; + +const IIDX_WINDOWS: RulesetWindowTables = { + note: IIDX_NOTE, + scratch: IIDX_NOTE, + longNoteEnd: IIDX_LN_END, + longScratchEnd: IIDX_LN_END, +}; + +/** LR2 default TOTAL (OpenLR2 `LR2_bmsload.cpp`): piecewise-linear in the note count, ×0.8. */ +export function resolveLr2DefaultTotal(noteCount: number): number { + const n = Math.max(0, noteCount); + let base: number; + if (n < 400) { + base = n / 5 + 200; + } else if (n < 600) { + base = (n - 400) / 2.5 + 280; + } else { + base = (n - 600) / 5 + 360; + } + return base * 0.8; +} + +/** beatoraja default TOTAL (`BMSPlayerRule.calculateDefaultTotal`, keyboard modes excluded). */ +export function resolveBeatorajaDefaultTotal(noteCount: number): number { + const n = Math.max(1, noteCount); + return Math.max(260.0, (7.605 * n) / (0.01 * n + 6.5)); +} + +/** + * IIDX gauge recovery unit ("a value", percent per PGREAT/GREAT) — iidx.org measurement: `260 / n` up to 338 + * notes, `760.5 / (n + 650)` beyond, rounded to the nearest 0.02 %. + */ +export function resolveIidxGaugeUnit(noteCount: number): number { + const n = Math.max(1, noteCount); + const raw = n <= 338 ? 260 / n : 760.5 / (n + 650); + return Math.round(raw / 0.02 + 1e-9) * 0.02; +} + +/** + * lr2oraja `MODIFY_DAMAGE` — LR2 HARD/EX-HARD damage multiplier from TOTAL (fix1) and note count (fix2). + */ +export function resolveLr2HardDamageMultiplier(total: number, noteCount: number): number { + const fix1 = 10.0 / Math.min(10.0, Math.max(1.0, Math.floor(total / 16.0) - 5.0)); + const n = noteCount; + let fix2: number; + if (n <= 20) fix2 = 10.0; + else if (n < 30) fix2 = 8.0 + 0.2 * (30 - n); + else if (n < 60) fix2 = 5.0 + (0.2 * (60 - n)) / 3.0; + else if (n < 125) fix2 = 4.0 + (125 - n) / 65.0; + else if (n < 250) fix2 = 3.0 + 0.008 * (250 - n); + else if (n < 500) fix2 = 2.0 + 0.004 * (500 - n); + else if (n < 1000) fix2 = 1.0 + 0.002 * (1000 - n); + else fix2 = 1.0; + return Math.max(fix1, fix2); +} + +/** beatoraja `LIMIT_INCREMENT` — HARD/EX-HARD recovery scale from TOTAL and note count. */ +export function resolveBeatorajaHardRecoverMultiplier(total: number, noteCount: number): number { + const pg = Math.max(Math.min(0.15, (2 * total - 320) / Math.max(1, noteCount)), 0); + return pg / 0.15; +} + +type GaugeValues = readonly [number, number, number, number, number, number]; + +function totalModifier(values: GaugeValues, total: number, noteCount: number): GaugeValues { + return values.map((value) => + value > 0 ? (value * total) / Math.max(1, noteCount) : value, + ) as unknown as GaugeValues; +} + +function scalePositive(values: GaugeValues, multiplier: number): GaugeValues { + return values.map((value) => (value > 0 ? value * multiplier : value)) as unknown as GaugeValues; +} + +function scaleNegative(values: GaugeValues, multiplier: number): GaugeValues { + return values.map((value) => (value < 0 ? value * multiplier : value)) as unknown as GaugeValues; +} + +function resolveLr2Gauge(gaugeId: string, total: number, noteCount: number): GaugeSpec { + switch (gaugeId) { + case 'EASY': + return { + id: 'EASY', + min: 2, + max: 100, + initial: 20, + border: 80, + survival: false, + values: totalModifier([1.2, 1.2, 0.6, -3.2, -4.8, -1.6], total, noteCount), + guts: [], + }; + case 'HARD': { + const damage = resolveLr2HardDamageMultiplier(total, noteCount); + return { + id: 'HARD', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + death: 2, + values: scaleNegative([0.1, 0.1, 0.05, -6.0, -10.0, -2.0], damage), + guts: [{ threshold: 32, multiplier: 0.6 }], + }; + } + case 'EX-HARD': { + const damage = resolveLr2HardDamageMultiplier(total, noteCount); + return { + id: 'EX-HARD', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + death: 2, + values: scaleNegative([0.1, 0.1, 0.05, -12.0, -20.0, -2.0], damage), + guts: [], + }; + } + case 'DEATH': + // lr2oraja HAZARD_LR2 (beatoraja-derived values — LR2's own G-ATTACK/P-ATTACK family has no exact analog). + return { + id: 'DEATH', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + death: 2, + values: [0.15, 0.06, 0, -100, -100, -10], + guts: [], + }; + default: + return { + id: 'GROOVE', + min: 2, + max: 100, + initial: 20, + border: 80, + survival: false, + values: totalModifier([1.0, 1.0, 0.5, -4.0, -6.0, -2.0], total, noteCount), + guts: [], + }; + } +} + +const BEATORAJA_HARD_GUTS: readonly GaugeGutsStep[] = [ + { threshold: 10, multiplier: 0.4 }, + { threshold: 20, multiplier: 0.5 }, + { threshold: 30, multiplier: 0.6 }, + { threshold: 40, multiplier: 0.7 }, + { threshold: 50, multiplier: 0.8 }, +]; + +function resolveBeatorajaGauge(gaugeId: string, total: number, noteCount: number): GaugeSpec { + switch (gaugeId) { + case 'ASSIST-EASY': + return { + id: 'ASSIST-EASY', + min: 2, + max: 100, + initial: 20, + border: 60, + survival: false, + values: totalModifier([1.0, 1.0, 0.5, -1.5, -3.0, -0.5], total, noteCount), + guts: [], + }; + case 'EASY': + return { + id: 'EASY', + min: 2, + max: 100, + initial: 20, + border: 80, + survival: false, + values: totalModifier([1.0, 1.0, 0.5, -1.5, -4.5, -1.0], total, noteCount), + guts: [], + }; + case 'HARD': { + const recover = resolveBeatorajaHardRecoverMultiplier(total, noteCount); + return { + id: 'HARD', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + values: scalePositive([0.15, 0.12, 0.03, -5.0, -10.0, -5.0], recover), + guts: BEATORAJA_HARD_GUTS, + }; + } + case 'EX-HARD': { + const recover = resolveBeatorajaHardRecoverMultiplier(total, noteCount); + return { + id: 'EX-HARD', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + values: scalePositive([0.15, 0.06, 0, -8.0, -16.0, -8.0], recover), + guts: [], + }; + } + case 'HAZARD': + return { + id: 'HAZARD', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + values: [0.15, 0.06, 0, -100, -100, -10], + guts: [], + }; + default: + return { + id: 'NORMAL', + min: 2, + max: 100, + initial: 20, + border: 80, + survival: false, + values: totalModifier([1.0, 1.0, 0.5, -3.0, -6.0, -2.0], total, noteCount), + guts: [], + }; + } +} + +function resolveIidxGauge(gaugeId: string, noteCount: number): GaugeSpec { + const a = resolveIidxGaugeUnit(noteCount); + switch (gaugeId) { + case 'ASSISTED-EASY': + return { + id: 'ASSISTED-EASY', + min: 0, + max: 100, + initial: 22, + border: 60, + survival: false, + values: [a, a, a / 2, -1.6, -4.8, -1.6], + guts: [], + }; + case 'EASY': + return { + id: 'EASY', + min: 0, + max: 100, + initial: 22, + border: 80, + survival: false, + values: [a, a, a / 2, -1.6, -4.8, -1.6], + guts: [], + }; + case 'HARD': + return { + id: 'HARD', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + // Low Life Adjustment: at or below 30 %, BAD / POOR damage is halved (iidx.org). + values: [0.16, 0.16, 0, -5, -9, -5], + guts: [{ threshold: 30, multiplier: 0.5, inclusive: true }], + }; + case 'EX-HARD': + return { + id: 'EX-HARD', + min: 0, + max: 100, + initial: 100, + border: 0, + survival: true, + values: [0.16, 0.16, 0, -10, -18, -10], + guts: [], + }; + default: + return { + id: 'NORMAL', + min: 0, + max: 100, + initial: 22, + border: 80, + survival: false, + values: [a, a, a / 2, -2, -6, -2], + guts: [], + }; + } +} + +/** Maps the play-log's LR2-family gauge pick onto each ruleset's own gauge id. */ +function resolveDefaultGaugeId(rulesetId: PlaylogRulesetId, playGauge: string): string { + switch (playGauge) { + case 'EASY': + return 'EASY'; + case 'HARD': + return 'HARD'; + case 'DEATH': + return rulesetId === 'lr2' ? 'DEATH' : rulesetId === 'beatoraja' ? 'HAZARD' : 'EX-HARD'; + default: + return rulesetId === 'lr2' ? 'GROOVE' : 'NORMAL'; + } +} + +function countRulesetNotes(chart: PlaylogChart, style: LongNoteStyle): number { + let count = 0; + for (const note of chart.notes) { + if (note.type === 'normal') { + count += 1; + } else if (note.type === 'long') { + const mode = note.lnMode ?? chart.lnMode; + const chargeHeadAndTail = style === 'charge' || (style === 'per-note' && (mode === 2 || mode === 3)); + count += chargeHeadAndTail ? 2 : 1; + } + } + return count; +} + +function resolveEffectiveTotal(rulesetId: PlaylogRulesetId, chart: PlaylogChart, baseNoteCount: number): number { + const raw = chart.total; + if (rulesetId === 'beatoraja') { + const fallback = resolveBeatorajaDefaultTotal(baseNoteCount); + if (chart.sourceFormat === 'bmson') { + // bmson `info.total` is a percentage of the default TOTAL in beatoraja. + return typeof raw === 'number' && raw > 0 ? (raw / 100) * fallback : fallback; + } + return typeof raw === 'number' && raw > 0 ? raw : fallback; + } + if (typeof raw === 'number' && raw > 0) { + return raw; + } + return resolveLr2DefaultTotal(baseNoteCount); +} + +/** Number of scorable base notes (longs count 1) — the TOTAL formulas all use this denominator. */ +function countBaseNotes(chart: PlaylogChart): number { + let count = 0; + for (const note of chart.notes) { + if (note.type === 'normal' || note.type === 'long') { + count += 1; + } + } + return count; +} + +export function resolveRulesetConfig( + playlog: BeMusicPlaylog, + rulesetId: PlaylogRulesetId, + options: ResolveRulesetOptions = {}, +): RulesetConfig { + const chart = playlog.chart; + const baseNotes = countBaseNotes(chart); + const gaugeId = options.gauge ?? resolveDefaultGaugeId(rulesetId, playlog.play.gauge); + const overrideBadMs = playlog.play.judgeWindowOverrideMs; + + if (rulesetId === 'lr2') { + const noteCount = countRulesetNotes(chart, 'ln'); + const effectiveTotal = resolveEffectiveTotal('lr2', chart, baseNotes); + const timeline = chart.judgeRank.timeline ?? []; + const staticTables = resolveLr2WindowTables(chart.judgeRank.percent, overrideBadMs); + const timelineTables = timeline.map((change) => ({ + timeUs: change.timeUs, + tables: resolveLr2WindowTables(bmsExRankValueToJudgeRankPercent(change.exRankValue), overrideBadMs), + })); + return { + id: 'lr2/1', + rulesetId: 'lr2', + windows: staticTables, + windowsAt: (timeUs) => { + let active = staticTables; + for (const change of timelineTables) { + if (change.timeUs <= timeUs) { + active = change.tables; + } else { + break; + } + } + return active; + }, + selection: 'lowest', + multiBad: true, + ignoreLateBadOnLnHead: true, + longNoteStyle: 'ln', + headBadSkipsTail: false, + comboBreaksOnEmptyPoor: false, + hcnTickUs: 200_000, + hcnTick: { heldJudge: 1, heldRate: 0.5, releasedJudge: 3, releasedRate: 0.5 }, + gauge: resolveLr2Gauge(gaugeId, effectiveTotal, baseNotes), + noteCount, + effectiveTotal, + moneyScore: true, + }; + } + + if (rulesetId === 'beatoraja') { + const noteCount = countRulesetNotes(chart, 'per-note'); + const effectiveTotal = resolveEffectiveTotal('beatoraja', chart, baseNotes); + const tables = resolveBeatorajaWindowTables(chart); + const mode = resolveBeatorajaMode(chart.laneMode); + // FIVEKEYS / PMS break combo on an empty POOR (JudgeProperty combo[MS] = false). + const comboBreaksOnEmptyPoor = mode === BEATORAJA_MODES.FIVEKEYS || mode === BEATORAJA_MODES.PMS; + return { + id: 'beatoraja/1', + rulesetId: 'beatoraja', + windows: tables, + windowsAt: () => tables, + selection: options.judgeAlgorithm ?? 'combo', + multiBad: false, + ignoreLateBadOnLnHead: false, + longNoteStyle: 'per-note', + headBadSkipsTail: false, + comboBreaksOnEmptyPoor, + hcnTickUs: 200_000, + hcnTick: { heldJudge: 1, heldRate: 0.5, releasedJudge: 3, releasedRate: 0.5 }, + gauge: resolveBeatorajaGauge(gaugeId, effectiveTotal, baseNotes), + noteCount, + effectiveTotal, + moneyScore: false, + }; + } + + const noteCount = countRulesetNotes(chart, 'charge'); + const effectiveTotal = resolveEffectiveTotal('lr2', chart, baseNotes); + return { + id: 'iidx/1', + rulesetId: 'iidx', + windows: IIDX_WINDOWS, + windowsAt: () => IIDX_WINDOWS, + selection: 'lowest', + multiBad: false, + ignoreLateBadOnLnHead: false, + longNoteStyle: 'charge', + headBadSkipsTail: true, + comboBreaksOnEmptyPoor: false, + hcnTickUs: 200_000, + hcnTick: { heldJudge: 0, heldRate: 1, releasedJudge: 5, releasedRate: 1 }, + gauge: resolveIidxGauge(gaugeId, noteCount), + noteCount, + effectiveTotal, + moneyScore: false, + }; +} diff --git a/packages/player/src/playlog/simulate.test.ts b/packages/player/src/playlog/simulate.test.ts new file mode 100644 index 00000000..de427fe3 --- /dev/null +++ b/packages/player/src/playlog/simulate.test.ts @@ -0,0 +1,340 @@ +import { describe, expect, test } from 'vitest'; +import { + BE_MUSIC_PLAYLOG_FORMAT, + BE_MUSIC_PLAYLOG_VERSION, + type BeMusicPlaylog, + type PlaylogInputEvent, + type PlaylogNote, +} from './format.ts'; +import { + resolveBeatorajaDefaultTotal, + resolveBeatorajaHardRecoverMultiplier, + resolveIidxGaugeUnit, + resolveLr2DefaultTotal, + resolveLr2HardDamageMultiplier, + simulatePlaylog, + simulatePlaylogRulesets, + type PlaylogRulesetId, +} from './simulate.ts'; + +function note(timeUs: number, overrides: Partial<PlaylogNote> = {}): PlaylogNote { + return { id: 0, channel: '11', type: 'normal', timeUs, ...overrides }; +} + +function down(timeUs: number, channels: string[] = ['11']): Omit<PlaylogInputEvent, 'seq'> { + return { timeUs, action: 'down', channels }; +} + +function up(timeUs: number, channels: string[] = ['11']): Omit<PlaylogInputEvent, 'seq'> { + return { timeUs, action: 'up', channels }; +} + +interface MakePlaylogOverrides { + notes?: PlaylogNote[]; + inputs?: Array<Omit<PlaylogInputEvent, 'seq'>>; + chart?: Partial<BeMusicPlaylog['chart']>; + play?: Partial<BeMusicPlaylog['play']>; +} + +function makePlaylog(overrides: MakePlaylogOverrides = {}): BeMusicPlaylog { + const notes = (overrides.notes ?? []).map((entry, index) => ({ ...entry, id: index })); + return { + format: BE_MUSIC_PLAYLOG_FORMAT, + version: BE_MUSIC_PLAYLOG_VERSION, + clock: { unit: 'us', origin: 'chart-zero' }, + chart: { + sourceFormat: 'bms', + laneMode: '7keys', + lnMode: 1, + // LR2 #RANK 2 (NORMAL): internal percent 75; beatoraja reads sourceRank 2 → judgerank 75 %. + judgeRank: { percent: 75, sourceRank: 2 }, + noteCount: notes.filter((entry) => entry.type === 'normal' || entry.type === 'long').length, + notes, + ...overrides.chart, + }, + inputs: (overrides.inputs ?? []).map((input, seq) => ({ ...input, seq })), + play: { mode: 'manual', autoScratch: false, gauge: 'GROOVE', ...overrides.play }, + }; +} + +/** One note at t = 1s, one press at `dmUs` before it (dm = noteTimeUs − inputTimeUs; positive = early). */ +function simulateSingleNote(ruleset: PlaylogRulesetId, dmUs: number) { + return simulatePlaylog(makePlaylog({ notes: [note(1_000_000)], inputs: [down(1_000_000 - dmUs)] }), { ruleset }); +} + +describe('simulatePlaylog', () => { + test('a single note hit dead-on scores PGREAT on every ruleset', () => { + const playlog = makePlaylog({ notes: [note(1_000_000)], inputs: [down(1_000_000)] }); + const results = simulatePlaylogRulesets(playlog); + for (const ruleset of ['lr2', 'beatoraja', 'iidx'] as const) { + const result = results[ruleset]!; + expect(result.judge, ruleset).toEqual({ pgreat: 1, great: 0, good: 0, bad: 0, poor: 0, emptyPoor: 0 }); + expect(result.exScore, ruleset).toBe(2); + expect(result.maxCombo, ruleset).toBe(1); + expect(result.noteCount, ruleset).toBe(1); + // A one-note chart's gauge gain saturates every normal gauge. + expect(result.gauge.final, ruleset).toBe(100); + expect(result.gauge.cleared, ruleset).toBe(true); + } + expect(results.lr2!.ruleset).toBe('lr2/1'); + expect(results.beatoraja!.ruleset).toBe('beatoraja/1'); + expect(results.iidx!.ruleset).toBe('iidx/1'); + expect(results.lr2!.score).toBe(200000); // (4 PG × 50000) / 1 note + expect(results.lr2!.djLevel).toBe('AAA'); + expect(results.beatoraja!.score).toBeUndefined(); // money score is LR2-only + }); + + test('LR2 RANK 2 windows: PGREAT ±18ms / GREAT ±40ms / GOOD ±100ms / BAD ±200ms, inclusive', () => { + expect(simulateSingleNote('lr2', 18_000).judge.pgreat).toBe(1); + + const fastGreat = simulateSingleNote('lr2', 19_000); + expect(fastGreat.judge.great).toBe(1); + expect(fastGreat.fast).toBe(1); // positive dm = early press = FAST + expect(fastGreat.slow).toBe(0); + + expect(simulateSingleNote('lr2', 40_000).judge.great).toBe(1); + expect(simulateSingleNote('lr2', 41_000).judge.good).toBe(1); + expect(simulateSingleNote('lr2', 100_000).judge.good).toBe(1); + + const bad = simulateSingleNote('lr2', 101_000); + expect(bad.judge.bad).toBe(1); + expect(bad.judge.poor).toBe(0); // the BAD consumed the note + + // Late presses mirror the early windows and count as SLOW. + const slowGreat = simulateSingleNote('lr2', -19_000); + expect(slowGreat.judge.great).toBe(1); + expect(slowGreat.slow).toBe(1); + expect(slowGreat.fast).toBe(0); + }); + + test('LR2: outside BAD but inside the early-only MS window is an empty POOR that leaves the note', () => { + const result = simulateSingleNote('lr2', 201_000); + expect(result.judge.emptyPoor).toBe(1); + expect(result.judge.bad).toBe(0); + expect(result.judge.poor).toBe(1); // the untouched note eventually misses + expect(result.maxCombo).toBe(0); + }); + + test('IIDX windows: ±16.67ms PGREAT / ±33.33ms GREAT / ±116.67ms GOOD / ±250ms BAD', () => { + expect(simulateSingleNote('iidx', 16_667).judge.pgreat).toBe(1); + expect(simulateSingleNote('iidx', 16_668).judge.great).toBe(1); + expect(simulateSingleNote('iidx', 33_333).judge.great).toBe(1); + expect(simulateSingleNote('iidx', 33_334).judge.good).toBe(1); + expect(simulateSingleNote('iidx', 116_667).judge.good).toBe(1); + expect(simulateSingleNote('iidx', 116_668).judge.bad).toBe(1); + expect(simulateSingleNote('iidx', 250_000).judge.bad).toBe(1); + + const beyondBad = simulateSingleNote('iidx', 250_001); + expect(beyondBad.judge.emptyPoor).toBe(1); + expect(beyondBad.judge.poor).toBe(1); + }); + + test('beatoraja #RANK 2 scales the SEVENKEYS PGREAT window to ±15ms (20ms × 0.75)', () => { + expect(simulateSingleNote('beatoraja', 15_000).judge.pgreat).toBe(1); + expect(simulateSingleNote('beatoraja', 15_001).judge.great).toBe(1); + expect(simulateSingleNote('beatoraja', -15_000).judge.pgreat).toBe(1); + }); + + test('unplayed notes miss as POOR and drain the gauge', () => { + const playlog = makePlaylog({ notes: [note(1_000_000), note(2_000_000)] }); + const results = simulatePlaylogRulesets(playlog); + for (const ruleset of ['lr2', 'beatoraja', 'iidx'] as const) { + const result = results[ruleset]!; + expect(result.judge.poor, ruleset).toBe(2); + expect(result.exScore, ruleset).toBe(0); + expect(result.maxCombo, ruleset).toBe(0); + expect(result.gauge.cleared, ruleset).toBe(false); + } + expect(results.lr2!.gauge.final).toBeCloseTo(8, 6); // 20 − 6 − 6 + }); + + test('a press 900ms early: LR2 empty POOR; beatoraja is outside its MS window and does nothing', () => { + const playlog = makePlaylog({ notes: [note(2_000_000)], inputs: [down(1_100_000)] }); + + const lr2 = simulatePlaylog(playlog, { ruleset: 'lr2' }); + expect(lr2.judge.emptyPoor).toBe(1); + expect(lr2.judge.poor).toBe(1); // the note itself still misses + + const beatoraja = simulatePlaylog(playlog, { ruleset: 'beatoraja' }); + expect(beatoraja.judge.emptyPoor).toBe(0); // MS window is only 500ms early + expect(beatoraja.judge.poor).toBe(1); + }); + + test('LR2 multi-BAD: one press BADs every note inside BAD but outside GOOD', () => { + const playlog = makePlaylog({ + notes: [note(1_000_000), note(1_050_000), note(1_100_000)], + inputs: [down(850_000)], // dm = +150ms / +200ms / +250ms + }); + + const lr2 = simulatePlaylog(playlog, { ruleset: 'lr2' }); + expect(lr2.judge.bad).toBe(2); // notes 1 & 2; note 3 sits beyond the ±200ms BAD window + expect(lr2.judge.poor).toBe(1); // note 3 eventually misses + expect(lr2.judge.emptyPoor).toBe(0); + expect(lr2.maxCombo).toBe(0); + + // beatoraja has no multi-BAD: the same press consumes exactly one note. + const beatoraja = simulatePlaylog(playlog, { ruleset: 'beatoraja' }); + expect(beatoraja.judge.bad).toBe(1); + expect(beatoraja.judge.poor).toBe(2); + }); + + test('beatoraja note selection: combo picks the in-GOOD-reach later note, lowest the earliest', () => { + // First note is 120ms late (outside GOOD ±112.5ms), second is 40ms early (GREAT). + const playlog = makePlaylog({ + notes: [note(1_000_000), note(1_160_000)], + inputs: [down(1_120_000)], + }); + + const combo = simulatePlaylog(playlog, { ruleset: 'beatoraja' }); // beatoraja default algorithm + expect(combo.judge).toEqual({ pgreat: 0, great: 1, good: 0, bad: 0, poor: 1, emptyPoor: 0 }); + + const lowest = simulatePlaylog(playlog, { ruleset: 'beatoraja', judgeAlgorithm: 'lowest' }); + expect(lowest.judge).toEqual({ pgreat: 0, great: 0, good: 0, bad: 1, poor: 1, emptyPoor: 0 }); + }); + + test('LN (mode 1): head press held to the tail judges exactly once', () => { + for (const ruleset of ['lr2', 'beatoraja'] as const) { + const heldToEnd = simulatePlaylog( + makePlaylog({ + notes: [note(1_000_000, { type: 'long', endTimeUs: 2_000_000, lnMode: 1 })], + inputs: [down(1_000_000)], // never released — the hold survives to the tail + }), + { ruleset }, + ); + expect(heldToEnd.judge, ruleset).toEqual({ pgreat: 1, great: 0, good: 0, bad: 0, poor: 0, emptyPoor: 0 }); + expect(heldToEnd.exScore, ruleset).toBe(2); + expect(heldToEnd.noteCount, ruleset).toBe(1); + expect(heldToEnd.maxCombo, ruleset).toBe(1); + + const releasedAfterEnd = simulatePlaylog( + makePlaylog({ + notes: [note(1_000_000, { type: 'long', endTimeUs: 2_000_000, lnMode: 1 })], + inputs: [down(1_000_000), up(2_100_000)], + }), + { ruleset }, + ); + expect(releasedAfterEnd.judge.pgreat, ruleset).toBe(1); + expect(releasedAfterEnd.exScore, ruleset).toBe(2); + } + }); + + test('LN (mode 1): an early release is a single BAD', () => { + const result = simulatePlaylog( + makePlaylog({ + notes: [note(1_000_000, { type: 'long', endTimeUs: 2_000_000, lnMode: 1 })], + inputs: [down(1_000_000), up(1_200_000)], // released 800ms before the tail + }), + { ruleset: 'lr2' }, + ); + expect(result.judge).toEqual({ pgreat: 0, great: 0, good: 0, bad: 1, poor: 0, emptyPoor: 0 }); + expect(result.exScore).toBe(0); + }); + + test('CN (mode 2): beatoraja judges head and tail; noteCount is style-dependent', () => { + const playlog = makePlaylog({ + notes: [note(1_000_000, { type: 'long', endTimeUs: 2_000_000, lnMode: 2 })], + inputs: [down(1_000_000), up(2_000_000)], + }); + + const beatoraja = simulatePlaylog(playlog, { ruleset: 'beatoraja' }); + expect(beatoraja.judge.pgreat).toBe(2); + expect(beatoraja.exScore).toBe(4); + expect(beatoraja.noteCount).toBe(2); // charge style counts head + tail + expect(beatoraja.maxCombo).toBe(2); + + // LR2 plays the same chart as an LN: one deferred judgment. + const lr2 = simulatePlaylog(playlog, { ruleset: 'lr2' }); + expect(lr2.judge.pgreat).toBe(1); + expect(lr2.exScore).toBe(2); + expect(lr2.noteCount).toBe(1); + }); + + test('IIDX: a BAD on a charge-note head skips the tail judgment', () => { + const result = simulatePlaylog( + makePlaylog({ + notes: [note(1_000_000, { type: 'long', endTimeUs: 2_000_000 })], + inputs: [down(800_000)], // +200ms: inside BAD, outside GOOD + }), + { ruleset: 'iidx' }, + ); + expect(result.judge.bad).toBe(1); + expect(result.judge.poor).toBe(0); // no tail judgment at all + expect(result.judge.pgreat).toBe(0); + expect(result.noteCount).toBe(2); // the denominator still counts head + tail + }); + + test('HARD fails mid-play at 0 and stays failed; GROOVE bottoms out at its 2 % floor', () => { + const hard = simulatePlaylog( + makePlaylog({ + notes: [note(1_000_000), note(3_000_000)], + inputs: [down(850_000), down(2_850_000)], // two +150ms BADs at ×10 damage (tiny note count) + play: { gauge: 'HARD' }, + }), + { ruleset: 'lr2' }, + ); + expect(hard.judge.bad).toBe(2); + expect(hard.gauge.type).toBe('HARD'); + expect(hard.gauge.final).toBe(0); + expect(hard.gauge.failedMidPlay).toBe(true); + expect(hard.gauge.cleared).toBe(false); + + const groove = simulatePlaylog( + makePlaylog({ + notes: [note(1_000_000), note(2_000_000), note(3_000_000), note(4_000_000), note(5_000_000)], + }), + { ruleset: 'lr2' }, + ); + expect(groove.judge.poor).toBe(5); + expect(groove.gauge.final).toBe(2); // GROOVE's soft floor — it never dies + expect(groove.gauge.failedMidPlay).toBeUndefined(); + expect(groove.gauge.cleared).toBe(false); + }); + + test('auto play scores every note PGREAT and clears', () => { + const result = simulatePlaylog(makePlaylog({ notes: [note(1_000_000), note(2_000_000)], play: { mode: 'auto' } }), { + ruleset: 'lr2', + }); + expect(result.judge).toEqual({ pgreat: 2, great: 0, good: 0, bad: 0, poor: 0, emptyPoor: 0 }); + expect(result.maxCombo).toBe(2); + expect(result.gauge.final).toBe(100); + expect(result.gauge.cleared).toBe(true); + }); + + test('autoScratch auto-plays the scratch channel without inputs', () => { + const notes = [note(1_000_000, { channel: '16' })]; + + const auto = simulatePlaylog(makePlaylog({ notes, play: { autoScratch: true } }), { ruleset: 'lr2' }); + expect(auto.judge.pgreat).toBe(1); + expect(auto.judge.poor).toBe(0); + + const manual = simulatePlaylog(makePlaylog({ notes }), { ruleset: 'lr2' }); + expect(manual.judge.pgreat).toBe(0); + expect(manual.judge.poor).toBe(1); + }); +}); + +describe('ruleset helpers', () => { + test('resolveLr2DefaultTotal follows the OpenLR2 piecewise formula (×0.8)', () => { + expect(resolveLr2DefaultTotal(0)).toBeCloseTo(160, 9); + expect(resolveLr2DefaultTotal(500)).toBeCloseTo(256, 9); // ((500 − 400) / 2.5 + 280) × 0.8 + expect(resolveLr2DefaultTotal(1000)).toBeCloseTo(352, 9); // ((1000 − 600) / 5 + 360) × 0.8 + }); + + test('resolveBeatorajaDefaultTotal floors at 260', () => { + expect(resolveBeatorajaDefaultTotal(10)).toBe(260); + expect(resolveBeatorajaDefaultTotal(2000)).toBeCloseTo((7.605 * 2000) / (0.01 * 2000 + 6.5), 9); // ≈ 573.96 + }); + + test('resolveIidxGaugeUnit rounds to the nearest 0.02 %', () => { + expect(resolveIidxGaugeUnit(100)).toBeCloseTo(2.6, 9); // 260 / 100 + expect(resolveIidxGaugeUnit(338)).toBeCloseTo(0.76, 9); // 260 / 338 ≈ 0.769 → 0.76 + expect(resolveIidxGaugeUnit(1000)).toBeCloseTo(0.46, 9); // 760.5 / 1650 ≈ 0.461 → 0.46 + }); + + test('LR2 hard damage / beatoraja hard recovery multipliers', () => { + expect(resolveLr2HardDamageMultiplier(240, 1000)).toBe(1); // fix1 = 1, fix2 = 1 + expect(resolveLr2HardDamageMultiplier(160, 2)).toBe(10); // tiny charts hit the fix2 = 10 cap + expect(resolveBeatorajaHardRecoverMultiplier(300, 2000)).toBeCloseTo(0.14 / 0.15, 9); + expect(resolveBeatorajaHardRecoverMultiplier(160, 100)).toBe(0); // 2 × TOTAL − 320 = 0 + }); +}); diff --git a/packages/player/src/playlog/simulate.ts b/packages/player/src/playlog/simulate.ts new file mode 100644 index 00000000..a72e4b5c --- /dev/null +++ b/packages/player/src/playlog/simulate.ts @@ -0,0 +1,721 @@ +import { resolveIidxRankLabel } from '../core/scoring.ts'; +import type { BeMusicPlaylog, PlaylogInputEvent, PlaylogRulesetResult } from './format.ts'; +import { + resolveRulesetConfig, + type GaugeSpec, + type JudgeWindowSetUs, + type PlaylogRulesetId, + type ResolveRulesetOptions, + type RulesetConfig, + type RulesetWindowTables, +} from './rulesets.ts'; + +export type { PlaylogRulesetId, BeatorajaJudgeAlgorithm, ResolveRulesetOptions } from './rulesets.ts'; +export { + resolveRulesetConfig, + resolveLr2DefaultTotal, + resolveBeatorajaDefaultTotal, + resolveIidxGaugeUnit, + resolveLr2HardDamageMultiplier, + resolveBeatorajaHardRecoverMultiplier, +} from './rulesets.ts'; + +export interface SimulatePlaylogOptions extends ResolveRulesetOptions { + ruleset: PlaylogRulesetId; +} + +export const PLAYLOG_SIMULATOR_RULESETS: readonly PlaylogRulesetId[] = ['lr2', 'beatoraja', 'iidx']; + +/** + * Re-derives one ruleset's judgments / EX-SCORE / combo / gauge from a playlog's canonical data (resolved chart + + * raw input stream + play settings). Pure function — never mutates the playlog. + * + * The LR2 simulation follows lr2oraja / OpenLR2 semantics, the beatoraja simulation the current beatoraja master, + * and the IIDX simulation the community-measured behavior of recent arcade versions (with documented stand-ins + * where no measurement exists — see `rulesets.ts`). + */ +export function simulatePlaylog(playlog: BeMusicPlaylog, options: SimulatePlaylogOptions): PlaylogRulesetResult { + const config = resolveRulesetConfig(playlog, options.ruleset, options); + return new PlaylogSimulation(playlog, config).run(); +} + +/** Runs {@link simulatePlaylog} for each requested ruleset (default: LR2, beatoraja, IIDX). */ +export function simulatePlaylogRulesets( + playlog: BeMusicPlaylog, + rulesets: readonly PlaylogRulesetId[] = PLAYLOG_SIMULATOR_RULESETS, + options: ResolveRulesetOptions = {}, +): Record<string, PlaylogRulesetResult> { + const results: Record<string, PlaylogRulesetResult> = {}; + for (const ruleset of rulesets) { + results[ruleset] = simulatePlaylog(playlog, { ...options, ruleset }); + } + return results; +} + +// Judge indices follow beatoraja: 0 PG / 1 GR / 2 GD / 3 BD / 4 missed POOR / 5 empty POOR. +const JUDGE_PGREAT = 0; +const JUDGE_GREAT = 1; +const JUDGE_GOOD = 2; +const JUDGE_BAD = 3; +const JUDGE_MISS_POOR = 4; +const JUDGE_EMPTY_POOR = 5; +/** Selection-time marker: no window matched. */ +const JUDGE_NONE = 6; + +type SimLongStyle = 1 | 2 | 3; + +interface SimNote { + timeUs: number; + endTimeUs?: number; + scratch: boolean; + isLong: boolean; + /** Resolved long-note style for this ruleset (1 LN / 2 CN / 3 HCN). */ + longStyle?: SimLongStyle; + judged: boolean; + holding: boolean; + /** Miss-sweep deadline (input time past which the head can no longer be judged). */ + missDeadlineUs: number; +} + +interface SimMine { + timeUs: number; + damage: number; + applied: boolean; +} + +interface ActiveHold { + note: SimNote; + /** Deferred LN head judge (style 1). */ + headJudge?: number; + headDmUs?: number; + /** IIDX charge heads that BAD/POOR'd skip the tail — such notes never become holds. */ + /** Held-past-end deadline for charge tails. */ + tailMissDeadlineUs: number; + /** Signed HCN tick accumulator (µs). */ + hcnCounterUs: number; +} + +interface SimLane { + channel: string; + scratch: boolean; + notes: SimNote[]; + mines: SimMine[]; + sweepCursor: number; + mineCursor: number; + held: boolean; + hold?: ActiveHold; + /** Auto-played lane (AUTO mode or AUTO SCRATCH): every note resolves PGREAT on schedule. */ + auto: boolean; + autoCursor: number; +} + +class SimGauge { + value: number; + failedMidPlay = false; + private dead = false; + + constructor(private readonly spec: GaugeSpec) { + this.value = spec.initial; + } + + update(judgeIndex: number, rate = 1): void { + if (this.dead) return; + let delta = this.spec.values[judgeIndex]! * rate; + if (delta < 0) { + for (const step of this.spec.guts) { + if (step.inclusive === true ? this.value <= step.threshold : this.value < step.threshold) { + delta *= step.multiplier; + break; + } + } + } + this.set(this.value + delta); + } + + addRaw(delta: number): void { + if (this.dead) return; + this.set(this.value + delta); + } + + cleared(): boolean { + if (this.spec.survival) { + return !this.failedMidPlay && this.value > 0; + } + return this.value >= this.spec.border; + } + + private set(next: number): void { + let value = Math.min(this.spec.max, Math.max(this.spec.min, next)); + if (this.spec.death !== undefined && value < this.spec.death) { + value = 0; + } + if (this.spec.survival && value <= 0) { + value = 0; + this.dead = true; + this.failedMidPlay = true; + } + this.value = value; + } +} + +interface SelectionCandidate { + lane: SimLane; + note: SimNote; + dmUs: number; + /** 0..3 scoreable, 4 pending-in-MS-window, 5 judged-in-MS-window. */ + judge: number; +} + +class PlaylogSimulation { + private readonly lanes = new Map<string, SimLane>(); + private readonly counts = [0, 0, 0, 0, 0, 0]; + private readonly gauge: SimGauge; + private combo = 0; + private maxCombo = 0; + private fast = 0; + private slow = 0; + private exScore = 0; + private lastAdvanceUs = Number.NEGATIVE_INFINITY; + + constructor( + private readonly playlog: BeMusicPlaylog, + private readonly config: RulesetConfig, + ) { + this.gauge = new SimGauge(config.gauge); + this.buildLanes(); + } + + run(): PlaylogRulesetResult { + const inputs = [...this.playlog.inputs].sort((left, right) => left.timeUs - right.timeUs || left.seq - right.seq); + for (const input of inputs) { + this.advanceTime(input.timeUs); + if (input.action === 'down') { + this.handleDown(input); + } else { + this.handleUp(input); + } + } + this.advanceTime(Number.POSITIVE_INFINITY); + + const result: PlaylogRulesetResult = { + ruleset: this.config.id, + judge: { + pgreat: this.counts[JUDGE_PGREAT]!, + great: this.counts[JUDGE_GREAT]!, + good: this.counts[JUDGE_GOOD]!, + bad: this.counts[JUDGE_BAD]!, + poor: this.counts[JUDGE_MISS_POOR]!, + emptyPoor: this.counts[JUDGE_EMPTY_POOR]!, + }, + fast: this.fast, + slow: this.slow, + exScore: this.exScore, + noteCount: this.config.noteCount, + maxCombo: this.maxCombo, + djLevel: resolveIidxRankLabel(this.exScore, this.config.noteCount), + gauge: { + type: this.config.gauge.id, + final: Math.round(this.gauge.value * 100) / 100, + cleared: this.gauge.cleared(), + }, + }; + if (this.gauge.failedMidPlay) { + result.gauge.failedMidPlay = true; + } + if (this.config.moneyScore) { + const notes = Math.max(1, this.config.noteCount); + result.score = Math.floor( + ((4 * this.counts[JUDGE_PGREAT]! + 2 * this.counts[JUDGE_GREAT]! + this.counts[JUDGE_GOOD]!) * 50000) / notes, + ); + } + return result; + } + + private buildLanes(): void { + const autoPlay = this.playlog.play.mode === 'auto'; + const autoScratch = this.playlog.play.autoScratch; + for (const note of this.playlog.chart.notes) { + if (note.type === 'invisible' || note.type === 'freezone') { + continue; + } + const lane = this.laneFor(note.channel, autoPlay, autoScratch); + if (note.type === 'mine') { + lane.mines.push({ timeUs: note.timeUs, damage: note.damage ?? 0, applied: false }); + continue; + } + const isLong = + note.type === 'long' && typeof note.endTimeUs === 'number' && note.endTimeUs > note.timeUs ? true : false; + const longStyle = isLong ? this.resolveLongStyle(note.lnMode ?? this.playlog.chart.lnMode) : undefined; + const windows = this.config.windowsAt(note.timeUs); + const noteWindows = lane.scratch ? windows.scratch : windows.note; + const simNote: SimNote = { + timeUs: note.timeUs, + scratch: lane.scratch, + isLong, + judged: false, + holding: false, + missDeadlineUs: note.timeUs - noteWindows.judges[JUDGE_BAD]![0], + }; + if (isLong) { + simNote.endTimeUs = note.endTimeUs; + simNote.longStyle = longStyle; + } + lane.notes.push(simNote); + } + for (const lane of this.lanes.values()) { + lane.notes.sort((left, right) => left.timeUs - right.timeUs); + lane.mines.sort((left, right) => left.timeUs - right.timeUs); + } + } + + private laneFor(channel: string, autoPlay: boolean, autoScratch: boolean): SimLane { + let lane = this.lanes.get(channel); + if (!lane) { + const scratch = channel === '16' || channel === '26'; + lane = { + channel, + scratch, + notes: [], + mines: [], + sweepCursor: 0, + mineCursor: 0, + held: false, + auto: autoPlay || (autoScratch && scratch), + autoCursor: 0, + }; + this.lanes.set(channel, lane); + } + return lane; + } + + private resolveLongStyle(chartMode: SimLongStyle): SimLongStyle { + switch (this.config.longNoteStyle) { + case 'ln': + return 1; + case 'charge': + return chartMode === 3 ? 3 : 2; + default: + return chartMode; + } + } + + // ---- time advancement -------------------------------------------------------------------------------------- + + private advanceTime(untilUs: number): void { + interface TimedEvent { + timeUs: number; + kind: 'miss' | 'mine' | 'hold-deadline' | 'auto'; + lane: SimLane; + note?: SimNote; + mine?: SimMine; + } + const events: TimedEvent[] = []; + for (const lane of this.lanes.values()) { + if (lane.auto) { + for (let index = lane.autoCursor; index < lane.notes.length; index += 1) { + const note = lane.notes[index]!; + if (note.timeUs >= untilUs) break; + // LN-style longs score once at the tail; everything else at the head. (Charge-style auto applies the + // head and tail PGREATs together at the head — a simplification that only shifts gauge gain earlier.) + const autoAt = note.isLong && note.longStyle === 1 ? note.endTimeUs! : note.timeUs; + if (autoAt >= untilUs) continue; + events.push({ timeUs: autoAt, kind: 'auto', lane, note }); + } + } else { + for (let index = lane.sweepCursor; index < lane.notes.length; index += 1) { + const note = lane.notes[index]!; + if (note.missDeadlineUs >= untilUs) break; + if (!note.judged && !note.holding) { + events.push({ timeUs: note.missDeadlineUs, kind: 'miss', lane, note }); + } + } + if (lane.hold && lane.hold.tailMissDeadlineUs < untilUs) { + events.push({ timeUs: lane.hold.tailMissDeadlineUs, kind: 'hold-deadline', lane, note: lane.hold.note }); + } + } + for (let index = lane.mineCursor; index < lane.mines.length; index += 1) { + const mine = lane.mines[index]!; + if (mine.timeUs >= untilUs) break; + events.push({ timeUs: mine.timeUs, kind: 'mine', lane, mine }); + } + } + events.sort((left, right) => left.timeUs - right.timeUs); + + for (const event of events) { + if (event.kind === 'auto') { + const note = event.note!; + if (note.judged) continue; + note.judged = true; + this.applyJudge(JUDGE_PGREAT, undefined); + if (note.isLong && note.longStyle !== 1) { + // Charge styles judge head and tail; auto play scores both as PGREAT. + this.applyJudge(JUDGE_PGREAT, undefined); + } + } else if (event.kind === 'miss') { + const note = event.note!; + if (note.judged || note.holding) continue; + note.judged = true; + this.applyJudge(JUDGE_MISS_POOR, undefined); + if (note.isLong && note.longStyle !== 1 && !this.config.headBadSkipsTail) { + // beatoraja: a missed CN/HCN head also POORs the tail. IIDX (headBadSkipsTail) skips it. + this.applyJudge(JUDGE_MISS_POOR, undefined); + } + } else if (event.kind === 'mine') { + const mine = event.mine!; + if (mine.applied) continue; + mine.applied = true; + if (event.lane.held && mine.damage > 0) { + this.gauge.addRaw(-mine.damage); + } + } else { + // Charge tail held past its late window — the tail resolves as a missed POOR (beatoraja / IIDX). + const lane = event.lane; + const hold = lane.hold; + if (!hold || hold.note !== event.note) continue; + this.integrateHcn(lane, event.timeUs); + lane.hold = undefined; + hold.note.holding = false; + hold.note.judged = true; + this.applyJudge(JUDGE_MISS_POOR, undefined); + } + } + + // LN (style 1) holds confirm their deferred head judgment once the tail time is reached while still held. + for (const lane of this.lanes.values()) { + const hold = lane.hold; + if (hold && hold.note.longStyle === 1 && hold.note.endTimeUs! < untilUs) { + this.integrateHcn(lane, hold.note.endTimeUs!); + lane.hold = undefined; + hold.note.holding = false; + hold.note.judged = true; + this.applyJudge(hold.headJudge ?? JUDGE_BAD, hold.headDmUs); + } + this.integrateHcn(lane, untilUs); + } + + // Advance sweep cursors past settled notes. + for (const lane of this.lanes.values()) { + while (lane.sweepCursor < lane.notes.length) { + const note = lane.notes[lane.sweepCursor]!; + if (note.judged || (note.missDeadlineUs < untilUs && !note.holding)) { + lane.sweepCursor += 1; + } else { + break; + } + } + while (lane.autoCursor < lane.notes.length && lane.notes[lane.autoCursor]!.judged) { + lane.autoCursor += 1; + } + while (lane.mineCursor < lane.mines.length && lane.mines[lane.mineCursor]!.applied) { + lane.mineCursor += 1; + } + } + this.lastAdvanceUs = untilUs; + } + + /** Integrates the beatoraja-model HCN hold ticks for a lane up to `untilUs`. */ + private integrateHcn(lane: SimLane, untilUs: number): void { + const hold = lane.hold; + if (!hold || hold.note.longStyle !== 3) return; + const from = Math.max(hold.note.timeUs, this.lastAdvanceUs === Number.NEGATIVE_INFINITY ? 0 : this.lastAdvanceUs); + const to = Math.min(untilUs, hold.note.endTimeUs!); + if (!(to > from)) return; + let dt = to - from; + const tick = this.config.hcnTickUs; + if (lane.held) { + hold.hcnCounterUs += dt; + while (hold.hcnCounterUs > tick) { + this.gauge.update(this.config.hcnTick.heldJudge, this.config.hcnTick.heldRate); + hold.hcnCounterUs -= tick; + } + } else { + hold.hcnCounterUs -= dt; + while (hold.hcnCounterUs < -tick) { + this.gauge.update(this.config.hcnTick.releasedJudge, this.config.hcnTick.releasedRate); + hold.hcnCounterUs += tick; + } + } + } + + // ---- input handling ---------------------------------------------------------------------------------------- + + private handleDown(input: PlaylogInputEvent): void { + const timeUs = input.timeUs; + const windows = this.config.windowsAt(timeUs); + const lanes = this.resolveInputLanes(input); + for (const lane of lanes) { + lane.held = true; + } + if (lanes.length === 0) { + return; + } + + const selected = this.selectCandidate(lanes, timeUs, windows); + if (!selected) { + return; + } + if (selected.judge >= JUDGE_MISS_POOR) { + // Empty POOR — the note is never consumed. + this.applyJudge(JUDGE_EMPTY_POOR, undefined); + return; + } + + const { note, lane, dmUs } = selected; + if (note.isLong) { + this.startLongNote(lane, note, selected.judge, dmUs); + } else { + note.judged = true; + this.applyJudge(selected.judge, dmUs); + } + if (this.config.multiBad) { + this.applyMultiBad(lanes, timeUs, windows, note, selected.judge); + } + } + + private handleUp(input: PlaylogInputEvent): void { + const timeUs = input.timeUs; + for (const lane of this.resolveInputLanes(input)) { + lane.held = false; + const hold = lane.hold; + if (!hold) continue; + this.integrateHcn(lane, timeUs); + const note = hold.note; + const endWindows = note.scratch + ? this.config.windowsAt(timeUs).longScratchEnd + : this.config.windowsAt(timeUs).longNoteEnd; + const dmUs = note.endTimeUs! - timeUs; + const endJudge = classifyJudge(dmUs, endWindows); + lane.hold = undefined; + note.holding = false; + note.judged = true; + if (note.longStyle === 1) { + // LN: worse of head and tail; an early release outside the GOOD reach is a BAD. + let judge = Math.max(endJudge === JUDGE_NONE ? JUDGE_MISS_POOR : endJudge, hold.headJudge ?? JUDGE_BAD); + if (judge >= JUDGE_BAD && dmUs > 0) { + judge = JUDGE_BAD; + } + const worseDm = hold.headDmUs !== undefined && Math.abs(hold.headDmUs) > Math.abs(dmUs) ? hold.headDmUs : dmUs; + this.applyJudge(Math.min(judge, JUDGE_MISS_POOR), worseDm); + } else { + // CN / HCN tail: judged by the release timing; early releases beyond the windows are POOR. + const judge = endJudge === JUDGE_NONE ? JUDGE_MISS_POOR : endJudge; + this.applyJudge(judge, dmUs); + } + } + } + + private resolveInputLanes(input: PlaylogInputEvent): SimLane[] { + const lanes: SimLane[] = []; + for (const channel of input.channels) { + const lane = this.lanes.get(channel); + if (lane && !lane.auto) { + lanes.push(lane); + } + } + return lanes; + } + + private startLongNote(lane: SimLane, note: SimNote, judge: number, dmUs: number): void { + const style = note.longStyle ?? 1; + if (style === 1) { + note.holding = true; + lane.hold = { + note, + headJudge: judge, + headDmUs: dmUs, + tailMissDeadlineUs: Number.POSITIVE_INFINITY, + hcnCounterUs: 0, + }; + return; + } + // Charge styles score the head immediately. + this.applyJudge(judge, dmUs); + if (this.config.headBadSkipsTail && judge >= JUDGE_BAD) { + // IIDX: a BAD head cancels the tail judgment entirely. + note.judged = true; + return; + } + note.holding = true; + const endWindows = note.scratch ? this.config.windows.longScratchEnd : this.config.windows.longNoteEnd; + lane.hold = { + note, + tailMissDeadlineUs: note.endTimeUs! - endWindows.judges[JUDGE_BAD]![0], + hcnCounterUs: 0, + }; + } + + private selectCandidate( + lanes: readonly SimLane[], + timeUs: number, + windows: RulesetWindowTables, + ): SelectionCandidate | undefined { + const candidates: SelectionCandidate[] = []; + for (const lane of lanes) { + const set = lane.scratch ? windows.scratch : windows.note; + const scanLate = Math.min(set.judges[JUDGE_BAD]![0], set.ms?.[0] ?? 0); + const scanEarly = Math.max(set.judges[JUDGE_BAD]![1], set.ms?.[1] ?? 0); + for (const note of lane.notes) { + const dmUs = note.timeUs - timeUs; + if (dmUs < scanLate) continue; + if (dmUs > scanEarly) break; + if (note.holding) continue; + let judge: number; + if (note.judged) { + judge = set.ms && dmUs >= set.ms[0] && dmUs <= set.ms[1] ? JUDGE_EMPTY_POOR : JUDGE_NONE; + } else { + judge = classifyJudge(dmUs, set); + if (judge === JUDGE_NONE && set.ms && dmUs >= set.ms[0] && dmUs <= set.ms[1]) { + judge = JUDGE_MISS_POOR; + } + if ( + this.config.ignoreLateBadOnLnHead && + judge === JUDGE_BAD && + dmUs < 0 && + note.isLong && + (note.longStyle ?? 1) === 1 + ) { + // LR2: long-note heads have no late BAD — the press falls through. + judge = JUDGE_NONE; + } + } + if (judge === JUDGE_NONE) continue; + candidates.push({ lane, note, dmUs, judge }); + } + } + if (candidates.length === 0) { + return undefined; + } + candidates.sort((left, right) => left.note.timeUs - right.note.timeUs); + + let best: SelectionCandidate | undefined; + for (const candidate of candidates) { + if (!best) { + best = candidate; + continue; + } + const bestScoreable = best.judge < JUDGE_MISS_POOR; + const candScoreable = candidate.judge < JUDGE_MISS_POOR; + if (!bestScoreable) { + if (candScoreable) { + best = candidate; + } else if (Math.abs(candidate.dmUs) < Math.abs(best.dmUs)) { + best = candidate; + } + continue; + } + if (!candScoreable) { + continue; + } + if (this.shouldSwitchCandidate(best, candidate, timeUs, windows)) { + best = candidate; + } + } + return best; + } + + private shouldSwitchCandidate( + best: SelectionCandidate, + candidate: SelectionCandidate, + timeUs: number, + windows: RulesetWindowTables, + ): boolean { + const algorithm = this.config.selection; + if (algorithm === 'lowest') { + return false; + } + if (algorithm === 'duration') { + return Math.abs(candidate.dmUs) < Math.abs(best.dmUs); + } + // combo (GOOD reach) / score (GREAT reach) — beatoraja JudgeAlgorithm semantics. + const judgeIndex = algorithm === 'combo' ? JUDGE_GOOD : JUDGE_GREAT; + const bestSet = windowSetFor(best, windows); + const candidateSet = windowSetFor(candidate, windows); + return ( + best.note.timeUs < timeUs + bestSet.judges[judgeIndex]![0] && + candidate.note.timeUs <= timeUs + candidateSet.judges[judgeIndex]![1] + ); + } + + /** + * lr2oraja `MultiBadCollector`: after the press consumed `tnote`, every other unjudged note inside the BAD + * window but outside the GOOD window also resolves as a BAD — with the collector's own pruning rules. + */ + private applyMultiBad( + lanes: readonly SimLane[], + timeUs: number, + windows: RulesetWindowTables, + tnote: SimNote, + tnoteJudge: number, + ): void { + const extras: Array<{ note: SimNote }> = []; + for (const lane of lanes) { + const set = lane.scratch ? windows.scratch : windows.note; + const badWindow = set.judges[JUDGE_BAD]!; + const goodWindow = set.judges[JUDGE_GOOD]!; + for (const note of lane.notes) { + const dmUs = note.timeUs - timeUs; + if (dmUs < badWindow[0]) continue; + if (dmUs > badWindow[1]) break; + if (note.judged || note.holding || note === tnote) continue; + if (dmUs >= goodWindow[0] && dmUs <= goodWindow[1]) continue; + extras.push({ note }); + } + } + if (extras.length === 0) return; + extras.sort((left, right) => left.note.timeUs - right.note.timeUs); + const tnoteIsBad = tnoteJudge === JUDGE_BAD; + const filtered = extras.filter(({ note }) => { + if ((!tnoteIsBad || tnote.isLong) && note.timeUs > tnote.timeUs) return false; + if (note.isLong && note.timeUs < tnote.timeUs) return false; + return true; + }); + for (const { note } of filtered) { + note.judged = true; + this.applyJudge(JUDGE_BAD, undefined); + if (note.isLong && (note.longStyle ?? 1) !== 1 && !this.config.headBadSkipsTail) { + this.applyJudge(JUDGE_MISS_POOR, undefined); + } + } + } + + private applyJudge(judgeIndex: number, dmUs: number | undefined): void { + this.counts[judgeIndex]! += 1; + if (judgeIndex === JUDGE_PGREAT) { + this.exScore += 2; + } else if (judgeIndex === JUDGE_GREAT) { + this.exScore += 1; + } + if (judgeIndex <= JUDGE_GOOD) { + this.combo += 1; + if (this.combo > this.maxCombo) { + this.maxCombo = this.combo; + } + } else if (judgeIndex === JUDGE_BAD || judgeIndex === JUDGE_MISS_POOR) { + this.combo = 0; + } else if (judgeIndex === JUDGE_EMPTY_POOR && this.config.comboBreaksOnEmptyPoor) { + this.combo = 0; + } + if (dmUs !== undefined && (judgeIndex === JUDGE_GREAT || judgeIndex === JUDGE_GOOD)) { + if (dmUs > 0) { + this.fast += 1; + } else { + this.slow += 1; + } + } + this.gauge.update(judgeIndex); + } +} + +function classifyJudge(dmUs: number, set: JudgeWindowSetUs): number { + for (let index = 0; index < set.judges.length; index += 1) { + const window = set.judges[index]!; + if (dmUs >= window[0] && dmUs <= window[1]) { + return index; + } + } + return JUDGE_NONE; +} + +function windowSetFor(candidate: SelectionCandidate, windows: RulesetWindowTables): JudgeWindowSetUs { + return candidate.lane.scratch ? windows.scratch : windows.note; +} diff --git a/packages/player/tsdown.config.ts b/packages/player/tsdown.config.ts index 631a044e..c565279f 100644 --- a/packages/player/tsdown.config.ts +++ b/packages/player/tsdown.config.ts @@ -12,6 +12,7 @@ export default createPackageTsdownConfig({ 'image-resize-algorithm': 'src/image-resize-algorithm.ts', judging: 'src/judging.ts', 'playable-notes': 'src/playable-notes.ts', + playlog: 'src/playlog/index.ts', 'core/bga-timeline': 'src/core/bga-timeline.ts', 'core/engine': 'src/core/engine.ts', 'core/groove-gauge': 'src/core/groove-gauge.ts', diff --git a/scripts/bench/packages/player.ts b/scripts/bench/packages/player.ts index 765589eb..8cfa2898 100644 --- a/scripts/bench/packages/player.ts +++ b/scripts/bench/packages/player.ts @@ -1,5 +1,6 @@ import * as playerApi from '@be-music/player'; import * as judgingApi from '@be-music/player/judging'; +import * as playlogApi from '@be-music/player/playlog'; import { registerPlayerExportsCases } from '../../../packages/player/scripts/exports-cases.ts'; import type { BenchmarkPackageDefinition } from '../exports.types.ts'; @@ -7,6 +8,10 @@ export const playerBenchmarkPackage: BenchmarkPackageDefinition = { module: { ...(playerApi as Record<string, unknown>), 'judging.findClosestCandidateInWindow': judgingApi.findClosestCandidateInWindow, + 'playlog.serializePlaylog': playlogApi.serializePlaylog, + 'playlog.parsePlaylog': playlogApi.parsePlaylog, + 'playlog.simulatePlaylog': playlogApi.simulatePlaylog, + 'playlog.simulatePlaylogRulesets': playlogApi.simulatePlaylogRulesets, }, registerCases: registerPlayerExportsCases, }; diff --git a/vitest.config.ts b/vitest.config.ts index 73879e30..365fef44 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -33,6 +33,7 @@ const workspaceAliases = [ replacement: resolve(rootDir, 'packages/player/src/image-resize-algorithm.ts'), }, { find: '@be-music/player/judging', replacement: resolve(rootDir, 'packages/player/src/judging.ts') }, + { find: '@be-music/player/playlog', replacement: resolve(rootDir, 'packages/player/src/playlog/index.ts') }, { find: '@be-music/player/state-signals', replacement: resolve(rootDir, 'packages/player/src/state-signals.ts') }, { find: '@be-music/player/utils', replacement: resolve(rootDir, 'packages/player/src/utils.ts') }, { find: '@be-music/player/core', replacement: resolve(rootDir, 'packages/player/src/core') }, From 692b419d8fe852bc446b392bf1feda89ba2d4b48 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 00:34:23 +0900 Subject: [PATCH 30/39] chore: upgrade toolchain to Node 26 Pin .node-version to 26.7.0, raise engines.node to >=26, and move the tsdown and SEA build targets from node25 to node26. Bump @types/node to 26.x and update the Node version stated in both READMEs and the build-sea CLI help and error messages. --- .node-version | 2 +- README.ja.md | 4 +-- README.md | 4 +-- package.json | 4 +-- pnpm-lock.yaml | 58 +++++++++++++++++++-------------------- scripts/build-sea.ts | 8 +++--- tsdown.package.config.mts | 2 +- 7 files changed, 41 insertions(+), 41 deletions(-) diff --git a/.node-version b/.node-version index 9af71224..91d2624e 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -25.8.2 +26.7.0 diff --git a/README.ja.md b/README.ja.md index 32397fb6..ebbefe09 100644 --- a/README.ja.md +++ b/README.ja.md @@ -22,7 +22,7 @@ TypeScript + pnpm workspaces で構成した BMS/BMSON ツールチェーンで ## 必要環境 -- Node.js `>= 25` +- Node.js `>= 26` - pnpm workspaces ## セットアップ @@ -401,7 +401,7 @@ pnpm run audio-renderer:sea --node-binary /path/to/node 補足: -- Node.js 25.5+ が必要です。 +- Node.js 26+ が必要です。 - SEA 生成は built-in の `--build-sea` を使用します。 ## Exports ベンチマーク diff --git a/README.md b/README.md index 6b8361f5..f86a55fa 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ BMS/BMSON toolchain composed of TypeScript + pnpm workspaces. ## Required environment -- Node.js `>= 25` +- Node.js `>= 26` - pnpm workspaces ## Setup @@ -401,7 +401,7 @@ pnpm run audio-renderer:sea --node-binary /path/to/node supplement: -- Requires Node.js 25.5+. +- Requires Node.js 26+. - SEA generation uses built-in `--build-sea`. ## Exports Benchmark diff --git a/package.json b/package.json index 0add6369..45170f3d 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "devDependencies": { "@changesets/cli": "^2.31.0", - "@types/node": "^25.9.1", + "@types/node": "^26.2.0", "@vitest/coverage-v8": "^4.1.10", "oxfmt": "^0.57.0", "oxlint": "^1.73.0", @@ -47,7 +47,7 @@ "vitest": "^4.1.10" }, "engines": { - "node": ">=25" + "node": ">=26" }, "packageManager": "pnpm@10.30.3", "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c6d360d..e45e9a70 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: devDependencies: '@changesets/cli': specifier: ^2.31.0 - version: 2.31.0(@types/node@25.9.1) + version: 2.31.0(@types/node@26.2.0) '@types/node': - specifier: ^25.9.1 - version: 25.9.1 + specifier: ^26.2.0 + version: 26.2.0 '@vitest/coverage-v8': specifier: ^4.1.10 version: 4.1.10(vitest@4.1.10) @@ -40,10 +40,10 @@ importers: version: 7.0.1-rc vite: specifier: ^8.1.3 - version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + version: 8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0) vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + version: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0)) packages/audio-renderer: dependencies: @@ -272,10 +272,10 @@ importers: version: 3.0.2 vite: specifier: ^8.1.3 - version: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + version: 8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0) vite-plugin-node-polyfills: specifier: ^0.28.0 - version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + version: 0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0)) wrangler: specifier: ^4.107.0 version: 4.107.0(@cloudflare/workers-types@5.20260707.1) @@ -1516,8 +1516,8 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@25.9.1': - resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==} + '@types/node@26.2.0': + resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} '@types/wicg-file-system-access@2020.9.8': resolution: {integrity: sha512-ggMz8nOygG7d/stpH40WVaNvBwuyYLnrg5Mbyf6bmsj/8+gb6Ei4ZZ9/4PNpcPNTT8th9Q8sM8wYmWGjMWLX/A==} @@ -3105,8 +3105,8 @@ packages: unconfig-core@7.5.0: resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} - undici-types@7.24.6: - resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} undici@7.28.0: resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} @@ -3364,7 +3364,7 @@ snapshots: dependencies: '@changesets/types': 6.1.0 - '@changesets/cli@2.31.0(@types/node@25.9.1)': + '@changesets/cli@2.31.0(@types/node@26.2.0)': dependencies: '@changesets/apply-release-plan': 7.1.1 '@changesets/assemble-release-plan': 6.0.10 @@ -3380,7 +3380,7 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.3(@types/node@25.9.1) + '@inquirer/external-editor': 1.0.3(@types/node@26.2.0) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 enquirer: 2.4.1 @@ -3732,12 +3732,12 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@inquirer/external-editor@1.0.3(@types/node@25.9.1)': + '@inquirer/external-editor@1.0.3(@types/node@26.2.0)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 25.9.1 + '@types/node': 26.2.0 '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -4163,9 +4163,9 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@25.9.1': + '@types/node@26.2.0': dependencies: - undici-types: 7.24.6 + undici-types: 8.3.0 '@types/wicg-file-system-access@2020.9.8': {} @@ -4275,7 +4275,7 @@ snapshots: obug: 2.1.3 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0)) '@vitest/expect@4.1.10': dependencies: @@ -4286,13 +4286,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0))': + '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0) '@vitest/pretty-format@4.1.10': dependencies: @@ -5860,7 +5860,7 @@ snapshots: '@quansync/fs': 1.0.0 quansync: 1.0.0 - undici-types@7.24.6: {} + undici-types@8.3.0: {} undici@7.28.0: {} @@ -5890,15 +5890,15 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.20 - vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): + vite-plugin-node-polyfills@0.28.0(rollup@4.59.0)(vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) node-stdlib-browser: 1.3.1 - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0) transitivePeerDependencies: - rollup - vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0): + vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.5 @@ -5906,15 +5906,15 @@ snapshots: rolldown: 1.1.4 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 25.9.1 + '@types/node': 26.2.0 esbuild: 0.28.1 fsevents: 2.3.3 tsx: 4.23.0 - vitest@4.1.10(@types/node@25.9.1)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)): + vitest@4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0)) + '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -5931,10 +5931,10 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@25.9.1)(esbuild@0.28.1)(tsx@4.23.0) + vite: 8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.9.1 + '@types/node': 26.2.0 '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) transitivePeerDependencies: - msw diff --git a/scripts/build-sea.ts b/scripts/build-sea.ts index 8d8030c1..29e16a0d 100644 --- a/scripts/build-sea.ts +++ b/scripts/build-sea.ts @@ -146,7 +146,7 @@ function printUsage() { ' -h, --help Show this help', '', 'Requirements:', - ' Node.js 25.5+ with built-in `--build-sea` support', + ' Node.js 26+ with built-in `--build-sea` support', ].join('\n') + '\n', ); } @@ -282,7 +282,7 @@ async function buildSeaBundle(config: SeaTargetConfig, seaDir: string): Promise< mainFields: [...defaultServerMainFields], }, build: { - target: 'node25', + target: 'node26', outDir: seaDir, emptyOutDir: true, codeSplitting: false, @@ -497,7 +497,7 @@ async function runSeaBuild(nodeBinaryPath: string, cwd: string, configFilePath: if (output.includes('--build-sea') && output.toLowerCase().includes('unknown')) { throw new Error( `The selected Node executable does not support --build-sea: ${nodeBinaryPath}. ` + - 'Use Node.js 25.5+ with built-in SEA support.', + 'Use Node.js 26+ with built-in SEA support.', ); } @@ -573,7 +573,7 @@ async function main(): Promise<void> { if (!hasBuildSea) { throw new Error( `The selected Node executable does not support --build-sea: ${nodeBinaryPath}. ` + - 'Use Node.js 25.5+ with built-in SEA support.', + 'Use Node.js 26+ with built-in SEA support.', ); } diff --git a/tsdown.package.config.mts b/tsdown.package.config.mts index 27c94a2e..c67ab433 100644 --- a/tsdown.package.config.mts +++ b/tsdown.package.config.mts @@ -35,7 +35,7 @@ export function createPackageTsdownConfig(options: CreatePackageTsdownConfigOpti outDir: 'dist', platform: 'node', sourcemap: true, - target: 'node25', + target: 'node26', plugins: Object.hasOwn(entry, 'cli') ? [createCliShebangPlugin()] : undefined, }); } From 18a3ec44a7f166b1c00e3e7eab70298bcb94b862 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 00:34:49 +0900 Subject: [PATCH 31/39] feat: replay dropped play-logs and latch playlog options per play MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PlayerOptions.replayInputs re-drives a recorded input stream deterministically inside manualPlay — each event fires at its exact chart-relative microsecond timestamp while live lane input is ignored. The LR2/default gameplay scene accepts a play-log via PixiGameplayViewOptions.replay and re-applies the recorded note arrangement onto the freshly prepared chart (applyPlaylogArrangement), so RANDOM / MIRROR runs replay without re-rolling; mismatched #RANDOM control flow fails the prepare instead of replaying a wrong chart. The demo starts a replay when a *.bmplay.json file is dropped and the matching song is loaded (chartPath match first, title/artist fallback), and replays record no new play-log. The Debug Menu's playlog option is now latched at song start and its controller is disabled during a play — mid-song changes no longer apply. --- .changeset/playlog-player-web.md | 2 + .changeset/playlog-player.md | 2 +- docs/player-web.ja.md | 2 +- docs/player-web.md | 2 +- docs/playlog.ja.md | 19 ++- docs/playlog.md | 19 ++- packages/player-web-demo/src/main.ts | 144 ++++++++++++++++-- .../src/chart/playlog-arrangement.test.ts | 104 +++++++++++++ .../src/chart/playlog-arrangement.ts | 91 +++++++++++ .../src/scene/beatoraja/gameplay.ts | 6 +- packages/player-web/src/scene/lr2/gameplay.ts | 134 ++++++++++------ packages/player/src/core/engine.ts | 79 +++++++++- packages/player/src/index.test.ts | 61 ++++++++ 13 files changed, 593 insertions(+), 72 deletions(-) create mode 100644 packages/player-web/src/chart/playlog-arrangement.test.ts create mode 100644 packages/player-web/src/chart/playlog-arrangement.ts diff --git a/.changeset/playlog-player-web.md b/.changeset/playlog-player-web.md index 1c160ab5..41f63129 100644 --- a/.changeset/playlog-player-web.md +++ b/.changeset/playlog-player-web.md @@ -3,3 +3,5 @@ --- Record a play log (`*.bmplay.json` input replay) for every gameplay run: the LR2/default gameplay scene exposes it through `PixiGameplayResultData.playlog`, the beatoraja scene through `PixiBeatorajaGameplayView.getPlaylog()`, and the `@be-music/player-web/runtime` subpath re-exports the playlog serializer helpers (`serializePlaylog`, `parsePlaylog`, `resolvePlaylogFilename`) for hosts. + +The LR2/default gameplay scene also plays a recorded log back: `PixiGameplayViewOptions.replay` re-applies the log's resolved note arrangement onto the freshly prepared chart (`applyPlaylogArrangement` — RANDOM / MIRROR arrangements replay without re-rolling) and feeds the recorded inputs through the engine's deterministic replay path. diff --git a/.changeset/playlog-player.md b/.changeset/playlog-player.md index 4ff290c4..354213de 100644 --- a/.changeset/playlog-player.md +++ b/.changeset/playlog-player.md @@ -4,4 +4,4 @@ Add the `@be-music/player/playlog` subpath: a play-history ("playlog") format that records the resolved chart, the raw key press/release stream, and the play settings as an input replay, plus LR2 / beatoraja / IIDX ruleset simulators (`simulatePlaylog`) that re-derive judgments, EX-SCORE, max combo, money score, and groove gauge from the same recorded inputs. -New `PlayerOptions.onPlaylogRecorded` / `PlayerOptions.recordPlaylog` enable engine-side recording for both `manualPlay` and `autoPlay` (including ESC-aborted runs). `ScoreTracker` now latches `maxCombo`, `resolveJudgeRankPercent` exposes the chart's initial judgerank percent, and the landmine gauge-damage rule moved to the shared `core/landmine.ts` helper. +New `PlayerOptions.onPlaylogRecorded` / `PlayerOptions.recordPlaylog` enable engine-side recording for both `manualPlay` and `autoPlay` (including ESC-aborted runs), and `PlayerOptions.replayInputs` re-drives a recorded input stream deterministically for replay playback (live lane input is ignored while a replay is active). `ScoreTracker` now latches `maxCombo`, `resolveJudgeRankPercent` exposes the chart's initial judgerank percent, and the landmine gauge-damage rule moved to the shared `core/landmine.ts` helper. diff --git a/docs/player-web.ja.md b/docs/player-web.ja.md index 45ada74d..c0cf6919 100644 --- a/docs/player-web.ja.md +++ b/docs/player-web.ja.md @@ -162,7 +162,7 @@ pnpm bench -- --packages player-web - browser demo は、未対応 video asset を playback 前に ffmpeg.wasm path で transcode できます。 - chart の自然終了時は、短い post-chart delay を置いてから result scene を開きます。視覚的に result へ遷移しても、残っている gameplay audio tail は中断しません。 - gameplay recorder は WebM output を書き出し、active recording が gameplay bus の破棄前に flush されるよう、scene disposal より前に stop / finalization を終えます。 -- 毎プレイでプレイログ(`*.bmplay.json` 入力リプレイ — 解決済み譜面、生の押下/解放列、プレイ設定。[playlog.ja.md](./playlog.ja.md) 参照)を記録します。demo は result scene のマウント時に自動ダウンロードし、Debug Menu の「Auto-save play history」チェックボックス(デフォルト ON)で制御します。`bms-playlog` CLI がこのファイルから LR2 / beatoraja / IIDX のリザルトを再現します。 +- 毎プレイでプレイログ(`*.bmplay.json` 入力リプレイ — 解決済み譜面、生の押下/解放列、プレイ設定。[playlog.ja.md](./playlog.ja.md) 参照)を記録します。demo は result scene のマウント時に自動ダウンロードし、Debug Menu の「Auto-save play history」チェックボックス(デフォルト ON。曲開始時にラッチされ、プレイ中は disabled)で制御します。`bms-playlog` CLI がこのファイルから LR2 / beatoraja / IIDX のリザルトを再現します。プレイログをページへドロップすると、対応する楽曲がロード済みの場合に記録されたランをリプレイ再生します。 ## Compatibility boundary diff --git a/docs/player-web.md b/docs/player-web.md index 7c437963..6c10ffce 100644 --- a/docs/player-web.md +++ b/docs/player-web.md @@ -172,7 +172,7 @@ pnpm bench -- --packages player-web - Natural chart completion waits for a short post-chart delay before opening the result scene. The visual transition does not cut off the remaining gameplay audio tail. - The gameplay recorder writes WebM output and coordinates stop/finalization before scene disposal so active recordings are flushed before the gameplay bus is torn down. -- Every play records a play log (`*.bmplay.json` input replay — resolved chart, raw press/release stream, play settings; see [playlog.md](./playlog.md)). The demo auto-downloads it when the result scene mounts, controlled by the Debug Menu's "Auto-save play history" checkbox (ON by default). The `bms-playlog` CLI re-derives LR2 / beatoraja / IIDX results from the file. +- Every play records a play log (`*.bmplay.json` input replay — resolved chart, raw press/release stream, play settings; see [playlog.md](./playlog.md)). The demo auto-downloads it when the result scene mounts, controlled by the Debug Menu's "Auto-save play history" checkbox (ON by default; latched at song start and disabled during a play). The `bms-playlog` CLI re-derives LR2 / beatoraja / IIDX results from the file, and dropping a play-log onto the page replays the recorded run when the matching song is loaded. ## Compatibility boundary diff --git a/docs/playlog.ja.md b/docs/playlog.ja.md index 32ddfc9a..3c21ed52 100644 --- a/docs/playlog.ja.md +++ b/docs/playlog.ja.md @@ -45,7 +45,24 @@ TypeScript 型・シリアライザ・防御的パーサは - LR2 / default ゲームプレイシーンは `PixiGameplayResultData.playlog` として公開します。 - beatoraja ゲームプレイシーンは `PixiBeatorajaGameplayView.getPlaylog()` として公開します。 - デモはリザルトシーンのマウント時に `<タイトル>-<タイムスタンプ>.bmplay.json` を自動ダウンロードします。 - Debug Menu の **Auto-save play history** チェックボックス(デフォルト ON)で制御します。 + Debug Menu の **Auto-save play history** チェックボックス(デフォルト ON)で制御します。プレイログ関連 + オプションは曲の開始時にラッチされ、曲の途中では変更できません — プレイ中はチェックボックスが disabled + になり、曲開始時点の値がそのプレイに適用されます。 + +## リプレイ再生 + +`*.bmplay.json` ファイルをブラウザプレイヤーへドロップすると、対応する楽曲がロード済みの場合にリプレイ再生が +始まります(曲フォルダとログを同時にドロップしても動作します — 曲のロード後にリプレイが始まります)。 +楽曲のマッチングは `play.native.chartPath` に記録された chartPath の完全一致を優先し、それが無い古いログは +タイトル+アーティストで照合します。 + +リプレイは共有エンジン内で記録済み入力列を決定論的に再駆動します(`PlayerOptions.replayInputs`)。各イベントは +記録された譜面相対マイクロ秒の時刻ちょうどで発火し、ライブのレーン入力は無視され(ESC / ポーズ / ハイスピは +有効)、リプレイ実行では新しいプレイログを記録しません。ログは解決済みの最終配置を保存しているため、譜面準備 +では RANDOM / MIRROR を引き直す代わりに記録済みチャンネルを再適用します(`applyPlaylogArrangement`)— つまり +シャッフルされたプレイも正確にリプレイできます。`#RANDOM` 制御構文の分岐が記録時と異なる譜面は再整列できない +ため、ステータス表示でエラーになります。リプレイは記録時のスキンファミリーに関わらず常に LR2 / default の +ゲームプレイパスで実行されます。 ## LR2 / beatoraja / IIDX リザルトの再現 diff --git a/docs/playlog.md b/docs/playlog.md index 110281d3..65ecbcd3 100644 --- a/docs/playlog.md +++ b/docs/playlog.md @@ -45,7 +45,24 @@ In the browser player: - The LR2 / default gameplay scene exposes the recorded log through `PixiGameplayResultData.playlog`. - The beatoraja gameplay scene exposes it through `PixiBeatorajaGameplayView.getPlaylog()`. - The demo auto-downloads the log as `<title>-<timestamp>.bmplay.json` when the result scene mounts, controlled by - the Debug Menu's **Auto-save play history** checkbox (ON by default). + the Debug Menu's **Auto-save play history** checkbox (ON by default). Play-log options are latched at song start + and cannot change mid-play — the checkbox is disabled while a song is playing, and the value in effect when the + song started governs that play. + +## Replay playback + +Dropping a `*.bmplay.json` file onto the browser player starts replay playback when the matching song is loaded +(dropping the song folder together with the log works too — the songs load first). Matching prefers the exact +`chartPath` recorded in `play.native.chartPath`, with a title + artist fallback for older logs. + +Replay re-drives the recorded input stream deterministically inside the shared engine +(`PlayerOptions.replayInputs`): every event fires at its exact chart-relative microsecond timestamp, live lane +input is ignored (ESC / pause / hi-speed keep working), and no new play-log is recorded for the run. Because the +log stores the resolved note arrangement, the chart prepare re-applies the recorded channels onto the freshly +loaded chart (`applyPlaylogArrangement`) instead of re-rolling RANDOM / MIRROR — so shuffled plays replay exactly. +A chart whose `#RANDOM` control flow rolls differently from the recorded run cannot be re-aligned; the replay +fails with a status message instead of playing a mismatched chart. Replay always runs on the LR2 / default +gameplay path regardless of which skin family recorded the log. ## Re-deriving LR2 / beatoraja / IIDX results diff --git a/packages/player-web-demo/src/main.ts b/packages/player-web-demo/src/main.ts index 779b67d4..3d12ad28 100644 --- a/packages/player-web-demo/src/main.ts +++ b/packages/player-web-demo/src/main.ts @@ -51,8 +51,10 @@ import { import { downloadBlob, parseCompressorMode, + parsePlaylog, resolvePlaylogFilename, serializePlaylog, + PLAYLOG_FILE_SUFFIX, type BeMusicPlaylog, type CompressorMode, } from '@be-music/player-web/runtime'; @@ -364,6 +366,18 @@ class PlayerWebDemoApp { private gui: GUI | undefined; private compressorStageFolder: GUI | undefined; private recordController: Controller | undefined; + /** + * "Auto-save play history" checkbox controller. Held so the play-start path can `disable()` it for the duration + * of a play — the playlog options are latched when a song starts and cannot change mid-song — and the result / + * select paths can `enable()` it again. + */ + private playlogSaveController: Controller | undefined; + /** + * `guiState.autoSavePlaylog` as it was when the current play STARTED. The result-screen auto-save decision reads + * this latch, not the live checkbox, so the value in effect at song start governs the whole play (the checkbox is + * disabled during gameplay anyway — this latch is the enforcement for any path that slips through). + */ + private activePlayAutoSavePlaylog = true; /** * Top-level "Skin family" dropdown. Rebuilt via {@link rebuildSkinFamilyPicker} on every theme load / wipe so its * option list reflects which families are actually selectable (LR2 only shows up once an `.lr2skin` has been @@ -751,7 +765,9 @@ class PlayerWebDemoApp { // Play-history auto-save — ON by default. When enabled, every finished play downloads its play-log // (`*.bmplay.json`, the raw input replay defined in `@be-music/player/playlog`) as soon as the result scene // mounts. The file feeds the `bms-playlog` CLI, which re-derives LR2 / beatoraja / IIDX scores from the replay. - gui + // The value is LATCHED at song start (`lockPlaylogOptionsForPlay`) and the controller is disabled while a song + // is playing — playlog options cannot change mid-play. + this.playlogSaveController = gui .add(this.guiState, 'autoSavePlaylog') .name('Auto-save play history') .onChange((value: boolean) => { @@ -850,6 +866,16 @@ class PlayerWebDemoApp { if (files.length === 0) { return; } + // Play-log files ride their own path: they are replay inputs, not chart / theme assets. They are peeled off + // BEFORE the song/theme split so a stray `.bmplay.json` never classifies as a theme candidate — and handled + // AFTER the split's loaders ran, so dropping a song folder together with its play-log loads the song first and + // then starts the replay in one gesture. + const playlogFiles = files.filter((file) => file.name.toLowerCase().endsWith(PLAYLOG_FILE_SUFFIX)); + files = files.filter((file) => !file.name.toLowerCase().endsWith(PLAYLOG_FILE_SUFFIX)); + if (files.length === 0 && playlogFiles.length > 0) { + await this.startPlaylogReplayFromFile(playlogFiles[0]!); + return; + } const { themeFiles, songFiles } = splitDroppedSongAndThemeFiles(files); // `splitDroppedSongAndThemeFiles` routes any non-chart files outside a chart directory into `themeFiles`. That // includes stray `readme.txt` / `info.json` / album-art images sitting at the root of a BMS pack that isn't a real @@ -906,6 +932,62 @@ class PlayerWebDemoApp { this.setStatus('Theme loaded'); } await this.showSelect(); + if (playlogFiles.length > 0) { + await this.startPlaylogReplayFromFile(playlogFiles[0]!); + } + } + + /** + * Parses a dropped play-log file and starts replay playback when the matching song is loaded. Matching prefers + * the exact `chartPath` the log recorded (`play.native.chartPath`); older logs without it fall back to a + * title + artist match. When no match (or the chart's `#RANDOM` roll differs so the resolved notes can't be + * re-aligned), the failure lands in the status row instead of throwing — a bad drop must never wedge the UI. + */ + private async startPlaylogReplayFromFile(file: File): Promise<void> { + let playlog: BeMusicPlaylog; + try { + playlog = parsePlaylog(await file.text()); + } catch (error) { + dropLog.warn('play-log parse failed', error); + this.setStatus(`Replay: invalid play-log (${(error as Error).message})`); + return; + } + const song = this.findSongForPlaylog(playlog); + if (!song) { + this.setStatus(`Replay: song not loaded (${playlog.chart.title ?? 'untitled'})`); + return; + } + this.setStatus(`Replaying: ${song.title}`); + try { + // Replay always drives the LR2/default gameplay path — the shared engine owns the playback either way, so + // the recorded run reproduces regardless of which skin family recorded it. + await this.playSong(song, { autoPlay: playlog.play.mode === 'auto', replay: playlog }); + } catch (error) { + gameplayLog.warn('play-log replay failed', error); + this.setStatus(`Replay failed: ${(error as Error).message}`); + await this.showSelect(); + } + } + + /** + * Finds the loaded song a play-log belongs to. Exact `chartPath` match first (recorded since the replay feature + * landed), then a title + artist heuristic for logs recorded before the path rode along. + */ + private findSongForPlaylog(playlog: BeMusicPlaylog): BrowserSongEntry | undefined { + const nativeChartPath = playlog.play.native?.chartPath; + if (typeof nativeChartPath === 'string' && nativeChartPath.length > 0) { + const exact = this.collection.songs.find((entry) => entry.chartPath === nativeChartPath); + if (exact) { + return exact; + } + } + const title = playlog.chart.title; + if (title === undefined || title.length === 0) { + return undefined; + } + return this.collection.songs.find( + (entry) => entry.title === title && (playlog.chart.artist === undefined || entry.artist === playlog.chart.artist), + ); } /** @@ -1542,6 +1624,7 @@ class PlayerWebDemoApp { // Auto-save fires even when the theme ships no result skin — falling back to select // shouldn't cost the user their replay file. this.maybeAutoSavePlaylog(playlog); + this.unlockPlaylogOptions(); }); }, onError: (error) => { @@ -1557,6 +1640,7 @@ class PlayerWebDemoApp { this.currentBeatorajaPlayVariant = variant; await this.sceneHost.setScene(this.beatorajaGameplayView); this.setStatus(`Playing (beatoraja): ${song.title}`); + this.lockPlaylogOptionsForPlay(); // Consume the "user pressed Record on the select screen" flag. Same flow as the LR2 // gameplay path — `autoRecordArmed` is set when the user clicks the Record button @@ -2598,6 +2682,7 @@ class PlayerWebDemoApp { private async showSelect(): Promise<void> { this.elements.shell.classList.remove('playing'); + this.unlockPlaylogOptions(); // The `.empty` class drives the centered "Drop BMS folder…" hint. Toggle it off the moment we have charts to show, // and back on after a wipe / failed drop so the hint comes back instead of leaving the user staring at a blank // canvas. @@ -2791,9 +2876,10 @@ class PlayerWebDemoApp { private buildLr2GameplayView( song: BrowserSongEntry, playSkin: Lr2Skin | undefined, - overrides: { autoPlay?: boolean }, + overrides: { autoPlay?: boolean; replay?: BeMusicPlaylog }, ): PixiGameplayView { const playOptions = this.selectView?.getPlayOptions(); + const replay = overrides.replay; const sharedOptions = { autoPlay: overrides.autoPlay ?? playOptions?.autoPlay ?? this.guiState.autoPlay, autoPauseOnBlur: this.guiState.autoPauseOnBlur, @@ -2806,12 +2892,16 @@ class PlayerWebDemoApp { hiddenSudden2P: playOptions?.hiddenSudden2P, shutter: playOptions?.shutter, laneCover: playOptions?.laneCover, - autoScratch1P: playOptions?.autoScratch1P, - autoScratch2P: playOptions?.autoScratch2P, - dpFlip: playOptions?.dpFlip, - random1P: playOptions?.random1P, - random2P: playOptions?.random2P, - gauge: playOptions?.gauge1P, + // Replay playback restores the RECORDED play setup: the log's auto-scratch / gauge govern judging and the + // gauge readout, and the lane transforms stay off because the view re-applies the recorded arrangement + // directly (see `PixiGameplayViewOptions.replay`). + autoScratch1P: replay !== undefined ? replay.play.autoScratch : playOptions?.autoScratch1P, + autoScratch2P: replay !== undefined ? false : playOptions?.autoScratch2P, + dpFlip: replay !== undefined ? false : playOptions?.dpFlip, + random1P: replay !== undefined ? ('OFF' as const) : playOptions?.random1P, + random2P: replay !== undefined ? ('OFF' as const) : playOptions?.random2P, + gauge: replay !== undefined ? replay.play.gauge : playOptions?.gauge1P, + replay, audioCompressor: this.guiState.compressor, audioCompressorMode: this.compressorMode, audioCompressorStages: { @@ -2874,6 +2964,7 @@ class PlayerWebDemoApp { this.decideView?.dispose(); this.decideView = undefined; this.setStatus(`Playing: ${song.title}`); + this.lockPlaylogOptionsForPlay(); this.gameplayView.start(); if (this.autoRecordArmed) { this.autoRecordArmed = false; @@ -2891,12 +2982,16 @@ class PlayerWebDemoApp { } } - private async playSong(song: BrowserSongEntry, overrides: { autoPlay?: boolean } = {}): Promise<void> { + private async playSong( + song: BrowserSongEntry, + overrides: { autoPlay?: boolean; replay?: BeMusicPlaylog } = {}, + ): Promise<void> { // Family dispatch for the gameplay scene. The Debug Menu's "Skin family" pick funnels through here so a user // override of `'lr2'` / `'default'` forces that family even when beatoraja is technically available, while - // `'auto'` keeps the legacy preference (beatoraja → LR2 → default). + // `'auto'` keeps the legacy preference (beatoraja → LR2 → default). Replay playback always stays on the + // LR2/default path — that's where the play-log arrangement remap and `replayInputs` are wired. const gameplayFamily = pickActiveFamilyForScene(this.familyDispatchState(), 'gameplay', song); - if (gameplayFamily === 'beatoraja') { + if (gameplayFamily === 'beatoraja' && overrides.replay === undefined) { await this.playSongBeatoraja(song, overrides); return; } @@ -2920,6 +3015,7 @@ class PlayerWebDemoApp { const playSkin = gameplayFamily === 'lr2' ? pickLr2PlaySkin(this.playSkins, song) : undefined; this.gameplayView = this.buildLr2GameplayView(song, playSkin, overrides); this.setStatus(`Playing: ${song.title}`); + this.lockPlaylogOptionsForPlay(); await this.gameplayView.mount(this.sceneHost, song, resolveSongSource(this.collection, song)); // Consume the "user pressed Record on the select screen" flag now that gameplay is mounted — `startRecording` // requires the gameplay AudioContext to exist, which only happens after `mount`. Failing here is non-fatal: the @@ -2981,15 +3077,33 @@ class PlayerWebDemoApp { this.gameplayView = undefined; this.setStatus(`Result: ${data.song.title}`); this.maybeAutoSavePlaylog(data.playlog); + this.unlockPlaylogOptions(); + } + + /** + * Latches the playlog-related GUI options for the play that is about to start and disables their controllers. + * Playlog options are per-play: the value in effect at song start governs the whole play, and mid-song changes + * are rejected by keeping the controls disabled until {@link unlockPlaylogOptions} runs (result mounted or back + * at select). + */ + private lockPlaylogOptionsForPlay(): void { + this.activePlayAutoSavePlaylog = this.guiState.autoSavePlaylog; + this.playlogSaveController?.disable(); + } + + /** Re-enables the playlog option controllers once no play is in flight. */ + private unlockPlaylogOptions(): void { + this.playlogSaveController?.enable(); } /** - * Downloads the play-log (`*.bmplay.json` input replay) when the "Auto-save play history" toggle is on. Called - * from both result paths (LR2/default `showResult`, beatoraja `onComplete`) the moment the result presentation is - * up. Failures are non-fatal — the result screen must never be blocked by a download hiccup. + * Downloads the play-log (`*.bmplay.json` input replay) when the "Auto-save play history" toggle was on at song + * start (the latched value — the checkbox itself is disabled during a play). Called from both result paths + * (LR2/default `showResult`, beatoraja `onComplete`) the moment the result presentation is up. Failures are + * non-fatal — the result screen must never be blocked by a download hiccup. */ private maybeAutoSavePlaylog(playlog: BeMusicPlaylog | undefined): void { - if (!this.guiState.autoSavePlaylog || playlog === undefined) { + if (!this.activePlayAutoSavePlaylog || playlog === undefined) { return; } try { diff --git a/packages/player-web/src/chart/playlog-arrangement.test.ts b/packages/player-web/src/chart/playlog-arrangement.test.ts new file mode 100644 index 00000000..ac0656c9 --- /dev/null +++ b/packages/player-web/src/chart/playlog-arrangement.test.ts @@ -0,0 +1,104 @@ +import { describe, expect, test } from 'vitest'; +import type { PlaylogNote } from '@be-music/player/playlog'; +import { applyPlaylogArrangement } from './playlog-arrangement.ts'; + +function note(channel: string, seconds: number, endSeconds?: number) { + return endSeconds === undefined ? { channel, seconds } : { channel, seconds, endSeconds }; +} + +function playlogNote(overrides: Partial<PlaylogNote> & Pick<PlaylogNote, 'channel' | 'timeUs'>): PlaylogNote { + return { id: 0, type: 'normal', ...overrides }; +} + +describe('playlog-arrangement', () => { + test('re-applies a mirrored arrangement onto the original channels', () => { + // Original chart: lane 11 at 1.0s, lane 13 at 2.0s. Recorded (mirrored): 15 at 1.0s, 13 at 2.0s. + const target = { + notes: [note('11', 1), note('13', 2)], + landmineNotes: [], + invisibleNotes: [], + activeFreeZoneChannels: new Set<string>(), + }; + const result = applyPlaylogArrangement( + [playlogNote({ channel: '15', timeUs: 1_000_000 }), playlogNote({ channel: '13', timeUs: 2_000_000 })], + target, + ); + expect(result).toEqual({ ok: true }); + expect(target.notes.map((entry) => entry.channel)).toEqual(['15', '13']); + }); + + test('matches long notes by tail time and keeps mines / invisibles / freezones separate', () => { + const target = { + notes: [note('11', 1, 2), note('12', 1), note('17', 3, 4)], + landmineNotes: [note('13', 1)], + invisibleNotes: [note('14', 1)], + activeFreeZoneChannels: new Set(['17']), + }; + const result = applyPlaylogArrangement( + [ + playlogNote({ channel: '15', type: 'long', timeUs: 1_000_000, endTimeUs: 2_000_000, lnMode: 1 }), + playlogNote({ channel: '11', timeUs: 1_000_000 }), + playlogNote({ channel: '17', type: 'freezone', timeUs: 3_000_000, endTimeUs: 4_000_000 }), + playlogNote({ channel: '12', type: 'mine', timeUs: 1_000_000, damage: 4 }), + playlogNote({ channel: '13', type: 'invisible', timeUs: 1_000_000 }), + ], + target, + ); + expect(result).toEqual({ ok: true }); + // The long note takes the recorded long channel — never the same-time normal note's channel. + expect(target.notes.map((entry) => entry.channel)).toEqual(['15', '11', '17']); + expect(target.landmineNotes[0]!.channel).toBe('12'); + expect(target.invisibleNotes[0]!.channel).toBe('13'); + }); + + test('fails without mutating when the prepared chart has a note the log does not', () => { + const target = { + notes: [note('11', 1), note('12', 1.5)], + landmineNotes: [], + invisibleNotes: [], + activeFreeZoneChannels: new Set<string>(), + }; + const result = applyPlaylogArrangement([playlogNote({ channel: '11', timeUs: 1_000_000 })], target); + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.reason).toContain('1500000'); + } + expect(target.notes.map((entry) => entry.channel)).toEqual(['11', '12']); + }); + + test('fails when the log has extra notes the prepared chart does not', () => { + const target = { + notes: [note('11', 1)], + landmineNotes: [], + invisibleNotes: [], + activeFreeZoneChannels: new Set<string>(), + }; + const result = applyPlaylogArrangement( + [playlogNote({ channel: '11', timeUs: 1_000_000 }), playlogNote({ channel: '12', timeUs: 2_000_000 })], + target, + ); + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.reason).toContain('unmatched'); + } + }); + + test('chords at the same time consume recorded channels without duplication', () => { + const target = { + notes: [note('11', 1), note('12', 1), note('13', 1)], + landmineNotes: [], + invisibleNotes: [], + activeFreeZoneChannels: new Set<string>(), + }; + const result = applyPlaylogArrangement( + [ + playlogNote({ channel: '13', timeUs: 1_000_000 }), + playlogNote({ channel: '14', timeUs: 1_000_000 }), + playlogNote({ channel: '15', timeUs: 1_000_000 }), + ], + target, + ); + expect(result).toEqual({ ok: true }); + expect(target.notes.map((entry) => entry.channel).sort()).toEqual(['13', '14', '15']); + }); +}); diff --git a/packages/player-web/src/chart/playlog-arrangement.ts b/packages/player-web/src/chart/playlog-arrangement.ts new file mode 100644 index 00000000..8ddf051e --- /dev/null +++ b/packages/player-web/src/chart/playlog-arrangement.ts @@ -0,0 +1,91 @@ +import type { PlaylogNote } from '@be-music/player/playlog'; + +/** + * Re-applies a recorded play-log's note arrangement onto a freshly prepared chart for replay playback. + * + * A playlog stores the RESOLVED chart the player saw — post lane-shuffle (RANDOM / MIRROR / S-RANDOM) and post + * DP-flip. A fresh chart prepare (with those options off) yields the same notes at the same times but with the + * ORIGINAL channels, so replaying against it would judge the inputs on the wrong lanes. Lane transforms never move + * a note in time, only across channels, so the recorded arrangement can be re-applied by matching notes on + * `(kind, timeUs, endTimeUs)` and assigning the recorded channels back — no shuffle seed needed. + * + * Mutates the `channel` field of the given note objects in place (they are the same instances the prepared-chart + * bundle and the engine share). Returns an error string when the chart does not match the playlog — a different + * `#RANDOM` control-flow roll, a different chart file, or an edited chart — in which case the notes are left + * untouched (channels are only written after every bucket matched). + */ +export function applyPlaylogArrangement( + playlogNotes: readonly PlaylogNote[], + target: { + /** Playable notes (freezone included) — `PreparedPlaybackChartData.notes`. */ + notes: Array<{ channel: string; seconds: number; endSeconds?: number }>; + landmineNotes: Array<{ channel: string; seconds: number }>; + invisibleNotes: Array<{ channel: string; seconds: number }>; + activeFreeZoneChannels: ReadonlySet<string>; + }, +): { ok: true } | { ok: false; reason: string } { + const buckets = new Map<string, string[]>(); + for (const note of playlogNotes) { + const key = `${note.type}:${note.timeUs}:${note.endTimeUs ?? ''}`; + const bucket = buckets.get(key); + if (bucket) { + bucket.push(note.channel); + } else { + buckets.set(key, [note.channel]); + } + } + + interface Assignment { + note: { channel: string }; + channel: string; + } + const assignments: Assignment[] = []; + const takeChannel = (key: string): string | undefined => { + const bucket = buckets.get(key); + if (!bucket || bucket.length === 0) { + return undefined; + } + return bucket.shift(); + }; + + for (const note of target.notes) { + const timeUs = secondsToMicroseconds(note.seconds); + const hasTail = + typeof note.endSeconds === 'number' && Number.isFinite(note.endSeconds) && note.endSeconds > note.seconds; + const endTimeUs = hasTail ? secondsToMicroseconds(note.endSeconds!) : undefined; + const kind = target.activeFreeZoneChannels.has(note.channel) ? 'freezone' : hasTail ? 'long' : 'normal'; + const channel = takeChannel(`${kind}:${timeUs}:${endTimeUs ?? ''}`); + if (channel === undefined) { + return { ok: false, reason: `no recorded ${kind} note at ${timeUs}µs` }; + } + assignments.push({ note, channel }); + } + for (const mine of target.landmineNotes) { + const channel = takeChannel(`mine:${secondsToMicroseconds(mine.seconds)}:`); + if (channel === undefined) { + return { ok: false, reason: `no recorded mine at ${secondsToMicroseconds(mine.seconds)}µs` }; + } + assignments.push({ note: mine, channel }); + } + for (const invisible of target.invisibleNotes) { + const channel = takeChannel(`invisible:${secondsToMicroseconds(invisible.seconds)}:`); + if (channel === undefined) { + return { ok: false, reason: `no recorded invisible note at ${secondsToMicroseconds(invisible.seconds)}µs` }; + } + assignments.push({ note: invisible, channel }); + } + for (const [key, bucket] of buckets) { + if (bucket.length > 0) { + return { ok: false, reason: `recorded chart has ${bucket.length} unmatched note(s) at ${key}` }; + } + } + + for (const { note, channel } of assignments) { + note.channel = channel; + } + return { ok: true }; +} + +function secondsToMicroseconds(seconds: number): number { + return Math.round(seconds * 1_000_000); +} diff --git a/packages/player-web/src/scene/beatoraja/gameplay.ts b/packages/player-web/src/scene/beatoraja/gameplay.ts index 8b98c6f7..a8a63ca4 100644 --- a/packages/player-web/src/scene/beatoraja/gameplay.ts +++ b/packages/player-web/src/scene/beatoraja/gameplay.ts @@ -493,7 +493,11 @@ export class PixiBeatorajaGameplayView implements PixiScene { ...composeBeatorajaEngineOptions(this.options), // Play-log recording — the beatoraja path has no gauge picker yet, so the declared gauge stays the // engine's GROOVE default. DP flip is a chart transform the host already applied; record the intent. - recordPlaylog: this.options.dpFlip !== undefined ? { dpFlip: this.options.dpFlip } : {}, + // The chart path rides along in `native` so a dropped play-log can be matched back to its song. + recordPlaylog: { + ...(this.options.dpFlip !== undefined ? { dpFlip: this.options.dpFlip } : {}), + ...(this.options.chartPath !== undefined ? { native: { chartPath: this.options.chartPath } } : {}), + }, onPlaylogRecorded: (playlog) => { this.playlog = playlog; }, diff --git a/packages/player-web/src/scene/lr2/gameplay.ts b/packages/player-web/src/scene/lr2/gameplay.ts index 923e2bc5..492c7242 100644 --- a/packages/player-web/src/scene/lr2/gameplay.ts +++ b/packages/player-web/src/scene/lr2/gameplay.ts @@ -41,6 +41,7 @@ import { import { createScrollDistanceMapper, type ScrollDistanceMapperLike } from '@be-music/player/core/scroll-distance'; import { type TimedLandmineNote, type TimedPlayableNote } from '@be-music/player/playable-notes'; import type { BeMusicPlaylog } from '@be-music/player/playlog'; +import { applyPlaylogArrangement } from '../../chart/playlog-arrangement.ts'; import { findFirstIndexAtOrAfter, findFirstIndexNumberAtOrAfter, runWithConcurrency } from '@be-music/utils/core'; import type { BrowserSongAssetSource, BrowserSongEntry } from '../../collection/types.ts'; import { @@ -415,6 +416,14 @@ export interface PixiGameplayViewOptions { random1P?: 'OFF' | 'MIRROR' | 'RANDOM' | 'S-RANDOM' | 'SCATTER'; /** 2P side note arrangement (`#SRC_BUTTON,type=43`). */ random2P?: 'OFF' | 'MIRROR' | 'RANDOM' | 'S-RANDOM' | 'SCATTER'; + /** + * Replay playback: a recorded play-log to re-drive instead of live keyboard input. The chart prepare skips the + * usual DP-flip / lane-shuffle passes and re-applies the RECORDED arrangement (`applyPlaylogArrangement`), the + * engine consumes `playlog.inputs` deterministically (`PlayerOptions.replayInputs`), live lane input is ignored, + * and no new play-log is recorded for the run. `prepare` rejects when the loaded chart does not match the log + * (different `#RANDOM` roll / different chart file). + */ + replay?: BeMusicPlaylog; /** * 1P gauge variant (`#SRC_BUTTON,type=40`). Drives both the gauge formula (`createGrooveGaugeState`) and the * gauge-on- red-branch op flags (43 / 45). 2P-side gauge isn't yet separately wired — `createGrooveGaugeState` @@ -1857,41 +1866,52 @@ export class PixiGameplayView { this.notes = prepared.notes; this.mineNotes = prepared.landmineNotes; this.invisibleNotes = prepared.invisibleNotes; - // DP FLIP — swap 1P / 2P channels in place. Cheap O(n) walk because we already iterate `notes` for sorting; SP - // charts skip every entry (no `2x` channels exist). Mine notes are flipped together so they stay anchored to the - // same visual lane after the flip. - if (this.options.dpFlip) { - for (const note of this.notes) { - note.channel = flipDpChannel(note.channel); + if (this.options.replay !== undefined) { + // Replay playback — the recorded play-log carries the FINAL note arrangement (post-flip, post-shuffle), so + // instead of re-rolling the lane transforms we re-apply the recorded channels onto the freshly prepared + // notes. A mismatch means the loaded chart is not the one the log was recorded against (different `#RANDOM` + // roll or a different file) — surface it as a prepare failure rather than replaying garbage. + const arranged = applyPlaylogArrangement(this.options.replay.chart.notes, prepared); + if (!arranged.ok) { + throw new Error(`play-log replay chart mismatch: ${arranged.reason}`); } - for (const mine of this.mineNotes) { - mine.channel = flipDpChannel(mine.channel); - } - for (const invisible of this.invisibleNotes) { - invisible.channel = flipDpChannel(invisible.channel); + } else { + // DP FLIP — swap 1P / 2P channels in place. Cheap O(n) walk because we already iterate `notes` for sorting; SP + // charts skip every entry (no `2x` channels exist). Mine notes are flipped together so they stay anchored to the + // same visual lane after the flip. + if (this.options.dpFlip) { + for (const note of this.notes) { + note.channel = flipDpChannel(note.channel); + } + for (const mine of this.mineNotes) { + mine.channel = flipDpChannel(mine.channel); + } + for (const invisible of this.invisibleNotes) { + invisible.channel = flipDpChannel(invisible.channel); + } } + // RANDOM / MIRROR / S-RANDOM / SCATTER — shuffle the 1P / 2P keyboard lanes independently. Scratch (channels 16 / + // 26) never moves. Per LR2 convention, the shuffle is drawn at chart-prepare time so a single play session has a + // stable arrangement (F5-restart re-rolls it). Mine channels are included in the same shuffle pass so a mine on + // lane 4 lands wherever the shuffle moved lane 4 — keeping the mine's visual relationship to the surrounding chord + // intact. + applyRandomMode( + this.notes as Array<{ channel: string }>, + '1', + this.options.random1P ?? 'OFF', + Math.random, + this.mineNotes as Array<{ channel: string }>, + this.invisibleNotes as Array<{ channel: string }>, + ); + applyRandomMode( + this.notes as Array<{ channel: string }>, + '2', + this.options.random2P ?? 'OFF', + Math.random, + this.mineNotes as Array<{ channel: string }>, + this.invisibleNotes as Array<{ channel: string }>, + ); } - // RANDOM / MIRROR / S-RANDOM / SCATTER — shuffle the 1P / 2P keyboard lanes independently. Scratch (channels 16 / - // 26) never moves. Per LR2 convention, the shuffle is drawn at chart-prepare time so a single play session has a - // stable arrangement (F5-restart re-rolls it). Mine channels are included in the same shuffle pass so a mine on - // lane 4 lands wherever the shuffle moved lane 4 — keeping the mine's visual relationship to the surrounding chord - // intact. - applyRandomMode( - this.notes as Array<{ channel: string }>, - '1', - this.options.random1P ?? 'OFF', - Math.random, - this.mineNotes as Array<{ channel: string }>, - this.invisibleNotes as Array<{ channel: string }>, - ); - applyRandomMode( - this.notes as Array<{ channel: string }>, - '2', - this.options.random2P ?? 'OFF', - Math.random, - this.mineNotes as Array<{ channel: string }>, - this.invisibleNotes as Array<{ channel: string }>, - ); this.maxLongNoteBeatSpan = this.notes.reduce((max, note) => { if (note.endBeat === undefined) { return max; @@ -5588,24 +5608,38 @@ export class PixiGameplayView { // structurally impossible because there is only one extract. preparedChart: this.preparedChart, signal: (this.sharedEngineAbortController = new AbortController()).signal, - // Play-log recording: the engine snapshots the resolved (post-shuffle) chart and the raw input replay, - // then hands the assembled log here right before the play promise settles. The host reads it back through - // `getResultData().playlog` for the result screen's auto-save. - recordPlaylog: { - gauge: this.options.gauge, - ...(this.options.random1P !== undefined || this.options.random2P !== undefined - ? { - randomLane: { - ...(this.options.random1P !== undefined ? { p1: this.options.random1P } : {}), - ...(this.options.random2P !== undefined ? { p2: this.options.random2P } : {}), - }, - } - : {}), - ...(this.options.dpFlip !== undefined ? { dpFlip: this.options.dpFlip } : {}), - }, - onPlaylogRecorded: (playlog) => { - this.playlog = playlog; - }, + ...(this.options.replay !== undefined + ? { + // Replay playback — feed the recorded input stream; the engine ignores live lane input, and the run + // records no new play-log (replaying a replay would only duplicate the file). Auto scratch and the + // debug judge-window override are restored from the log so the judging setup matches the recording. + replayInputs: this.options.replay.inputs, + autoScratch: this.options.replay.play.autoScratch, + ...(this.options.replay.play.judgeWindowOverrideMs !== undefined + ? { judgeWindowMs: this.options.replay.play.judgeWindowOverrideMs } + : {}), + } + : { + // Play-log recording: the engine snapshots the resolved (post-shuffle) chart and the raw input + // replay, then hands the assembled log here right before the play promise settles. The host reads it + // back through `getResultData().playlog` for the result screen's auto-save. + recordPlaylog: { + gauge: this.options.gauge, + ...(this.options.random1P !== undefined || this.options.random2P !== undefined + ? { + randomLane: { + ...(this.options.random1P !== undefined ? { p1: this.options.random1P } : {}), + ...(this.options.random2P !== undefined ? { p2: this.options.random2P } : {}), + }, + } + : {}), + ...(this.options.dpFlip !== undefined ? { dpFlip: this.options.dpFlip } : {}), + ...(this.song?.chartPath !== undefined ? { native: { chartPath: this.song.chartPath } } : {}), + }, + onPlaylogRecorded: (playlog) => { + this.playlog = playlog; + }, + }), }, }) .then((summary) => { diff --git a/packages/player/src/core/engine.ts b/packages/player/src/core/engine.ts index f9d2a6c8..2e1e0edd 100644 --- a/packages/player/src/core/engine.ts +++ b/packages/player/src/core/engine.ts @@ -79,7 +79,7 @@ import { type GrooveGaugeJudgeKind, type GrooveGaugeType } from './groove-gauge. import { resolveLandmineGaugeEffect } from './landmine.ts'; import { resolveBmsJudgeWindowsMsForExRankValue, resolveJudgeWindowsMs } from './judge-window.ts'; import { createPlaylogRecorder, type PlaylogRecordingOptions } from '../playlog/recorder.ts'; -import type { BeMusicPlaylog } from '../playlog/format.ts'; +import type { BeMusicPlaylog, PlaylogInputEvent } from '../playlog/format.ts'; import { createBeatAtSecondsResolverFromTimingResolver, createBpmTimeline, @@ -263,6 +263,15 @@ export interface PlayerOptions { * tools. */ onPlaylogRecorded?: (playlog: BeMusicPlaylog) => void; + /** + * Replay playback: a recorded play-log input stream (`playlog.inputs`) `manualPlay` re-drives DETERMINISTICALLY. + * Each event fires at its exact chart-relative microsecond timestamp (no wall-clock jitter — the judge timestamp + * is the recorded one), so replaying a log against the same resolved chart reproduces the original judgments. + * While a replay is active, live lane / kitty input commands are ignored; pause, high-speed, and interrupt + * commands keep working. The caller is responsible for mounting the SAME resolved chart the log was recorded + * against (`preparedChart`, or a chart remapped to the log's note arrangement). + */ + replayInputs?: readonly PlaylogInputEvent[]; } export interface PlayerSummary { @@ -3082,7 +3091,18 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) if (candidateChannels.size === 0) { return; } + handleLaneInputChannels(candidateChannels, tokens, nowMs, nowSec); + }; + // Channel-direct core of the lane press handling. Live input goes through `handleMappedInputTokens` (token → + // channel resolution); replay playback calls this directly with the recorded channel set and the recorded + // chart-relative timestamp. + const handleLaneInputChannels = ( + candidateChannels: ReadonlySet<string>, + tokens: readonly string[], + nowMs: number, + nowSec: number, + ): void => { // Play-log press event — recorded BEFORE any judging so the log stays a raw input replay (recordInput copies // the shared channel-buffer synchronously). playlogRecorder?.recordInput('down', nowSec, tokens, candidateChannels); @@ -3292,6 +3312,11 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) }); }, onUnhandledCommand: (command) => { + // Replay playback drives the lanes from the recorded input stream — live lane / key-state input must not + // interleave with it (pause / high-speed / interrupt still arrive through the standard command path). + if (options.replayInputs !== undefined && (command.kind === 'kitty-state' || command.kind === 'lane-input')) { + return; + } if (command.kind === 'kitty-state') { if (!uiEnabled) { if (command.pressTokens.length > 0) { @@ -3387,6 +3412,57 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) }); }; + // Replay playback — recorded play-log inputs re-driven at their exact chart-relative timestamps. Events are + // processed at each tick boundary but judged with THEIR OWN chart seconds, so the replayed judgments are + // deterministic and independent of tick timing. Presses maintain `activeKittyPressedChannels` so long-note holds + // work exactly like the recorded run's key-state stream did. + const replayEvents = + options.replayInputs !== undefined && options.replayInputs.length > 0 + ? [...options.replayInputs].sort((left, right) => left.timeUs - right.timeUs || left.seq - right.seq) + : undefined; + let replayCursor = 0; + const processReplayEventsUntil = (untilSec: number): void => { + if (!replayEvents) return; + while (replayCursor < replayEvents.length) { + const event = replayEvents[replayCursor]!; + const eventSec = event.timeUs / 1_000_000; + if (eventSec > untilSec) break; + replayCursor += 1; + const channels = new Set(event.channels); + if (autoScratchEnabled) { + for (const channel of channels) { + if (scratchPlayableChannels.has(channel)) { + channels.delete(channel); + } + } + } + if (channels.size === 0) continue; + const eventMs = (eventSec * 1000) / speed; + if (event.action === 'down') { + for (const channel of channels) { + activeKittyPressedChannels.add(channel); + if (uiEnabled) { + uiSignals.pushCommand({ kind: 'press-lane', channel }); + } + } + playbackEventTracer.flushUntil(eventSec); + handleLaneInputChannels(channels, event.tokens ?? [], eventMs, eventSec); + } else { + // Mirror the live kitty-release recording so a replayed run re-records an equivalent playlog. + playlogRecorder?.recordInput('up', eventSec, event.tokens ?? [], channels); + for (const channel of channels) { + activeKittyPressedChannels.delete(channel); + if (uiEnabled) { + uiSignals.pushCommand({ kind: 'release-lane', channel }); + } + if (activeLongNotesByChannel.has(channel)) { + longHoldUntilMsByChannel.set(channel, eventMs); + } + } + } + } + }; + try { while (playbackClock.nowMs() < horizon) { consumeInputCommands(); @@ -3406,6 +3482,7 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) const nowSec = elapsedMsToGameSeconds(nowMs, speed); const scheduledSec = elapsedMsToGameSeconds(scheduledMs, speed); const nowBeat = beatAtSeconds(nowSec); + processReplayEventsUntil(nowSec); advanceDynamicJudgeRankChanges(nowSec); playbackEventTracer.flushUntil(nowSec); diff --git a/packages/player/src/index.test.ts b/packages/player/src/index.test.ts index 7d49c4e8..2b128c0d 100644 --- a/packages/player/src/index.test.ts +++ b/packages/player/src/index.test.ts @@ -1022,6 +1022,67 @@ describe('player', () => { expect(lr2.judge.pgreat + lr2.judge.great + lr2.judge.good + lr2.judge.bad + lr2.judge.poor).toBe(1); }); + test('player: replayInputs re-drives a recorded playlog deterministically', async () => { + // BPM 240 → notes at 1.0 s ('11') and 1.5 s ('12'). Record a play with two slightly-off presses, then replay + // the recorded input stream — the judgments must reproduce exactly, even at a different engine speed. + const json = createEmptyJson('bms'); + json.metadata.bpm = 240; + json.metadata.total = 300; + json.events = [ + { measure: 1, channel: '11', position: [0, 2], value: '01' }, + { measure: 1, channel: '12', position: [1, 2], value: '01' }, + ]; + + let recorded: BeMusicPlaylog | undefined; + const original = await manualPlay(json, { + speed: 1, + leadInMs: 0, + audio: false, + tui: false, + onPlaylogRecorded: (playlog) => { + recorded = playlog; + }, + createInputRuntime: createScheduledInputRuntime([ + { delayMs: 990, command: { kind: 'lane-input', tokens: ['z'] } }, + { delayMs: 1540, command: { kind: 'lane-input', tokens: ['s'] } }, + ]), + }); + expect(recorded).toBeDefined(); + expect(recorded!.inputs).toHaveLength(2); + const originalJudged = original.perfect + original.great + original.good + original.bad; + expect(originalJudged).toBeGreaterThan(0); + + let replayed: BeMusicPlaylog | undefined; + const replaySummary = await manualPlay(json, { + // Chart-relative replay timestamps are speed-independent — run the replay fast to keep the test quick. + speed: 8, + leadInMs: 0, + audio: false, + tui: false, + replayInputs: recorded!.inputs, + onPlaylogRecorded: (playlog) => { + replayed = playlog; + }, + }); + + expect(replaySummary.perfect).toBe(original.perfect); + expect(replaySummary.great).toBe(original.great); + expect(replaySummary.good).toBe(original.good); + expect(replaySummary.bad).toBe(original.bad); + expect(replaySummary.poor).toBe(original.poor); + expect(replaySummary.exScore).toBe(original.exScore); + expect(replaySummary.score).toBe(original.score); + expect(replaySummary.fast).toBe(original.fast); + expect(replaySummary.slow).toBe(original.slow); + expect(replaySummary.gauge?.current).toBeCloseTo(original.gauge?.current ?? -1, 6); + // The replayed run re-records an equivalent input stream (same actions, channels, and µs timestamps). + expect( + replayed!.inputs.map((input) => ({ action: input.action, timeUs: input.timeUs, channels: input.channels })), + ).toEqual( + recorded!.inputs.map((input) => ({ action: input.action, timeUs: input.timeUs, channels: input.channels })), + ); + }); + test('player: ESC-interrupted play records an aborted playlog', async () => { const json = createEmptyJson('bms'); json.metadata.bpm = 240; From e96d7fa200b9a04b28a954b66bed1305e8b32416 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 01:06:57 +0900 Subject: [PATCH 32/39] feat: hash-match play-logs, switchable judge rulesets, and lil-gui play options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The playlog stamps the source chart file's SHA-256 (chart.sha256, format version unchanged) and dropped logs match by hash first, then chartPath, then title/artist. PlayerOptions.judgeRuleset switches the live judge windows between LR2 (default), beatoraja (judgerank-scaled SEVENKEYS), and IIDX (fixed widths) — window widths only, recorded as play.judgeRuleset and re-applied by replays; dynamic #EXRANKxx stays LR2-only. The demo's Debug Menu gains a Play options folder (auto play, judge windows, gauge, random 1P/2P, DP flip, auto scratch) that two-way syncs with the LR2 select scene's PLAY OPTION panel, feeds every gameplay family, and is latched at song start — all controls are disabled while a song is playing. --- .changeset/playlog-player-web.md | 2 +- .changeset/playlog-player.md | 2 +- docs/playlog.ja.md | 23 +- docs/playlog.md | 28 ++- packages/player-web-demo/src/main.ts | 227 +++++++++++++++--- packages/player-web-demo/src/types.ts | 18 ++ .../src/collection/chart-hash.test.ts | 33 +++ .../player-web/src/collection/chart-hash.ts | 40 +++ packages/player-web/src/collection/index.ts | 1 + .../src/scene/beatoraja/gameplay.ts | 16 +- packages/player-web/src/scene/lr2/gameplay.ts | 18 +- packages/player/src/core/engine.ts | 78 ++++-- packages/player/src/core/judge-window.test.ts | 48 ++++ packages/player/src/core/judge-window.ts | 88 +++++++ packages/player/src/index.test.ts | 53 +++- packages/player/src/playlog/format.ts | 13 +- packages/player/src/playlog/recorder.ts | 20 +- 17 files changed, 631 insertions(+), 77 deletions(-) create mode 100644 packages/player-web/src/collection/chart-hash.test.ts create mode 100644 packages/player-web/src/collection/chart-hash.ts diff --git a/.changeset/playlog-player-web.md b/.changeset/playlog-player-web.md index 41f63129..6b8fe102 100644 --- a/.changeset/playlog-player-web.md +++ b/.changeset/playlog-player-web.md @@ -4,4 +4,4 @@ Record a play log (`*.bmplay.json` input replay) for every gameplay run: the LR2/default gameplay scene exposes it through `PixiGameplayResultData.playlog`, the beatoraja scene through `PixiBeatorajaGameplayView.getPlaylog()`, and the `@be-music/player-web/runtime` subpath re-exports the playlog serializer helpers (`serializePlaylog`, `parsePlaylog`, `resolvePlaylogFilename`) for hosts. -The LR2/default gameplay scene also plays a recorded log back: `PixiGameplayViewOptions.replay` re-applies the log's resolved note arrangement onto the freshly prepared chart (`applyPlaylogArrangement` — RANDOM / MIRROR arrangements replay without re-rolling) and feeds the recorded inputs through the engine's deterministic replay path. +The LR2/default gameplay scene also plays a recorded log back: `PixiGameplayViewOptions.replay` re-applies the log's resolved note arrangement onto the freshly prepared chart (`applyPlaylogArrangement` — RANDOM / MIRROR arrangements replay without re-rolling) and feeds the recorded inputs through the engine's deterministic replay path, restoring the log's judge-window ruleset. The `@be-music/player-web/collection` subpath adds `computeChartFileSha256` / `computeSha256Hex` for stamping and matching the playlog's chart-file hash, and both gameplay scenes accept the host-computed hash and judge ruleset for recording. diff --git a/.changeset/playlog-player.md b/.changeset/playlog-player.md index 354213de..40639566 100644 --- a/.changeset/playlog-player.md +++ b/.changeset/playlog-player.md @@ -4,4 +4,4 @@ Add the `@be-music/player/playlog` subpath: a play-history ("playlog") format that records the resolved chart, the raw key press/release stream, and the play settings as an input replay, plus LR2 / beatoraja / IIDX ruleset simulators (`simulatePlaylog`) that re-derive judgments, EX-SCORE, max combo, money score, and groove gauge from the same recorded inputs. -New `PlayerOptions.onPlaylogRecorded` / `PlayerOptions.recordPlaylog` enable engine-side recording for both `manualPlay` and `autoPlay` (including ESC-aborted runs), and `PlayerOptions.replayInputs` re-drives a recorded input stream deterministically for replay playback (live lane input is ignored while a replay is active). `ScoreTracker` now latches `maxCombo`, `resolveJudgeRankPercent` exposes the chart's initial judgerank percent, and the landmine gauge-damage rule moved to the shared `core/landmine.ts` helper. +New `PlayerOptions.onPlaylogRecorded` / `PlayerOptions.recordPlaylog` enable engine-side recording for both `manualPlay` and `autoPlay` (including ESC-aborted runs), and `PlayerOptions.replayInputs` re-drives a recorded input stream deterministically for replay playback (live lane input is ignored while a replay is active). `PlayerOptions.judgeRuleset` switches the live judge windows between LR2 (default), beatoraja, and IIDX — recorded as `play.judgeRuleset` so replays re-apply the same windows — and the playlog stamps the source chart file's SHA-256 (`chart.sha256`) when the host supplies one. `ScoreTracker` now latches `maxCombo`, `resolveJudgeRankPercent` exposes the chart's initial judgerank percent, and the landmine gauge-damage rule moved to the shared `core/landmine.ts` helper. diff --git a/docs/playlog.ja.md b/docs/playlog.ja.md index 3c21ed52..f48a692b 100644 --- a/docs/playlog.ja.md +++ b/docs/playlog.ja.md @@ -13,12 +13,14 @@ LR2 / beatoraja / IIDX のリザルトを再現するツールについて説明 (RANDOM / MIRROR / S-RANDOM)と DP FLIP の適用後の最終配置です。ロングノートは `timeUs` / `endTimeUs` を持つ 1 オブジェクトとして保存し、地雷は解決済みのゲージダメージを持ち、`#TOTAL` / `#RANK` / `#DEFEXRANK` は生の値のまま保持します(各ルールセットが自分のデフォルト式を適用できるように)。 + `chart.sha256` には譜面**ファイル**の SHA-256 を刻印し、ログを内容ベースで元譜面と照合できます。 2. **`inputs`** — プレイアブルレーンに届いた全ての生のキー押下・解放 (`{ seq, timeUs, action: 'down' | 'up', channels }`)。入力は判定へ変換せず、ノート ID への割り当ても 行わず、空 POOR の原因になる「ノートに対応しない入力」もすべて残します。ソートキーは常に `(timeUs, seq)` で、`seq` が同時刻イベントの順序を確定します。 3. **`play`** — スコアに影響する設定。モード(manual / auto)、オートスクラッチ、選択ゲージ、最終配置を - 生んだレーンオプションのラベル、デバッグ用判定幅オーバーライド、ESC 中断フラグです。 + 生んだレーンオプションのラベル、ライブ判定幅ルールセット(`judgeRuleset`、省略時 `'lr2'`)、デバッグ用 + 判定幅オーバーライド、ESC 中断フラグです。 判定数・EX スコア・コンボ・ゲージ値は **`results`**(ルールセット ID をキーとする再生成可能なキャッシュ。 `native` は記録時のエンジン自身のサマリ)にのみ存在します。正本が入力列なので、後からルールセットを修正 @@ -46,15 +48,28 @@ TypeScript 型・シリアライザ・防御的パーサは - beatoraja ゲームプレイシーンは `PixiBeatorajaGameplayView.getPlaylog()` として公開します。 - デモはリザルトシーンのマウント時に `<タイトル>-<タイムスタンプ>.bmplay.json` を自動ダウンロードします。 Debug Menu の **Auto-save play history** チェックボックス(デフォルト ON)で制御します。プレイログ関連 - オプションは曲の開始時にラッチされ、曲の途中では変更できません — プレイ中はチェックボックスが disabled + オプションは曲の開始時にラッチされ、曲の途中では変更できません — プレイ中はコントロールが disabled になり、曲開始時点の値がそのプレイに適用されます。 +- Debug Menu の **Play options** フォルダが記録対象のプレイ設定(オートプレイ、判定幅 + LR2 / beatoraja / IIDX、ゲージ、Random 1P/2P、DP FLIP、オートスクラッチ)を持ちます。LR2 セレクトシーンの + PLAY OPTION パネルに対応項目がある設定は双方向に同期します。 + +## ライブ判定幅ルールセット + +共有エンジンはライブプレイを `'lr2'`(デフォルト)/ `'beatoraja'` / `'iidx'` の判定幅で判定できます +(`PlayerOptions.judgeRuleset`)。切り替わるのは**判定幅のみ**です: LR2 はランク補間済みの LR2 幅、 +beatoraja は SEVENKEYS 幅を beatoraja の judgerank で線形スケール(非対称な BAD 窓は ±250 ms × judgerank に +対称化)、IIDX は固定 ±16.67/±33.33/±116.67/±250 ms。ノート選択・空 POOR・ロングノート仕様・ゲージは +エンジンの LR2 準拠のままです — ルールセットの完全再現はプレイログシミュレータが担います。動的 `#EXRANKxx` +は `'lr2'` のときだけ適用されます。選択値は `play.judgeRuleset` として記録され、リプレイは自動的に同じ +判定幅を再適用します。 ## リプレイ再生 `*.bmplay.json` ファイルをブラウザプレイヤーへドロップすると、対応する楽曲がロード済みの場合にリプレイ再生が 始まります(曲フォルダとログを同時にドロップしても動作します — 曲のロード後にリプレイが始まります)。 -楽曲のマッチングは `play.native.chartPath` に記録された chartPath の完全一致を優先し、それが無い古いログは -タイトル+アーティストで照合します。 +楽曲のマッチングは譜面ファイルのハッシュ(`chart.sha256` — セッションやファイル移動をまたいで安定)を最優先し、 +次に記録された `play.native.chartPath`、どちらも無い古いログはタイトル+アーティストで照合します。 リプレイは共有エンジン内で記録済み入力列を決定論的に再駆動します(`PlayerOptions.replayInputs`)。各イベントは 記録された譜面相対マイクロ秒の時刻ちょうどで発火し、ライブのレーン入力は無視され(ESC / ポーズ / ハイスピは diff --git a/docs/playlog.md b/docs/playlog.md index 65ecbcd3..1cb88a3b 100644 --- a/docs/playlog.md +++ b/docs/playlog.md @@ -12,13 +12,15 @@ A playlog is deliberately **not** a list of judgments. Its canonical payload is: 1. **`chart`** — the resolved chart that actually scrolled past the player: post-`#RANDOM` control flow, post lane-shuffle (RANDOM / MIRROR / S-RANDOM), post DP-flip. Long notes are stored as single objects with a `timeUs` / `endTimeUs` pair, mines carry their resolved gauge damage, and the raw `#TOTAL` / `#RANK` / - `#DEFEXRANK` metadata is preserved so each ruleset can apply its own defaults. + `#DEFEXRANK` metadata is preserved so each ruleset can apply its own defaults. `chart.sha256` stamps the + SHA-256 of the source chart FILE bytes so a log can be matched back to its chart by content. 2. **`inputs`** — every raw key press / release that reached a playable lane, as `{ seq, timeUs, action: 'down' | 'up', channels }`. Inputs are never converted into judgments, never assigned to a note id, and phantom presses (the ones that fire LR2 empty POORs) are kept. The sort key is always `(timeUs, seq)` — `seq` disambiguates same-microsecond events. 3. **`play`** — the settings that affect scoring: mode (manual / auto), auto scratch, the selected gauge, the - lane-arrangement options that produced the resolved chart, the debug judge-window override, and an ESC flag. + lane-arrangement options that produced the resolved chart, the live judge-window ruleset (`judgeRuleset`, + absent = `'lr2'`), the debug judge-window override, and an ESC flag. Judgments, EX-SCORE, combo, and gauge values live only in **`results`** — a regenerable cache keyed by ruleset id (`native` holds the engine's own summary at record time). Because the canonical data is the input stream, a later @@ -46,14 +48,28 @@ In the browser player: - The beatoraja gameplay scene exposes it through `PixiBeatorajaGameplayView.getPlaylog()`. - The demo auto-downloads the log as `<title>-<timestamp>.bmplay.json` when the result scene mounts, controlled by the Debug Menu's **Auto-save play history** checkbox (ON by default). Play-log options are latched at song start - and cannot change mid-play — the checkbox is disabled while a song is playing, and the value in effect when the - song started governs that play. + and cannot change mid-play — the controls are disabled while a song is playing, and the values in effect when + the song started govern that play. +- The Debug Menu's **Play options** folder covers the recorded play settings: auto play, judge windows + (LR2 / beatoraja / IIDX), gauge, Random 1P/2P, DP flip, and auto scratch. Where the LR2 select scene's + PLAY OPTION panel has a counterpart, the two surfaces two-way sync. + +## Live judge-window rulesets + +The shared engine can judge a live play under `'lr2'` (default), `'beatoraja'`, or `'iidx'` windows +(`PlayerOptions.judgeRuleset`). Only the WINDOW WIDTHS switch: LR2 uses the rank-interpolated LR2 windows, +beatoraja scales its SEVENKEYS windows linearly by beatoraja's judgerank (the asymmetric BAD gate is symmetrized +to ±250 ms × judgerank), and IIDX uses the fixed ±16.67/±33.33/±116.67/±250 ms widths. Note selection, empty-POOR +behavior, long-note mechanics, and the groove gauge stay on the engine's LR2-aligned semantics — the playlog +simulators remain the full per-ruleset reproduction. Dynamic `#EXRANKxx` only applies under `'lr2'`. The selected +ruleset is recorded as `play.judgeRuleset` and replays re-apply it automatically. ## Replay playback Dropping a `*.bmplay.json` file onto the browser player starts replay playback when the matching song is loaded -(dropping the song folder together with the log works too — the songs load first). Matching prefers the exact -`chartPath` recorded in `play.native.chartPath`, with a title + artist fallback for older logs. +(dropping the song folder together with the log works too — the songs load first). Matching prefers the chart-file +hash (`chart.sha256` — stable across sessions and file moves), then the recorded `play.native.chartPath`, then a +title + artist fallback for older logs. Replay re-drives the recorded input stream deterministically inside the shared engine (`PlayerOptions.replayInputs`): every event fires at its exact chart-relative microsecond timestamp, live lane diff --git a/packages/player-web-demo/src/main.ts b/packages/player-web-demo/src/main.ts index 3d12ad28..1f9d8faf 100644 --- a/packages/player-web-demo/src/main.ts +++ b/packages/player-web-demo/src/main.ts @@ -16,6 +16,7 @@ import { PixiSongSelectView, type BeatorajaSelectSystemSoundPaths, type PixiGameplayResultData, + type PixiPlayOptions, type PixiSongSelectNavigation, } from '@be-music/player-web/scenes'; import { @@ -40,6 +41,7 @@ import { prepareBeatorajaGameplayChart, type PreparedBeatorajaGameplayChart } fr import { BrowserSongCollectionStore, checkBrowserCompat, + computeChartFileSha256, describeSongCollection, loadAssetBytes, readDroppedFiles, @@ -372,6 +374,14 @@ class PlayerWebDemoApp { * select paths can `enable()` it again. */ private playlogSaveController: Controller | undefined; + /** + * Every "Play options" folder controller (auto play / judge / gauge / random / DP flip / auto scratch). Disabled + * together while a song is playing (`lockPlaylogOptionsForPlay`) and refreshed when the LR2 select panel pushes + * a change (`refreshPlayOptionControllers`). + */ + private readonly playOptionControllers: Controller[] = []; + /** Per-entry chart-file SHA-256 cache (`''` = lookup failed) — see {@link resolveChartSha256}. */ + private readonly chartSha256Cache = new Map<string, string>(); /** * `guiState.autoSavePlaylog` as it was when the current play STARTED. The result-screen auto-save decision reads * this latch, not the live checkbox, so the value in effect at song start governs the whole play (the checkbox is @@ -440,6 +450,16 @@ class PlayerWebDemoApp { // result scene mounts, so the input replay is preserved without the user having to remember anything. The // Debug Menu checkbox turns the download off for users who don't want per-play files piling up. autoSavePlaylog: true, + // Play options (playMode / chartOptions / assists / judge / gauge equivalents). Two-way synced with the LR2 + // select scene's PLAY OPTION panel where a counterpart exists; latched at song start and disabled during a + // play. The judge ruleset has no in-skin counterpart — the Debug Menu is its only surface. + judgeRuleset: 'lr2', + gauge: 'GROOVE', + random1P: 'OFF', + random2P: 'OFF', + dpFlip: false, + autoScratch1P: false, + autoScratch2P: false, // Skin-family routing defaults to `'auto'`: beatoraja > LR2 > default, picked per-scene from what's loaded. // The Debug Menu's "Skin family" dropdown lets users force a specific family; LR2 / beatoraja entries appear // in the dropdown only when their theme is loaded (see {@link rebuildSkinFamilyPicker}). @@ -762,6 +782,78 @@ class PlayerWebDemoApp { this.guiState.judgedNoteDisplay = value; this.gameplayView?.setJudgedNoteDisplay(value); }); + // Play options — the playMode / chartOptions / assists / judge / gauge settings that get recorded into the + // play-log. Two-way synced with the LR2 select scene's PLAY OPTION panel where a counterpart exists (the panel + // pushes user edits back through `onPlayOptionsChange`; these controllers push through `setPlayOptions`). All + // of them are latched at song start and DISABLED during a play — mid-song changes never apply. + const playOptionsFolder = gui.addFolder('Play options'); + const trackPlayOption = (controller: Controller): Controller => { + this.playOptionControllers.push(controller); + return controller; + }; + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'autoPlay') + .name('Auto play') + .onChange((value: boolean) => { + this.selectView?.setPlayOptions({ autoPlay: value }); + }), + ); + // Judge-window ruleset — no in-skin counterpart; the Debug Menu is its only surface. Window widths only (note + // selection / empty POOR / LN mechanics / gauge stay LR2-aligned — see docs/playlog.md). + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'judgeRuleset', { LR2: 'lr2', beatoraja: 'beatoraja', IIDX: 'iidx' }) + .name('Judge windows'), + ); + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'gauge', ['GROOVE', 'EASY', 'HARD', 'DEATH']) + .name('Gauge') + .onChange((value: DemoGuiState['gauge']) => { + this.selectView?.setPlayOptions({ gauge1P: value }); + }), + ); + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'random1P', ['OFF', 'MIRROR', 'RANDOM', 'S-RANDOM', 'SCATTER']) + .name('Random 1P') + .onChange((value: DemoGuiState['random1P']) => { + this.selectView?.setPlayOptions({ random1P: value }); + }), + ); + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'random2P', ['OFF', 'MIRROR', 'RANDOM', 'S-RANDOM', 'SCATTER']) + .name('Random 2P') + .onChange((value: DemoGuiState['random2P']) => { + this.selectView?.setPlayOptions({ random2P: value }); + }), + ); + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'dpFlip') + .name('DP flip') + .onChange((value: boolean) => { + this.selectView?.setPlayOptions({ dpFlip: value }); + }), + ); + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'autoScratch1P') + .name('Auto scratch 1P') + .onChange((value: boolean) => { + this.selectView?.setPlayOptions({ autoScratch1P: value }); + }), + ); + trackPlayOption( + playOptionsFolder + .add(this.guiState, 'autoScratch2P') + .name('Auto scratch 2P') + .onChange((value: boolean) => { + this.selectView?.setPlayOptions({ autoScratch2P: value }); + }), + ); // Play-history auto-save — ON by default. When enabled, every finished play downloads its play-log // (`*.bmplay.json`, the raw input replay defined in `@be-music/player/playlog`) as soon as the result scene // mounts. The file feeds the `bms-playlog` CLI, which re-derives LR2 / beatoraja / IIDX scores from the replay. @@ -952,7 +1044,7 @@ class PlayerWebDemoApp { this.setStatus(`Replay: invalid play-log (${(error as Error).message})`); return; } - const song = this.findSongForPlaylog(playlog); + const song = await this.findSongForPlaylog(playlog); if (!song) { this.setStatus(`Replay: song not loaded (${playlog.chart.title ?? 'untitled'})`); return; @@ -970,10 +1062,19 @@ class PlayerWebDemoApp { } /** - * Finds the loaded song a play-log belongs to. Exact `chartPath` match first (recorded since the replay feature - * landed), then a title + artist heuristic for logs recorded before the path rode along. + * Finds the loaded song a play-log belongs to. Chart-file SHA-256 first (`chart.sha256`), then the recorded + * `chartPath`, then a title + artist heuristic for logs recorded before either rode along. */ - private findSongForPlaylog(playlog: BeMusicPlaylog): BrowserSongEntry | undefined { + private async findSongForPlaylog(playlog: BeMusicPlaylog): Promise<BrowserSongEntry | undefined> { + // Content hash first — stable across sessions, machines, and file moves. + const sha256 = playlog.chart.sha256?.toLowerCase(); + if (sha256 !== undefined && sha256.length > 0) { + for (const entry of this.collection.songs) { + if ((await this.resolveChartSha256(entry)) === sha256) { + return entry; + } + } + } const nativeChartPath = playlog.play.native?.chartPath; if (typeof nativeChartPath === 'string' && nativeChartPath.length > 0) { const exact = this.collection.songs.find((entry) => entry.chartPath === nativeChartPath); @@ -990,6 +1091,21 @@ class PlayerWebDemoApp { ); } + /** + * SHA-256 (lowercase hex) of a song's source chart file, cached per entry id — the hash feeds both the play-log + * recording (`chart.sha256`) and dropped-log matching, and chart files are small enough that hashing the whole + * library on a dropped log stays cheap. + */ + private async resolveChartSha256(song: BrowserSongEntry): Promise<string | undefined> { + const cached = this.chartSha256Cache.get(song.id); + if (cached !== undefined) { + return cached === '' ? undefined : cached; + } + const hash = await computeChartFileSha256(resolveSongSource(this.collection, song), song.chartPath); + this.chartSha256Cache.set(song.id, hash ?? ''); + return hash; + } + /** * Auto-loads a music and/or skin archive named by the `?music=` / `?skin=` URL parameters at boot, reusing the drop * pipeline so nothing about song listing or skin application is special-cased. @@ -1400,6 +1516,8 @@ class PlayerWebDemoApp { private async playSongBeatoraja(song: BrowserSongEntry, overrides: { autoPlay?: boolean }): Promise<void> { const bundle = this.beatorajaTheme; if (!bundle) return; + // Chart-file hash for the recorded play-log (matched back on a future play-log drop). + const chartSha256 = await this.resolveChartSha256(song); // **TWO distinct variants** flow into the gameplay scene: // - `skinVariant`: which `play_*` skin file to load. The theme may not ship every // variant (a popular 7-only theme lacks a `play_9` skin, etc.), so this falls back @@ -1589,12 +1707,20 @@ class PlayerWebDemoApp { audio: prep.audio, skinAudio: this.beatorajaSkinAudio, mode: (overrides.autoPlay ?? this.guiState.autoPlay) ? 'auto' : 'manual', - // DP flip — when the user enabled it via the play-options panel AND the chart is a - // DP variant (10 / 14 keys), the chart's lane channels mirror at construction. SP - // charts pass through unchanged because they have no 2P channels to swap with. - // Reads from the LR2 select view's persisted play options (the same surface that - // already drives `dpFlip` on the LR2 path). - dpFlip: this.selectView?.getPlayOptions().dpFlip, + // DP flip — when the user enabled it via the Play options (Debug Menu / LR2 select panel, two-way synced + // into `guiState`) AND the chart is a DP variant (10 / 14 keys), the chart's lane channels mirror at + // construction. SP charts pass through unchanged because they have no 2P channels to swap with. + dpFlip: this.guiState.dpFlip, + // Judge-window ruleset + auto scratch + play-log extras ride the engine-options passthrough — the beatoraja + // scene forwards them onto the shared engine and merges `recordPlaylog` with its own fields. + engineOptions: { + judgeRuleset: this.guiState.judgeRuleset, + autoScratch: this.guiState.autoScratch1P || this.guiState.autoScratch2P, + recordPlaylog: { + gauge: this.guiState.gauge, + ...(chartSha256 !== undefined ? { chartSha256 } : {}), + }, + }, bgaTextures: prep.bga.textures, bgaVideoElements: prep.bga.videoElements, bgaCues: prep.bga.cues, @@ -2753,12 +2879,28 @@ class PlayerWebDemoApp { decideBgm: this.decideBgmBytes, systemSounds: this.systemSoundBundle, initialNavigation: this.lastSelectNavigation, - // Seed the in-scene panel's autoPlay value from the cached demo state (carries the last value the user picked - // across re-mounts of the select view). - initialPlayOptions: { autoPlay: this.guiState.autoPlay }, - onPlayOptionsChange: (options: { autoPlay: boolean }) => { - // Cache the last value so it survives a select-view re-mount even though the lil-gui toggle is gone. + // Seed the in-scene panel from the Debug Menu's "Play options" state (two-way sync: the panel's own edits + // come back through `onPlayOptionsChange` below; lil-gui edits push through `setPlayOptions`). + initialPlayOptions: { + autoPlay: this.guiState.autoPlay, + gauge1P: this.guiState.gauge, + random1P: this.guiState.random1P, + random2P: this.guiState.random2P, + dpFlip: this.guiState.dpFlip, + autoScratch1P: this.guiState.autoScratch1P, + autoScratch2P: this.guiState.autoScratch2P, + }, + onPlayOptionsChange: (options: PixiPlayOptions) => { + // Mirror the in-skin PLAY OPTION panel's edits back into the Debug Menu state so both surfaces always + // agree, then repaint the lil-gui controllers. this.guiState.autoPlay = options.autoPlay; + this.guiState.gauge = options.gauge1P; + this.guiState.random1P = options.random1P; + this.guiState.random2P = options.random2P; + this.guiState.dpFlip = options.dpFlip; + this.guiState.autoScratch1P = options.autoScratch1P; + this.guiState.autoScratch2P = options.autoScratch2P; + this.refreshPlayOptionControllers(); }, onSongSelected: (song: BrowserSongEntry) => { // Fire the decide cue first — it plays through the select view's AudioContext which keeps running even after @@ -2851,14 +2993,18 @@ class PlayerWebDemoApp { * Wired up here (rather than inline in `showDecide`) because the same option-marshalling + callback wiring is needed * whether we're going through Decide or the no-decide fast-path. `playSong` shares this construction shape. */ - private preloadGameplay(song: BrowserSongEntry, overrides: { autoPlay?: boolean }): Promise<void> { + private async preloadGameplay(song: BrowserSongEntry, overrides: { autoPlay?: boolean }): Promise<void> { this.recordingFilenameBase = sanitizeFilenameStem(song.title) || `gameplay-${Date.now()}`; // Same family check as `playSong` — picking `'default'` from the Debug Menu strips the LR2 skin even when one // is loaded for this chart. Computing `gameplayFamily` here keeps the decide → gameplay preload path consistent // with the no-decide fast-path. const gameplayFamily = pickActiveFamilyForScene(this.familyDispatchState(), 'gameplay', song); const playSkin = gameplayFamily === 'lr2' ? pickLr2PlaySkin(this.playSkins, song) : undefined; - this.gameplayView = this.buildLr2GameplayView(song, playSkin, overrides); + const chartSha256 = await this.resolveChartSha256(song); + this.gameplayView = this.buildLr2GameplayView(song, playSkin, { + ...overrides, + ...(chartSha256 !== undefined ? { chartSha256 } : {}), + }); return this.gameplayView.prepare(this.sceneHost, song, resolveSongSource(this.collection, song)); } @@ -2876,12 +3022,15 @@ class PlayerWebDemoApp { private buildLr2GameplayView( song: BrowserSongEntry, playSkin: Lr2Skin | undefined, - overrides: { autoPlay?: boolean; replay?: BeMusicPlaylog }, + overrides: { autoPlay?: boolean; replay?: BeMusicPlaylog; chartSha256?: string }, ): PixiGameplayView { const playOptions = this.selectView?.getPlayOptions(); const replay = overrides.replay; const sharedOptions = { - autoPlay: overrides.autoPlay ?? playOptions?.autoPlay ?? this.guiState.autoPlay, + // The playlog-relevant options (auto play / random / DP flip / auto scratch / gauge / judge) read from + // `guiState` — the Debug Menu's "Play options" folder and the LR2 select panel two-way sync into it, and it + // is the surface that exists on every family (default / beatoraja selects have no LR2 PLAY OPTION panel). + autoPlay: overrides.autoPlay ?? this.guiState.autoPlay, autoPauseOnBlur: this.guiState.autoPauseOnBlur, initialHiSpeed: playOptions?.hiSpeed, bga: playOptions?.bga, @@ -2892,15 +3041,17 @@ class PlayerWebDemoApp { hiddenSudden2P: playOptions?.hiddenSudden2P, shutter: playOptions?.shutter, laneCover: playOptions?.laneCover, - // Replay playback restores the RECORDED play setup: the log's auto-scratch / gauge govern judging and the - // gauge readout, and the lane transforms stay off because the view re-applies the recorded arrangement - // directly (see `PixiGameplayViewOptions.replay`). - autoScratch1P: replay !== undefined ? replay.play.autoScratch : playOptions?.autoScratch1P, - autoScratch2P: replay !== undefined ? false : playOptions?.autoScratch2P, - dpFlip: replay !== undefined ? false : playOptions?.dpFlip, - random1P: replay !== undefined ? ('OFF' as const) : playOptions?.random1P, - random2P: replay !== undefined ? ('OFF' as const) : playOptions?.random2P, - gauge: replay !== undefined ? replay.play.gauge : playOptions?.gauge1P, + // Replay playback restores the RECORDED play setup: the log's auto-scratch / gauge / judge ruleset govern + // judging and the gauge readout, and the lane transforms stay off because the view re-applies the recorded + // arrangement directly (see `PixiGameplayViewOptions.replay`). + autoScratch1P: replay !== undefined ? replay.play.autoScratch : this.guiState.autoScratch1P, + autoScratch2P: replay !== undefined ? false : this.guiState.autoScratch2P, + dpFlip: replay !== undefined ? false : this.guiState.dpFlip, + random1P: replay !== undefined ? ('OFF' as const) : this.guiState.random1P, + random2P: replay !== undefined ? ('OFF' as const) : this.guiState.random2P, + gauge: replay !== undefined ? replay.play.gauge : this.guiState.gauge, + ...(replay === undefined ? { judgeRuleset: this.guiState.judgeRuleset } : {}), + ...(overrides.chartSha256 !== undefined ? { chartSha256: overrides.chartSha256 } : {}), replay, audioCompressor: this.guiState.compressor, audioCompressorMode: this.compressorMode, @@ -3013,7 +3164,12 @@ class PlayerWebDemoApp { // is undefined and `PixiGameplayView` otherwise; see `preloadGameplay` for the matching call shape (both feed // the same helper so option marshalling stays in one place). const playSkin = gameplayFamily === 'lr2' ? pickLr2PlaySkin(this.playSkins, song) : undefined; - this.gameplayView = this.buildLr2GameplayView(song, playSkin, overrides); + // Chart-file hash for the recorded play-log (skipped for replays — they record nothing). + const chartSha256 = overrides.replay === undefined ? await this.resolveChartSha256(song) : undefined; + this.gameplayView = this.buildLr2GameplayView(song, playSkin, { + ...overrides, + ...(chartSha256 !== undefined ? { chartSha256 } : {}), + }); this.setStatus(`Playing: ${song.title}`); this.lockPlaylogOptionsForPlay(); await this.gameplayView.mount(this.sceneHost, song, resolveSongSource(this.collection, song)); @@ -3089,11 +3245,24 @@ class PlayerWebDemoApp { private lockPlaylogOptionsForPlay(): void { this.activePlayAutoSavePlaylog = this.guiState.autoSavePlaylog; this.playlogSaveController?.disable(); + for (const controller of this.playOptionControllers) { + controller.disable(); + } } /** Re-enables the playlog option controllers once no play is in flight. */ private unlockPlaylogOptions(): void { this.playlogSaveController?.enable(); + for (const controller of this.playOptionControllers) { + controller.enable(); + } + } + + /** Repaints the "Play options" controllers after an external write (the LR2 select panel's edits). */ + private refreshPlayOptionControllers(): void { + for (const controller of this.playOptionControllers) { + controller.updateDisplay(); + } } /** diff --git a/packages/player-web-demo/src/types.ts b/packages/player-web-demo/src/types.ts index f258ab23..05fbe369 100644 --- a/packages/player-web-demo/src/types.ts +++ b/packages/player-web-demo/src/types.ts @@ -107,6 +107,24 @@ export interface DemoGuiState { * beatoraja result paths. Toggled from the Debug Menu's "Auto-save play history" checkbox. */ autoSavePlaylog: boolean; + /** + * Judge-window ruleset for the shared engine (`PlayerOptions.judgeRuleset`): LR2 (default) / beatoraja / IIDX. + * Only the window widths switch — note selection, empty POOR, LN mechanics, and the gauge stay LR2-aligned. + * Latched at song start (the Play options folder is disabled during a play) and recorded into the play-log. + */ + judgeRuleset: 'lr2' | 'beatoraja' | 'iidx'; + /** Gauge variant for the next play. Two-way synced with the LR2 select scene's PLAY OPTION panel. */ + gauge: 'GROOVE' | 'HARD' | 'DEATH' | 'EASY'; + /** 1P lane arrangement for the next play. Two-way synced with the LR2 select panel. */ + random1P: 'OFF' | 'MIRROR' | 'RANDOM' | 'S-RANDOM' | 'SCATTER'; + /** 2P lane arrangement for the next play. Two-way synced with the LR2 select panel. */ + random2P: 'OFF' | 'MIRROR' | 'RANDOM' | 'S-RANDOM' | 'SCATTER'; + /** DP FLIP for the next play. Two-way synced with the LR2 select panel. */ + dpFlip: boolean; + /** 1P auto scratch for the next play. Two-way synced with the LR2 select panel. */ + autoScratch1P: boolean; + /** 2P auto scratch for the next play. Two-way synced with the LR2 select panel. */ + autoScratch2P: boolean; /** * Explicit skin-family override picked from the Debug Menu dropdown. `'auto'` (default) keeps the legacy * priority — beatoraja if a beatoraja theme is loaded and covers the chart, otherwise LR2 (which itself falls diff --git a/packages/player-web/src/collection/chart-hash.test.ts b/packages/player-web/src/collection/chart-hash.test.ts new file mode 100644 index 00000000..7f222a26 --- /dev/null +++ b/packages/player-web/src/collection/chart-hash.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, test } from 'vitest'; +import type { BrowserSongAssetSource } from './types.ts'; +import { computeChartFileSha256, computeSha256Hex } from './chart-hash.ts'; + +const encoder = new TextEncoder(); + +function makeSource(files: Record<string, Uint8Array>): BrowserSongAssetSource { + return { + id: 'src', + kind: 'directory', + label: 'src', + files: new Map(Object.entries(files)), + }; +} + +describe('chart-hash', () => { + test('computeSha256Hex matches the SHA-256 test vector for "abc"', async () => { + expect(await computeSha256Hex(encoder.encode('abc'))).toBe( + 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', + ); + }); + + test('computeChartFileSha256 hashes the chart file bytes (case-insensitive path lookup)', async () => { + const bytes = encoder.encode('#TITLE test\n#BPM 120\n'); + const source = makeSource({ 'songs/test.bms': bytes }); + expect(await computeChartFileSha256(source, 'songs/TEST.BMS')).toBe(await computeSha256Hex(bytes)); + }); + + test('computeChartFileSha256 returns undefined for a missing chart or source', async () => { + expect(await computeChartFileSha256(makeSource({}), 'songs/missing.bms')).toBeUndefined(); + expect(await computeChartFileSha256(undefined, 'songs/missing.bms')).toBeUndefined(); + }); +}); diff --git a/packages/player-web/src/collection/chart-hash.ts b/packages/player-web/src/collection/chart-hash.ts new file mode 100644 index 00000000..3da053b2 --- /dev/null +++ b/packages/player-web/src/collection/chart-hash.ts @@ -0,0 +1,40 @@ +import { normalizePath } from '@be-music/utils/core'; +import { loadAssetBytes, lookupBytesCaseInsensitive } from './file-lookup.ts'; +import type { BrowserSongAssetSource } from './types.ts'; + +/** + * SHA-256 (lowercase hex) of a byte buffer via Web Crypto. Shared by the play-log recorder plumbing (stamping + * `chart.sha256` at record time) and the play-log drop matching (hashing loaded charts for comparison). + */ +export async function computeSha256Hex(bytes: Uint8Array): Promise<string> { + const digest = await crypto.subtle.digest('SHA-256', bytes as BufferSource); + let hex = ''; + for (const byte of new Uint8Array(digest)) { + hex += byte.toString(16).padStart(2, '0'); + } + return hex; +} + +/** + * SHA-256 (lowercase hex) of a song entry's source chart FILE bytes, or `undefined` when the chart file cannot be + * located in the asset source (or the runtime lacks Web Crypto). The hash is over the file exactly as dropped — + * the same bytes any other tool would hash — so it is stable across sessions, machines, and `#RANDOM` rolls. + */ +export async function computeChartFileSha256( + source: BrowserSongAssetSource | undefined, + chartPath: string, +): Promise<string | undefined> { + if (!source || typeof crypto === 'undefined' || !crypto.subtle) { + return undefined; + } + const entry = lookupBytesCaseInsensitive(source.files, normalizePath(chartPath)); + const bytes = await loadAssetBytes(entry); + if (!bytes) { + return undefined; + } + try { + return await computeSha256Hex(bytes); + } catch { + return undefined; + } +} diff --git a/packages/player-web/src/collection/index.ts b/packages/player-web/src/collection/index.ts index 02ba8e19..03c528db 100644 --- a/packages/player-web/src/collection/index.ts +++ b/packages/player-web/src/collection/index.ts @@ -8,6 +8,7 @@ * Anything else under `collection/` (the case-insensitive file-lookup helpers) stays internal to the package. */ export * from './collection.ts'; +export * from './chart-hash.ts'; export * from './types.ts'; // Browser-side input helpers — same logical surface (= "getting files INTO the player from the browser"), kept diff --git a/packages/player-web/src/scene/beatoraja/gameplay.ts b/packages/player-web/src/scene/beatoraja/gameplay.ts index a8a63ca4..ca1b8ae8 100644 --- a/packages/player-web/src/scene/beatoraja/gameplay.ts +++ b/packages/player-web/src/scene/beatoraja/gameplay.ts @@ -491,12 +491,20 @@ export class PixiBeatorajaGameplayView implements PixiScene { // overriding the inference (rare) still take precedence. engineOptions: { ...composeBeatorajaEngineOptions(this.options), - // Play-log recording — the beatoraja path has no gauge picker yet, so the declared gauge stays the - // engine's GROOVE default. DP flip is a chart transform the host already applied; record the intent. - // The chart path rides along in `native` so a dropped play-log can be matched back to its song. + // Play-log recording — host-supplied `engineOptions.recordPlaylog` fields (gauge pick, chart hash, ...) + // are preserved; the view adds what it owns: the DP-flip intent it applied to the chart, and the chart + // path in `native` so a dropped play-log can be matched back to its song. recordPlaylog: { + ...this.options.engineOptions?.recordPlaylog, ...(this.options.dpFlip !== undefined ? { dpFlip: this.options.dpFlip } : {}), - ...(this.options.chartPath !== undefined ? { native: { chartPath: this.options.chartPath } } : {}), + ...(this.options.chartPath !== undefined + ? { + native: { + ...this.options.engineOptions?.recordPlaylog?.native, + chartPath: this.options.chartPath, + }, + } + : {}), }, onPlaylogRecorded: (playlog) => { this.playlog = playlog; diff --git a/packages/player-web/src/scene/lr2/gameplay.ts b/packages/player-web/src/scene/lr2/gameplay.ts index 492c7242..a23fa700 100644 --- a/packages/player-web/src/scene/lr2/gameplay.ts +++ b/packages/player-web/src/scene/lr2/gameplay.ts @@ -424,6 +424,16 @@ export interface PixiGameplayViewOptions { * (different `#RANDOM` roll / different chart file). */ replay?: BeMusicPlaylog; + /** + * Judge-window ruleset for the shared engine (`PlayerOptions.judgeRuleset`): `'lr2'` (default) / `'beatoraja'` + * / `'iidx'`. Recorded into the play-log; replays re-apply the log's own value instead. + */ + judgeRuleset?: 'lr2' | 'beatoraja' | 'iidx'; + /** + * SHA-256 (lowercase hex) of the source chart file bytes, when the host computed one. Stamped into the recorded + * play-log (`chart.sha256`) so a dropped log can be matched back to its chart by content. + */ + chartSha256?: string; /** * 1P gauge variant (`#SRC_BUTTON,type=40`). Drives both the gauge formula (`createGrooveGaugeState`) and the * gauge-on- red-branch op flags (43 / 45). 2P-side gauge isn't yet separately wired — `createGrooveGaugeState` @@ -5611,20 +5621,24 @@ export class PixiGameplayView { ...(this.options.replay !== undefined ? { // Replay playback — feed the recorded input stream; the engine ignores live lane input, and the run - // records no new play-log (replaying a replay would only duplicate the file). Auto scratch and the - // debug judge-window override are restored from the log so the judging setup matches the recording. + // records no new play-log (replaying a replay would only duplicate the file). Auto scratch, the + // judge ruleset, and the debug judge-window override are restored from the log so the judging setup + // matches the recording. replayInputs: this.options.replay.inputs, autoScratch: this.options.replay.play.autoScratch, + judgeRuleset: this.options.replay.play.judgeRuleset ?? 'lr2', ...(this.options.replay.play.judgeWindowOverrideMs !== undefined ? { judgeWindowMs: this.options.replay.play.judgeWindowOverrideMs } : {}), } : { + ...(this.options.judgeRuleset !== undefined ? { judgeRuleset: this.options.judgeRuleset } : {}), // Play-log recording: the engine snapshots the resolved (post-shuffle) chart and the raw input // replay, then hands the assembled log here right before the play promise settles. The host reads it // back through `getResultData().playlog` for the result screen's auto-save. recordPlaylog: { gauge: this.options.gauge, + ...(this.options.chartSha256 !== undefined ? { chartSha256: this.options.chartSha256 } : {}), ...(this.options.random1P !== undefined || this.options.random2P !== undefined ? { randomLane: { diff --git a/packages/player/src/core/engine.ts b/packages/player/src/core/engine.ts index 2e1e0edd..1b629ab3 100644 --- a/packages/player/src/core/engine.ts +++ b/packages/player/src/core/engine.ts @@ -77,7 +77,12 @@ import { } from './scoring.ts'; import { type GrooveGaugeJudgeKind, type GrooveGaugeType } from './groove-gauge.ts'; import { resolveLandmineGaugeEffect } from './landmine.ts'; -import { resolveBmsJudgeWindowsMsForExRankValue, resolveJudgeWindowsMs } from './judge-window.ts'; +import { + resolveBmsJudgeWindowsMsForExRankValue, + resolveJudgeWindowsMs, + resolveJudgeWindowsMsForRuleset, + type JudgeWindowRuleset, +} from './judge-window.ts'; import { createPlaylogRecorder, type PlaylogRecordingOptions } from '../playlog/recorder.ts'; import type { BeMusicPlaylog, PlaylogInputEvent } from '../playlog/format.ts'; import { @@ -263,6 +268,15 @@ export interface PlayerOptions { * tools. */ onPlaylogRecorded?: (playlog: BeMusicPlaylog) => void; + /** + * Judge-window ruleset for manual play: `'lr2'` (default — the engine's LR2-aligned windows), `'beatoraja'` + * (SEVENKEYS windows scaled by beatoraja's judgerank), or `'iidx'` (fixed ±16.67/±33.33/±116.67/±250 ms). + * Only the WINDOW WIDTHS switch — note selection, empty-POOR, long-note mechanics, and the gauge stay on the + * engine's LR2-aligned semantics (the playlog simulators are the full per-ruleset reproduction). Dynamic + * `#EXRANKxx` changes are an LR2 concept and only apply under `'lr2'`. Recorded into the playlog + * (`play.judgeRuleset`) so replays re-apply the same windows. + */ + judgeRuleset?: JudgeWindowRuleset; /** * Replay playback: a recorded play-log input stream (`playlog.inputs`) `manualPlay` re-drives DETERMINISTICALLY. * Each event fires at its exact chart-relative microsecond timestamp (no wall-clock jitter — the judge timestamp @@ -1799,17 +1813,22 @@ export async function autoPlay(json: BeMusicJson, options: PlayerOptions = {}): // auto run produces a structurally complete playlog (simulators treat an empty input stream as all-miss; the // cached native result carries the actual AUTO outcome). const playlogRecorder = options.onPlaylogRecorded - ? createPlaylogRecorder({ - json: resolvedJson, - chart: playbackChart, - dynamicJudgeRankChanges: collectDynamicBmsJudgeRankChanges(resolvedJson, timingResolver), - play: { - mode: 'auto', - autoScratch: false, - judgeWindowOverrideMs: options.judgeWindowMs, - ...options.recordPlaylog, - }, - }) + ? (() => { + const { chartSha256, ...hostPlaySettings } = options.recordPlaylog ?? {}; + return createPlaylogRecorder({ + json: resolvedJson, + chart: playbackChart, + chartSha256, + dynamicJudgeRankChanges: collectDynamicBmsJudgeRankChanges(resolvedJson, timingResolver), + play: { + mode: 'auto', + autoScratch: false, + judgeWindowOverrideMs: options.judgeWindowMs, + judgeRuleset: options.judgeRuleset, + ...hostPlaySettings, + }, + }); + })() : undefined; let combo = 0; let interruptedReason: PlayerInterruptReason | undefined; @@ -2359,11 +2378,15 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) const inferBmsLnTypeWhenMissing = Boolean(options.inferBmsLnTypeWhenMissing); const autoScratchEnabled = options.autoScratch === true; const speed = options.speed ?? 1; - let judgeWindows = resolveJudgeWindowsMs(resolvedJson, options.judgeWindowMs); + const judgeRuleset: JudgeWindowRuleset = options.judgeRuleset ?? 'lr2'; + let judgeWindows = resolveJudgeWindowsMsForRuleset(resolvedJson, judgeRuleset, options.judgeWindowMs); let badWindowMs = judgeWindows.bad; let badWindowSeconds = badWindowMs / 1000; const timingResolver = createTimingResolver(resolvedJson); - const dynamicJudgeRankChanges = collectDynamicBmsJudgeRankChanges(resolvedJson, timingResolver); + // Dynamic `#EXRANKxx` is an LR2 concept — beatoraja ignores it and IIDX has no BMS rank axis at all, so the + // non-LR2 rulesets keep their initial windows for the whole chart. + const dynamicJudgeRankChanges = + judgeRuleset === 'lr2' ? collectDynamicBmsJudgeRankChanges(resolvedJson, timingResolver) : []; const realtimeAudioVolumeEvents = collectRealtimeAudioVolumeEvents(resolvedJson, timingResolver); let dynamicJudgeRankCursor = 0; let maxBadWindowMs = badWindowMs; @@ -2425,17 +2448,22 @@ export async function manualPlay(json: BeMusicJson, options: PlayerOptions = {}) ); const scoreTracker = createScoreTracker(); const playlogRecorder = options.onPlaylogRecorded - ? createPlaylogRecorder({ - json: resolvedJson, - chart: playbackChart, - dynamicJudgeRankChanges, - play: { - mode: 'manual', - autoScratch: autoScratchEnabled, - judgeWindowOverrideMs: options.judgeWindowMs, - ...options.recordPlaylog, - }, - }) + ? (() => { + const { chartSha256, ...hostPlaySettings } = options.recordPlaylog ?? {}; + return createPlaylogRecorder({ + json: resolvedJson, + chart: playbackChart, + chartSha256, + dynamicJudgeRankChanges, + play: { + mode: 'manual', + autoScratch: autoScratchEnabled, + judgeWindowOverrideMs: options.judgeWindowMs, + judgeRuleset: options.judgeRuleset, + ...hostPlaySettings, + }, + }); + })() : undefined; let combo = 0; let highSpeed = resolveHighSpeedMultiplier(options.highSpeed); diff --git a/packages/player/src/core/judge-window.test.ts b/packages/player/src/core/judge-window.test.ts index 27be19e5..81274241 100644 --- a/packages/player/src/core/judge-window.test.ts +++ b/packages/player/src/core/judge-window.test.ts @@ -2,10 +2,12 @@ import { createEmptyJson } from '@be-music/json'; import { describe, expect, test } from 'vitest'; import { bmsExRankValueToJudgeRankPercent, + resolveBeatorajaJudgeRankPercent, resolveBmsJudgeWindowsMsForExRankValue, resolveBmsJudgeWindowsMsForPercent, resolveJudgeRankPercent, resolveJudgeWindowsMs, + resolveJudgeWindowsMsForRuleset, } from './judge-window.ts'; describe('judge-window', () => { @@ -132,4 +134,50 @@ describe('judge-window', () => { // `#EXRANK 120` matches the documented `#DEFEXRANK 120` interpolation. expect(resolveBmsJudgeWindowsMsForExRankValue(120).great).toBeCloseTo(52, 6); }); + + test("resolveJudgeWindowsMsForRuleset: 'iidx' uses the fixed IIDX widths regardless of #RANK", () => { + const json = createEmptyJson('bms'); + json.metadata.rank = 0; // VERY HARD — must not narrow the IIDX windows + const windows = resolveJudgeWindowsMsForRuleset(json, 'iidx'); + expect(windows.pgreat).toBeCloseTo(16.67, 6); + expect(windows.great).toBeCloseTo(33.33, 6); + expect(windows.good).toBeCloseTo(116.67, 6); + expect(windows.bad).toBe(250); + // The debug override still replaces the BAD width only. + expect(resolveJudgeWindowsMsForRuleset(json, 'iidx', 300).bad).toBe(300); + expect(resolveJudgeWindowsMsForRuleset(json, 'iidx', 300).pgreat).toBeCloseTo(16.67, 6); + }); + + test("resolveJudgeWindowsMsForRuleset: 'beatoraja' scales the SEVENKEYS windows by judgerank", () => { + const json = createEmptyJson('bms'); + json.metadata.rank = 2; // beatoraja NORMAL rule → judgerank 75 % + const windows = resolveJudgeWindowsMsForRuleset(json, 'beatoraja'); + expect(windows.pgreat).toBeCloseTo(15, 6); // 20 × 0.75 + expect(windows.great).toBeCloseTo(45, 6); // 60 × 0.75 + expect(windows.good).toBeCloseTo(112.5, 6); // 150 × 0.75 + expect(windows.bad).toBeCloseTo(187.5, 6); // symmetric ±250 stand-in × 0.75 + + // #RANK 4 (VERY EASY) is 125 % under beatoraja — unlike LR2's 75 %. + json.metadata.rank = 4; + expect(resolveBeatorajaJudgeRankPercent(json)).toBe(125); + expect(resolveJudgeWindowsMsForRuleset(json, 'beatoraja').pgreat).toBeCloseTo(25, 6); + }); + + test("resolveJudgeWindowsMsForRuleset: 'beatoraja' judgerank sources — #DEFEXRANK × 0.75, bmson judge_rank as-is", () => { + const bms = createEmptyJson('bms'); + bms.bms.defExRank = 100; + expect(resolveBeatorajaJudgeRankPercent(bms)).toBeCloseTo(75, 9); + + const bmson = createEmptyJson('bmson'); + bmson.bmson.info.judgeRank = 130; + expect(resolveBeatorajaJudgeRankPercent(bmson)).toBe(130); + bmson.bmson.info.judgeRank = undefined; + expect(resolveBeatorajaJudgeRankPercent(bmson)).toBe(100); + }); + + test("resolveJudgeWindowsMsForRuleset: 'lr2' matches resolveJudgeWindowsMs", () => { + const json = createEmptyJson('bms'); + json.metadata.rank = 3; + expect(resolveJudgeWindowsMsForRuleset(json, 'lr2')).toEqual(resolveJudgeWindowsMs(json)); + }); }); diff --git a/packages/player/src/core/judge-window.ts b/packages/player/src/core/judge-window.ts index 72870fda..bae96054 100644 --- a/packages/player/src/core/judge-window.ts +++ b/packages/player/src/core/judge-window.ts @@ -112,6 +112,94 @@ export function resolveJudgeWindowsMs(json: BeMusicJson, debugBadWindowMs?: numb return scaleJudgeWindowsMs(resolveJudgeRankPercent(json), debugBadWindowMs); } +/** + * Which player's judge WINDOW model the live engine applies. Only the window widths switch — note selection, + * empty-POOR behavior, long-note mechanics, and the groove gauge stay on the engine's LR2-aligned semantics + * regardless (the playlog simulators in `@be-music/player/playlog` are the full per-ruleset reproduction). + */ +export type JudgeWindowRuleset = 'lr2' | 'beatoraja' | 'iidx'; + +export const JUDGE_WINDOW_RULESETS: readonly JudgeWindowRuleset[] = ['lr2', 'beatoraja', 'iidx']; + +/** + * IIDX judge windows (current AC, community measurement — iidx.org): ±1F / ±2F / ±7F / ±15F at 60 fps. Rank + * independent — IIDX ignores the BMS `#RANK` axis. + */ +const IIDX_JUDGE_WINDOWS_MS: JudgeWindowsMs = { pgreat: 16.67, great: 33.33, good: 116.67, bad: 250 }; + +/** beatoraja `#RANK 0..4` → judgerank percent (`JudgeWindowRule.NORMAL`; VERY EASY = 125, unlike LR2's 75). */ +const BEATORAJA_BMS_RANK_JUDGERANK_PERCENTS = [25, 50, 75, 100, 125] as const; +const BEATORAJA_NORMAL_JUDGERANK_PERCENT = BEATORAJA_BMS_RANK_JUDGERANK_PERCENTS[2]; +/** + * beatoraja SEVENKEYS base note windows at judgerank 100 (`JudgeProperty.java`). The real BAD window is asymmetric + * (late 280 ms / early 220 ms); the engine's judge pipeline is symmetric, so the midpoint ±250 ms stands in. + */ +const BEATORAJA_BASE_WINDOWS_MS = { pgreat: 20, great: 60, good: 150, bad: 250 } as const; + +/** + * beatoraja judgerank percent for a chart (`BMSPlayerRule.validate`, NORMAL window rule): BMS `#DEFEXRANK` is + * `value × 75 / 100`, bmson `judge_rank` is used as-is, and `#RANK 0..4` maps through + * {@link BEATORAJA_BMS_RANK_JUDGERANK_PERCENTS} (default NORMAL = 75). + */ +export function resolveBeatorajaJudgeRankPercent(json: BeMusicJson): number { + if (json.sourceFormat === 'bmson') { + const judgeRank = json.bmson.info.judgeRank; + if (Number.isFinite(judgeRank) && (judgeRank ?? 0) > 0) { + return judgeRank!; + } + return 100; + } + const defExRank = json.bms.defExRank; + if (typeof defExRank === 'number' && Number.isFinite(defExRank) && defExRank > 0) { + return (defExRank * BEATORAJA_NORMAL_JUDGERANK_PERCENT) / 100; + } + const rankValue = Number.isFinite(json.metadata.rank) ? Math.trunc(json.metadata.rank!) : Number.NaN; + if (Number.isFinite(rankValue) && rankValue >= 0 && rankValue < BEATORAJA_BMS_RANK_JUDGERANK_PERCENTS.length) { + return BEATORAJA_BMS_RANK_JUDGERANK_PERCENTS[rankValue as 0 | 1 | 2 | 3 | 4]; + } + return BEATORAJA_NORMAL_JUDGERANK_PERCENT; +} + +/** + * Resolves the live engine's judge windows under the selected ruleset. `'lr2'` is the engine default + * ({@link resolveJudgeWindowsMs}); `'beatoraja'` scales the SEVENKEYS windows linearly by beatoraja's judgerank; + * `'iidx'` uses the fixed IIDX widths. The `debugBadWindowMs` override replaces the BAD width in every ruleset, + * mirroring {@link resolveJudgeWindowsMs}'s debug semantics. + */ +export function resolveJudgeWindowsMsForRuleset( + json: BeMusicJson, + ruleset: JudgeWindowRuleset, + debugBadWindowMs?: number, +): JudgeWindowsMs { + if (ruleset === 'iidx') { + return overrideBadWindow(IIDX_JUDGE_WINDOWS_MS, debugBadWindowMs); + } + if (ruleset === 'beatoraja') { + const scale = Math.max(0, resolveBeatorajaJudgeRankPercent(json)) / 100; + const windows: JudgeWindowsMs = { + pgreat: BEATORAJA_BASE_WINDOWS_MS.pgreat * scale, + great: BEATORAJA_BASE_WINDOWS_MS.great * scale, + good: BEATORAJA_BASE_WINDOWS_MS.good * scale, + bad: BEATORAJA_BASE_WINDOWS_MS.bad * scale, + }; + const result = overrideBadWindow(windows, debugBadWindowMs); + return { + pgreat: clampWindow(result.pgreat, result.bad), + great: clampWindow(result.great, result.bad), + good: clampWindow(result.good, result.bad), + bad: result.bad, + }; + } + return resolveJudgeWindowsMs(json, debugBadWindowMs); +} + +function overrideBadWindow(windows: JudgeWindowsMs, debugBadWindowMs?: number): JudgeWindowsMs { + if (typeof debugBadWindowMs === 'number' && Number.isFinite(debugBadWindowMs) && debugBadWindowMs > 0) { + return { ...windows, bad: debugBadWindowMs }; + } + return windows; +} + function scaleJudgeWindowsMs(judgeRankPercent: number, debugBadWindowMs?: number): JudgeWindowsMs { const bad = typeof debugBadWindowMs === 'number' && Number.isFinite(debugBadWindowMs) && debugBadWindowMs > 0 diff --git a/packages/player/src/index.test.ts b/packages/player/src/index.test.ts index 2b128c0d..a49177fa 100644 --- a/packages/player/src/index.test.ts +++ b/packages/player/src/index.test.ts @@ -95,7 +95,7 @@ import { } from './index.ts'; import type { PlayerInputCommand } from './core/input-signal-bus.ts'; import { resolveChartVolWavGain, resolveDisplayedJudgeRankLabel, resolveDisplayedJudgeRankValue } from './utils.ts'; -import { simulatePlaylog, type BeMusicPlaylog } from './playlog/index.ts'; +import { parsePlaylog, serializePlaylog, simulatePlaylog, type BeMusicPlaylog } from './playlog/index.ts'; const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); const unifiedBmsChartPath = resolve(rootDir, 'examples/test/four-measure-command-combo-test.bms'); @@ -1083,6 +1083,57 @@ describe('player', () => { ); }); + test('player: judgeRuleset switches the manual judge windows (LR2 / beatoraja / IIDX)', async () => { + // BPM 240 → one note at 1.0 s; the replayed press lands 35 ms LATE. Under the default (LR2, RANK 2 → GREAT + // ±40 ms) and beatoraja (judgerank 75 % → GREAT ±45 ms) windows that is a GREAT; under IIDX (GREAT ±33.33 ms, + // GOOD ±116.67 ms) it is a GOOD. + const json = createEmptyJson('bms'); + json.metadata.bpm = 240; + json.metadata.rank = 2; + json.events = [{ measure: 1, channel: '11', position: [0, 1], value: '01' }]; + const replayInputs = [{ seq: 0, timeUs: 1_035_000, action: 'down' as const, channels: ['11'] }]; + const base = { speed: 8, leadInMs: 0, audio: false, tui: false, replayInputs } as const; + + const lr2 = await manualPlay(json, { ...base }); + const beatoraja = await manualPlay(json, { ...base, judgeRuleset: 'beatoraja' }); + const iidx = await manualPlay(json, { ...base, judgeRuleset: 'iidx' }); + + expect(lr2.great).toBe(1); + expect(lr2.good).toBe(0); + expect(beatoraja.great).toBe(1); + expect(beatoraja.good).toBe(0); + expect(iidx.great).toBe(0); + expect(iidx.good).toBe(1); + }); + + test('player: recordPlaylog stamps the chart hash and judge ruleset into the playlog', async () => { + const json = createEmptyJson('bms'); + json.metadata.bpm = 240; + json.events = [{ measure: 1, channel: '11', position: [0, 1], value: '01' }]; + + let playlog: BeMusicPlaylog | undefined; + await manualPlay(json, { + speed: 8, + leadInMs: 0, + audio: false, + tui: false, + judgeRuleset: 'iidx', + recordPlaylog: { chartSha256: 'ABCDEF0123456789' }, + onPlaylogRecorded: (recorded) => { + playlog = recorded; + }, + createInputRuntime: createScheduledInputRuntime([ + { delayMs: 50, command: { kind: 'interrupt', reason: 'escape' } }, + ]), + }); + + expect(playlog!.chart.sha256).toBe('abcdef0123456789'); + expect(playlog!.play.judgeRuleset).toBe('iidx'); + const parsed = parsePlaylog(serializePlaylog(playlog!)); + expect(parsed.chart.sha256).toBe('abcdef0123456789'); + expect(parsed.play.judgeRuleset).toBe('iidx'); + }); + test('player: ESC-interrupted play records an aborted playlog', async () => { const json = createEmptyJson('bms'); json.metadata.bpm = 240; diff --git a/packages/player/src/playlog/format.ts b/packages/player/src/playlog/format.ts index a7d167e4..56faf921 100644 --- a/packages/player/src/playlog/format.ts +++ b/packages/player/src/playlog/format.ts @@ -72,6 +72,8 @@ export interface PlaylogChart { subtitle?: string; artist?: string; genre?: string; + /** Lowercase-hex SHA-256 of the source chart FILE bytes — the primary key for matching a log back to its chart. */ + sha256?: string; sourceFormat: 'bms' | 'bmson'; /** Engine lane display mode (`'7keys'` / `'14keys'` / ... — `resolveLaneDisplayMode` output). */ laneMode: string; @@ -95,6 +97,8 @@ export interface PlaylogPlay { dpFlip?: boolean; /** Debug BAD-window override (`PlayerOptions.judgeWindowMs`) — simulations of such plays are non-standard. */ judgeWindowOverrideMs?: number; + /** Judge-window ruleset the live engine ran (`PlayerOptions.judgeRuleset`). Absent = `'lr2'` (the default). */ + judgeRuleset?: 'lr2' | 'beatoraja' | 'iidx'; /** True when the play ended early (ESC). The input stream stops at the abort point. */ aborted?: boolean; /** Lossless bag for host-specific settings that don't affect simulation (hi-speed, skin, ...). */ @@ -261,6 +265,7 @@ function parseChart(chart: Record<string, unknown>): PlaylogChart { subtitle: optionalString(chart.subtitle, 'chart.subtitle'), artist: optionalString(chart.artist, 'chart.artist'), genre: optionalString(chart.genre, 'chart.genre'), + sha256: optionalString(chart.sha256, 'chart.sha256'), sourceFormat, laneMode: expectString(chart.laneMode, 'chart.laneMode'), total: optionalFiniteNumber(chart.total, 'chart.total'), @@ -269,7 +274,7 @@ function parseChart(chart: Record<string, unknown>): PlaylogChart { noteCount: expectFiniteNumber(chart.noteCount, 'chart.noteCount'), notes, }; - for (const key of ['title', 'subtitle', 'artist', 'genre', 'total'] as const) { + for (const key of ['title', 'subtitle', 'artist', 'genre', 'sha256', 'total'] as const) { if (parsed[key] === undefined) delete parsed[key]; } return parsed; @@ -373,6 +378,12 @@ function parsePlay(play: Record<string, unknown>): PlaylogPlay { if (play.dpFlip !== undefined) parsed.dpFlip = play.dpFlip === true; const judgeWindowOverrideMs = optionalFiniteNumber(play.judgeWindowOverrideMs, 'play.judgeWindowOverrideMs'); if (judgeWindowOverrideMs !== undefined) parsed.judgeWindowOverrideMs = judgeWindowOverrideMs; + if (play.judgeRuleset !== undefined) { + if (play.judgeRuleset !== 'lr2' && play.judgeRuleset !== 'beatoraja' && play.judgeRuleset !== 'iidx') { + throw new PlaylogParseError(`play.judgeRuleset: expected 'lr2' | 'beatoraja' | 'iidx'`); + } + parsed.judgeRuleset = play.judgeRuleset; + } if (play.aborted !== undefined) parsed.aborted = play.aborted === true; if (play.native !== undefined) { const native = expectRecord(play.native, 'play.native'); diff --git a/packages/player/src/playlog/recorder.ts b/packages/player/src/playlog/recorder.ts index 9706cc66..ce7e3411 100644 --- a/packages/player/src/playlog/recorder.ts +++ b/packages/player/src/playlog/recorder.ts @@ -37,19 +37,29 @@ export interface PlaylogRecorderPlaySettings { randomLane?: { p1?: string; p2?: string }; dpFlip?: boolean; judgeWindowOverrideMs?: number; + /** Judge-window ruleset the engine ran (`PlayerOptions.judgeRuleset`). Absent = `'lr2'`. */ + judgeRuleset?: 'lr2' | 'beatoraja' | 'iidx'; native?: Record<string, string | number | boolean | null>; } /** - * Host-declared subset of the play settings — the fields the engine cannot know by itself. Passed through - * `PlayerOptions.recordPlaylog`. + * Host-declared subset of the recording inputs — the fields the engine cannot know by itself. Passed through + * `PlayerOptions.recordPlaylog`. `chartSha256` is the SHA-256 (lowercase hex) of the source chart FILE bytes; + * hosts that have the raw file compute it so dropped logs can be matched back to their chart by content. */ -export type PlaylogRecordingOptions = Pick<PlaylogRecorderPlaySettings, 'gauge' | 'randomLane' | 'dpFlip' | 'native'>; +export type PlaylogRecordingOptions = Pick< + PlaylogRecorderPlaySettings, + 'gauge' | 'randomLane' | 'dpFlip' | 'native' +> & { + chartSha256?: string; +}; export interface PlaylogRecorderOptions { /** Resolved chart JSON (post `#RANDOM` control flow) — metadata source. */ json: BeMusicJson; chart: PlaylogRecorderChartData; + /** SHA-256 (lowercase hex) of the source chart file bytes, when the host computed one. */ + chartSha256?: string; play: PlaylogRecorderPlaySettings; /** Dynamic `#EXRANKxx` changes the engine collected (chart order). */ dynamicJudgeRankChanges?: ReadonlyArray<{ seconds: number; exRankValue: number }>; @@ -112,6 +122,7 @@ export function createPlaylogRecorder(options: PlaylogRecorderOptions): PlaylogR if (options.play.judgeWindowOverrideMs !== undefined) { play.judgeWindowOverrideMs = options.play.judgeWindowOverrideMs; } + if (options.play.judgeRuleset !== undefined) play.judgeRuleset = options.play.judgeRuleset; if (aborted === true) play.aborted = true; if (options.play.native !== undefined) play.native = options.play.native; @@ -205,6 +216,9 @@ function buildPlaylogChart(options: PlaylogRecorderOptions): PlaylogChart { noteCount: chart.scorableNotes.length, notes, }; + if (typeof options.chartSha256 === 'string' && options.chartSha256.length > 0) { + result.sha256 = options.chartSha256.toLowerCase(); + } if (typeof json.metadata.title === 'string' && json.metadata.title.length > 0) result.title = json.metadata.title; if (typeof json.metadata.subtitle === 'string' && json.metadata.subtitle.length > 0) { result.subtitle = json.metadata.subtitle; From e81baa9066b027da99f67317e45b6ebaa3d56b07 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 01:39:27 +0900 Subject: [PATCH 33/39] chore(deps-dev): move to TypeScript 7.0.2 stable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the root devDependency off the 7.0.1 release candidate onto the stable 7.0.2 release and drops the pnpm peerDependencyRules exception it needed: the RC was a prerelease, so it never satisfied the tsdown / rolldown-plugin-dts `~7.0.0` peer ranges without an explicit allowance, while 7.0.2 matches them directly. Also refreshes the stale `@typescript/native-preview` example in the changeset rules — that package was replaced by `typescript` 7 in 2b10f2a. --- AGENTS.md | 2 +- package.json | 9 +-- pnpm-lock.yaml | 182 ++++++++++++++++++++++++------------------------- 3 files changed, 94 insertions(+), 99 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index eac0a4ff..8dffaa51 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,7 +18,7 @@ - One changeset per package. Putting several packages in a single markdown makes Changesets duplicate the same note into every package's CHANGELOG. For a commit that spans multiple packages, split it into one changeset per package and write each note from that package's own perspective. - Only write entries that are worth landing in a CHANGELOG: - Include: `fix` / `feat` / `perf`, and bumps of public (runtime `dependencies`) packages (e.g. `fflate`, `node-web-audio-api`). - - Exclude: `devDependencies` dependabot bumps (e.g. `typescript`, `oxlint`, `wrangler`, `@typescript/native-preview`), tooling-only config changes that do not affect consumers (tsconfig paths, build scripts, bench cases), and WIP / in-progress features. + - Exclude: `devDependencies` dependabot bumps (e.g. `typescript`, `oxlint`, `wrangler`, `tsdown`), tooling-only config changes that do not affect consumers (tsconfig paths, build scripts, bench cases), and WIP / in-progress features. - Bump level: new export / new subpath / new public API → `minor`; bug fix / internal refactor / dependency bump → `patch`. - Writing style: - Keep each body paragraph on a single unwrapped line. diff --git a/package.json b/package.json index 4ea3b846..43aaa0d4 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "tinybench": "^6.1.3", "tsdown": "^0.22.14", "tsx": "^4.23.12", - "typescript": "7.0.1-rc", + "typescript": "^7.0.2", "vite": "^8.1.3", "vitest": "^4.1.10" }, @@ -53,11 +53,6 @@ "pnpm": { "onlyBuiltDependencies": [ "esbuild" - ], - "peerDependencyRules": { - "allowedVersions": { - "typescript": "7.0.1-rc" - } - } + ] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80b78ae5..099c857a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,13 +31,13 @@ importers: version: 6.1.3 tsdown: specifier: ^0.22.14 - version: 0.22.14(tsx@4.23.12)(typescript@7.0.1-rc)(unrun@0.2.37) + version: 0.22.14(tsx@4.23.12)(typescript@7.0.2)(unrun@0.2.37) tsx: specifier: ^4.23.12 version: 4.23.12 typescript: - specifier: 7.0.1-rc - version: 7.0.1-rc + specifier: ^7.0.2 + version: 7.0.2 vite: specifier: ^8.1.3 version: 8.1.3(@types/node@26.2.0)(esbuild@0.28.1)(tsx@4.23.12) @@ -1588,122 +1588,122 @@ packages: '@types/wicg-file-system-access@2020.9.8': resolution: {integrity: sha512-ggMz8nOygG7d/stpH40WVaNvBwuyYLnrg5Mbyf6bmsj/8+gb6Ei4ZZ9/4PNpcPNTT8th9Q8sM8wYmWGjMWLX/A==} - '@typescript/typescript-aix-ppc64@7.0.1-rc': - resolution: {integrity: sha512-oqq2ZfEJ7BQuufcC3QBQndZLPNyamYNHLao8lKRBeeSkZKypBqxPSgkzrcFZtbYcIaBvpiyUnQP9MT7DEYHWbw==} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} engines: {node: '>=16.20.0'} cpu: [ppc64] os: [aix] - '@typescript/typescript-darwin-arm64@7.0.1-rc': - resolution: {integrity: sha512-Slc0yTftT2F/uGDmtPst8ijydneL6uZaLEyr2UjahxZpbhTjHFBJ5agXtVz/TL4A+ldxzjzj+E8QtLZlh/5mXw==} + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [darwin] - '@typescript/typescript-darwin-x64@7.0.1-rc': - resolution: {integrity: sha512-h68iFW/LbA1/BsGgSRGFw981/3s1f/rY27YrmeZNuN+ly7dI+fiDduwT9ZT9866x2onoKNRq7PTyxSKyKDzfAQ==} + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} engines: {node: '>=16.20.0'} cpu: [x64] os: [darwin] - '@typescript/typescript-freebsd-arm64@7.0.1-rc': - resolution: {integrity: sha512-DE+ppd8Ix2c6OMuRkKY4PJ4hngMGJ9M95OQUP17p9xL/1IKXof7npIeuusMN/bgL5o5JzMfSGh+N+5scTYRg0Q==} + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [freebsd] - '@typescript/typescript-freebsd-x64@7.0.1-rc': - resolution: {integrity: sha512-ST1ozHMw0u+CLOnWkcTyWDMV4Qn9osZ6fd1V1lnKDM1t0hZIp81mdGpdHxyHJjd7jdGrb6Gb/QXcZ1uqZ0t5zw==} + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} engines: {node: '>=16.20.0'} cpu: [x64] os: [freebsd] - '@typescript/typescript-linux-arm64@7.0.1-rc': - resolution: {integrity: sha512-N46pRihK3t5zD5MUtTQcdmQUqr1WI4U2nxno1gLwOtRSsB4krFkRjPHcQNG7h2DtRkX64rQiReX6WKwg2wprMA==} + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [linux] - '@typescript/typescript-linux-arm@7.0.1-rc': - resolution: {integrity: sha512-gHmHwT5Naq5CKM8g9bbaGeEpnwQEvWCLn3fwP4K2m61VQdDKkPk0Dhab/OoZ4LV2SrMddmclYXTzpyg23YGt5g==} + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} engines: {node: '>=16.20.0'} cpu: [arm] os: [linux] - '@typescript/typescript-linux-loong64@7.0.1-rc': - resolution: {integrity: sha512-G17Sao312rgiPBTh2F4nOpLpa3CcnBSaNhqNghZk2LNhnsp1RaMO5HMq2me21gqu9xLpc6CIgHtOzU6JBgNlfg==} + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} engines: {node: '>=16.20.0'} cpu: [loong64] os: [linux] - '@typescript/typescript-linux-mips64el@7.0.1-rc': - resolution: {integrity: sha512-0FQspOb5UsQ4tQKvWgUO3pS9OIWkP7/8dPRWq+CRazJUeQZ4LBjtYK52jg5iIOrvItrVl2CwvRtrU3/9OihwJg==} + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} engines: {node: '>=16.20.0'} cpu: [mips64el] os: [linux] - '@typescript/typescript-linux-ppc64@7.0.1-rc': - resolution: {integrity: sha512-SUmwfVBEv6A2Ld0eWfcvW0FqrgemfQL8jFGOmV1qYxsDqumjE5DekHXqbstgmbE4SHr4rrjHjvmuGCY+kTH/vw==} + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} engines: {node: '>=16.20.0'} cpu: [ppc64] os: [linux] - '@typescript/typescript-linux-riscv64@7.0.1-rc': - resolution: {integrity: sha512-rxeqnNnGiYzv/LlPHi/3+4p0ooR1cNJLjRIHXKovtiVmxXGJq6gtw8VSpbHuWPekyFMXgIAoLCZN0SQ51rAALQ==} + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} engines: {node: '>=16.20.0'} cpu: [riscv64] os: [linux] - '@typescript/typescript-linux-s390x@7.0.1-rc': - resolution: {integrity: sha512-RYWCHCiPypxajdRHM2CNK/eM22e4Ex5TTjV2pXf7PTtBowGr0xX8i8kIMknyZS0LX2QfleYHouaoMVsFDSle3g==} + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} engines: {node: '>=16.20.0'} cpu: [s390x] os: [linux] - '@typescript/typescript-linux-x64@7.0.1-rc': - resolution: {integrity: sha512-PfLJSu0JzroDkqw2m4nqflPEcn8yev0m/vHFQlY9EzHorzjR6QG0wL8AJHvnD1e6h1s76AZngJ5u+z1K/D/HKw==} + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} engines: {node: '>=16.20.0'} cpu: [x64] os: [linux] - '@typescript/typescript-netbsd-arm64@7.0.1-rc': - resolution: {integrity: sha512-FfbPxH3dTfp8yVIaNM7bdWTixXuyxpzoemluqcqMROSIz+ImpCG3Q9HO9Ptzp9/giv+P9YYEnCMSXh61migj2w==} + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [netbsd] - '@typescript/typescript-netbsd-x64@7.0.1-rc': - resolution: {integrity: sha512-FzdTfSzhRYb6hlav6K3cI5RVgcvCTvNAu/vc+t7B6AmZkThQ+t/1ntnvT5fnHmY1Az2RIBw7/b+qtCEG61HJTQ==} + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} engines: {node: '>=16.20.0'} cpu: [x64] os: [netbsd] - '@typescript/typescript-openbsd-arm64@7.0.1-rc': - resolution: {integrity: sha512-PQGhlxfNig+0YQ9Wwzd0USPBkt6w/ZqkBQWsU7G/0JkTzunJel+jSWwhKw4947pak/m7hGSeYiI04xReDLGZww==} + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [openbsd] - '@typescript/typescript-openbsd-x64@7.0.1-rc': - resolution: {integrity: sha512-WJ7NYgO2mHmLUkI/tZ+hl8lFd26QPJqO8ONOHNuYbdsybLvSB6B6sep222JIVrOfPRDGvFinbGGB+l3m1FWRWA==} + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} engines: {node: '>=16.20.0'} cpu: [x64] os: [openbsd] - '@typescript/typescript-sunos-x64@7.0.1-rc': - resolution: {integrity: sha512-UYjDeUxd765V9qcwlUPk4pEXyL0i3G76CJm9baK4i99u1pGO1psf3nXDw4MMmElVOPvGbZag99ZR/O59E2OX6w==} + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} engines: {node: '>=16.20.0'} cpu: [x64] os: [sunos] - '@typescript/typescript-win32-arm64@7.0.1-rc': - resolution: {integrity: sha512-KzXzFSXZOm7zvEt2Aw0MsB2LbTL88znAiVqTDNAOHdlEb7brgmUQh/X2wM/8Be+N0fjEqWKl65cBKNwpWEbJiw==} + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} engines: {node: '>=16.20.0'} cpu: [arm64] os: [win32] - '@typescript/typescript-win32-x64@7.0.1-rc': - resolution: {integrity: sha512-98R3+OqDr/r0/PLWEoXu88AE0lGVLNd335Ew8ONgzK1JWkNs4ou/5BGt3Or1ij4iXjH+c7PRL+jFjCbtWze+EA==} + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} engines: {node: '>=16.20.0'} cpu: [x64] os: [win32] @@ -3244,8 +3244,8 @@ packages: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} - typescript@7.0.1-rc: - resolution: {integrity: sha512-drEP77wK7CCDlPfXZH4e008UUQOsw1DFmHmZOZjuNA+yoDLLnSNMZRXi90NbV/1LVo7SbNLq1bs3jjvk49TEqQ==} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} engines: {node: '>=16.20.0'} hasBin: true @@ -4344,64 +4344,64 @@ snapshots: '@types/wicg-file-system-access@2020.9.8': {} - '@typescript/typescript-aix-ppc64@7.0.1-rc': + '@typescript/typescript-aix-ppc64@7.0.2': optional: true - '@typescript/typescript-darwin-arm64@7.0.1-rc': + '@typescript/typescript-darwin-arm64@7.0.2': optional: true - '@typescript/typescript-darwin-x64@7.0.1-rc': + '@typescript/typescript-darwin-x64@7.0.2': optional: true - '@typescript/typescript-freebsd-arm64@7.0.1-rc': + '@typescript/typescript-freebsd-arm64@7.0.2': optional: true - '@typescript/typescript-freebsd-x64@7.0.1-rc': + '@typescript/typescript-freebsd-x64@7.0.2': optional: true - '@typescript/typescript-linux-arm64@7.0.1-rc': + '@typescript/typescript-linux-arm64@7.0.2': optional: true - '@typescript/typescript-linux-arm@7.0.1-rc': + '@typescript/typescript-linux-arm@7.0.2': optional: true - '@typescript/typescript-linux-loong64@7.0.1-rc': + '@typescript/typescript-linux-loong64@7.0.2': optional: true - '@typescript/typescript-linux-mips64el@7.0.1-rc': + '@typescript/typescript-linux-mips64el@7.0.2': optional: true - '@typescript/typescript-linux-ppc64@7.0.1-rc': + '@typescript/typescript-linux-ppc64@7.0.2': optional: true - '@typescript/typescript-linux-riscv64@7.0.1-rc': + '@typescript/typescript-linux-riscv64@7.0.2': optional: true - '@typescript/typescript-linux-s390x@7.0.1-rc': + '@typescript/typescript-linux-s390x@7.0.2': optional: true - '@typescript/typescript-linux-x64@7.0.1-rc': + '@typescript/typescript-linux-x64@7.0.2': optional: true - '@typescript/typescript-netbsd-arm64@7.0.1-rc': + '@typescript/typescript-netbsd-arm64@7.0.2': optional: true - '@typescript/typescript-netbsd-x64@7.0.1-rc': + '@typescript/typescript-netbsd-x64@7.0.2': optional: true - '@typescript/typescript-openbsd-arm64@7.0.1-rc': + '@typescript/typescript-openbsd-arm64@7.0.2': optional: true - '@typescript/typescript-openbsd-x64@7.0.1-rc': + '@typescript/typescript-openbsd-x64@7.0.2': optional: true - '@typescript/typescript-sunos-x64@7.0.1-rc': + '@typescript/typescript-sunos-x64@7.0.2': optional: true - '@typescript/typescript-win32-arm64@7.0.1-rc': + '@typescript/typescript-win32-arm64@7.0.2': optional: true - '@typescript/typescript-win32-x64@7.0.1-rc': + '@typescript/typescript-win32-x64@7.0.2': optional: true '@uwx/libav.js-fat@6.0.0-nightly.29.f420ff.ffmpeg.6.1.1': {} @@ -5686,7 +5686,7 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rolldown-plugin-dts@0.27.14(rolldown@1.2.4)(typescript@7.0.1-rc): + rolldown-plugin-dts@0.27.14(rolldown@1.2.4)(typescript@7.0.2): dependencies: dts-resolver: 3.0.0 get-tsconfig: 5.0.0-beta.5 @@ -5696,7 +5696,7 @@ snapshots: yuku-codegen: 0.8.7 yuku-parser: 0.8.7 optionalDependencies: - typescript: 7.0.1-rc + typescript: 7.0.2 transitivePeerDependencies: - oxc-resolver @@ -6012,7 +6012,7 @@ snapshots: transitivePeerDependencies: - supports-color - tsdown@0.22.14(tsx@4.23.12)(typescript@7.0.1-rc)(unrun@0.2.37): + tsdown@0.22.14(tsx@4.23.12)(typescript@7.0.2)(unrun@0.2.37): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -6023,7 +6023,7 @@ snapshots: obug: 2.1.4 picomatch: 4.0.5 rolldown: 1.2.4 - rolldown-plugin-dts: 0.27.14(rolldown@1.2.4)(typescript@7.0.1-rc) + rolldown-plugin-dts: 0.27.14(rolldown@1.2.4)(typescript@7.0.2) tinyexec: 1.2.4 tinyglobby: 0.2.17 tree-kill: 1.2.2 @@ -6031,7 +6031,7 @@ snapshots: verkit: 0.3.2 optionalDependencies: tsx: 4.23.12 - typescript: 7.0.1-rc + typescript: 7.0.2 unrun: 0.2.37 transitivePeerDependencies: - '@typescript/native-preview' @@ -6056,28 +6056,28 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.15 - typescript@7.0.1-rc: + typescript@7.0.2: optionalDependencies: - '@typescript/typescript-aix-ppc64': 7.0.1-rc - '@typescript/typescript-darwin-arm64': 7.0.1-rc - '@typescript/typescript-darwin-x64': 7.0.1-rc - '@typescript/typescript-freebsd-arm64': 7.0.1-rc - '@typescript/typescript-freebsd-x64': 7.0.1-rc - '@typescript/typescript-linux-arm': 7.0.1-rc - '@typescript/typescript-linux-arm64': 7.0.1-rc - '@typescript/typescript-linux-loong64': 7.0.1-rc - '@typescript/typescript-linux-mips64el': 7.0.1-rc - '@typescript/typescript-linux-ppc64': 7.0.1-rc - '@typescript/typescript-linux-riscv64': 7.0.1-rc - '@typescript/typescript-linux-s390x': 7.0.1-rc - '@typescript/typescript-linux-x64': 7.0.1-rc - '@typescript/typescript-netbsd-arm64': 7.0.1-rc - '@typescript/typescript-netbsd-x64': 7.0.1-rc - '@typescript/typescript-openbsd-arm64': 7.0.1-rc - '@typescript/typescript-openbsd-x64': 7.0.1-rc - '@typescript/typescript-sunos-x64': 7.0.1-rc - '@typescript/typescript-win32-arm64': 7.0.1-rc - '@typescript/typescript-win32-x64': 7.0.1-rc + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 unconfig-core@7.5.0: dependencies: From 575f65794eff8a0e02bba062a9782d3e3eeadbd1 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 01:47:59 +0900 Subject: [PATCH 34/39] chore: version packages --- .changeset/playlog-player-tui.md | 5 ----- .changeset/playlog-player-web.md | 7 ------- .changeset/playlog-player.md | 7 ------- packages/lr2-skin/CHANGELOG.md | 6 ++++++ packages/lr2-skin/package.json | 2 +- packages/player-tui/CHANGELOG.md | 12 ++++++++++++ packages/player-tui/package.json | 2 +- packages/player-web-demo/CHANGELOG.md | 10 ++++++++++ packages/player-web-demo/package.json | 2 +- packages/player-web/CHANGELOG.md | 17 +++++++++++++++++ packages/player-web/package.json | 2 +- packages/player/CHANGELOG.md | 12 ++++++++++++ packages/player/package.json | 2 +- 13 files changed, 62 insertions(+), 24 deletions(-) delete mode 100644 .changeset/playlog-player-tui.md delete mode 100644 .changeset/playlog-player-web.md delete mode 100644 .changeset/playlog-player.md diff --git a/.changeset/playlog-player-tui.md b/.changeset/playlog-player-tui.md deleted file mode 100644 index 20e98359..00000000 --- a/.changeset/playlog-player-tui.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@be-music/player-tui': minor ---- - -Add the `bms-playlog` CLI: reads recorded play-log files (`*.bmplay.json`) and re-derives LR2 / beatoraja / IIDX judgments, EX-SCORE, DJ LEVEL, max combo, money score, and groove gauge from the raw input replay, printing a per-ruleset comparison table (or `--json`). diff --git a/.changeset/playlog-player-web.md b/.changeset/playlog-player-web.md deleted file mode 100644 index 6b8fe102..00000000 --- a/.changeset/playlog-player-web.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@be-music/player-web': minor ---- - -Record a play log (`*.bmplay.json` input replay) for every gameplay run: the LR2/default gameplay scene exposes it through `PixiGameplayResultData.playlog`, the beatoraja scene through `PixiBeatorajaGameplayView.getPlaylog()`, and the `@be-music/player-web/runtime` subpath re-exports the playlog serializer helpers (`serializePlaylog`, `parsePlaylog`, `resolvePlaylogFilename`) for hosts. - -The LR2/default gameplay scene also plays a recorded log back: `PixiGameplayViewOptions.replay` re-applies the log's resolved note arrangement onto the freshly prepared chart (`applyPlaylogArrangement` — RANDOM / MIRROR arrangements replay without re-rolling) and feeds the recorded inputs through the engine's deterministic replay path, restoring the log's judge-window ruleset. The `@be-music/player-web/collection` subpath adds `computeChartFileSha256` / `computeSha256Hex` for stamping and matching the playlog's chart-file hash, and both gameplay scenes accept the host-computed hash and judge ruleset for recording. diff --git a/.changeset/playlog-player.md b/.changeset/playlog-player.md deleted file mode 100644 index 40639566..00000000 --- a/.changeset/playlog-player.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@be-music/player': minor ---- - -Add the `@be-music/player/playlog` subpath: a play-history ("playlog") format that records the resolved chart, the raw key press/release stream, and the play settings as an input replay, plus LR2 / beatoraja / IIDX ruleset simulators (`simulatePlaylog`) that re-derive judgments, EX-SCORE, max combo, money score, and groove gauge from the same recorded inputs. - -New `PlayerOptions.onPlaylogRecorded` / `PlayerOptions.recordPlaylog` enable engine-side recording for both `manualPlay` and `autoPlay` (including ESC-aborted runs), and `PlayerOptions.replayInputs` re-drives a recorded input stream deterministically for replay playback (live lane input is ignored while a replay is active). `PlayerOptions.judgeRuleset` switches the live judge windows between LR2 (default), beatoraja, and IIDX — recorded as `play.judgeRuleset` so replays re-apply the same windows — and the playlog stamps the source chart file's SHA-256 (`chart.sha256`) when the host supplies one. `ScoreTracker` now latches `maxCombo`, `resolveJudgeRankPercent` exposes the chart's initial judgerank percent, and the landmine gauge-damage rule moved to the shared `core/landmine.ts` helper. diff --git a/packages/lr2-skin/CHANGELOG.md b/packages/lr2-skin/CHANGELOG.md index 7969d781..7cfa66a4 100644 --- a/packages/lr2-skin/CHANGELOG.md +++ b/packages/lr2-skin/CHANGELOG.md @@ -1,5 +1,11 @@ # @be-music/lr2-skin +## 0.1.5 + +### Patch Changes + +- Emit declaration-compatible types for the public `LR2_PLAY_VARIANTS` and path-table constants so consumers building under `isolatedDeclarations` no longer fail on the inferred `as const satisfies ...` types. + ## 0.1.4 ### Patch Changes diff --git a/packages/lr2-skin/package.json b/packages/lr2-skin/package.json index a069b3c6..5c34159a 100644 --- a/packages/lr2-skin/package.json +++ b/packages/lr2-skin/package.json @@ -1,6 +1,6 @@ { "name": "@be-music/lr2-skin", - "version": "0.1.4", + "version": "0.1.5", "description": "Renderer-independent Lunatic Rave 2 skin parser and theme loader for be-music", "license": "MIT", "files": [ diff --git a/packages/player-tui/CHANGELOG.md b/packages/player-tui/CHANGELOG.md index 2aa9755d..a6cdf4e1 100644 --- a/packages/player-tui/CHANGELOG.md +++ b/packages/player-tui/CHANGELOG.md @@ -1,5 +1,17 @@ # @be-music/player +## 0.4.0 + +### Minor Changes + +- ab210cb: Add the `bms-playlog` CLI: reads recorded play-log files (`*.bmplay.json`) and re-derives LR2 / beatoraja / IIDX judgments, EX-SCORE, DJ LEVEL, max combo, money score, and groove gauge from the raw input replay, printing a per-ruleset comparison table (or `--json`). + +### Patch Changes + +- Updated dependencies +- Updated dependencies [ab210cb] + - @be-music/player@0.6.0 + ## 0.3.0 ### Minor Changes diff --git a/packages/player-tui/package.json b/packages/player-tui/package.json index 4e4961f9..0a4c679f 100644 --- a/packages/player-tui/package.json +++ b/packages/player-tui/package.json @@ -1,6 +1,6 @@ { "name": "@be-music/player-tui", - "version": "0.3.0", + "version": "0.4.0", "description": "Terminal UI and CLI frontend for the be-music player", "license": "MIT", "bin": { diff --git a/packages/player-web-demo/CHANGELOG.md b/packages/player-web-demo/CHANGELOG.md index aa56b6c3..325c5fa9 100644 --- a/packages/player-web-demo/CHANGELOG.md +++ b/packages/player-web-demo/CHANGELOG.md @@ -1,5 +1,15 @@ # @be-music/player-web-demo +## 0.3.2 + +### Patch Changes + +- Updated dependencies +- Updated dependencies +- Updated dependencies [ab210cb] + - @be-music/lr2-skin@0.1.5 + - @be-music/player-web@0.7.0 + ## 0.3.1 ### Patch Changes diff --git a/packages/player-web-demo/package.json b/packages/player-web-demo/package.json index 2692076a..da121777 100644 --- a/packages/player-web-demo/package.json +++ b/packages/player-web-demo/package.json @@ -1,6 +1,6 @@ { "name": "@be-music/player-web-demo", - "version": "0.3.1", + "version": "0.3.2", "private": true, "type": "module", "scripts": { diff --git a/packages/player-web/CHANGELOG.md b/packages/player-web/CHANGELOG.md index faffaf68..cfc7fb89 100644 --- a/packages/player-web/CHANGELOG.md +++ b/packages/player-web/CHANGELOG.md @@ -1,5 +1,22 @@ # @be-music/player-web +## 0.7.0 + +### Minor Changes + +- ab210cb: Record a play log (`*.bmplay.json` input replay) for every gameplay run: the LR2/default gameplay scene exposes it through `PixiGameplayResultData.playlog`, the beatoraja scene through `PixiBeatorajaGameplayView.getPlaylog()`, and the `@be-music/player-web/runtime` subpath re-exports the playlog serializer helpers (`serializePlaylog`, `parsePlaylog`, `resolvePlaylogFilename`) for hosts. + + The LR2/default gameplay scene also plays a recorded log back: `PixiGameplayViewOptions.replay` re-applies the log's resolved note arrangement onto the freshly prepared chart (`applyPlaylogArrangement` — RANDOM / MIRROR arrangements replay without re-rolling) and feeds the recorded inputs through the engine's deterministic replay path, restoring the log's judge-window ruleset. The `@be-music/player-web/collection` subpath adds `computeChartFileSha256` / `computeSha256Hex` for stamping and matching the playlog's chart-file hash, and both gameplay scenes accept the host-computed hash and judge ruleset for recording. + +### Patch Changes + +- Emit declaration-compatible types for the beatoraja theme's playable-variant constant so consumers building under `isolatedDeclarations` no longer fail on the inferred `as const satisfies ...` type. +- Updated dependencies +- Updated dependencies +- Updated dependencies [ab210cb] + - @be-music/lr2-skin@0.1.5 + - @be-music/player@0.6.0 + ## 0.6.2 ### Patch Changes diff --git a/packages/player-web/package.json b/packages/player-web/package.json index 192060a9..0c0c6aca 100644 --- a/packages/player-web/package.json +++ b/packages/player-web/package.json @@ -1,6 +1,6 @@ { "name": "@be-music/player-web", - "version": "0.6.2", + "version": "0.7.0", "description": "Vanilla browser PixiJS core for be-music song selection and gameplay", "license": "MIT", "files": [ diff --git a/packages/player/CHANGELOG.md b/packages/player/CHANGELOG.md index fd300190..c5b8a354 100644 --- a/packages/player/CHANGELOG.md +++ b/packages/player/CHANGELOG.md @@ -1,5 +1,17 @@ # @be-music/player +## 0.6.0 + +### Minor Changes + +- ab210cb: Add the `@be-music/player/playlog` subpath: a play-history ("playlog") format that records the resolved chart, the raw key press/release stream, and the play settings as an input replay, plus LR2 / beatoraja / IIDX ruleset simulators (`simulatePlaylog`) that re-derive judgments, EX-SCORE, max combo, money score, and groove gauge from the same recorded inputs. + + New `PlayerOptions.onPlaylogRecorded` / `PlayerOptions.recordPlaylog` enable engine-side recording for both `manualPlay` and `autoPlay` (including ESC-aborted runs), and `PlayerOptions.replayInputs` re-drives a recorded input stream deterministically for replay playback (live lane input is ignored while a replay is active). `PlayerOptions.judgeRuleset` switches the live judge windows between LR2 (default), beatoraja, and IIDX — recorded as `play.judgeRuleset` so replays re-apply the same windows — and the playlog stamps the source chart file's SHA-256 (`chart.sha256`) when the host supplies one. `ScoreTracker` now latches `maxCombo`, `resolveJudgeRankPercent` exposes the chart's initial judgerank percent, and the landmine gauge-damage rule moved to the shared `core/landmine.ts` helper. + +### Patch Changes + +- Bump the `node-web-audio-api` runtime dependency from `2.0.0` to `2.2.0`. + ## 0.5.0 ### Minor Changes diff --git a/packages/player/package.json b/packages/player/package.json index 38efa863..aad9cdd6 100644 --- a/packages/player/package.json +++ b/packages/player/package.json @@ -1,6 +1,6 @@ { "name": "@be-music/player", - "version": "0.5.0", + "version": "0.6.0", "description": "Core playback engine and shared gameplay helpers for be-music", "license": "MIT", "files": [ From 92e2c1aa13196d126f00a25150631fd0bf1269a3 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 01:52:26 +0900 Subject: [PATCH 35/39] fix(ci): register benchmark cases for the new player-web playlog exports The exports benchmark validates that every exported function has a case, so the playlog serializer re-exports (serializePlaylog / parsePlaylog / resolvePlaylogFilename) and the chart-hash helpers (computeChartFileSha256 / computeSha256Hex) added in ab210cb and e96d7fa failed the CI benchmark job with "Missing benchmark cases". --- packages/player-web/scripts/exports-cases.ts | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/player-web/scripts/exports-cases.ts b/packages/player-web/scripts/exports-cases.ts index 00e5e05a..7ddb41e4 100644 --- a/packages/player-web/scripts/exports-cases.ts +++ b/packages/player-web/scripts/exports-cases.ts @@ -18,6 +18,8 @@ const BENCH_APPEND_BMS_FILE = makeBenchFile('Songs/BenchExtra/main.bms', '#TITLE const BENCH_WAV_FILE = makeBenchFile('Songs/Bench/kick.wav', 'RIFF'); const BENCH_SOURCE = makeBenchSource(); const BENCH_SONG = makeBenchSong(); +const BENCH_PLAYLOG = makeBenchPlaylog(); +const BENCH_PLAYLOG_JSON = JSON.stringify(BENCH_PLAYLOG); const BENCH_PMS_SONG = makeBenchPmsSong(); const BENCH_COLLECTION = { sources: [BENCH_SOURCE], @@ -225,6 +227,16 @@ export function registerPlayerWebCoreExportsCases(define: DefineBenchmarkCase): playerWebCoreApi.computeResultOps(makeResultData(), makeLr2Skin()); }, }); + define('player-web.computeChartFileSha256', { + run: async () => { + await playerWebCoreApi.computeChartFileSha256(BENCH_SOURCE, 'Songs/Bench/main.bms'); + }, + }); + define('player-web.computeSha256Hex', { + run: async () => { + await playerWebCoreApi.computeSha256Hex(BENCH_BYTES); + }, + }); define('player-web.createSkinFamilyRegistry', { run: () => { const registry = playerWebCoreApi.createSkinFamilyRegistry([ @@ -423,6 +435,21 @@ export function registerPlayerWebCoreExportsCases(define: DefineBenchmarkCase): playerWebCoreApi.parseCompressorMode('split'); }, }); + define('player-web.parsePlaylog', { + run: () => { + playerWebCoreApi.parsePlaylog(BENCH_PLAYLOG_JSON); + }, + }); + define('player-web.resolvePlaylogFilename', { + run: () => { + playerWebCoreApi.resolvePlaylogFilename(BENCH_PLAYLOG); + }, + }); + define('player-web.serializePlaylog', { + run: () => { + playerWebCoreApi.serializePlaylog(BENCH_PLAYLOG); + }, + }); define('player-web.pickRecorderMimeType', { run: () => { playerWebCoreApi.pickRecorderMimeType((type) => type === 'video/webm'); @@ -690,6 +717,37 @@ function makeBenchSong(): playerWebCoreApi.BrowserSongEntry { }; } +function makeBenchPlaylog(): playerWebCoreApi.BeMusicPlaylog { + return { + format: 'be-music-playlog', + version: 1, + createdAt: '2026-01-01T00:00:00.000Z', + clock: { unit: 'us', origin: 'chart-zero' }, + chart: { + title: 'Bench Song', + sourceFormat: 'bms', + laneMode: '7keys', + total: 300, + lnMode: 1, + judgeRank: { percent: 75, sourceRank: 2 }, + noteCount: 32, + notes: Array.from({ length: 32 }, (_, index) => ({ + id: index, + channel: `1${(index % 7) + 1}`, + type: 'normal' as const, + timeUs: 250_000 * (index + 1), + })), + }, + inputs: Array.from({ length: 64 }, (_, index) => ({ + seq: index, + timeUs: 125_000 * (index + 1), + action: index % 2 === 0 ? ('down' as const) : ('up' as const), + channels: [`1${((index >> 1) % 7) + 1}`], + })), + play: { mode: 'manual', autoScratch: false, gauge: 'GROOVE' }, + }; +} + function makeBenchPmsSong(): playerWebCoreApi.BrowserSongEntry { const chart: BeMusicJson = createEmptyJson('bms'); chart.metadata.title = 'Bench PMS Song'; From fd01a56a8034758643db4111e2a9637521e60094 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 01:57:22 +0900 Subject: [PATCH 36/39] fix(ci): map the @be-music/player/playlog subpath in the typecheck tsconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typecheck and the exports benchmark both run against sources without a prior build, resolving cross-package subpaths through tsconfig.typecheck.json's `paths`. The playlog subpath added in ab210cb had no mapping, so both jobs fell back to the package's `exports` `types` / `default` entries and failed on the missing `packages/player/dist/playlog.*` — locally they passed only because a previous build had populated dist. Verified with dist removed: `pnpm typecheck` and `pnpm run bench` both pass. --- tsconfig.typecheck.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.typecheck.json b/tsconfig.typecheck.json index 4fd87fcc..a28e5105 100644 --- a/tsconfig.typecheck.json +++ b/tsconfig.typecheck.json @@ -12,6 +12,7 @@ "@be-music/player/audio-sink": ["./packages/player/src/audio-sink.ts"], "@be-music/player/image-resize-algorithm": ["./packages/player/src/image-resize-algorithm.ts"], "@be-music/player/judging": ["./packages/player/src/judging.ts"], + "@be-music/player/playlog": ["./packages/player/src/playlog/index.ts"], "@be-music/player/state-signals": ["./packages/player/src/state-signals.ts"], "@be-music/player/utils": ["./packages/player/src/utils.ts"], "@be-music/player/core/*": ["./packages/player/src/core/*.ts"], From 5cec87c682c064adaf234be8d2aff91bc3efea0d Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 02:04:31 +0900 Subject: [PATCH 37/39] fix(ci): pass benchmark snapshots through the environment, not argv The benchmark compare jobs restored their base64 snapshots by handing them to `node -e` as a command-line argument. Linux caps a single argv entry at `MAX_ARG_STRLEN` (128 KiB), and the snapshot crossed that once the benchmarked export count grew (133,928 base64 bytes at fd01a56), so every compare job died with `node: Argument list too long` and exit 126. macOS has no per-argument cap, which is why it only reproduced on the runners. All four restore steps now take the snapshot from the step environment and decode it off stdin via the `printf` builtin, so the payload is never attached to an exec. Job outputs still cap at 1 MiB, leaving ample headroom. --- .github/workflows/ci.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51a9633e..4a6e568e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -303,20 +303,29 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile --prefer-offline + # The snapshot travels as a base64 job output. It MUST reach the decoder through the environment and stdin, + # never as a command-line argument: Linux caps a single argv entry at `MAX_ARG_STRLEN` (128 KiB), and the + # snapshot passed that once the benchmarked export count grew — the step died with + # `node: Argument list too long` (exit 126). `printf` is a bash builtin, so piping the env var into + # `base64 -d` never execs with the payload attached. - name: Restore head benchmark snapshot shell: bash + env: + HEAD_SNAPSHOT_B64: ${{ needs.benchmark-pr-head.outputs.snapshot_b64 }} run: | set -euo pipefail mkdir -p tmp/bench - node -e "const fs=require('node:fs'); fs.writeFileSync('tmp/bench/head.json', Buffer.from(process.argv[1], 'base64'));" '${{ needs.benchmark-pr-head.outputs.snapshot_b64 }}' + printf '%s' "$HEAD_SNAPSHOT_B64" | base64 -d > tmp/bench/head.json - name: Restore base benchmark snapshot if: needs.benchmark-pr-base.outputs.available == 'true' shell: bash + env: + BASE_SNAPSHOT_B64: ${{ needs.benchmark-pr-base.outputs.snapshot_b64 }} run: | set -euo pipefail mkdir -p tmp/bench - node -e "const fs=require('node:fs'); fs.writeFileSync('tmp/bench/base.json', Buffer.from(process.argv[1], 'base64'));" '${{ needs.benchmark-pr-base.outputs.snapshot_b64 }}' + printf '%s' "$BASE_SNAPSHOT_B64" | base64 -d > tmp/bench/base.json - name: Generate benchmark report shell: bash @@ -569,20 +578,25 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile --prefer-offline + # Env + stdin, never argv — see the matching note on the PR-side restore steps (`MAX_ARG_STRLEN`). - name: Restore head benchmark snapshot shell: bash + env: + HEAD_SNAPSHOT_B64: ${{ needs.benchmark-push-head.outputs.snapshot_b64 }} run: | set -euo pipefail mkdir -p tmp/bench - node -e "const fs=require('node:fs'); fs.writeFileSync('tmp/bench/head.json', Buffer.from(process.argv[1], 'base64'));" '${{ needs.benchmark-push-head.outputs.snapshot_b64 }}' + printf '%s' "$HEAD_SNAPSHOT_B64" | base64 -d > tmp/bench/head.json - name: Restore base benchmark snapshot if: needs.benchmark-push-base.outputs.available == 'true' shell: bash + env: + BASE_SNAPSHOT_B64: ${{ needs.benchmark-push-base.outputs.snapshot_b64 }} run: | set -euo pipefail mkdir -p tmp/bench - node -e "const fs=require('node:fs'); fs.writeFileSync('tmp/bench/base.json', Buffer.from(process.argv[1], 'base64'));" '${{ needs.benchmark-push-base.outputs.snapshot_b64 }}' + printf '%s' "$BASE_SNAPSHOT_B64" | base64 -d > tmp/bench/base.json - name: Generate benchmark report shell: bash From d10b8dce7a1d607e932ba8fec771a4cd2da3cec6 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 02:14:10 +0900 Subject: [PATCH 38/39] fix(ci): move benchmark snapshots between jobs as artifacts, and alias the playlog subpath for Vite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two remaining CI failures, same underlying shape — a payload or a module the job could not reach. Benchmark compare jobs: the base64 snapshot was handed over as a job output and then materialized on the command line, which died with `Argument list too long` once the snapshot passed 128 KiB. Routing it through the step environment hit the same wall, because `MAX_ARG_STRLEN` caps every argv AND envp string — the runner could no longer even spawn bash. The snapshot now travels as an upload/download-artifact pair, which has no such ceiling; the base uploads carry the aggregate step's availability guard so a PR whose base lacks the bench script still skips cleanly instead of failing `if-no-files-found: error`. Cloudflare Workers Builds: the demo's Vite build resolves workspace subpaths through the alias table in vite.config.ts and runs without a prior workspace build, so `@be-music/player/playlog` had nothing to resolve to and rolldown failed the build. Added the missing alias — the third and last resolution map that enumerates player subpaths (vitest.config.ts and tsconfig.typecheck.json were the earlier two). Verified with dist removed: the demo build succeeds, and a two-run bench + aggregate + compare rehearsal reproduces the CI pipeline end to end. --- .github/workflows/ci.yml | 114 ++++++++++++------------ packages/player-web-demo/vite.config.ts | 4 + 2 files changed, 60 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a6e568e..da268e7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,8 +111,6 @@ jobs: needs.changes.outputs.code_changed == 'true' runs-on: ubuntu-24.04-arm timeout-minutes: 30 - outputs: - snapshot_b64: ${{ steps.aggregate-head.outputs.snapshot_b64 }} env: BENCH_TIME_MS: 20 BENCH_WARMUP_TIME_MS: 10 @@ -156,12 +154,18 @@ jobs: run: | set -euo pipefail pnpm run bench:aggregate -- --output tmp/bench/head.json tmp/bench/head-runs/*.json - { - echo "snapshot_b64<<__SNAPSHOT__" - node -e "const fs=require('node:fs'); process.stdout.write(fs.readFileSync('tmp/bench/head.json').toString('base64'));" - echo - echo "__SNAPSHOT__" - } >> "$GITHUB_OUTPUT" + + # The snapshot moves between jobs as an artifact, never as a job output. It outgrew both limits a job + # output would impose: a single argv/envp string caps at `MAX_ARG_STRLEN` (128 KiB) so the compare job + # could neither pass it to `node` nor even start `bash` with it in the environment, and job outputs + # themselves cap at 1 MiB. Artifacts have no such ceiling and keep the payload off the process image. + - name: Upload head benchmark snapshot + uses: actions/upload-artifact@v7 + with: + name: bench-pr-head-snapshot + path: tmp/bench/head.json + retention-days: 1 + if-no-files-found: error benchmark-pr-base: name: Benchmark Base (PR) @@ -173,7 +177,6 @@ jobs: outputs: available: ${{ steps.detect-bench.outputs.available == 'true' && steps.run-base-benchmark.outcome == 'success' }} - snapshot_b64: ${{ steps.aggregate-base.outputs.snapshot_b64 }} env: BENCH_TIME_MS: 20 BENCH_WARMUP_TIME_MS: 10 @@ -259,12 +262,16 @@ jobs: run: | set -euo pipefail pnpm run bench:aggregate -- --output tmp/bench/base.json tmp/bench/base-runs/*.json - { - echo "snapshot_b64<<__SNAPSHOT__" - node -e "const fs=require('node:fs'); process.stdout.write(fs.readFileSync('tmp/bench/base.json').toString('base64'));" - echo - echo "__SNAPSHOT__" - } >> "$GITHUB_OUTPUT" + + - name: Upload base benchmark snapshot + if: steps.detect-bench.outputs.available == 'true' && + steps.run-base-benchmark.outcome == 'success' + uses: actions/upload-artifact@v7 + with: + name: bench-pr-base-snapshot + path: tmp/bench/base.json + retention-days: 1 + if-no-files-found: error benchmark-pr: name: Benchmark (PR) @@ -309,23 +316,17 @@ jobs: # `node: Argument list too long` (exit 126). `printf` is a bash builtin, so piping the env var into # `base64 -d` never execs with the payload attached. - name: Restore head benchmark snapshot - shell: bash - env: - HEAD_SNAPSHOT_B64: ${{ needs.benchmark-pr-head.outputs.snapshot_b64 }} - run: | - set -euo pipefail - mkdir -p tmp/bench - printf '%s' "$HEAD_SNAPSHOT_B64" | base64 -d > tmp/bench/head.json + uses: actions/download-artifact@v8 + with: + name: bench-pr-head-snapshot + path: tmp/bench - name: Restore base benchmark snapshot if: needs.benchmark-pr-base.outputs.available == 'true' - shell: bash - env: - BASE_SNAPSHOT_B64: ${{ needs.benchmark-pr-base.outputs.snapshot_b64 }} - run: | - set -euo pipefail - mkdir -p tmp/bench - printf '%s' "$BASE_SNAPSHOT_B64" | base64 -d > tmp/bench/base.json + uses: actions/download-artifact@v8 + with: + name: bench-pr-base-snapshot + path: tmp/bench - name: Generate benchmark report shell: bash @@ -384,8 +385,6 @@ jobs: if: github.event_name == 'push' && needs.changes.outputs.code_changed == 'true' runs-on: ubuntu-24.04-arm timeout-minutes: 30 - outputs: - snapshot_b64: ${{ steps.aggregate-head.outputs.snapshot_b64 }} env: BENCH_TIME_MS: 20 BENCH_WARMUP_TIME_MS: 10 @@ -429,12 +428,14 @@ jobs: run: | set -euo pipefail pnpm run bench:aggregate -- --output tmp/bench/head.json tmp/bench/head-runs/*.json - { - echo "snapshot_b64<<__SNAPSHOT__" - node -e "const fs=require('node:fs'); process.stdout.write(fs.readFileSync('tmp/bench/head.json').toString('base64'));" - echo - echo "__SNAPSHOT__" - } >> "$GITHUB_OUTPUT" + + - name: Upload head benchmark snapshot + uses: actions/upload-artifact@v7 + with: + name: bench-push-head-snapshot + path: tmp/bench/head.json + retention-days: 1 + if-no-files-found: error benchmark-push-base: name: Benchmark Base (Push) @@ -445,7 +446,6 @@ jobs: outputs: available: ${{ steps.detect-bench.outputs.available == 'true' && steps.run-base-benchmark.outcome == 'success' }} - snapshot_b64: ${{ steps.aggregate-base.outputs.snapshot_b64 }} env: BENCH_TIME_MS: 20 BENCH_WARMUP_TIME_MS: 10 @@ -536,12 +536,16 @@ jobs: run: | set -euo pipefail pnpm run bench:aggregate -- --output tmp/bench/base.json tmp/bench/base-runs/*.json - { - echo "snapshot_b64<<__SNAPSHOT__" - node -e "const fs=require('node:fs'); process.stdout.write(fs.readFileSync('tmp/bench/base.json').toString('base64'));" - echo - echo "__SNAPSHOT__" - } >> "$GITHUB_OUTPUT" + + - name: Upload base benchmark snapshot + if: steps.detect-bench.outputs.available == 'true' && + steps.run-base-benchmark.outcome == 'success' + uses: actions/upload-artifact@v7 + with: + name: bench-push-base-snapshot + path: tmp/bench/base.json + retention-days: 1 + if-no-files-found: error benchmark-push: name: Benchmark (Push) @@ -580,23 +584,17 @@ jobs: # Env + stdin, never argv — see the matching note on the PR-side restore steps (`MAX_ARG_STRLEN`). - name: Restore head benchmark snapshot - shell: bash - env: - HEAD_SNAPSHOT_B64: ${{ needs.benchmark-push-head.outputs.snapshot_b64 }} - run: | - set -euo pipefail - mkdir -p tmp/bench - printf '%s' "$HEAD_SNAPSHOT_B64" | base64 -d > tmp/bench/head.json + uses: actions/download-artifact@v8 + with: + name: bench-push-head-snapshot + path: tmp/bench - name: Restore base benchmark snapshot if: needs.benchmark-push-base.outputs.available == 'true' - shell: bash - env: - BASE_SNAPSHOT_B64: ${{ needs.benchmark-push-base.outputs.snapshot_b64 }} - run: | - set -euo pipefail - mkdir -p tmp/bench - printf '%s' "$BASE_SNAPSHOT_B64" | base64 -d > tmp/bench/base.json + uses: actions/download-artifact@v8 + with: + name: bench-push-base-snapshot + path: tmp/bench - name: Generate benchmark report shell: bash diff --git a/packages/player-web-demo/vite.config.ts b/packages/player-web-demo/vite.config.ts index 067e905a..b3c11690 100644 --- a/packages/player-web-demo/vite.config.ts +++ b/packages/player-web-demo/vite.config.ts @@ -441,6 +441,10 @@ const workspaceSubpathAliases: WorkspaceAlias[] = [ find: '@be-music/player/judging', replacement: resolve(repositoryDir, 'packages/player/src/judging.ts'), }, + { + find: '@be-music/player/playlog', + replacement: resolve(repositoryDir, 'packages/player/src/playlog/index.ts'), + }, { find: '@be-music/player/state-signals', replacement: resolve(repositoryDir, 'packages/player/src/state-signals.ts'), From dc51b63a0023e4d2b7d6cf8d135feadc34731f81 Mon Sep 17 00:00:00 2001 From: Seiya KONNO <nulltask@gmail.com> Date: Tue, 18 Aug 2026 02:19:20 +0900 Subject: [PATCH 39/39] fix(ci): retry the benchmark comment through transient GitHub 5xx The benchmark comparison itself succeeded, then `Post benchmark comment` died on a GitHub API 503 during a platform incident, failing the whole job for a result that had already been computed. `actions/github-script` defaults to zero retries; its retry list already exempts 400/401/403/404/422, so a missing permission or bad payload still fails immediately rather than being retried into a timeout. --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da268e7e..de3b9840 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -341,6 +341,7 @@ jobs: - name: Post benchmark comment uses: actions/github-script@v9 with: + retries: 3 script: | const fs = require('node:fs'); const marker = '<!-- be-music-exports-benchmark -->'; @@ -609,6 +610,7 @@ jobs: - name: Post benchmark comment uses: actions/github-script@v9 with: + retries: 3 script: | const fs = require('node:fs'); const marker = '<!-- be-music-exports-benchmark -->';