18 Commits
0.4.0 ... main

Author SHA1 Message Date
dlp-bot
2597979114 Update 9 actions in 2 workflows (#63)
* Bump actions/cache v5.0.4 => v5.0.5
* Bump actions/checkout v6.0.2 => v6.0.3
* Bump actions/setup-node v6.3.0 => v6.4.0
* Bump actions/upload-artifact v7.0.0 => v7.0.1
* Bump astral-sh/ruff-action v3.6.1 => v4.0.0
* Bump denoland/setup-deno v2.0.3 => v2.0.4
* Bump pnpm/action-setup v5.0.0 => v6.0.8
* Bump pypa/gh-action-pypi-publish v1.13.0 => v1.14.0
* Bump zizmorcore/zizmor-action v0.5.2 => v0.5.6
2026-06-09 00:48:56 +00:00
bashonly
44d6ff9c90 Test with Python 3.15 (#69) 2026-06-07 22:20:36 +00:00
bashonly
830f4ce421 Manage dependency cooldown via config files (#68) 2026-06-07 22:16:05 +00:00
Simon Sawicki
d60b8244e7 Replace prettier and eslint with oxfmt and oxlint (#61) 2026-05-24 19:30:13 +00:00
bashonly
64067b031b Update documentation and CI/CD (#67)
* Add required versions to README
* Bump CI/CD runtimes to new minimum supported versions
2026-05-24 18:12:38 +00:00
bashonly
7c5c5e0dd1 CI/CD cleanup (#62) 2026-05-16 23:00:59 +00:00
Simon Sawicki
2231f1fd6e Use esbuild instead of rollup (#45) 2026-04-07 21:20:36 +00:00
bashonly
aef78f70e7 Bump actions pins (#57)
* Bump actions/cache v5.0.3 → v5.0.4
* Bump actionlint 1.7.11 → 1.7.12
2026-04-07 00:10:47 +00:00
bashonly
4fb477f4af Bump actions pins (#55)
* Bump actions/cache v5.0.1 → v5.0.3
* Bump actions/checkout v6.0.1 → v6.0.2
* Bump actions/download-artifact v7.0.0 → v8.0.1
* Bump actions/setup-node v6.1.0 → v6.3.0
* Bump actions/setup-python v6.1.0 → v6.2.0
* Bump actions/upload-artifact v6.0.0 → v7.0.0
* Bump astral-sh/ruff-action v3.5.1 → v3.6.1
* Bump oven-sh/setup-bun v2.0.2 → v2.2.0
* Bump pnpm/action-setup v4.2.0 → v5.0.0
* Bump zizmorcore/zizmor-action v0.3.0 → v0.5.2
* Bump actionlint v1.7.9 → v1.7.11
* Bump zizmor v1.19.0 → v1.23.1
2026-03-17 16:24:02 +00:00
bashonly
68448fa0ab Expose window global as self (#56)
Ref: https://github.com/yt-dlp/yt-dlp/issues/16256

Co-authored-by: Simon Sawicki <contact@grub4k.dev>
2026-03-17 16:12:08 +00:00
bashonly
cd4e87f52e Fix sig value encoding (#54)
Co-authored-by: Simon Sawicki <contact@grub4k.dev>
2026-03-13 07:23:10 +00:00
Simon Sawicki
41ff68e6f8 Solve new player variants (#53) 2026-03-13 01:05:48 +01:00
Simon Sawicki
5bc9811c7a Fix sig solving for tce and es6 player variants (#47) 2026-02-21 17:32:45 +01:00
toddynnn
1b648c34c1 Fix sig extraction in main variant of player 4e51e895 (#48) 2026-02-16 23:27:40 +01:00
Simon Sawicki
d13ca53401 Simplify package scripts 2026-02-08 21:58:03 +01:00
Simon Sawicki
a3095891a9 Use parallel testing in CI for deno 2026-02-08 21:58:03 +01:00
Simon Sawicki
c51d14fa61 Implement extract.ts helper for quick manual testing 2026-02-08 21:58:03 +01:00
Simon Sawicki
96c417f90a More robust solver extraction
- Do not hard fail if a single extraction fails
- Do not fail if multiple solutions exist but they are the same
2026-02-08 21:58:03 +01:00
31 changed files with 3051 additions and 6569 deletions

View File

@@ -1,15 +1,10 @@
name: CI name: CI
on: on:
push: push:
branches: branches: ['main']
- '**' # This workflow contains required checks and needs to run for EVERY pull_request
paths-ignore:
- 'README.md'
- 'LICENSE'
pull_request: pull_request:
paths-ignore: branches: ['**']
- 'README.md'
- 'LICENSE'
permissions: {} permissions: {}
@@ -18,9 +13,10 @@ concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' }} cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env: env:
ACTIONLINT_VERSION: "1.7.9" ACTIONLINT_VERSION: "1.7.12"
ACTIONLINT_SHA256SUM: 233b280d05e100837f4af1433c7b40a5dcb306e3aa68fb4f17f8a7f45a7df7b4 ACTIONLINT_SHA256SUM: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8
ACTIONLINT_REPO: https://github.com/rhysd/actionlint ACTIONLINT_REPO: rhysd/actionlint
GH_TELEMETRY: "false"
jobs: jobs:
actionlint: actionlint:
@@ -29,26 +25,31 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.14"
- name: Install requirements - name: Install requirements
env: env:
GH_TOKEN: ${{ github.token }}
ACTIONLINT_TARBALL: ${{ format('actionlint_{0}_linux_amd64.tar.gz', env.ACTIONLINT_VERSION) }} ACTIONLINT_TARBALL: ${{ format('actionlint_{0}_linux_amd64.tar.gz', env.ACTIONLINT_VERSION) }}
shell: bash shell: bash
run: | run: |
sudo apt -y install shellcheck sudo apt -y install shellcheck
python -m pip install -U pyflakes gh release download \
curl -LO "${ACTIONLINT_REPO}/releases/download/v${ACTIONLINT_VERSION}/${ACTIONLINT_TARBALL}" --repo "${ACTIONLINT_REPO}" \
--pattern "${ACTIONLINT_TARBALL}" \
"v${ACTIONLINT_VERSION}"
gh attestation verify \
--repo "${ACTIONLINT_REPO}" \
"${ACTIONLINT_TARBALL}"
printf '%s %s' "${ACTIONLINT_SHA256SUM}" "${ACTIONLINT_TARBALL}" | sha256sum -c - printf '%s %s' "${ACTIONLINT_SHA256SUM}" "${ACTIONLINT_TARBALL}" | sha256sum -c -
tar xvzf "${ACTIONLINT_TARBALL}" actionlint tar xvzf "${ACTIONLINT_TARBALL}" actionlint
chmod +x actionlint sudo install -D --mode=755 actionlint /usr/bin/
- name: Run actionlint - name: Run actionlint
run: | run: |
./actionlint -color actionlint -color
zizmor: zizmor:
name: Audit workflows name: Audit workflows
@@ -57,79 +58,87 @@ jobs:
actions: read # Needed by zizmorcore/zizmor-action if repository is private actions: read # Needed by zizmorcore/zizmor-action if repository is private
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Run zizmor - name: Run zizmor
uses: zizmorcore/zizmor-action@e639db99335bc9038abc0e066dfcd72e23d26fb4 # v0.3.0 uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
with: with:
advanced-security: false advanced-security: false
persona: pedantic persona: pedantic
version: v1.19.0
ruff_format: py_format:
name: Ruff format check name: Python format check
permissions: permissions:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: astral-sh/ruff-action@57714a7c8a2e59f32539362ba31877a1957dded1 # v3.5.1
- uses: astral-sh/ruff-action@0ce1b0bf8b818ef400413f810f8a11cdbda0034b # v4.0.0
with: with:
args: "check --output-format github" args: "check --output-format github"
ruff_lint: py_lint:
name: Ruff linting check name: Python lint check
permissions: permissions:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: astral-sh/ruff-action@57714a7c8a2e59f32539362ba31877a1957dded1 # v3.5.1
- uses: astral-sh/ruff-action@0ce1b0bf8b818ef400413f810f8a11cdbda0034b # v4.0.0
with: with:
args: "format --check --diff" args: "format --check --diff"
prettier: js_format:
name: Prettier check name: JavaScript format check
permissions: permissions:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Install Deno v2.x (latest) - name: Install Deno v2.x (latest)
uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
with: with:
deno-version: v2.x deno-version: v2.x
- name: Install Deno requirements - name: Install Deno requirements
run: | run: |
deno install --frozen deno install --frozen
- name: Run Prettier check
- name: Run format check
run: | run: |
deno task fmt:check deno task fmt:check
eslint: js_lint:
name: ESLint check name: JavaScript lint check
permissions: permissions:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Install Deno v2.x (latest) - name: Install Deno v2.x (latest)
uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
with: with:
deno-version: v2.x deno-version: v2.x
- name: Install Deno requirements - name: Install Deno requirements
run: | run: |
deno install --frozen deno install --frozen
- name: Run ESLint check
- name: Run lint check
run: | run: |
deno task lint deno task lint
@@ -142,32 +151,38 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
runner: [ubuntu-latest, windows-latest] runner: [ubuntu-latest, windows-latest]
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', pypy-3.11] python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15', pypy-3.11]
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# required for hatch-vcs versioning # required for hatch-vcs versioning
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: Install Deno v2.x (latest) - name: Install Deno v2.x (latest)
uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
with: with:
deno-version: v2.x deno-version: v2.x
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Build project - name: Build project
shell: bash shell: bash
run: | run: |
# `pip install -e` omits the force-included JS, so use `build` instead # `pip install -e` omits the force-included JS, so use `build` instead
python -m pip install -U build python -m pip install -U build
python -m build python -m build
- name: Unpack wheel (Linux) - name: Unpack wheel (Linux)
if: matrix.runner == 'ubuntu-latest' if: matrix.runner == 'ubuntu-latest'
shell: bash shell: bash
run: | run: |
unzip -u dist/yt_dlp_ejs-*.whl "yt_dlp_ejs/*" unzip -u dist/yt_dlp_ejs-*.whl "yt_dlp_ejs/*"
- name: Unpack wheel (Windows) - name: Unpack wheel (Windows)
if: matrix.runner == 'windows-latest' if: matrix.runner == 'windows-latest'
shell: pwsh shell: pwsh
@@ -175,6 +190,7 @@ jobs:
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $true $PSNativeCommandUseErrorActionPreference = $true
Expand-Archive -Path dist/yt_dlp_ejs-*.whl -DestinationPath ./ -Force Expand-Archive -Path dist/yt_dlp_ejs-*.whl -DestinationPath ./ -Force
- name: Run Python tests - name: Run Python tests
timeout-minutes: 5 timeout-minutes: 5
shell: bash shell: bash
@@ -187,40 +203,47 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Install Deno v2.x (latest) - name: Install Deno v2.x (latest)
uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
with: with:
deno-version: v2.x deno-version: v2.x
- name: Install Deno requirements - name: Install Deno requirements
run: | run: |
deno install --frozen deno install --frozen
- name: Build control bundle - name: Build control bundle
run: | run: |
deno task bundle deno task bundle
- name: Generate bundle hashes - name: Generate bundle hashes
shell: bash shell: bash
run: | run: |
pushd dist pushd dist
sha256sum -- yt.solver.*.js | tee SHA2-256SUMS sha256sum -- yt.solver.*.js | tee SHA2-256SUMS
popd popd
- name: Upload bundle hashes - name: Upload bundle hashes
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: bundle-hashes name: bundle-hashes
path: | path: |
dist/SHA2-256SUMS dist/SHA2-256SUMS
compression-level: 0 compression-level: 0
- name: Cache player JS files - name: Cache player JS files
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
env: env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
with: with:
path: | path: |
src/yt/solver/test/players src/yt/solver/test/players
key: test-player-js-${{ hashFiles('src/yt/solver/test/tests.ts') }} key: test-player-js-${{ hashFiles('src/yt/solver/test/tests.ts') }}
- name: Download player JS files - name: Download player JS files
timeout-minutes: 15 timeout-minutes: 15
run: | run: |
@@ -231,8 +254,9 @@ jobs:
--allow-net=www.youtube.com \ --allow-net=www.youtube.com \
--allow-sys=uid \ --allow-sys=uid \
src/yt/solver/test/download.ts src/yt/solver/test/download.ts
- name: Upload player JS artifact - name: Upload player JS artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: player-js name: player-js
path: | path: |
@@ -246,25 +270,31 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# required for hatch-vcs versioning # required for hatch-vcs versioning
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
with: with:
version: 10 # minimum supported version
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 version: "10.16.0"
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
# minimum supported version # minimum supported version
python-version: "3.10" python-version: "3.10"
- name: Install Python requirements - name: Install Python requirements
run: | run: |
python -m pip install -U build python -m pip install -U build
- name: Test pnpm build - name: Test pnpm build
run: | run: |
python -m build python -m build
- name: Verify artifact contents - name: Verify artifact contents
shell: bash shell: bash
run: | run: |
@@ -272,17 +302,21 @@ jobs:
unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents
- name: Install pnpm requirements - name: Install pnpm requirements
run: | run: |
pnpm install --frozen-lockfile pnpm install --frozen-lockfile
- name: Bundle with pnpm - name: Bundle with pnpm
run: | run: |
pnpm run bundle pnpm run bundle
- name: Download bundle hashes - name: Download bundle hashes
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: dist path: dist
name: bundle-hashes name: bundle-hashes
- name: Verify bundle hashes - name: Verify bundle hashes
run: | run: |
cd dist cd dist
@@ -294,13 +328,15 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
# minimum supported version # minimum supported version
python-version: "3.10" python-version: "3.10"
- name: Verify lockfile - name: Verify lockfile
run: | run: |
python ./check.py python ./check.py
@@ -312,26 +348,31 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# required for hatch-vcs versioning # required for hatch-vcs versioning
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: Install Deno - name: Install Deno
uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
with: with:
# minimum supported version # minimum supported version
deno-version: "2.0.0" deno-version: "2.3.0"
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
# minimum supported version # minimum supported version
python-version: "3.10" python-version: "3.10"
- name: Install Python requirements - name: Install Python requirements
run: | run: |
python -m pip install -U build python -m pip install -U build
- name: Test Deno build - name: Test Deno build
run: | run: |
python -m build python -m build
- name: Verify artifact contents - name: Verify artifact contents
shell: bash shell: bash
run: | run: |
@@ -339,17 +380,21 @@ jobs:
unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents
- name: Install Deno requirements - name: Install Deno requirements
run: | run: |
deno install --frozen deno install --frozen
- name: Bundle with Deno - name: Bundle with Deno
run: | run: |
deno task bundle deno task bundle
- name: Download bundle hashes - name: Download bundle hashes
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: dist path: dist
name: bundle-hashes name: bundle-hashes
- name: Verify bundle hashes - name: Verify bundle hashes
run: | run: |
cd dist cd dist
@@ -362,27 +407,33 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Install Deno - name: Install Deno
uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
with: with:
# minimum supported version # minimum supported version
deno-version: "2.0.0" deno-version: "2.3.0"
- name: Install Deno requirements - name: Install Deno requirements
run: | run: |
deno install --frozen deno install --frozen
- name: Download player JS artifact - name: Download player JS artifact
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: src/yt/solver/test/players path: src/yt/solver/test/players
name: player-js name: player-js
- name: Run Deno tests - name: Run Deno tests
run: | run: |
deno test \ xargs -n 1 -P 10 deno test \
--no-prompt \ --no-prompt \
--allow-read=src/yt/solver/test/players/ --no-check \
--allow-read=src/yt/solver/test/players/ \
--filter <<<"$(printf -- '-%s-\n' main tcc tce es5 es6 tv tv_es6 phone es6_tcc es6_tce)"
bun_build: bun_build:
name: Test Bun build name: Test Bun build
@@ -391,27 +442,32 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# required for hatch-vcs versioning # required for hatch-vcs versioning
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: Install Bun - name: Install Bun
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with: with:
# minimum supported version # minimum supported version
bun-version: "1.0.31" bun-version: "1.2.11"
no-cache: true no-cache: true
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
# minimum supported version # minimum supported version
python-version: "3.10" python-version: "3.10"
- name: Install Python requirements - name: Install Python requirements
run: | run: |
python -m pip install -U build python -m pip install -U build
- name: Test Bun build - name: Test Bun build
run: | run: |
python -m build python -m build
- name: Verify artifact contents - name: Verify artifact contents
shell: bash shell: bash
run: | run: |
@@ -419,17 +475,21 @@ jobs:
unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents
- name: Install Bun requirements - name: Install Bun requirements
run: | run: |
bun install --frozen-lockfile bun install --frozen-lockfile
- name: Bundle with Bun - name: Bundle with Bun
run: | run: |
bun --bun run bundle bun --bun run bundle
- name: Download bundle hashes - name: Download bundle hashes
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: dist path: dist
name: bundle-hashes name: bundle-hashes
- name: Verify bundle hashes - name: Verify bundle hashes
run: | run: |
cd dist cd dist
@@ -442,23 +502,27 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Install Bun - name: Install Bun
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with: with:
# XXX: We support 1.0.31, but test suite requires 1.2.11+ # minimum supported version
bun-version: "1.2.11" bun-version: "1.2.11"
no-cache: true no-cache: true
- name: Install Bun requirements - name: Install Bun requirements
run: | run: |
bun install --frozen-lockfile bun install --frozen-lockfile
- name: Download player JS artifact - name: Download player JS artifact
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: src/yt/solver/test/players path: src/yt/solver/test/players
name: player-js name: player-js
- name: Run Bun tests - name: Run Bun tests
run: | run: |
bun test bun test
@@ -470,26 +534,31 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
# required for hatch-vcs versioning # required for hatch-vcs versioning
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
- name: Install Node - name: Install Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
# minimum supported version # minimum supported version
node-version: "20.0" node-version: "22.0.0"
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
# minimum supported version # minimum supported version
python-version: "3.10" python-version: "3.10"
- name: Install Python requirements - name: Install Python requirements
run: | run: |
python -m pip install -U build python -m pip install -U build
- name: Test Node build - name: Test Node build
run: | run: |
python -m build python -m build
- name: Verify artifact contents - name: Verify artifact contents
shell: bash shell: bash
run: | run: |
@@ -497,17 +566,21 @@ jobs:
unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents unzip -l dist/yt_dlp_ejs-*.whl | tee .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/core\.min\.js' .wheel_contents
grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents grep -q 'yt_dlp_ejs/yt/solver/lib\.min\.js' .wheel_contents
- name: Install Node requirements - name: Install Node requirements
run: | run: |
npm ci npm ci
- name: Bundle with Node - name: Bundle with Node
run: | run: |
npm run bundle npm run bundle
- name: Download bundle hashes - name: Download bundle hashes
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: dist path: dist
name: bundle-hashes name: bundle-hashes
- name: Verify bundle hashes - name: Verify bundle hashes
run: | run: |
cd dist cd dist
@@ -520,35 +593,40 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Install Node - name: Install Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
# XXX: We support 20.0, but test suite requires 22.18+ # minimum supported version
node-version: "22.18" node-version: "22.0.0"
- name: Install Node requirements - name: Install Node requirements
run: | run: |
npm ci npm ci
- name: Download player JS artifact - name: Download player JS artifact
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: src/yt/solver/test/players path: src/yt/solver/test/players
name: player-js name: player-js
- name: Run Node tests - name: Run Node tests
run: | run: |
node --test node --test
all_passed: all_passed:
# Required check; do not change name
name: all_passed name: all_passed
needs: needs:
- actionlint - actionlint
- zizmor - zizmor
- ruff_format - py_format
- ruff_lint - py_lint
- prettier - js_format
- eslint - js_lint
- python_tests - python_tests
- pnpm_build - pnpm_build
- deno_lock_check - deno_lock_check
@@ -558,8 +636,7 @@ jobs:
- bun_tests - bun_tests
- node_build - node_build
- node_tests - node_tests
runs-on: ubuntu-latest runs-on: ubuntu-slim
steps: steps:
- name: All checks passed - run: |
run: | true
echo "All checks passed!"

View File

@@ -6,6 +6,9 @@ on:
permissions: {} permissions: {}
env:
GH_TELEMETRY: "false"
jobs: jobs:
build: build:
name: Build artifacts name: Build artifacts
@@ -13,37 +16,44 @@ jobs:
contents: read contents: read
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
fetch-depth: 0 # Needed for hatch-vcs versioning fetch-depth: 0 # Needed for hatch-vcs versioning
persist-credentials: false persist-credentials: false
- uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3
- uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
with: with:
deno-version: 3fbb1daddbc9333cddf0d8c0735811717dd70f7a # v2.6.3 deno-version: 3fbb1daddbc9333cddf0d8c0735811717dd70f7a # v2.6.3
cache: false cache: false
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.10" python-version: "3.14"
- name: Install Python requirements - name: Install Python requirements
run: | run: |
python -m pip install -U build python -m pip install -U build
- name: Build Python artifacts - name: Build Python artifacts
run: | run: |
python -m build python -m build
- name: Upload Python artifacts - name: Upload Python artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: artifacts-py name: artifacts-py
path: | path: |
dist/yt_dlp_ejs-*.whl dist/yt_dlp_ejs-*.whl
dist/yt_dlp_ejs-*.tar.gz dist/yt_dlp_ejs-*.tar.gz
compression-level: 0 compression-level: 0
- name: Build JavaScript artifacts - name: Build JavaScript artifacts
run: | run: |
deno install --frozen deno install --frozen
deno task bundle deno task bundle
- name: Upload JavaScript artifacts - name: Upload JavaScript artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: artifacts-js name: artifacts-js
path: | path: |
@@ -58,12 +68,13 @@ jobs:
id-token: write # Needed for PyPI trusted publishing id-token: write # Needed for PyPI trusted publishing
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: dist path: dist
name: artifacts-py name: artifacts-py
- name: Publish to PyPI - name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with: with:
verbose: true verbose: true
@@ -75,14 +86,16 @@ jobs:
contents: write # Needed by gh to publish release to Github contents: write # Needed by gh to publish release to Github
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: dist path: dist
pattern: artifacts-* pattern: artifacts-*
merge-multiple: true merge-multiple: true
- name: Create GitHub Release - name: Create GitHub Release
env: env:
TAG: ${{ github.ref_name }} TAG: ${{ github.ref_name }}

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
min-release-age = 7

6
.oxfmtrc.json Normal file
View File

@@ -0,0 +1,6 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"printWidth": 80,
"sortImports": true,
"ignorePatterns": ["**/*.toml", ".github/**"]
}

View File

@@ -10,6 +10,18 @@ Install ejs into the same environment as yt-dlp:
pip install -U yt-dlp-ejs pip install -U yt-dlp-ejs
``` ```
## Runtime requirements
This project supports the following runtimes/engines:
| Runtime / engine | Required version |
| ------------------ | -------------------- |
| deno | `>=2.3` |
| node | `>=22` |
| quickjs | `>=2023-12-9` |
| quickjs-ng | any |
| bun _(deprecated)_ | `>=1.2.11, <=1.3.14` |
## Development ## Development
The project provides lockfiles for every supported package manager. The project provides lockfiles for every supported package manager.
@@ -18,7 +30,24 @@ If you only have Python and a JS runtime, then you may instead run `./hatch_buil
This will transparently invoke one of the supported JS runtimes for the build. This will transparently invoke one of the supported JS runtimes for the build.
If you notice differences between different runtimes' builds If you notice differences between different runtimes' builds
please open an issue [here](<https://github.com/yt-dlp/ejs/issues/new>). please open an issue [here](https://github.com/yt-dlp/ejs/issues/new).
### Development requirements
Developers should have the following tools installed:
| Runtime / package manager | Required version |
| ------------------------- | --------------------------------- |
| deno | `>=2.6` |
| node | `^24.14.1 \|\| ^25.7.0 \|\| >=26` |
| npm | `>=11.10` |
| bun | `>=1.2.11, <=1.3.14` |
| pnpm | `>=10.16.0` |
| quickjs _(optional)_ | `>=2025-4-26` |
| quickjs-ng _(optional)_ | `>=0.12.0` |
quickjs/quickjs-ng is only needed for yt-dlp integration tests,
which can usually be handled by CI.
### Build ### Build
@@ -33,6 +62,18 @@ python hatch_build.py
This will automatically select an available runtime and build using it. This will automatically select an available runtime and build using it.
For more fine-grained control over how to build the package, you can set these environment variables:
- `EJS_BUILD_SKIP_INSTALL`: If this environment variable is set, the install step will be skipped.
It is expected that the required packages are available for the selected bundler.
No network access should be required if this variable is set.
- `EJS_BUILD_INSTALLER`: Order of installers to try, separated by `:` on POSIX or `;` on Windows.
These will be used to install the required dependencies for bundling the JavaScript package.
Can be any of `pnpm`, `deno`, `bun` or `npm` (this is also the default order).
- `EJS_BUILD_BUNDLER`: Order of bundlers to try, separated by `:` on POSIX or `;` on Windows.
These will be used to perform the bundling of the JavaScript package (calling rollup under the hood).
Can be any of `esbuild`, `pnpm`, `deno`, `bun`, `node` (this is also the default order).
### Tests ### Tests
First, make sure the project's dependencies are installed and download the player JS files: First, make sure the project's dependencies are installed and download the player JS files:
@@ -70,30 +111,32 @@ When upgrading packages in package.json, all lockfiles must be updated simultane
To do this, run the following commands: To do this, run the following commands:
```bash ```bash
# Upgrade packages automatically (or manually adjust versions) # 1. Upgrade all packages automatically
pnpm upgrade --latest pnpm upgrade --latest
# or upgrade only development dependencies
pnpm upgrade --latest --dev
# or upgrade a specific package, e.g. meriyah
pnpm upgrade --latest meriyah
# Generate base `package-lock.json` # 2. Generate base `package-lock.json` with npm
rm -rf node_modules rm -rf node_modules package-lock.json
npm install npm install
# Migrate to other package managers # 3. Migrate to other package managers
pnpm import pnpm import
bun pm migrate --force bun pm migrate --force
# Make sure to use a deno with lockfile v4 (<2.3) # 4. Generate a separate `deno.lock`
deno install --lockfile-only deno install --lockfile-only
# Ensure that `deno.json` is the same as `package-lock.json`. # 5. Ensure that `deno.lock` is equivalent to `package-lock.json`
# Note: you may need to manually update the `ADDITIONAL_PACKAGES_NODE`
# and/or `ADDITIONAL_PACKAGES_DENO` variables in `./check.py`.
python check.py python check.py
``` ```
## Licensing ## Licensing
This code is licensed under [Unlicense](<https://unlicense.org/>). This code is licensed under [Unlicense](https://unlicense.org/).
An exception to this is the prebuilt wheels, which contain both An exception to this is the prebuilt wheels, which contain both
[`meriyah`](<https://github.com/meriyah/meriyah>) and [`astring`](<https://github.com/davidbonnet/astring>), [`meriyah`](https://github.com/meriyah/meriyah) and [`astring`](https://github.com/davidbonnet/astring),
licensed under [`ISC`](<https://github.com/meriyah/meriyah?tab=ISC-1-ov-file>) and [`MIT`](<https://github.com/davidbonnet/astring?tab=MIT-1-ov-file>), respectively. licensed under [`ISC`](https://github.com/meriyah/meriyah?tab=ISC-1-ov-file) and [`MIT`](https://github.com/davidbonnet/astring?tab=MIT-1-ov-file), respectively.

32
build.mjs Normal file
View File

@@ -0,0 +1,32 @@
import * as esbuild from "esbuild";
const buildConfig = await stdinJSON();
const result = await esbuild.build(buildConfig);
console.log(JSON.stringify(result.metafile ?? null));
await esbuild.stop();
async function stdinJSON() {
const chunks = [];
if (globalThis.Deno) {
for await (const chunk of globalThis.Deno.stdin.readable) {
chunks.push(chunk);
}
const length = chunks.reduce(
(previous, chunk) => previous + chunk.length,
0,
);
const buffer = new Uint8Array(length);
let offset = 0;
for (const chunk of chunks) {
buffer.set(chunk, offset);
offset += chunk.length;
}
return JSON.parse(new TextDecoder().decode(buffer));
}
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const text = Buffer.concat(chunks).toString("utf-8");
return JSON.parse(text);
}

449
bun.lock
View File

@@ -1,5 +1,6 @@
{ {
"lockfileVersion": 1, "lockfileVersion": 1,
"configVersion": 1,
"workspaces": { "workspaces": {
"": { "": {
"name": "ejs", "name": "ejs",
@@ -8,443 +9,171 @@
"meriyah": "6.1.4", "meriyah": "6.1.4",
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.38.0",
"@rollup/plugin-node-resolve": "16.0.3",
"@rollup/plugin-sucrase": "5.0.2",
"@rollup/plugin-terser": "0.4.4",
"@types/bun": "1.3.0", "@types/bun": "1.3.0",
"@types/deno": "2.5.0", "@types/deno": "2.5.0",
"@types/node": "24.8.1", "@types/node": "24.8.1",
"eslint": "9.38.0", "esbuild": "0.28.0",
"globals": "16.4.0", "globals": "16.4.0",
"prettier": "3.6.2", "oxfmt": "^0.48.0",
"rollup": "4.52.5", "oxlint": "^1.63.0",
"rollup-plugin-license": "3.6.0",
"typescript-eslint": "8.46.2",
}, },
}, },
}, },
"packages": { "packages": {
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.28.0", "", { "os": "android", "cpu": "arm" }, "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ=="],
"@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.0", "", { "os": "android", "cpu": "arm64" }, "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], "@esbuild/android-x64": ["@esbuild/android-x64@0.28.0", "", { "os": "android", "cpu": "x64" }, "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA=="],
"@eslint/core": ["@eslint/core@0.16.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q=="], "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ=="],
"@eslint/js": ["@eslint/js@9.38.0", "", {}, "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A=="], "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A=="],
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg=="],
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ=="],
"@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.0", "", { "os": "linux", "cpu": "x64" }, "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.0", "", { "os": "none", "cpu": "x64" }, "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA=="],
"@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@16.0.3", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" } }, "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg=="], "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w=="],
"@rollup/plugin-sucrase": ["@rollup/plugin-sucrase@5.0.2", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "sucrase": "^3.27.0" }, "peerDependencies": { "rollup": "^2.53.1||^3.0.0||^4.0.0" } }, "sha512-4MhIVH9Dy2Hwose1/x5QMs0XF7yn9jDd/yozHqzdIrMWIolgFpGnrnVhQkqTaK1RALY/fpyrEKmwH/04vr1THA=="], "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw=="],
"@rollup/plugin-terser": ["@rollup/plugin-terser@0.4.4", "", { "dependencies": { "serialize-javascript": "^6.0.1", "smob": "^1.0.0", "terser": "^5.17.4" }, "peerDependencies": { "rollup": "^2.0.0||^3.0.0||^4.0.0" } }, "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A=="], "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA=="],
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" } }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.5", "", { "os": "android", "cpu": "arm" }, "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ=="], "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.0", "", { "os": "win32", "cpu": "x64" }, "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.5", "", { "os": "android", "cpu": "arm64" }, "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA=="], "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.48.0", "", { "os": "android", "cpu": "arm" }, "sha512-uwqk+/KhQvBIpULD8SMM/zAafMRC/+DV/xsEQjkkIsJ/kLmEI/2bxonVowcYTiXqqZ/a0FEW8DPkZY3VvwELDA=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.52.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA=="], "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.48.0", "", { "os": "android", "cpu": "arm64" }, "sha512-VUCiKuXK5+McVssgHEJdrcGK7hRJzrRb36zm9/jwzMholyYt4BgXhw5Nm1V1DX6Ce717Zi/1jk432b/tgmQgtQ=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.52.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA=="], "@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.48.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-IkKp8rnIyQLW6Jt+6jragCbUVYSayk55lapiprLjIVvt4NczLyO/nwX2GgefLQ5iaBdfS8UEAFgCs/pLO6Cl0w=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.52.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA=="], "@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.48.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-+aFuhsGIuvnoOjXyKVHMhPKJZR1kQkAl8QyrKoMlA7yJsSTC3N0Asl53La8TChSHhW8epToQ/Q0nvLmEmfNmLg=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.52.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ=="], "@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.48.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fbqzQL8FjI9gGnktI7RIo0dksDziTAYBy7xlI7jU7eID5fxLF/25fS4Xj6GydD8Y5oWHL83U4NK160QaOAxtyg=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.52.5", "", { "os": "linux", "cpu": "arm" }, "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ=="], "@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.48.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hn4i0zhAyTiB3ZHjQfYUZkDvrbVkohw1S7pySWxWUoZ87HnkDoTFThj7QTxk40hNPOTUP0vHbPRNamFIv1HBJQ=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.52.5", "", { "os": "linux", "cpu": "arm" }, "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ=="], "@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.48.0", "", { "os": "linux", "cpu": "arm" }, "sha512-R4WBD9qF3QM9hqgdAa+fBGXmquTvDUujrPQ36t2Sjk8RPOSKGHDeN7l/khr10hqbQaOq9KCgPHG9ubNET/X/RQ=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.52.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg=="], "@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.48.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-5bVdwSwlm1M8wbYCorLOxWxUBw/8tBvHYyQNIfwWVPwOJaj5vg1APSGJQVpwJfV5VNE9PSrR91UKEpoNwHhqUA=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.52.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q=="], "@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.48.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vCS3Fk7gFslTqE1lUE2IlroyVV7u/9SmMA/uBqDoshuck2psGWcjW0ePyPZI3rM3+qtf2pDaMVIKMHozraifuw=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.52.5", "", { "os": "linux", "cpu": "none" }, "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA=="], "@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.48.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gKtfFfueUClXDumyoHUbymqRf7prHejOOyzJK0eIJn93GF9JBdFHdo60TM1ZBHxkEwZvjuOgHmKtneKbEOc/Eg=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.52.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw=="], "@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.48.0", "", { "os": "linux", "cpu": "none" }, "sha512-SYt0UhOvZD/UwZz9sXq6J2uAw8o24f5VZpLB2DH01f6MevshmlgakQlZe2lwek2sZJkd07eLu7mZa0g7yeiw7Q=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.52.5", "", { "os": "linux", "cpu": "none" }, "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw=="], "@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.48.0", "", { "os": "linux", "cpu": "none" }, "sha512-JLbrwck2AopG4ud/XklZO5N+qxGC7cS7ROvXZVNfx0MCLDDL2kGOLvzuWORkVjnjAM0CMAfIMU2zNBtQbM+4dw=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.52.5", "", { "os": "linux", "cpu": "none" }, "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg=="], "@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.48.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-mdxt5L8OQLxkQH+JVpdC/lknZNe0lX4hlO3d8+xvw2wToo+iDrid9tiGOd5bmHfUVd5wVhrUry0qlu5vq66NkQ=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.52.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ=="], "@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.48.0", "", { "os": "linux", "cpu": "x64" }, "sha512-oEz1BQwMrV7OMEFx/3VPDU3n9TM0AnxpktDYXjEg5i6nTX87wo18wSfBvkl4tzAICdKtoAQAdBIl7Y7hsPlx5w=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.5", "", { "os": "linux", "cpu": "x64" }, "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q=="], "@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.48.0", "", { "os": "linux", "cpu": "x64" }, "sha512-g2SKTTurP5mWjd8Ecait0erYqmltL4IqW1EwttM25BxM6NiTt4ubobJYMR1uox1V2QgG4UfHH10CGRvWlUixjw=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.52.5", "", { "os": "linux", "cpu": "x64" }, "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg=="], "@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.48.0", "", { "os": "none", "cpu": "arm64" }, "sha512-CIg24VgheEpvolHL2gQuax5qcQ602bRMHrJ9g8XsQr3iVj9aSPgopigBKuMqrXsupwkrU+RQCn5cG8PgFntR6w=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.52.5", "", { "os": "none", "cpu": "arm64" }, "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw=="], "@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.48.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-zeaWkcxcEULwkGF3I/HgEvcDPN8buYDrxibBUa/IFh5Vmwyge+KpLO+hEwSovW349H0O/C0Z2kaFmEzEDm00/Q=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.52.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w=="], "@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.48.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-yiEKnIAGvx5CyZQOlMaNlZkAbwT7/Quk0j3WLt+PR5hK+qYjPTRRJYDfD77wCBPLvEYAG41v4KG3iL0H+uxoxg=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.52.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg=="], "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.48.0", "", { "os": "win32", "cpu": "x64" }, "sha512-GSD2+7t2UoVMV2NgxXypa4bKewflPMAjYnF0Xw9/ht82ZfafAHhb8STwrEd7wlH2PFogt5zw3WVCxYJaHUdbeQ=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.52.5", "", { "os": "win32", "cpu": "x64" }, "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ=="], "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.63.0", "", { "os": "android", "cpu": "arm" }, "sha512-A9xLtQt7i0OA1PoB/meog6kikXI9CdwEp7ZwQqmgnpKn3G3b1orvTDy8CQ6T7w1HvDrgWGB78PkFKcWgibcTCg=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg=="], "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.63.0", "", { "os": "android", "cpu": "arm64" }, "sha512-SQo+ZMvdR9l3CxZp5W5gFNxSiDxclY6lOzzNpKYLF8asESpm3Pwumx0gER5T7aHLF1/2BAAtLD3DiDkdgy4V1A=="],
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.63.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6W82XjJDTmMnjg30427l0dufpnyLoq7wEukKdM6/g2VIybRVuQiBVh43EA4b+UxZ3+tLcKm+Or/pXGNgLCEU8g=="],
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.63.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-CnWd/YCuVG5W1BYkjJEVbJG11o526O9qAwBEQM+nh8K19CRFUkFdROXCyYkGmroHEYQe4vgQ6+lh3550Lp35Xw=="],
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.63.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-a4eZAqrmtajqcxfdAzC+l7g3PaE3V8hpAYqqeD3fTxLXOMFdK3eNTZrU80n4dDEVm0JXy1aL5PqvqWldBl6zYA=="],
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.63.0", "", { "os": "linux", "cpu": "arm" }, "sha512-tYUtU9TdbU3uXF5D62g5zXJ13iniFGhXQx5vp9cyEjGdbSAY3VdFBSaldYvyoDmgMZ0ZYuwQP1Y4t2Fhejwa0w=="],
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.63.0", "", { "os": "linux", "cpu": "arm" }, "sha512-I5r3twFf776UZg9dmRo2xbrKt00tTkORXEVe0ctg4vdTkQvJAjiCHxnbAU2HL1AiJ9cqADA76MAliuilsAWnvg=="],
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.63.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-t7ltUkg6FFh4b564QyGir8xIj/QZbXu8FlcRkcyW9+ztr/mfRHlvUOFd95pJCXi9s/L5DrUeWWgpXRS+V+6igQ=="],
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.63.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q5mmZy/XWjuYFUuQyYjOvZ5U/JkKEwnpir6hGxhh6HcdP0V/BKxLo8dqkfF/t7r7AguB17dfS/8+go5AQDRR6g=="],
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.63.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-uBGtuZ0TzLB4x5wVa82HGNvYqY8buwDhyCnCP0R0gkk9szqVsP0MeTtD5HX7EsEuFIt+aYmYxuxeVxs3nTSwtQ=="],
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-h4s6FwxE+9MeA181o0dnDwHP32Y/bG8EiB/vrD6Ib+AMt6haigDc/0bUtI/sLmQDBMJnUfaCmtSSrEAqjtEVrA=="],
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-2EaNcCBR8Mcjl5ARtuN3BdEpVkX7KpjSjMGZ/mJMIeaXgTtdz5ytg2VwygMSStA/k0ixfvZFoZOfjDEcouV5vQ=="],
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.63.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4hlf/fd7TrYYl3QrWWD0GocqJefwMu3cHQhmi2FvEB/YOvFb5DZN3SMBaPi7B1TM5DeypkEtrVib674q1KKPg=="],
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.63.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Vgq9rkRVcPcjbcH+ihYTfpeR7vCXfqpd+z5ItTGc0yYUV59L5ceHYN1iV4H9bKGV7Rn5hkVc7x3mSvHegduENA=="],
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.63.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3/Lkq/ncooA61rorrC+ZQed1Bc4VpGj+WnGsp58zmxKgvZ2vhreu+dcVyr3mX8NUpq7mfZ4gDDTou/yrF1Pd7A=="],
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.63.0", "", { "os": "none", "cpu": "arm64" }, "sha512-0/EdD/6hDkx5Mfd769PTjvEM8mZ/6Dfukp1dBCL/2PjlIVGEtYdNZyok6ChqYPsT9JcFnlQnUeQzO0/1L/oC9w=="],
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.63.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-wb0CUkN8ngwPiRQBjD1Cj0LsHeNvm+Xt6YBHDMtj2DVQVD6Oj8Ri7g6BD+KICf6LaBqZlmzOvy6nF9E/8yyGOg=="],
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.63.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-BX5iq+ovdNlVYhSn5qPMUIT0uwAwt2lmEnCnzK+Gkhw4DovIvhGb96OFhV8yzQNUnQxn/xGkOR+X+BLrLDNm8w=="],
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.63.0", "", { "os": "win32", "cpu": "x64" }, "sha512-QeN/WELOfsXMeYwxvfgQrl6CbVftYUCZsGXHjXQd5Trccm8+i4gmtxaOui4xbJQaiDlviF8F3yLSBloQUeFsfA=="],
"@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="], "@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="],
"@types/deno": ["@types/deno@2.5.0", "", {}, "sha512-g8JS38vmc0S87jKsFzre+0ZyMOUDHPVokEJymSCRlL57h6f/FdKPWBXgdFh3Z8Ees9sz11qt9VWELU9Y9ZkiVw=="], "@types/deno": ["@types/deno@2.5.0", "", {}, "sha512-g8JS38vmc0S87jKsFzre+0ZyMOUDHPVokEJymSCRlL57h6f/FdKPWBXgdFh3Z8Ees9sz11qt9VWELU9Y9ZkiVw=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], "@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="],
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="], "@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="],
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.2", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/type-utils": "8.46.2", "@typescript-eslint/utils": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.2", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.46.2", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.2", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.2", "@typescript-eslint/types": "^8.46.2", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.2", "", { "dependencies": { "@typescript-eslint/types": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2" } }, "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.2", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.46.2", "", { "dependencies": { "@typescript-eslint/types": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/utils": "8.46.2", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.46.2", "", {}, "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.2", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.2", "@typescript-eslint/tsconfig-utils": "8.46.2", "@typescript-eslint/types": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.46.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.2", "", { "dependencies": { "@typescript-eslint/types": "8.46.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w=="],
"acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"array-find-index": ["array-find-index@1.0.2", "", {}, "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw=="],
"astring": ["astring@1.9.0", "", { "bin": "bin/astring" }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], "astring": ["astring@1.9.0", "", { "bin": "bin/astring" }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
"bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="], "bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
"commenting": ["commenting@1.1.0", "", {}, "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "esbuild": ["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" }, "bin": "bin/esbuild" }, "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.38.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.1", "@eslint/core": "^0.16.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.38.0", "@eslint/plugin-kit": "^0.4.0", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": "bin/eslint.js" }, "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="], "globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="],
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"meriyah": ["meriyah@6.1.4", "", {}, "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ=="], "meriyah": ["meriyah@6.1.4", "", {}, "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "oxfmt": ["oxfmt@0.48.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.48.0", "@oxfmt/binding-android-arm64": "0.48.0", "@oxfmt/binding-darwin-arm64": "0.48.0", "@oxfmt/binding-darwin-x64": "0.48.0", "@oxfmt/binding-freebsd-x64": "0.48.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.48.0", "@oxfmt/binding-linux-arm-musleabihf": "0.48.0", "@oxfmt/binding-linux-arm64-gnu": "0.48.0", "@oxfmt/binding-linux-arm64-musl": "0.48.0", "@oxfmt/binding-linux-ppc64-gnu": "0.48.0", "@oxfmt/binding-linux-riscv64-gnu": "0.48.0", "@oxfmt/binding-linux-riscv64-musl": "0.48.0", "@oxfmt/binding-linux-s390x-gnu": "0.48.0", "@oxfmt/binding-linux-x64-gnu": "0.48.0", "@oxfmt/binding-linux-x64-musl": "0.48.0", "@oxfmt/binding-openharmony-arm64": "0.48.0", "@oxfmt/binding-win32-arm64-msvc": "0.48.0", "@oxfmt/binding-win32-ia32-msvc": "0.48.0", "@oxfmt/binding-win32-x64-msvc": "0.48.0" }, "bin": "bin/oxfmt" }, "sha512-AVaLh+7XeGx+R1zfFV+f6VV61nT2MWVJXVUDhbTm5LBWGyNt64xAyh3NYYyjeY2WykNt9AvqSQLPHcbWquYF9g=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "oxlint": ["oxlint@1.63.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.63.0", "@oxlint/binding-android-arm64": "1.63.0", "@oxlint/binding-darwin-arm64": "1.63.0", "@oxlint/binding-darwin-x64": "1.63.0", "@oxlint/binding-freebsd-x64": "1.63.0", "@oxlint/binding-linux-arm-gnueabihf": "1.63.0", "@oxlint/binding-linux-arm-musleabihf": "1.63.0", "@oxlint/binding-linux-arm64-gnu": "1.63.0", "@oxlint/binding-linux-arm64-musl": "1.63.0", "@oxlint/binding-linux-ppc64-gnu": "1.63.0", "@oxlint/binding-linux-riscv64-gnu": "1.63.0", "@oxlint/binding-linux-riscv64-musl": "1.63.0", "@oxlint/binding-linux-s390x-gnu": "1.63.0", "@oxlint/binding-linux-x64-gnu": "1.63.0", "@oxlint/binding-linux-x64-musl": "1.63.0", "@oxlint/binding-openharmony-arm64": "1.63.0", "@oxlint/binding-win32-arm64-msvc": "1.63.0", "@oxlint/binding-win32-ia32-msvc": "1.63.0", "@oxlint/binding-win32-x64-msvc": "1.63.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.22.1" }, "optionalPeers": ["oxlint-tsgolint"], "bin": "bin/oxlint" }, "sha512-9TGXetdjgIHOJ9OiReomP7nnrMkV9HxC1xM2ramJSLQpzxjsAJtQwa4wqkJN2f/uCrqZuJseFuSlWDdvcruveg=="],
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], "tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"package-name-regex": ["package-name-regex@2.0.6", "", {}, "sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"prettier": ["prettier@3.6.2", "", { "bin": "bin/prettier.cjs" }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="],
"resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rollup": ["rollup@4.52.5", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.5", "@rollup/rollup-android-arm64": "4.52.5", "@rollup/rollup-darwin-arm64": "4.52.5", "@rollup/rollup-darwin-x64": "4.52.5", "@rollup/rollup-freebsd-arm64": "4.52.5", "@rollup/rollup-freebsd-x64": "4.52.5", "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", "@rollup/rollup-linux-arm-musleabihf": "4.52.5", "@rollup/rollup-linux-arm64-gnu": "4.52.5", "@rollup/rollup-linux-arm64-musl": "4.52.5", "@rollup/rollup-linux-loong64-gnu": "4.52.5", "@rollup/rollup-linux-ppc64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-musl": "4.52.5", "@rollup/rollup-linux-s390x-gnu": "4.52.5", "@rollup/rollup-linux-x64-gnu": "4.52.5", "@rollup/rollup-linux-x64-musl": "4.52.5", "@rollup/rollup-openharmony-arm64": "4.52.5", "@rollup/rollup-win32-arm64-msvc": "4.52.5", "@rollup/rollup-win32-ia32-msvc": "4.52.5", "@rollup/rollup-win32-x64-gnu": "4.52.5", "@rollup/rollup-win32-x64-msvc": "4.52.5", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw=="],
"rollup-plugin-license": ["rollup-plugin-license@3.6.0", "", { "dependencies": { "commenting": "~1.1.0", "fdir": "^6.4.3", "lodash": "~4.17.21", "magic-string": "~0.30.0", "moment": "~2.30.1", "package-name-regex": "~2.0.6", "spdx-expression-validate": "~2.0.0", "spdx-satisfies": "~5.0.1" }, "peerDependencies": { "rollup": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" } }, "sha512-1ieLxTCaigI5xokIfszVDRoy6c/Wmlot1fDEnea7Q/WXSR8AqOjYljHDLObAx7nFxHC2mbxT3QnTSPhaic2IYw=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"smob": ["smob@1.5.0", "", {}, "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
"spdx-compare": ["spdx-compare@1.0.0", "", { "dependencies": { "array-find-index": "^1.0.2", "spdx-expression-parse": "^3.0.0", "spdx-ranges": "^2.0.0" } }, "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A=="],
"spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
"spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="],
"spdx-expression-validate": ["spdx-expression-validate@2.0.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0" } }, "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg=="],
"spdx-license-ids": ["spdx-license-ids@3.0.22", "", {}, "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ=="],
"spdx-ranges": ["spdx-ranges@2.1.1", "", {}, "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA=="],
"spdx-satisfies": ["spdx-satisfies@5.0.1", "", { "dependencies": { "spdx-compare": "^1.0.0", "spdx-expression-parse": "^3.0.0", "spdx-ranges": "^2.0.0" } }, "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw=="],
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": "bin/terser" }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="],
"thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-eslint": ["typescript-eslint@8.46.2", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.46.2", "@typescript-eslint/parser": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/utils": "8.46.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg=="],
"undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], "undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/config-helpers/@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
} }
} }

3
deno.json Normal file
View File

@@ -0,0 +1,3 @@
{
"minimumDependencyAge": "P7D"
}

1243
deno.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.node },
},
tseslint.configs.recommended,
]);

View File

@@ -1,7 +1,18 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import annotations
import hashlib
import json
import os import os
import os.path
import pathlib
import re
import shlex
import shutil import shutil
import subprocess import subprocess
import sys
import tempfile
import typing
try: try:
from hatchling.builders.hooks.plugin.interface import BuildHookInterface from hatchling.builders.hooks.plugin.interface import BuildHookInterface
@@ -9,19 +20,123 @@ except ImportError:
BuildHookInterface = object BuildHookInterface = object
BASE_PATH = pathlib.Path(__file__).parent.resolve()
DEFAULT_BUNDLER = ["esbuild", "pnpm", "deno", "bun", "node"]
DEFAULT_INSTALLER = ["pnpm", "deno", "bun", "npm"]
def run():
if not os.environ.get("EJS_BUILD_SKIP_INSTALL"):
name, path = find_executable("EJS_BUILD_INSTALLER", DEFAULT_INSTALLER)
args, env = build_install_args(name)
cmd = [path, *args]
print(f"Install command: {shlex.join(cmd)}")
subprocess.run(cmd, env=env, check=False)
esbuild = ESBuild(*find_executable("EJS_BUILD_BUNDLER", DEFAULT_BUNDLER))
print(f"Bundle command: {shlex.join(esbuild.cmd)}", file=sys.stderr)
externals = list(get_external_packages(esbuild))
builds = create_builds(externals)
print("SHA3-512 checksums:", file=sys.stderr)
for build in builds:
outfile = build.get("outfile")
assert outfile
esbuild.run(build)
path = BASE_PATH / outfile
# Workaround for https://github.com/evanw/esbuild/issues/3717#issuecomment-3765731197
data = path.read_bytes()
if not build.get("minify"):
data = re.sub(
rb"^\s+// node_modules[^\n]+$",
b"",
data,
flags=re.ASCII | re.MULTILINE,
)
path.write_bytes(data)
digest = hashlib.sha3_512(data).hexdigest()
print(f"{digest} {path.name}")
def create_builds(externals: list[Package]) -> list[ESBuildOptions]:
with (BASE_PATH / "package.json").open("rb") as file:
pkg = json.load(file)
LICENSE_PREAMBLE = (
"SPDX-License-Identifier: Unlicense\n"
+ f"This file was automatically generated by {pkg['homepage']}"
)
BANNER_WITHOUT_DEPENDENCIES = {"js": license_comment(LICENSE_PREAMBLE)}
BANNER_WITH_DEPENDENCIES = {
"js": license_comment(
LICENSE_PREAMBLE
+ "\n\nBundled dependencies:\n\n"
+ "------\n\n".join(map(Package.license_comment, externals))
)
}
EXTERNALS = [pkg.name for pkg in externals]
ALIASES_DENO = {pkg.name: f"npm:{pkg.name}@{pkg.version}" for pkg in externals}
ALIASES_BUN = {pkg.name: f"{pkg.name}@{pkg.version}" for pkg in externals}
return [
{
"entryPoints": ["src/yt/solver/main.ts"],
"outfile": "dist/yt.solver.core.js",
"format": "iife",
"globalName": "jsc",
"banner": BANNER_WITHOUT_DEPENDENCIES,
"external": EXTERNALS,
},
{
"entryPoints": ["src/yt/solver/main.ts"],
"outfile": "dist/yt.solver.core.min.js",
"minify": True,
"format": "iife",
"globalName": "jsc",
"banner": BANNER_WITHOUT_DEPENDENCIES,
"external": EXTERNALS,
},
{
"entryPoints": ["src/yt/solver/lib.ts"],
"outfile": "dist/yt.solver.lib.js",
"format": "iife",
"globalName": "lib",
"banner": BANNER_WITH_DEPENDENCIES,
},
{
"entryPoints": ["src/yt/solver/lib.ts"],
"outfile": "dist/yt.solver.lib.min.js",
"minify": True,
"format": "iife",
"globalName": "lib",
"banner": BANNER_WITH_DEPENDENCIES,
},
{
"entryPoints": ["src/yt/solver/lib.ts"],
"outfile": "dist/yt.solver.bun.lib.js",
"minifySyntax": True,
"format": "esm",
"globalName": "lib",
"banner": BANNER_WITHOUT_DEPENDENCIES,
"alias": ALIASES_BUN,
"external": list(ALIASES_BUN.values()),
},
{
"entryPoints": ["src/yt/solver/lib.ts"],
"outfile": "dist/yt.solver.deno.lib.js",
"minifySyntax": True,
"format": "esm",
"globalName": "lib",
"banner": BANNER_WITHOUT_DEPENDENCIES,
"alias": ALIASES_DENO,
"external": list(ALIASES_DENO.values()),
},
]
class CustomBuildHook(BuildHookInterface): class CustomBuildHook(BuildHookInterface):
def initialize(self, version, build_data): def initialize(self, version, build_data):
name, cmds, env = build_bundle_cmds() run()
if cmds is None:
raise RuntimeError(
"One of 'pnpm', 'deno', 'bun', or 'npm' could not be found. "
"Please install one of them to proceed with the build."
)
print(f"Building with {name}...")
for cmd in cmds:
subprocess.run(cmd, env=env, check=True)
build_data["force_include"].update( build_data["force_include"].update(
{ {
"dist/yt.solver.core.min.js": "yt_dlp_ejs/yt/solver/core.min.js", "dist/yt.solver.core.min.js": "yt_dlp_ejs/yt/solver/core.min.js",
@@ -33,47 +148,278 @@ class CustomBuildHook(BuildHookInterface):
shutil.rmtree("node_modules", ignore_errors=True) shutil.rmtree("node_modules", ignore_errors=True)
def build_bundle_cmds(): def find_executable(env: str, defaults: list[str]):
env = os.environ.copy() values = defaults
if value := os.getenv(env):
values = value.split(os.path.pathsep)
for value in values:
if path := shutil.which(value):
name = pathlib.Path(path).name.partition(".")[0]
return name, path
if pnpm := shutil.which("pnpm"): return None, ""
name = "pnpm"
install = [pnpm, "install", "--frozen-lockfile"]
bundle = [pnpm, "run", "bundle"]
elif deno := shutil.which("deno"):
name = "deno" def build_install_args(name: str | None):
if name == "pnpm":
return ["install", "--frozen-lockfile"], None
if name == "deno":
env = os.environ.copy()
env["DENO_NO_UPDATE_CHECK"] = "1" env["DENO_NO_UPDATE_CHECK"] = "1"
install = [deno, "install", "--frozen"] return ["install", "--frozen"], env
bundle = [deno, "task", "bundle"]
elif bun := shutil.which("bun"): if name == "bun":
name = "bun" return ["install", "--frozen-lockfile"], None
install = [bun, "install", "--frozen-lockfile"]
bundle = [bun, "--bun", "run", "bundle"]
elif npm := shutil.which("npm"): if name == "npm":
name = "npm (node)" return ["ci"], None
install = [npm, "ci"]
bundle = [npm, "run", "bundle"]
else: raise RuntimeError(
return None, None, None "Only 'pnpm', 'deno', 'bun', or 'npm' are supported for installing dependencies. "
"Please install one of them or pass EJS_BUILD_SKIP_INSTALL=1 to skip install step."
)
return name, [install, bundle], env
class ESBuild:
def __init__(self, name: str | None, path: str, /):
self._stdin = True
self._env = None
if name == "esbuild":
self._stdin = False
self.cmd = [path]
elif name == "pnpm":
self._stdin = False
self.cmd = [path, "run", "esbuild"]
elif name == "deno":
self._env = os.environ.copy()
self._env["DENO_NO_UPDATE_CHECK"] = "1"
self.cmd = [
path,
"run",
"--allow-read",
"--allow-env",
"--allow-run",
"build.mjs",
]
elif name == "bun":
self.cmd = [path, "--bun", "run", "build.mjs"]
elif name == "node":
self.cmd = [path, "build.mjs"]
else:
raise RuntimeError(
"One of 'esbuild', 'pnpm', 'deno', 'bun', or 'node' could not be found. "
"Please install one of them to be able to run esbuild."
)
def run(self, options: ESBuildOptions, /):
options = options.copy()
if entrypoints := options.get("entryPoints"):
options["entryPoints"] = [str(BASE_PATH / path) for path in entrypoints]
if outfile := options.get("outfile"):
options["outfile"] = str(BASE_PATH / outfile)
if self._stdin:
process = self._run(self.cmd, json.dumps({"bundle": True, **options}))
return json.loads(process.stdout)
cmd = [*self.cmd, "--bundle", *self._convert_args(options)]
fd = name = None
if options.pop("metafile", None):
fd, name = tempfile.mkstemp(prefix="ejs-build-metadata-", suffix=".json")
cmd.append(f"--metafile={name}")
try:
self._run(cmd)
if fd and name:
with open(fd, "rb", closefd=True) as file:
return json.load(file)
return None
finally:
if name:
os.unlink(name)
def _run(self, cmd: list[str], stdin: str | None = None, /):
process = subprocess.run(
cmd,
env=self._env,
input=stdin,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=False,
)
if process.returncode:
raise RuntimeError(
f"failed to run esbuild:\n{process.stdout}{process.stderr}"
)
return process
@staticmethod
def _convert_args(options: ESBuildOptions):
for entrypoint in options.pop("entryPoints", ()):
yield entrypoint
if not options.pop("write", True):
options["outfile"] = "NUL" if os.name == "nt" else "/dev/null"
for name, value in options.items():
parameter = "--" + re.sub(r"[A-Z]", lambda x: "-" + x[0].lower(), name)
if isinstance(value, bool):
yield f"{parameter}={str(value).lower()}"
elif isinstance(value, str):
yield f"{parameter}={value}"
elif isinstance(value, list):
if name == "absPaths":
v = ",".join(value)
yield f"{parameter}={v}"
else:
for v in value:
yield f"{parameter}:{v}"
elif isinstance(value, dict):
for k, v in value.items():
yield f"{parameter}:{k}={v}"
class ESBuildOptions(typing.TypedDict, total=False):
entryPoints: list[str]
write: bool
absPaths: list[str]
metafile: bool
outfile: str
minify: bool
minifySyntax: bool
format: str
globalName: str
banner: dict[str, str]
alias: dict[str, str]
external: list[str]
def get_external_packages(esbuild: ESBuild):
metafile = esbuild.run(
{
"entryPoints": ["src/yt/solver/lib.ts"],
"absPaths": ["metafile"],
"metafile": True,
"write": False,
}
)
if not metafile:
raise RuntimeError("failed to gather build metadata")
_externals = {}
for input_file, meta in metafile["inputs"].items():
try:
pathlib.Path(input_file).relative_to(BASE_PATH)
except ValueError:
continue
for import_meta in meta["imports"]:
if "." in (import_meta.get("original") or ""):
continue
path = pathlib.Path(import_meta["path"])
_externals[path] = None
for path in _externals:
current = path.parent
while current != BASE_PATH:
package_path = current / "package.json"
if package_path.is_file():
break
current = current.parent
else:
msg = f"Failed to find package dir for {path}"
raise ValueError(msg)
yield Package.parse(current / "package.json")
class Package:
def __init__(
self,
/,
name: str,
description: str,
version: str,
author: str,
repository: str,
license: str,
license_text: str,
):
self.name = name
self.description = description
self.version = version
self.author = author
self.repository = repository
self.license = license
self.license_text = license_text
@staticmethod
def _parse_author(author):
if isinstance(author, str):
return author
result = [author["name"]]
if email := author.get("email"):
result.append(f"<{email}>")
if url := author.get("url"):
result.append(f"({url})")
return " ".join(result)
@classmethod
def parse(cls, path: pathlib.Path, /):
with path.open("rb") as file:
data = json.load(file)
licenses = list(path.parent.glob("LICENSE*"))
if len(licenses) != 1:
msg = "could not find appropriate license"
raise ValueError(msg)
return cls(
name=data["name"],
version=data["version"],
author=cls._parse_author(data["author"]),
description=data["description"],
repository=data["repository"]["url"],
license=data["license"],
license_text=licenses[0].read_text(encoding="utf-8"),
)
def _license_comment(self, /):
for name in (
"name",
"description",
"version",
"author",
"repository",
"license",
"license_text",
):
if name == "license_text":
yield "\n"
else:
yield name.capitalize()
yield ": "
yield getattr(self, name)
yield "\n"
def license_comment(self, /):
return "".join(self._license_comment())
def license_comment(data: str):
return "/*!\n * " + "\n * ".join(data.splitlines()) + "\n */"
if __name__ == "__main__": if __name__ == "__main__":
import sys
name, cmds, env = build_bundle_cmds()
if cmds is None:
print("ERROR: No suitable JavaScript runtime found", file=sys.stderr)
sys.exit(128)
print(f"Bundling using {name}...", file=sys.stderr)
try: try:
for cmd in cmds: run()
subprocess.check_call(cmd, env=env) except RuntimeError as error:
except subprocess.CalledProcessError as error: print("ERROR:", error.args[0], file=sys.stderr)
sys.exit(error.returncode) sys.exit(128)

3505
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,26 @@
{ {
"name": "ejs", "name": "ejs",
"homepage": "https://github.com/yt-dlp/ejs",
"type": "module", "type": "module",
"scripts": { "scripts": {
"bundle": "rollup -c", "bundle": "python hatch_build.py",
"fmt": "prettier --write \"src/**.ts\" \"package.json\" \"rollup.config.js\" \"run.ts\" \"eslint.config.js\"", "esbuild": "esbuild",
"fmt:check": "prettier --check \"src/**.ts\" \"package.json\" \"rollup.config.js\" \"run.ts\" \"eslint.config.js\"", "fmt": "oxfmt",
"lint": "eslint src" "fmt:check": "oxfmt --check",
"lint": "oxlint --fix",
"lint:check": "oxlint"
}, },
"dependencies": { "dependencies": {
"astring": "1.9.0", "astring": "1.9.0",
"meriyah": "6.1.4" "meriyah": "6.1.4"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.38.0",
"@rollup/plugin-node-resolve": "16.0.3",
"@rollup/plugin-sucrase": "5.0.2",
"@rollup/plugin-terser": "0.4.4",
"@types/bun": "1.3.0", "@types/bun": "1.3.0",
"@types/deno": "2.5.0", "@types/deno": "2.5.0",
"@types/node": "24.8.1", "@types/node": "24.8.1",
"eslint": "9.38.0", "esbuild": "0.28.0",
"globals": "16.4.0", "globals": "16.4.0",
"prettier": "3.6.2", "oxfmt": "^0.48.0",
"rollup": "4.52.5", "oxlint": "^1.63.0"
"rollup-plugin-license": "3.6.0",
"typescript-eslint": "8.46.2"
} }
} }

2163
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,4 @@
allowBuilds:
esbuild: true
minimumReleaseAge: 10080

View File

@@ -1,250 +0,0 @@
import { defineConfig } from "rollup";
import nodeResolve from "@rollup/plugin-node-resolve";
import sucrase from "@rollup/plugin-sucrase";
import terser from "@rollup/plugin-terser";
import { createHash } from "node:crypto";
import license from "rollup-plugin-license";
import { readFileSync } from "node:fs";
import prettier from "prettier";
const pkg = JSON.parse(readFileSync("./package.json"));
const LICENSE_BANNER =
"SPDX-License-Identifier: Unlicense\n" +
"This file was automatically generated by https://github.com/yt-dlp/ejs" +
"<% if (dependencies && dependencies.length) { %>" +
"\n\nBundled Dependencies:" +
"<% _.forEach(dependencies, function (dependency) { if (!dependency.private) { %>" +
"\n\n---\nName: <%= dependency.name %>" +
"<% if (dependency.version) { %>\nVersion: <%= dependency.version %><% } %>" +
"\nLicense: <%= dependency.license %>" +
"<% if (dependency.repository && dependency.repository.url) { %>\nRepository: <%= dependency.repository.url %><% } %>" +
"<% if (dependency.homepage && dependency.homepage.url) { %>\nHomepage: <%= dependency.homepage.url %><% } %>" +
"<% if (dependency.author) { %>\nAuthor: <%= dependency.author.text() %><% } %>" +
"<% if (dependency.licenseText) { %>\n\n<%= dependency.licenseText %><% } %>" +
"\n---<% } }) %>\n<% } %>";
function printHash() {
return {
name: "hash-output-plugin",
writeBundle(_options, bundle) {
for (const [fileName, assetInfo] of Object.entries(bundle)) {
if (assetInfo.code) {
try {
const digest = createHash("sha3-512")
.update(assetInfo.code)
.digest("hex");
console.log(`SHA3-512 for ${assetInfo.fileName}: ${digest}`);
} catch (err) {
console.error(`Error hashing ${fileName}:`, err.message);
}
}
}
},
};
}
function dynamicImportRewrite({ format = "deno" } = {}) {
return {
name: "dynamic-import-rewrite-plugin",
resolveId(source) {
if (pkg.dependencies[source]) {
if (format === "deno") {
return {
id: `npm:${source}@${pkg.dependencies[source]}`,
external: true,
};
} else if (format === "bun") {
return {
id: `${source}@${pkg.dependencies[source]}`,
external: true,
};
}
return null;
}
return null;
},
renderDynamicImport() {
return null;
},
};
}
function prettifyOutput() {
return {
name: "prettify-output",
renderChunk(code) {
return prettier.format(code, { parser: "babel", singleQuote: true });
},
};
}
export default defineConfig([
{
input: "src/yt/solver/main.ts",
output: {
name: "jsc",
globals: {
astring: "astring",
input: "input",
meriyah: "meriyah",
},
file: "dist/yt.solver.core.js",
format: "iife",
},
external: ["astring", "meriyah"],
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
commentStyle: "ignored",
content: LICENSE_BANNER,
},
}),
// Use terser to remove comments but do not minify
terser({
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
{
input: "src/yt/solver/main.ts",
output: {
name: "jsc",
globals: {
astring: "astring",
input: "input",
meriyah: "meriyah",
},
file: "dist/yt.solver.core.min.js",
compact: true,
format: "iife",
minifyInternalExports: true,
},
external: ["astring", "meriyah"],
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
commentStyle: "ignored",
content: LICENSE_BANNER,
},
}),
terser(),
printHash(),
],
},
{
input: "src/yt/solver/lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.lib.js",
format: "iife",
exports: "named",
},
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
commentStyle: "ignored",
content: LICENSE_BANNER,
},
}),
// Use terser to remove comments but do not minify
terser({
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
{
input: "src/yt/solver/lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.lib.min.js",
compact: true,
format: "iife",
minifyInternalExports: true,
},
plugins: [
nodeResolve(),
sucrase({
exclude: ["node_modules/**"],
transforms: ["typescript"],
}),
license({
banner: {
commentStyle: "ignored",
content: LICENSE_BANNER,
},
}),
terser(),
printHash(),
],
},
{
input: "src/yt/solver/dynamic.lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.deno.lib.js",
format: "es",
},
plugins: [
dynamicImportRewrite(),
license({
banner: {
commentStyle: "ignored",
content: LICENSE_BANNER,
},
}),
// Use terser to remove comments but do not minify
terser({
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
{
input: "src/yt/solver/dynamic.lib.ts",
output: {
name: "lib",
file: "dist/yt.solver.bun.lib.js",
format: "es",
},
plugins: [
dynamicImportRewrite({ format: "bun" }),
license({
banner: {
commentStyle: "ignored",
content: LICENSE_BANNER,
},
}),
// Use terser to remove comments but do not minify
terser({
compress: false,
mangle: false,
}),
prettifyOutput(),
printHash(),
],
},
]);

6
run.ts
View File

@@ -1,5 +1,5 @@
import { argv, exit } from "node:process";
import { readFileSync } from "node:fs"; import { readFileSync } from "node:fs";
import { argv, exit } from "node:process";
import { isOneOf } from "./src/utils.ts"; import { isOneOf } from "./src/utils.ts";
import main from "./src/yt/solver/main.ts"; import main from "./src/yt/solver/main.ts";
@@ -7,9 +7,7 @@ import main from "./src/yt/solver/main.ts";
const args = argv.slice(2); const args = argv.slice(2);
if (args.length < 2) { if (args.length < 2) {
console.error( console.error(
`ERROR: Missing argument\nusage: ${ `ERROR: Missing argument\nusage: ${argv[1]} <player> [<type>:<request> ...]`,
argv[1]
} <player> [<type>:<request> ...]`,
); );
exit(1); exit(1);
} }

View File

@@ -1,4 +1,5 @@
import { type ESTree } from "meriyah"; import { parse, type ESTree } from "meriyah";
import { type DeepPartial } from "./types.ts"; import { type DeepPartial } from "./types.ts";
export function matchesStructure<T extends ESTree.Node>( export function matchesStructure<T extends ESTree.Node>(
@@ -42,3 +43,10 @@ export function matchesStructure<T extends ESTree.Node>(
export function isOneOf<T>(value: unknown, ...of: readonly T[]): value is T { export function isOneOf<T>(value: unknown, ...of: readonly T[]): value is T {
return of.includes(value as T); return of.includes(value as T);
} }
export function generateArrowFunction(
data: string,
): ESTree.ArrowFunctionExpression {
return (parse(data).body[0] as ESTree.ExpressionStatement)
.expression as ESTree.ArrowFunctionExpression;
}

26
src/yt/solver/extract.ts Normal file
View File

@@ -0,0 +1,26 @@
import { argv } from "node:process";
import { generate } from "astring";
import { parse } from "meriyah";
import { getSolutions, modifyPlayer } from "./solvers.ts";
import { getIO } from "./test/io.ts";
import { downloadCached } from "./test/utils.ts";
const data = await (
argv.length > 3
? () => downloadCached(argv[2], argv[3])
: async () => {
const io = await getIO();
return await io.read(argv[2]);
}
)();
const program = parse(data);
const statements = modifyPlayer(program);
const solutionMap = getSolutions(statements);
for (const solutions of Object.values(solutionMap)) {
for (const solution of solutions) {
console.log(String.raw`${generate(solution)}`);
}
}

View File

@@ -1,5 +1,7 @@
import { parse } from "meriyah";
import { generate } from "astring"; import { generate } from "astring";
import { parse } from "meriyah";
export const meriyah = { parse }; export const lib = {
export const astring = { generate }; meriyah: { parse },
astring: { generate },
};

View File

@@ -1,5 +1,5 @@
import { getFromPrepared, preprocessPlayer } from "./solvers.ts";
import { isOneOf } from "../../utils.ts"; import { isOneOf } from "../../utils.ts";
import { getFromPrepared, preprocessPlayer } from "./solvers.ts";
export default function main(input: Input): Output { export default function main(input: Input): Output {
const preprocessedPlayer = const preprocessedPlayer =

View File

@@ -1,179 +0,0 @@
import { type ESTree } from "meriyah";
import { matchesStructure } from "../../utils.ts";
import { type DeepPartial } from "../../types.ts";
const identifier: DeepPartial<ESTree.Node> = {
or: [
{
type: "VariableDeclaration",
kind: "var",
declarations: {
anykey: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
},
init: {
type: "ArrayExpression",
elements: [
{
type: "Identifier",
},
],
},
},
],
},
},
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
left: {
type: "Identifier",
},
operator: "=",
right: {
type: "ArrayExpression",
elements: [
{
type: "Identifier",
},
],
},
},
},
],
} as const;
const catchBlockBody = [
{
type: "ReturnStatement",
argument: {
type: "BinaryExpression",
left: {
type: "MemberExpression",
object: {
type: "Identifier",
},
computed: true,
property: {
type: "Literal",
},
optional: false,
},
right: {
type: "Identifier",
},
operator: "+",
},
},
] as const;
export function extract(
node: ESTree.Node,
): ESTree.ArrowFunctionExpression | null {
if (!matchesStructure(node, identifier)) {
// Fallback search for try { } catch { return X[12] + Y }
let name: string | undefined | null = null;
let block: ESTree.BlockStatement | null | undefined = null;
switch (node.type) {
case "ExpressionStatement": {
if (
node.expression.type === "AssignmentExpression" &&
node.expression.left.type === "Identifier" &&
node.expression.right.type === "FunctionExpression" &&
node.expression.right.params.length === 1
) {
name = node.expression.left.name;
block = node.expression.right.body;
}
break;
}
case "FunctionDeclaration": {
if (node.params.length === 1) {
name = node.id?.name;
block = node.body;
}
break;
}
}
if (!block || !name) {
return null;
}
const tryNode = block.body.at(-2);
if (
tryNode?.type !== "TryStatement" ||
tryNode.handler?.type !== "CatchClause"
) {
return null;
}
const catchBody = tryNode.handler!.body.body;
if (matchesStructure(catchBody, catchBlockBody)) {
return makeSolverFuncFromName(name);
}
return null;
}
if (node.type === "VariableDeclaration") {
for (const declaration of node.declarations) {
if (
declaration.type !== "VariableDeclarator" ||
!declaration.init ||
declaration.init.type !== "ArrayExpression" ||
declaration.init.elements.length !== 1
) {
continue;
}
const [firstElement] = declaration.init.elements;
if (firstElement && firstElement.type === "Identifier") {
return makeSolverFuncFromName(firstElement.name);
}
}
} else if (node.type === "ExpressionStatement") {
const expr = node.expression;
if (
expr.type === "AssignmentExpression" &&
expr.left.type === "Identifier" &&
expr.operator === "=" &&
expr.right.type === "ArrayExpression" &&
expr.right.elements.length === 1
) {
const [firstElement] = expr.right.elements;
if (firstElement && firstElement.type === "Identifier") {
return makeSolverFuncFromName(firstElement.name);
}
}
}
return null;
}
function makeSolverFuncFromName(name: string): ESTree.ArrowFunctionExpression {
return {
type: "ArrowFunctionExpression",
params: [
{
type: "Identifier",
name: "n",
},
],
body: {
type: "CallExpression",
callee: {
type: "Identifier",
name: name,
},
arguments: [
{
type: "Identifier",
name: "n",
},
],
optional: false,
},
async: false,
expression: false,
generator: false,
};
}

144
src/yt/solver/nsig.ts Normal file
View File

@@ -0,0 +1,144 @@
import { generate } from "astring";
import { type ESTree } from "meriyah";
import { type DeepPartial } from "../../types.ts";
import { matchesStructure, generateArrowFunction } from "../../utils.ts";
const identifier: DeepPartial<ESTree.Node> = {
or: [
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
or: [{ type: "Identifier" }, { type: "MemberExpression" }],
},
right: {
type: "FunctionExpression",
async: false,
},
},
},
{
type: "FunctionDeclaration",
async: false,
id: { type: "Identifier" },
},
{
type: "VariableDeclaration",
declarations: {
anykey: [
{
type: "VariableDeclarator",
init: {
type: "FunctionExpression",
async: false,
},
},
],
},
},
],
} as const;
const asdasd: DeepPartial<ESTree.ExpressionStatement> = {
type: "ExpressionStatement",
expression: {
type: "CallExpression",
callee: {
type: "MemberExpression",
object: { type: "Identifier" },
property: {},
optional: false,
},
arguments: [
{
type: "Literal",
value: "alr",
},
{
type: "Literal",
value: "yes",
},
],
optional: false,
},
};
export function extract(
node: ESTree.Node,
): ESTree.ArrowFunctionExpression | null {
if (!matchesStructure(node, identifier)) {
return null;
}
const options: {
name: ESTree.Expression;
statements: ESTree.Statement[];
}[] = [];
if (node.type === "FunctionDeclaration") {
if (node.id && node.body?.body) {
options.push({
name: node.id,
statements: node.body?.body,
});
}
} else if (node.type === "ExpressionStatement") {
if (node.expression.type !== "AssignmentExpression") {
return null;
}
const name = node.expression.left;
const body = (node.expression.right as ESTree.FunctionExpression)?.body
?.body;
if (name && body) {
options.push({
name: name,
statements: body,
});
}
} else if (node.type === "VariableDeclaration") {
for (const declaration of node.declarations) {
const name = declaration.id;
const body = (declaration.init as ESTree.FunctionExpression)?.body?.body;
if (name && body) {
options.push({
name: name,
statements: body,
});
}
}
}
for (const { name, statements } of options) {
if (matchesStructure(statements, { anykey: [asdasd] })) {
return createSolver(name);
}
}
return null;
}
function createSolver(
expression: ESTree.Expression,
): ESTree.ArrowFunctionExpression {
return generateArrowFunction(`
({sig, n}) => {
const url = (${generate(expression)})("https://youtube.com/watch?v=yt-dlp-wins", "s", sig ? encodeURIComponent(sig) : undefined);
url.set("n", n);
const proto = Object.getPrototypeOf(url);
const keys = Object.keys(proto).concat(Object.getOwnPropertyNames(proto));
for (const key of keys) {
if (!["constructor", "set", "get", "clone"].includes(key)) {
url[key]();
break;
}
}
const s = url.get("s");
return {
sig: s ? decodeURIComponent(s) : null,
n: url.get("n") ?? null,
};
}
`);
}

View File

@@ -4,9 +4,8 @@ export const setupNodes = parse(`
if (typeof globalThis.XMLHttpRequest === "undefined") { if (typeof globalThis.XMLHttpRequest === "undefined") {
globalThis.XMLHttpRequest = { prototype: {} }; globalThis.XMLHttpRequest = { prototype: {} };
} }
const window = Object.create(null);
if (typeof URL === "undefined") { if (typeof URL === "undefined") {
window.location = { globalThis.location = {
hash: "", hash: "",
host: "www.youtube.com", host: "www.youtube.com",
hostname: "www.youtube.com", hostname: "www.youtube.com",
@@ -20,7 +19,7 @@ if (typeof URL === "undefined") {
username: "", username: "",
}; };
} else { } else {
window.location = new URL("https://www.youtube.com/watch?v=yt-dlp-wins"); globalThis.location = new URL("https://www.youtube.com/watch?v=yt-dlp-wins");
} }
if (typeof globalThis.document === "undefined") { if (typeof globalThis.document === "undefined") {
globalThis.document = Object.create(null); globalThis.document = Object.create(null);
@@ -31,4 +30,7 @@ if (typeof globalThis.navigator === "undefined") {
if (typeof globalThis.self === "undefined") { if (typeof globalThis.self === "undefined") {
globalThis.self = globalThis; globalThis.self = globalThis;
} }
if (typeof globalThis.window === "undefined") {
globalThis.window = globalThis;
}
`).body; `).body;

View File

@@ -1,232 +0,0 @@
import { type ESTree } from "meriyah";
import { matchesStructure } from "../../utils.ts";
import { type DeepPartial } from "../../types.ts";
const nsigExpression: DeepPartial<ESTree.Statement> = {
type: "VariableDeclaration",
kind: "var",
declarations: [
{
type: "VariableDeclarator",
init: {
type: "CallExpression",
callee: {
type: "Identifier",
},
arguments: [
{
type: "Literal",
},
{
type: "CallExpression",
callee: {
type: "Identifier",
name: "decodeURIComponent",
},
},
],
},
},
],
};
const logicalExpression: DeepPartial<ESTree.ExpressionStatement> = {
type: "ExpressionStatement",
expression: {
type: "LogicalExpression",
left: {
type: "Identifier",
},
right: {
type: "SequenceExpression",
expressions: [
{
type: "AssignmentExpression",
left: {
type: "Identifier",
},
operator: "=",
right: {
type: "CallExpression",
callee: {
type: "Identifier",
},
arguments: {
or: [
[
{ type: "Literal" },
{
type: "CallExpression",
callee: {
type: "Identifier",
name: "decodeURIComponent",
},
arguments: [{ type: "Identifier" }],
optional: false,
},
],
[
{
type: "CallExpression",
callee: {
type: "Identifier",
name: "decodeURIComponent",
},
arguments: [{ type: "Identifier" }],
optional: false,
},
],
],
},
optional: false,
},
},
{
type: "CallExpression",
},
],
},
operator: "&&",
},
};
const identifier: DeepPartial<ESTree.Node> = {
or: [
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "Identifier",
},
right: {
type: "FunctionExpression",
params: [{}, {}, {}],
},
},
},
{
type: "FunctionDeclaration",
params: [{}, {}, {}],
},
{
type: "VariableDeclaration",
declarations: {
anykey: [
{
type: "VariableDeclarator",
init: {
type: "FunctionExpression",
params: [{}, {}, {}],
},
},
],
},
},
],
} as const;
export function extract(
node: ESTree.Node,
): ESTree.ArrowFunctionExpression | null {
if (!matchesStructure(node, identifier)) {
return null;
}
let block: ESTree.BlockStatement | undefined | null;
if (
node.type === "ExpressionStatement" &&
node.expression.type === "AssignmentExpression" &&
node.expression.right.type === "FunctionExpression"
) {
block = node.expression.right.body;
} else if (node.type === "VariableDeclaration") {
for (const decl of node.declarations) {
if (
decl.type === "VariableDeclarator" &&
decl.init?.type === "FunctionExpression" &&
decl.init?.params.length === 3
) {
block = decl.init.body;
break;
}
}
} else if (node.type === "FunctionDeclaration") {
block = node.body;
} else {
return null;
}
const relevantExpression = block?.body.at(-2);
let call: ESTree.CallExpression | null = null;
if (matchesStructure(relevantExpression!, logicalExpression)) {
if (
relevantExpression?.type !== "ExpressionStatement" ||
relevantExpression.expression.type !== "LogicalExpression" ||
relevantExpression.expression.right.type !== "SequenceExpression" ||
relevantExpression.expression.right.expressions[0].type !==
"AssignmentExpression" ||
relevantExpression.expression.right.expressions[0].right.type !==
"CallExpression"
) {
return null;
}
call = relevantExpression.expression.right.expressions[0].right;
} else if (
relevantExpression?.type === "IfStatement" &&
relevantExpression.consequent.type === "BlockStatement"
) {
for (const n of relevantExpression.consequent.body) {
if (!matchesStructure(n, nsigExpression)) {
continue;
}
if (
n.type !== "VariableDeclaration" ||
n.declarations[0].init?.type !== "CallExpression"
) {
continue;
}
call = n.declarations[0].init;
break;
}
}
if (call === null) {
return null;
}
// TODO: verify identifiers here
return {
type: "ArrowFunctionExpression",
params: [
{
type: "Identifier",
name: "sig",
},
],
body: {
type: "CallExpression",
callee: {
type: "Identifier",
name: call.callee.name,
},
arguments:
call.arguments.length === 1
? [
{
type: "Identifier",
name: "sig",
},
]
: [
call.arguments[0],
{
type: "Identifier",
name: "sig",
},
],
optional: false,
},
async: false,
expression: false,
generator: false,
};
}

View File

@@ -1,14 +1,14 @@
import { getFromPrepared, preprocessPlayer } from "./solvers.ts"; import { getFromPrepared, preprocessPlayer } from "./solvers.ts";
import { getIO } from "./test/io.ts";
import { players, tests } from "./test/tests.ts"; import { players, tests } from "./test/tests.ts";
import { getCachePath } from "./test/utils.ts"; import { getCachePath } from "./test/utils.ts";
import { getIO } from "./test/io.ts";
const io = await getIO(); const io = await getIO();
for (const test of tests) { for (const test of tests) {
for (const variant of test.variants ?? players.keys()) { for (const variant of test.variants ?? players.keys()) {
const path = getCachePath(test.player, variant); const path = getCachePath(test.player, variant);
await io.test(`${test.player} ${variant}`, async (assert, subtest) => { await io.test(`-${test.player}-${variant}-`, async (assert, subtest) => {
const content = await io.read(path); const content = await io.read(path);
const solvers = getFromPrepared(preprocessPlayer(content)); const solvers = getFromPrepared(preprocessPlayer(content));
for (const mode of ["n", "sig"] as const) { for (const mode of ["n", "sig"] as const) {

View File

@@ -1,14 +1,46 @@
import { type ESTree, parse } from "meriyah";
import { generate } from "astring"; import { generate } from "astring";
import { extract as extractSig } from "./sig.ts"; import { type ESTree, parse } from "meriyah";
import { extract as extractN } from "./n.ts";
import { generateArrowFunction } from "../../utils.ts";
import { extract } from "./nsig.ts";
import { setupNodes } from "./setup.ts"; import { setupNodes } from "./setup.ts";
export function preprocessPlayer(data: string): string { export function preprocessPlayer(data: string): string {
const ast = parse(data); const program = parse(data);
const body = ast.body; const plainStatements = modifyPlayer(program);
const solutions = getSolutions(plainStatements);
for (const [name, options] of Object.entries(solutions)) {
plainStatements.push({
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "MemberExpression",
computed: false,
object: {
type: "Identifier",
name: "_result",
},
property: {
type: "Identifier",
name: name,
},
optional: false,
},
right: multiTry(options),
},
});
}
const block = (() => { program.body.splice(0, 0, ...setupNodes);
return generate(program);
}
export function modifyPlayer(program: ESTree.Program) {
const body = program.body;
const block: ESTree.BlockStatement = (() => {
switch (body.length) { switch (body.length) {
case 1: { case 1: {
const func = body[0]; const func = body[0];
@@ -40,19 +72,7 @@ export function preprocessPlayer(data: string): string {
throw "unexpected structure"; throw "unexpected structure";
})(); })();
const found = { block.body = block.body.filter((node: ESTree.Statement) => {
n: [] as ESTree.ArrowFunctionExpression[],
sig: [] as ESTree.ArrowFunctionExpression[],
};
const plainExpressions = block.body.filter((node: ESTree.Node) => {
const n = extractN(node);
if (n) {
found.n.push(n);
}
const sig = extractSig(node);
if (sig) {
found.sig.push(sig);
}
if (node.type === "ExpressionStatement") { if (node.type === "ExpressionStatement") {
if (node.expression.type === "AssignmentExpression") { if (node.expression.type === "AssignmentExpression") {
return true; return true;
@@ -61,43 +81,75 @@ export function preprocessPlayer(data: string): string {
} }
return true; return true;
}); });
block.body = plainExpressions;
for (const [name, options] of Object.entries(found)) { return block.body;
// TODO: this is cringe fix plz }
const unique = new Set(options.map((x) => JSON.stringify(x)));
if (unique.size !== 1) { export function getSolutions(
const message = `found ${unique.size} ${name} function possibilities`; statements: ESTree.Statement[],
throw ( ): Record<string, ESTree.ArrowFunctionExpression[]> {
message + const found = {
(unique.size ? `: ${options.map((x) => generate(x)).join(", ")}` : "") n: [] as ESTree.ArrowFunctionExpression[],
sig: [] as ESTree.ArrowFunctionExpression[],
};
for (const statement of statements) {
const result = extract(statement);
if (result) {
found.n.push(
makeSolver(result, {
type: "Identifier",
name: "n",
}),
);
found.sig.push(
makeSolver(result, {
type: "Identifier",
name: "sig",
}),
); );
} }
plainExpressions.push({
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "MemberExpression",
computed: false,
object: {
type: "Identifier",
name: "_result",
},
property: {
type: "Identifier",
name: name,
},
},
right: options[0],
},
});
} }
return found;
}
ast.body.splice(0, 0, ...setupNodes); function makeSolver(
result: ESTree.ArrowFunctionExpression,
return generate(ast); ident: ESTree.Identifier,
): ESTree.ArrowFunctionExpression {
return {
type: "ArrowFunctionExpression",
params: [ident],
body: {
type: "MemberExpression",
object: {
type: "CallExpression",
callee: result,
arguments: [
{
type: "ObjectExpression",
properties: [
{
type: "Property",
key: ident,
value: ident,
kind: "init",
computed: false,
method: false,
shorthand: true,
},
],
},
],
optional: false,
},
computed: false,
property: ident,
optional: false,
},
async: false,
expression: true,
generator: false,
};
} }
export function getFromPrepared(code: string): { export function getFromPrepared(code: string): {
@@ -108,3 +160,31 @@ export function getFromPrepared(code: string): {
Function("_result", code)(resultObj); Function("_result", code)(resultObj);
return resultObj; return resultObj;
} }
function multiTry(
generators: ESTree.ArrowFunctionExpression[],
): ESTree.ArrowFunctionExpression {
return generateArrowFunction(`
(_input) => {
const _results = new Set();
const errors = [];
for (const _generator of ${generate({
type: "ArrayExpression",
elements: generators,
} as ESTree.Node)}) {
try {
_results.add(_generator(_input));
} catch (e) {
errors.push(e);
}
}
if (!_results.size) {
throw \`no solutions: \${errors.join(", ")}\`;
}
if (_results.size !== 1) {
throw \`invalid solutions: \${[..._results].map(x => JSON.stringify(x)).join(", ")}\`;
}
return _results.values().next().value;
}
`);
}

View File

@@ -1,24 +1,13 @@
import { players, tests } from "./tests.ts"; import { players, tests } from "./tests.ts";
import { getCachePath } from "./utils.ts"; import { downloadCached } from "./utils.ts";
import { getIO } from "./io.ts";
const io = await getIO();
for (const test of tests) { for (const test of tests) {
const variants = test.variants ?? players.keys(); const variants = test.variants ?? players.keys();
for (const variant of variants) { for (const variant of variants) {
const path = getCachePath(test.player, variant); try {
if (await io.exists(path)) { await downloadCached(test.player, variant);
continue; } catch (e) {
console.error(e);
} }
const playerPath = players.get(variant);
const url = `https://www.youtube.com/s/player/${test.player}/${playerPath}`;
console.log("Requesting", url);
const response = await fetch(url);
if (!response.ok) {
console.error(`Failed to request ${variant} player for ${test.player}`);
continue;
}
await io.write(path, response);
} }
} }

View File

@@ -83,8 +83,6 @@ async function _getIO(): Promise<IO> {
}; };
} }
throw new Error( throw new Error(
`unsupported runtime for testing${ `unsupported runtime for testing${navigator.userAgent ? `: ${navigator.userAgent}` : ""}`,
navigator.userAgent ? `: ${navigator.userAgent}` : ""
}`,
); );
} }

View File

@@ -10,293 +10,103 @@ export const tests: {
sig?: Step[]; sig?: Step[];
}[] = [ }[] = [
{ {
player: "3d3ba064", // 20522
player: "74edf1a3",
n: [ n: [
{ input: "ZdZIqFPQK-Ty8wId", expected: "qmtUsIz04xxiNW" }, { input: "IlLiA21ny7gqA2m4p37", expected: "9nRTxrbM1f0yHg" },
{ input: "4GMrWHyKI5cEvhDO", expected: "N9gmEX7YhKTSmw" }, { input: "eabGFpsUKuWHXGh6FR4", expected: "izmYqDEY6kl7Sg" },
{ input: "eabGF/ps%UK=uWHXGh6FR4", expected: "LACmqlhaBpiPlgE-a" },
], ],
sig: [ sig: [
{ {
input: input:
"gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", "NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz",
expected: expected:
"ttJC2JfQdSswRAIgGBCxZyAfKyi0cjXCb3gqEctUw-NYdNmOEvaepit0zJAtIEsgOV2SXZjhSHMNy0NXNG_1kNyBf6HPuAuCduh-a7O", "NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hzMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzl",
},
{
input:
"\x00\x01\x02%\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49",
expected:
"\x00\x01\x02%\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x40\x41\x42\x49\x44\x45\x46\x47\x48\x43",
}, },
], ],
}, },
{ {
player: "5ec65609", // 20523
n: [{ input: "0eRGgQWJGfT5rFHFj", expected: "4SvMpDQH-vBJCw" }], player: "901741ab",
n: [{ input: "BQoJvGBkC2nj1ZZLK-", expected: "UMPovvBZRh-sjb" }],
sig: [ sig: [
{ {
input: input:
"AAJAJfQdSswRQIhAMG5SN7-cAFChdrE7tLA6grH0rTMICA1mmDc0HoXgW3CAiAQQ4=CspfaF_vt82XH5yewvqcuEkvzeTsbRuHssRMyJQ=I", "NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz",
expected: expected:
"AJfQdSswRQIhAMG5SN7-cAFChdrE7tLA6grI0rTMICA1mmDc0HoXgW3CAiAQQ4HCspfaF_vt82XH5yewvqcuEkvzeTsbRuHssRMyJQ==", "wgwCHlydB9Hg7PMegXoVzaoAXXB8woPSNZqRUC3Pe7vAEiApVSCMlhwmt5ON-8MB=5RPyyzdAM9MPM-kPfjgTxEK0IAhIgRwE0jiEJA",
}, },
], ],
}, },
{ {
player: "6742b2b9", // 20524
n: [ player: "e7573094",
{ input: "_HPB-7GFg1VTkn9u", expected: "qUAsPryAO_ByYg" }, n: [{ input: "IlLiA21ny7gqA2m4p37", expected: "3KuQ3235dojTSjo4" }],
{ input: "K1t_fcB6phzuq2SF", expected: "Y7PcOt3VE62mog" },
],
sig: [ sig: [
{ {
input: input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA", "NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz",
expected: expected:
"AJfQdSswRAIgMVVvrovTbw6UNh99kPa4D_XQjGT4qYu7S6SHM8EjoCACIEQnz-nKN5RgG6iUTnNJC58csYPSrnS_SzricuUMJZGM", "yEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyNPRt=BM8-XO5tm5hlMCSVNAiEAvpeP3CURqZJSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=g",
}, },
], ],
}, },
{ {
player: "23ccdd25", // 20525
n: [ player: "9fcf08e8",
// Synthetic test n: [{ input: "4JRSxxN0E_fLVnxmd", expected: "xhAoMP8xPcR5wg" }],
{ input: "0eRGgQWJGfT5rFHFj", expected: "orSsTqUaUO-j" },
],
sig: [ sig: [
// Synthetic test
{ {
input: input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA", "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a",
expected: expected:
"ZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hAU6wbTvorvVVMgIARwsSdQfJAN", "\x6a\x69\x68\x67\x66\x65\x64\x63\x62\x61\x60\x5f\x5e\x5d\x5c\x5b\x5a\x59\x58\x57\x56\x55\x54\x53\x52\x51\x50\x4f\x4e\x4d\x4c\x4b\x4a\x49\x48\x47\x46\x45\x44\x43\x42\x41\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39\x38\x37\x36\x35\x34\x33\x32\x31\x30\x2f\x2e\x2d\x2c\x2b\x2a\x29\x28\x27\x26\x25\x24\x23\x22\x21\x20\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18\x17\x16\x15\x14\x13\x12\x11\x10\x0f\x0e\x0d\x0c\x0b\x03\x09\x08\x07\x06\x05\x04\x0a",
}, },
], ],
}, },
{ {
player: "3597727b", // 20527
n: [ player: "21cd2156",
// Synthetic test n: [{ input: "16EF3jx-Mr_TLuGH", expected: "OQJDc7IrlWCkfg" }],
{ input: "0eRGgQWJGfT5rFHFj", expected: "PRwo5dDfisg0ejA2" },
],
sig: [ sig: [
// Synthetic test
{ {
input: input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA", "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a",
expected: expected:
"AAJfQdSswRAIgMVVvrovTbw6UNh99kPa4D_XQjGT4qYuMS6SHM8Ej7CACIEQnz-nKN5RgG6iUTnNJC58csYPSroS_SzricuUMJZG", "\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x00\x46\x47\x48\x49\x4a\x4b\x6a\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x4c",
}, },
], ],
}, },
{ {
// tce causes exception even in browser // 20528 (tv & tv_es6 needed self.location.origin fix)
player: "3752a005", player: "76ad2fe8",
variants: ["main", "tcc", "es5", "es6", "tv", "tv_es6", "phone"], n: [{ input: "V8pdMGD0Sz_M0DRT", expected: "rBnTGCWGFpwByA" }],
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "j22ZtsqVsR0Dn" },
],
sig: [ sig: [
// Synthetic test
{ {
input: input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA", "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a",
expected: expected:
"ZJM_ucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHG6S7uYq4TGjQXSD4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA", "\x46\x66\x65\x64\x63\x62\x61\x60\x5f\x5e\x67\x6a\x5b\x5a\x59\x58\x57\x56\x55\x54\x53\x52\x51\x50\x4f\x4e\x4d\x4c\x4b\x4a\x49\x48\x47\x2c\x45\x44\x43\x42\x41\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39\x38\x13\x36\x35\x34\x33\x32\x31\x30\x2f\x2e\x2d\x5d\x2b\x2a\x29\x28\x27\x26\x25\x24\x23\x22\x21\x20\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18\x17\x16\x15\x14\x0c\x12\x11\x10\x0f\x0e\x0d\x00\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x37",
}, },
], ],
}, },
{ {
// tce causes exception even in browser // 20529 (tv & tv_es6 needed self.location.origin fix)
player: "afc7785b", player: "631d3938",
variants: ["main", "tcc", "es5", "es6", "tv", "tv_es6", "phone"], n: [{ input: "KBx1qz7jMhxELa8c", expected: "ttPvh7WIptsgSw" }],
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "j22ZtsqVsR0Dn" },
],
sig: [ sig: [
// Synthetic test
{ {
input: input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA", "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66",
expected: expected:
"ZJM_ucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHG6S7uYq4TGjQXSD4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA", "\x19\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x00\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63",
},
],
},
{
// tce causes exception even in browser
player: "b9645327",
variants: ["main", "tcc", "es5", "es6", "tv", "tv_es6", "phone"],
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "j22ZtsqVsR0Dn" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
expected:
"ZJM_ucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHG6S7uYq4TGjQXSD4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
},
],
},
{
// tce causes exception even in browser
player: "035b9195",
variants: ["main", "tcc", "es5", "es6", "tv", "tv_es6", "phone"],
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "j22ZtsqVsR0Dn" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
expected:
"ZJM_ucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHG6S7uYq4TGjQXSD4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
},
],
},
{
player: "6740c111",
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "AVsXYE0uE1k8e" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
expected:
"JfQdSswRAIgMVVvrovTbw6UNh99kPa4D_XQjGT4qYu7S6SHM8EjoCACIEQnz-MKN5RgG6iUTnNJC58csYPSrnS_SzricuUMJZGn",
},
],
},
{
player: "f6a4f3bc",
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "H1NKYFbhlqZ" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
expected:
"JfQdSswRAIgMVVvrovTbw6UNh99kPa4D_XQjGT4qYM7S6SHM8EjoCACIEQnz-nKM5RgG6iUTnNJC58cNYPSrnS_SzricuUMJZGu",
},
],
},
{
player: "b66835e2",
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "H1NKYFbhlqZ" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
expected:
"JfQdSswRAIgMVVvrovTbw6UNh99kPa4D_XQjGT4qYM7S6SHM8EjoCACIEQnz-nKM5RgG6iUTnNJC58cNYPSrnS_SzricuUMJZGu",
},
],
},
{
player: "4f8fa943",
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "JWWr7hDSRpMq5" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
expected:
"AAJfQdSswRAIgMVVvrovTbw6UNh99kPa4D_XQjGT4qYu7S6SHr8EjoCACIEQnz-nKN5RgG6iUTnNZC58csYPSMnS_SzricuUM",
},
],
},
{
player: "0004de42",
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "OPd7UEsCDmCw4qD0" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJAA",
expected:
"ZJMUucirzS_SnrSPYsc85MJNnTUi6GgR5NCn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQ",
},
],
},
{
player: "2b83d2e0",
n: [
// Synthetic test
{ input: "0eRGgQWJGfT5rFHFj", expected: "euHbygrCMLksxd" },
],
sig: [
// Synthetic test
{
input:
"MMGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKn-znQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJA",
expected:
"-MGZJMUucirzS_SnrSPYsc85CJNnTUi6GgR5NKnMznQEICACojE8MHS6S7uYq4TGjQX_D4aPk99hNU6wbTvorvVVMgIARwsSdQfJ",
},
],
},
{
player: "638ec5c6",
n: [
// Synthetic test
{ input: "ZdZIqFPQK-Ty8wId", expected: "1qov8-KM-yH" },
],
sig: [
// Synthetic test
{
input:
"gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt",
expected:
"MhudCuAuP-6fByOk1_GNXN7gNHHShjyXS2VOgsEItAJz0tipeav0OmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt",
},
],
},
{
player: "87644c66",
n: [
// Synthetic test
{ input: "ZdZIqFPQK-Ty8wId", expected: "iF5NxEm1BYk" },
],
sig: [
// Synthetic test
{
input:
"gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt",
expected:
"atJC2JfQdSswRAtgGBCxZyAfKyi0cjXCb3DqEctUw-NYdNmOEvIepit0zJAtIEsgOV2SXZjhSHMNy0NXNG_1kOyBf6HPuAuCduh-a7Ng",
},
],
},
{
// tce variant broke sig solving; n and other variants are added only for regression testing
player: "c1c87fb0",
n: [
// Synthetic test
{ input: "ZdZIqFPQK-Ty8wId", expected: "jCHBK5GuAFNa2" },
],
sig: [
// Synthetic test
{
input:
"gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt",
expected:
"ttJC2JfQdSswRAIgGBCxZyAfKyi0cjXCb3DqEctUw-NYdNmOEvaepit0zJAtIEsgOV2SXZjhSHMNy0NXNGa1kOyBf6HPuAuCduh-_",
}, },
], ],
}, },
@@ -306,11 +116,12 @@ export const players = new Map([
["main", "player_ias.vflset/en_US/base.js"], ["main", "player_ias.vflset/en_US/base.js"],
["tcc", "player_ias_tcc.vflset/en_US/base.js"], ["tcc", "player_ias_tcc.vflset/en_US/base.js"],
["tce", "player_ias_tce.vflset/en_US/base.js"], ["tce", "player_ias_tce.vflset/en_US/base.js"],
["es5", "player_es5.vflset/en_US/base.js"],
["es6", "player_es6.vflset/en_US/base.js"], ["es6", "player_es6.vflset/en_US/base.js"],
["tv", "tv-player-ias.vflset/tv-player-ias.js"], ["tv", "tv-player-ias.vflset/tv-player-ias.js"],
["tv_es6", "tv-player-es6.vflset/tv-player-es6.js"], ["tv_es6", "tv-player-es6.vflset/tv-player-es6.js"],
["phone", "player-plasma-ias-phone-en_US.vflset/base.js"], ["phone", "player-plasma-ias-phone-en_US.vflset/base.js"],
["es6_tcc", "player_es6_tcc.vflset/en_US/base.js"],
["es6_tce", "player_es6_tce.vflset/en_US/base.js"],
] as const); ] as const);
export type Variant = typeof players extends Map<infer T, unknown> ? T : never; export type Variant = typeof players extends Map<infer T, unknown> ? T : never;

View File

@@ -1,5 +1,26 @@
import { type Variant } from "./tests.ts"; import { getIO } from "./io.ts";
import { players, type Variant } from "./tests.ts";
export function getCachePath(player: string, variant: Variant) { export function getCachePath(player: string, variant: Variant) {
return `src/yt/solver/test/players/${player}-${variant}`; return `src/yt/solver/test/players/${player}-${variant}`;
} }
export async function downloadCached(player: string, variant: string) {
const io = await getIO();
const playerPath = players.get(variant as Variant);
if (!playerPath) {
throw `Invalid player variant: ${variant}`;
}
const path = getCachePath(player, variant as Variant);
if (!(await io.exists(path))) {
const url = `https://www.youtube.com/s/player/${player}/${playerPath}`;
console.log("Requesting", url);
const response = await fetch(url);
if (!response.ok) {
throw `Failed to request ${variant} player for ${player}`;
}
await io.write(path, response);
}
return await io.read(path);
}