diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml new file mode 100644 index 00000000..fc2ddf70 --- /dev/null +++ b/.github/workflows/create-release-pr.yml @@ -0,0 +1,137 @@ +name: create-release-pr +run-name: create-release-pr +description: | + Create a release PR for a project in the repository + +on: + workflow_dispatch: + inputs: + version: + type: string + required: true + description: | + Version to prep for release (ex. `0.1.0`, `0.1.0-rc.0`) + +permissions: + contents: none + +jobs: + create-release-pr: + runs-on: ubuntu-24.04 + permissions: + id-token: write + pull-requests: write + contents: write + issues: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + # Install Rust deps + - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 + - uses: taiki-e/cache-cargo-install-action@5c9abe9a3f79d831011df7c47177debbeb320405 # v2.1.2 + with: + tool: git-cliff + + - name: Cache npm install + id: cache-node-modules + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + key: node-modules-dev-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package.json') }} + path: | + node_modules + + - name: Install debug NPM packages + run: | + npm install -D + + - name: Gather project metadata + id: project-meta + env: + NEXT_VERSION: ${{ inputs.version }} + shell: bash + run: | + if [[ $NEXT_VERSION == v* ]]; then + echo "::error::next version [$NEXT_VERSION] starts with 'v' -- enter only the semver version (ex. '0.1.0', not 'v0.1.0')"; + exit 1; + fi + + export PROJECT_DIR=$PWD; + export CURRENT_VERSION=$(node -e "process.stdout.write(require(process.env.PROJECT_DIR + '/package.json').version)"); + + echo -e "project-dir=$PROJECT_DIR" + echo -e "current-version=$CURRENT_VERSION" + echo -e "next-version=$NEXT_VERSION" + + echo -e "project-dir=$PROJECT_DIR" >> $GITHUB_OUTPUT + echo -e "current-version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo -e "next-version=$NEXT_VERSION" >> $GITHUB_OUTPUT + + - name: Ensure next version is after current + run: | + IS_AFTER=$(node scripts/semver-lt.mjs ${{ steps.project-meta.outputs.current-version }} ${{ steps.project-meta.outputs.next-version }}); + if [ "$IS_AFTER" == "false" ]; then \ + echo "::error::project [componentize-js] next version [${{ steps.project-meta.outputs.next-version }}] is not after current version [${{ steps.project-meta.outputs.current-version }}]"; + exit 1; + fi + + # Set project version + - name: Set project version + working-directory: ${{ steps.project-meta.outputs.project-dir }} + shell: bash + run: | + npm pkg set version=${{ steps.project-meta.outputs.next-version }}; + sed -i \ + "s/version('${{ steps.project-meta.outputs.current-version }}')/version('${{ steps.project-meta.outputs.next-version }}')/" \ + src/cli.js; + + # Generate changelog + # + # NOTE: we use the 'latest' tag here, because starting from an rc/alpha/beta release + # the rc/alpha/beta release tags are ignored and the "latest" tag is the previous stable version + - name: Generate changelog + working-directory: ${{ steps.project-meta.outputs.project-dir }} + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }} + run: | + export IS_PRERELEASE=$(node scripts/semver-is-prerelease.mjs ${{ steps.project-meta.outputs.next-version }}); + + export OPT_TAG=--tag=${{ steps.project-meta.outputs.next-version }}; + + export OPT_TAG_PATTERN=--tag-pattern='^[0-9]+.[0-9]+.[0-9]+$'; + if [ "true" == "$IS_PRERELEASE" ]; then + export OPT_TAG_PATTERN=--tag-pattern='^[0-9]+.[0-9]+.[0-9]+(-beta|-rc|-alpha)?'; + fi + + git cliff \ + --repository=${{ github.workspace }}/.git \ + --config=./cliff.toml \ + --unreleased \ + $OPT_TAG \ + $OPT_TAG_PATTERN \ + --prepend=CHANGELOG.md + + # Create release PR + - name: Create release prep PR + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + with: + branch: prep-release-v${{ steps.project-meta.outputs.next-version }} + token: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }} + commit-message: | + release: componentize-js v${{ steps.project-meta.outputs.next-version }} + title: | + release: componentize-js v${{ steps.project-meta.outputs.next-version }} + labels: | + release-pr + assignees: >- + vados-cosmonic, + tschneidereit + signoff: true + body: | + This is a release prep branch for `componentize-js` release `v${{ steps.project-meta.outputs.next-version }}`. + + To ensure this release is ready to be merged: + - [ ] Review updated CHANGELOG(s) + + After this PR is merged tagging, artifact builds and releasing will run automatically. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 28576625..c93d6fb9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,9 +2,12 @@ name: CI on: push: - branches: [main] + branches: + - main pull_request: - branches: [main] + branches: + - main + defaults: run: shell: bash @@ -15,6 +18,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true + jobs: lint: runs-on: ubuntu-latest @@ -25,15 +29,29 @@ jobs: rustup update stable rustup default stable rustup component add rustfmt + - name: Format source code run: cargo fmt -- --check + - name: Run clippy + run: cargo clippy --workspace --all-targets --all-features + ######### # Build # ######### build-splicer: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + node-version: + - '24.10.0' + rust-version: + - 'stable' + os: + - windows-latest + - ubuntu-latest + - macos-latest steps: - uses: actions/checkout@v4 @@ -41,7 +59,7 @@ jobs: uses: actions/cache@v4 id: splicer-build with: - key: splicer-${{ hashFiles('Cargo.lock', 'crates/spidermonkey-embedding-splicer/src/**/*.rs') }} + key: splicer-${{ matrix.os }}-${{ hashFiles('Cargo.lock', 'crates/spidermonkey-embedding-splicer/src/**/*.rs') }} path: | lib target @@ -49,14 +67,14 @@ jobs: - name: Install Rust Toolchain if: steps.splicer-build.outputs.cache-hit != 'true' run: | - rustup toolchain install 1.80.0 - rustup target add wasm32-wasip1 --toolchain 1.80.0 + rustup toolchain install ${{ matrix.rust-version }} + rustup target add wasm32-wasip1 --toolchain ${{ matrix.rust-version }} rustup target add wasm32-wasip1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 if: steps.splicer-build.outputs.cache-hit != 'true' with: - node-version: '23.10.0' + node-version: ${{ matrix.node-version }} - name: Install NPM packages if: steps.splicer-build.outputs.cache-hit != 'true' @@ -67,16 +85,23 @@ jobs: run: make lib/spidermonkey-embedding-splicer.js build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} needs: - build-splicer strategy: fail-fast: false matrix: + node-version: + - '24.10.0' + rust-version: + - 'stable' + os: + # NOTE: at present the build does *not* work on windows. Required binaries are built here + # (only on linux) and reused in later steps + - ubuntu-latest build-type: - 'release' - 'debug' - - 'weval' steps: - uses: actions/checkout@v4 with: @@ -95,8 +120,8 @@ jobs: - name: Install Rust Toolchain if: steps.starlingmonkey-build.outputs.cache-hit != 'true' run: | - rustup toolchain install 1.80.0 - rustup target add wasm32-wasip1 --toolchain 1.80.0 + rustup toolchain install ${{ matrix.rust-version }} + rustup target add wasm32-wasip1 --toolchain ${{ matrix.rust-version }} rustup target add wasm32-wasip1 - name: Install wasm-tools @@ -107,15 +132,15 @@ jobs: uses: actions/cache/restore@v4 id: splicer-build with: - key: splicer-${{ hashFiles('Cargo.lock', 'crates/spidermonkey-embedding-splicer/src/**/*.rs') }} + key: splicer-${{ matrix.os }}-${{ hashFiles('Cargo.lock', 'crates/spidermonkey-embedding-splicer/src/**/*.rs') }} path: | lib target - - uses: actions/setup-node@v4 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 if: steps.starlingmonkey-build.outputs.cache-hit != 'true' with: - node-version: '23.10.0' + node-version: ${{ matrix.node-version }} - name: Install NPM packages if: steps.starlingmonkey-build.outputs.cache-hit != 'true' @@ -139,8 +164,8 @@ jobs: fail-fast: false matrix: node-version: - - '23.10.0' - # - latest reenable when https://github.com/nodejs/node/issues/57172 is fixed + - '24.10.0' + - latest # reenable when https://github.com/nodejs/node/issues/57172 is fixed os: - ubuntu-latest - windows-latest @@ -148,7 +173,6 @@ jobs: build-type: - 'release' - 'debug' - - 'weval' steps: - uses: actions/checkout@v4 @@ -164,7 +188,16 @@ jobs: key: starlingmonkey-${{matrix.build-type}}-${{ steps.starlingmonkey-commit.outputs.STARLINGMONKEY_HASH }} path: lib - - uses: actions/setup-node@v4 + - name: Restore Embedding Splicer from cache + uses: actions/cache/restore@v4 + id: splicer-build + with: + key: splicer-${{ matrix.os }}-${{ hashFiles('Cargo.lock', 'crates/spidermonkey-embedding-splicer/src/**/*.rs') }} + path: | + lib + target + + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: ${{matrix.node-version}} @@ -172,12 +205,19 @@ jobs: run: npm install - name: Test - run: npm run test:${{matrix.build-type}} + run: | + npm run test:${{matrix.build-type}} test-example: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} needs: - build + strategy: + matrix: + node-version: + - '24.10.0' + os: + - ubuntu-latest steps: - uses: actions/checkout@v4 @@ -192,9 +232,18 @@ jobs: key: starlingmonkey-release-${{ steps.starlingmonkey-commit.outputs.STARLINGMONKEY_HASH }} path: lib - - uses: actions/setup-node@v4 + - name: Restore Embedding Splicer from cache + uses: actions/cache/restore@v4 + id: splicer-build + with: + key: splicer-${{ matrix.os }}-${{ hashFiles('Cargo.lock', 'crates/spidermonkey-embedding-splicer/src/**/*.rs') }} + path: | + lib + target + + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: - node-version: '23.10.0' + node-version: ${{ matrix.node-version }} - name: Install NPM packages run: npm install @@ -203,8 +252,8 @@ jobs: uses: actions/cache@v4 with: path: 'examples/hello-world/host/target/release/wasmtime-test*' - key: example-hello-world-cargo-${{ hashFiles('examples/hello-world/host/src/main.rs', - 'examples/hello-world/host/Cargo.lock', + key: example-hello-world-cargo-${{ hashFiles('examples/hello-world/host/src/main.rs', + 'examples/hello-world/host/Cargo.lock', 'examples/hello-world/guest/hello.wit') }} - name: Test Example diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..7fbe146e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,288 @@ +name: release +run-name: release + +on: + push: + # NOTE: pushes from CI without a PAT will not trigger the tags below + tags: + - "[0-9]+.[0-9]+.[0-9]+*" + - "[0-9]+.[0-9]+.[0-9]+-*" + branches: + - "prep-release-v[0-9]+.[0-9]+.[0-9]+*" + - "prep-release-v[0-9]+.[0-9]+.[0-9]+-*" + + workflow_dispatch: + inputs: + version: + type: string + required: true + description: | + Version tag to release (e.x. `0.1.0`, `0.2.0`) + +permissions: + contents: none + +jobs: + meta: + runs-on: ubuntu-24.04 + outputs: + version: ${{ steps.meta.outputs.version }} + project-dir: ${{ steps.project-meta.outputs.project-dir }} + artifacts-glob: ${{ steps.project-meta.outputs.artifacts-glob }} + artifact-name: ${{ steps.project-meta.outputs.artifact-name }} + next-release-tag: ${{ steps.project-meta.outputs.next-release-tag }} + is-prerelease: ${{ steps.project-meta.outputs.is-prerelease }} + prerelease-tag: ${{ steps.project-meta.outputs.prerelease-tag }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: ">=22" + + - name: Cache npm install + id: cache-node-modules + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + key: node-modules-dev-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package-lock.json') }} + path: | + node_modules + - name: Install debug NPM packages + run: | + npm install -D + + - name: Collect metadata + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: meta + with: + script: | + if (context.payload.inputs?.version) { + core.setOutput('version', context.payload.inputs.version); + return; + } + + if (context.ref.startsWith('refs/tags/')) { + match = context.ref.replace('refs/tags/', '').match(/^([^\s]+)$/); + } else if (context.ref.startsWith('refs/heads/')) { + match = context.ref.replace('refs/heads/', '').match(/^prep-release-v([^\s]+)$/); + } else { + throw new Error(`Unexpected context ref [${context.ref}]`); + } + if (!match) { throw new Error(`Failed to parse tag/branch: [${context.ref}]`); } + const [_, version] = match; + core.setOutput('version', version); + + - name: Gather project metadata + id: project-meta + env: + NEXT_VERSION: ${{ steps.meta.outputs.version }} + shell: bash + run: | + if [[ $NEXT_VERSION == v* ]]; then + echo "::error::next version [$NEXT_VERSION] starts with 'v' -- enter only the semver version (ex. '0.1.0', not 'v0.1.0')"; + exit 1; + fi + + export PROJECT_DIR=$PWD; + export CURRENT_VERSION=$(node -e "process.stdout.write(require(process.env.PROJECT_DIR + '/package.json').version)"); + export ARTIFACTS_GLOB="bytecodealliance-componentize-js-*.tgz"; + export ARTIFACT_NAME="bytecodealliance-componentize-js-$NEXT_VERSION.tgz"; + + echo -e "project-dir=$PROJECT_DIR" >> $GITHUB_OUTPUT; + echo -e "artifacts-glob=$ARTIFACTS_GLOB" >> $GITHUB_OUTPUT; + echo -e "artifact-name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT; + echo -e "next-release-tag=${NEXT_VERSION}" >> $GITHUB_OUTPUT; + + export IS_PRERELEASE=$(node scripts/semver-is-prerelease.mjs $NEXT_VERSION); + echo -e "is-prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT; + export PRERELEASE_TAG=$(node scripts/semver-get-prerelease.mjs $NEXT_VERSION); + echo -e "prerelease-tag=$PRERELEASE_TAG" >> $GITHUB_OUTPUT; + + pack-npm-release: + runs-on: ubuntu-24.04 + needs: + - meta + strategy: + matrix: + rust-version: + - stable + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + submodules: recursive + + - name: Get StarlingMonkey Commit + id: starlingmonkey-commit + run: echo "STARLINGMONKEY_HASH=$(git submodule status | head -c9 | tail -c8)" >> "$GITHUB_OUTPUT" + + - name: Install Rust Toolchain + run: | + rustup toolchain install ${{ matrix.rust-version }} + rustup target add wasm32-wasip1 --toolchain ${{ matrix.rust-version }} + rustup target add wasm32-wasip1 + + # NOTE: we must use a node version new-enough to have --experimental-wasm-jspi + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: ">=22" + + - name: Cache npm install + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package-lock.json') }} + path: | + node_modules + + - name: Install NPM packages + run: | + npm install + + - name: Create release package + working-directory: ${{ needs.meta.outputs.project-dir }} + run: | + npm pack + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + if-no-files-found: error + path: | + ${{ needs.meta.outputs.artifact-name }} + + test-npm-release: + runs-on: ubuntu-24.04 + needs: + - meta + - pack-npm-release + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: artifacts + + - name: Test built componentize-js NPM package + shell: bash + run: | + export PACKAGE_FILE_PATH=${{ github.workspace }}/artifacts/artifact/${{ needs.meta.outputs.artifact-name }} + cp -r examples/hello-world/guest /tmp/test + cd /tmp/test + npm install --save $PACKAGE_FILE_PATH + npm run all + + npm-publish: + runs-on: ubuntu-24.04 + needs: + - meta + - test-npm-release + permissions: + id-token: write + env: + PREPACK_SKIP_BUILD: "true" + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: ">=22" + + - name: Add npmrc + run: | + echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc + + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: artifacts + + - name: Publish componentize-js to NPM + env: + NPM_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + shell: bash + run: | + export PACKAGE_FILE_PATH=${{ github.workspace }}/artifacts/artifact/${{ needs.meta.outputs.artifact-name }} + + export OPT_DRY_RUN="--dry-run" + if [ "tag" == "${{ github.ref_type }}" ]; then + export OPT_DRY_RUN=""; + fi + + export OPT_RELEASE_TAG="" + if [ "true" == "${{ needs.meta.outputs.is-prerelease }}" ]; then + export OPT_RELEASE_TAG="--tag ${{ needs.meta.outputs.prerelease-tag }}"; + fi + + npm publish \ + --verbose \ + -w @bytecodealliance/componentize-js \ + --access=public \ + --provenance \ + $OPT_DRY_RUN \ + $OPT_RELEASE_TAG \ + $PACKAGE_FILE_PATH + + create-gh-release: + runs-on: ubuntu-24.04 + if: always() + needs: + - meta + - test-npm-release + - npm-publish + permissions: + contents: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - uses: taiki-e/install-action@2cab843126c0d8cf950bf55f4e9b8413f70f553f # v2.54.1 + with: + fallback: none + tool: git-cliff + + # Re-generate the current changelog so we can use it in the GH release announcement + # + # NOTE: if this workflow is being run due to a tag push, that's an *already committed* release + # tag and likely the one corresponding to this release, so we use the latest + # + - name: Re-generate current changelog + working-directory: ${{ needs.meta.outputs.project-dir }} + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }} + GITHUB_REPO: ${{ github.repository }} + run: | + export OPT_START=--unreleased; + export OPT_TAG=; + if [ "tag" == "${{ github.ref_type }}" ]; then + export OPT_START=--current; + export OPT_TAG=--tag=${{ needs.meta.outputs.next-release-tag }}; + fi + + export OPT_TAG_PATTERN=--tag-pattern='^[0-9]+.[0-9]+.[0-9]+$'; + if [ "true" == "${{ needs.meta.outputs.is-prerelease }}" ]; then + export OPT_TAG_PATTERN=--tag-pattern='^[0-9]+.[0-9]+.[0-9]+(-beta|-rc|-alpha)?'; + fi + + git cliff \ + --repository=${{ github.workspace }}/.git \ + --config=./cliff.toml \ + $OPT_START \ + $OPT_TAG \ + $OPT_TAG_PATTERN \ + > CHANGELOG.current; + + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: artifacts + + - name: Create GH release + uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2 + with: + token: ${{ secrets.RELEASE_PAT || github.token }} + prerelease: ${{ github.ref_type != 'tag' || needs.meta.outputs.is-prerelease == 'true' }} + draft: ${{ github.ref_type != 'tag' }} + tag_name: ${{ needs.meta.outputs.next-release-tag }} + generate_release_notes: false + make_latest: ${{ github.ref_type == 'tag' && needs.meta.outputs.is-prerelease == 'false' }} + body_path: ${{ needs.meta.outputs.project-dir }}/CHANGELOG.current + files: | + ./artifacts/*/* diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml new file mode 100644 index 00000000..6bd75ece --- /dev/null +++ b/.github/workflows/tag-release.yml @@ -0,0 +1,92 @@ +name: tag-release +run-name: tag-release +description: | + Tag a given commit as a release + +on: + merge_group: + pull_request: + types: + - closed + + workflow_dispatch: + inputs: + ref: + type: string + required: true + description: | + Repository ref to tag (e.x. 'branch', '0.1.0', '') + + version: + type: string + required: true + description: | + Version tag (e.x. `0.1.0`) + +permissions: + contents: none + +jobs: + tag-release: + runs-on: ubuntu-24.04 + if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged }} + permissions: + contents: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + ref: ${{ github.event.inputs.ref || 'main' }} + token: ${{ secrets.RELEASE_PAT || github.token }} + + - name: Collect metadata + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: meta + with: + script: | + switch (context.eventName) { + case 'pull_request': + const pr = context?.payload?.pull_request; + if (!pr) { + throw new Error("Invalid/missing pull request payload"); + return; + } + console.log(`sha: [${pr.merge_commit_sha}]`); + const headMerged = pr.merged; + const numCommits = pr.commits.len; + const title = pr.title; + + if (!headMerged) { + console.log("Invalid/unexpected pull request event type (must be merged)"); + return; + } + + if (!title?.startsWith("release:")) { + console.log(`Invalid ref [${title}]: does not include 'prep-release'`); + return; + } + + const [_, _project, version] = /^release:\s+([^\s]+)\s+v([^\s]+)$/.exec(title); + + core.setOutput('proceed', "true"); + core.setOutput('version', version); + return; + case 'workflow_dispatch': + core.setOutput('proceed', "true"); + core.setOutput('version', context.payload.inputs.version); + return; + default: + console.log(`unexpected github event name [${context.eventName}]`); + return; + } + + - name: Push tag + if: ${{ steps.meta.outputs.proceed }} + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }} + run: | + git config user.name "github-actions[bot]"; + git config user.email "github-actions[bot]@users.noreply.github.com"; + export TAG=${{ steps.meta.outputs.version }}; + git tag $TAG; + git push origin $TAG; diff --git a/.gitignore b/.gitignore index 66610a23..8823a6d9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ examples/hello-world/guest/package-lock.json examples/hello-world/guest/hello.component.wasm /build-debug /build-release -/build-release-weval .vscode /package-lock.json .idea diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..d3d43e6d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,340 @@ +# Changelog + +## [0.19.3] - 2025-10-27 + +### 🐛 Bug Fixes + +* move jco dependency back to active (#315) by @vados-cosmonic in #315 + +* *(ci)* miscellaneous improvements to CI and tests (#310) by @vados-cosmonic in #310 + +* duplicated function names for same interfaces and export (#306) by @SanderVanRiessen in #306 + + +### Other Changes + +* *(other changes)* Updated orca_wasm into wirm latest version (#300) by @EngoDev in #300 + + + +## New Contributors +* @EngoDev made their first contribution in [#300](https://github.com/bytecodealliance/ComponentizeJS/pull/300) +* @SanderVanRiessen made their first contribution in [#306](https://github.com/bytecodealliance/ComponentizeJS/pull/306) + + +## [0.19.2] - 2025-10-17 + +### 🚀 Features + +* Update StarlingMonkey to v0.2.1 (#311) by @tschneidereit in #311 + + +### 🐛 Bug Fixes + +* *(ci)* test runs on windows runner (#308) by @vados-cosmonic in #308 + +* separate folder component path use (#299) by @vados-cosmonic in #299 + +* remove shell setting for wizer call (#303) by @vados-cosmonic in #303 + +* *(ci)* temporarily downgrade windows runners from latest to 2022 (#302) by @vados-cosmonic in #302 + + + + +## [0.19.1] - 2025-09-16 + +### 🐛 Bug Fixes + +* *(ci)* set latest release when creating GH release (#294) by @vados-cosmonic in #294 + + +### Other Changes + +* *(other changes)* Fix memory leak in call() retptr allocation (#295) by @ludfjig in #295 + + + +## New Contributors +* @ludfjig made their first contribution in [#295](https://github.com/bytecodealliance/ComponentizeJS/pull/295) + + +## [0.19.0] - 2025-09-08 + +### 🐛 Bug Fixes + +* *(ops)* add catch-all for non-conventional commits (#290) by @vados-cosmonic in #290 + +* *(tests)* race condition with server random port (#288) by @vados-cosmonic in #288 + + +### Other Changes + +* *(other changes)* Update starlingmonkey to 0.2.0 (#285) by @karthik2804 in #285 + + + + +## [0.18.5] - 2025-08-28 + +### 🚀 Features + +* *(tests)* replace mocha with vitest (#277) by @vados-cosmonic in #277 + + +### 🐛 Bug Fixes + +* *(docs)* Fix typo (#280) by @Mishra-Suraj in #280 + + +### 🚜 Refactor + +* *(tests)* split up test suites, update docs (#278) by @vados-cosmonic in #278 + + +### ⚙️ Miscellaneous Tasks + +* *(deps)* update wizer to ^10.0.0 (#283) by @vados-cosmonic in #283 + + + +## New Contributors +* @Mishra-Suraj made their first contribution in [#280](https://github.com/bytecodealliance/ComponentizeJS/pull/280) + + +## [0.18.4] - 2025-07-23 + +### 🚀 Features + +* update weval to v0.3.4 (#267) by @vados-cosmonic in #267 + + +### 🐛 Bug Fixes + +* logic for stubbing outgoing http and fetch-event (#268) by @vados-cosmonic in #268 + +* reuse feature list for CLI, add 'fetch-event' (#269) by @vados-cosmonic in #269 + +* remove log during realloc (#273) by @vados-cosmonic in #273 + +* *(tests)* responseOutparam usage (#271) by @vados-cosmonic in #271 + +* *(ci)* release changelog generation (#263) by @vados-cosmonic in #263 + +* *(ci)* create rc releases as prerelease (#264) by @vados-cosmonic in #264 + + +### 🚜 Refactor + +* 'features' -> 'feature' in WIT & Rust component (#270) by @vados-cosmonic in #270 + +* *(tests)* refactor expected globals test (#262) by @vados-cosmonic in #262 + + +### ⚙️ Miscellaneous Tasks + +* update StarlingMonkey to commit 1f6f81f (#260) by @vados-cosmonic in #260 + +* *(docs)* add comments to API type in README (#261) by @vados-cosmonic in #261 + + + + +## [0.18.4-rc.1] - 2025-07-22 + +### 🚀 Features + +* update weval to v0.3.4 (#267) by @vados-cosmonic in #267 + + +### 🐛 Bug Fixes + +* logic for stubbing outgoing http and fetch-event (#268) by @vados-cosmonic in #268 + +* reuse feature list for CLI, add 'fetch-event' (#269) by @vados-cosmonic in #269 + +* remove log during realloc (#273) by @vados-cosmonic in #273 + +* *(tests)* responseOutparam usage (#271) by @vados-cosmonic in #271 + + +### 🚜 Refactor + +* 'features' -> 'feature' in WIT & Rust component (#270) by @vados-cosmonic in #270 + + + + +## [0.18.4-rc.0] - 2025-07-21 + +## Important Updates + +This release contains an update to [StarlingMonkey][sm], the engine that powers `componentize-js`. +Important new features and bugfixes from StarlingMonkey relevant to `componentize-js` that are +pulled in by this update are listed below: + +- Implement `EventTarget` and `Event` builtin ([#220](https://github.com/bytecodealliance/StarlingMonkey/pull/220)) +- Add support for two-argument `has` and `delete` in `URLSearchParams` ([#236](https://github.com/bytecodealliance/StarlingMonkey/pull/236)) + +[sm]: https://github.com/bytecodealliance/StarlingMonkey + +### 🐛 Bug Fixes + +* *(ci)* release changelog generation (#263) by @vados-cosmonic in #263 + +* *(ci)* create rc releases as prerelease (#264) by @vados-cosmonic in #264 + + +### 🚜 Refactor + +* *(tests)* refactor expected globals test (#262) by @vados-cosmonic in #262 + + +### ⚙️ Miscellaneous Tasks + +* update StarlingMonkey to commit 1f6f81f (#260) by @vados-cosmonic in #260 + +* *(docs)* add comments to API type in README (#261) by @vados-cosmonic in #261 + + + + +## [0.18.3] - 2025-07-16 + +### 🚀 Features + +* *(ci)* add release automation (#226) by @vados-cosmonic in #226 + +### 🐛 Bug Fixes + +* allow for use of both manual & fetchEvent based HTTP (#247) by @vados-cosmonic in #247 + +* makefile dep for splicer component (#251) by @vados-cosmonic in #251 + +* add repository.url to package.json (#243) by @vados-cosmonic in #243 + +* (ci) npm release artifact (#241) by @vados-cosmonic in #241 + +* (ci) NPM public access release (#239) by @vados-cosmonic in #239 + +* (ci) remove packages prefix (#232) by @vados-cosmonic in #232 + +* (ci) remove if for JS projects (#231) by @vados-cosmonic in #231 + +* (ops) add CHANGELOG.md (#229) by @vados-cosmonic in #229 + +* do not skip wasi:http export processing (#218) by @vados-cosmonic in #218 + +* (ci) use a local test server for fetch test (#207) by @vados-cosmonic in #207 + +### 🚜 Refactor + +* splicer WIT and generated bindings (#252) by @vados-cosmonic in #252 + +* componentize code (#203) by @vados-cosmonic in #203 + +* (splicer) add explicit error for invalid WIT source (#219) by @vados-cosmonic in #219 + +### ⚙️ Miscellaneous Tasks + +* *(ci)* add clippy (#248) by @vados-cosmonic in #248 + +* add CHANGELOG.md (#227) by @vados-cosmonic in #227 + +* (deps) update upstream wasm deps to *.227.1 (#204) by @vados-cosmonic in #204 + + +## [0.18.3-rc.6] - 2025-07-14 + +### 🐛 Bug Fixes + +* allow for use of both manual & fetchEvent based HTTP (#247) by @vados-cosmonic in #247 + +* makefile dep for splicer component (#251) by @vados-cosmonic in #251 + + +### 🚜 Refactor + +* splicer WIT and generated bindings (#252) by @vados-cosmonic in #252 + + +### ⚙️ Miscellaneous Tasks + +* *(ci)* add clippy (#248) by @vados-cosmonic in #248 + + + + +## [0.18.3-rc.5] - 2025-07-08 + +### 🐛 Bug Fixes + +* add repository.url to package.json (#243) by @vados-cosmonic in #243 + + + + +## [0.18.3-rc.4] - 2025-07-08 + +### 🐛 Bug Fixes + +* *(ci)* npm release artifact (#241) by @vados-cosmonic in #241 + + + + +## [0.18.3-rc.3] - 2025-07-07 + +### 🐛 Bug Fixes + +* *(ci)* NPM public access release (#239) by @vados-cosmonic in #239 + + + + +## [0.18.3-rc.2] - 2025-07-07 + + + +## [0.18.3-rc.1] - 2025-06-30 + +### 🐛 Bug Fixes + +* *(ci)* remove packages prefix (#232) by @vados-cosmonic in #232 + +* *(ci)* remove if for JS projects (#231) by @vados-cosmonic in #231 + + + + +## [0.18.3-rc.0] - 2025-06-27 + +### 🚀 Features + +* *(ci)* add release automation (#226) by @vados-cosmonic in #226 + + +### 🐛 Bug Fixes + +* *(ops)* add CHANGELOG.md (#229) by @vados-cosmonic in #229 + +* do not skip wasi:http export processing (#218) by @vados-cosmonic in #218 + +* *(ci)* use a local test server for fetch test (#207) by @vados-cosmonic in #207 + + +### 🚜 Refactor + +* componentize code (#203) by @vados-cosmonic in #203 + +* *(splicer)* add explicit error for invalid WIT source (#219) by @vados-cosmonic in #219 + + +### ⚙️ Miscellaneous Tasks + +* add CHANGELOG.md (#227) by @vados-cosmonic in #227 + +* *(deps)* update upstream wasm deps to *.227.1 (#204) by @vados-cosmonic in #204 + + +## [0.18.2] - 2025-04-09 diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e21e105..7b1fb059 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,14 +26,10 @@ set(EMBEDDING_DEP "starling-raw.wasm") # Define output filenames based on build configuration set(OUTPUT_NAME_RELEASE "starlingmonkey_embedding.wasm") set(OUTPUT_NAME_DEBUG "starlingmonkey_embedding.debug.wasm") -set(OUTPUT_NAME_WEVAL "starlingmonkey_embedding_weval.wasm") # Set the appropriate name based on current configuration if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") set(OUTPUT_FILENAME ${OUTPUT_NAME_DEBUG}) -elseif(WEVAL) - set(OUTPUT_FILENAME ${OUTPUT_NAME_WEVAL}) - set(EMBEDDING_DEP "starling-ics.wevalcache") else() set(OUTPUT_FILENAME ${OUTPUT_NAME_RELEASE}) endif() diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..9ca38d9e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @tschneidereit @vados-cosmonic diff --git a/Cargo.lock b/Cargo.lock index c7050301..fcc90796 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "anstream" version = "0.6.18" @@ -58,6 +64,18 @@ version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +[[package]] +name = "auditable-serde" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7bf8143dfc3c0258df908843e169b5cc5fcf76c7718bd66135ef4a9cd558c5" +dependencies = [ + "semver", + "serde", + "serde_json", + "topological-sort", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -142,9 +160,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "cranelift-bitset" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573c641174c40ef31021ae4a5a3ad78974e280633502d0dfc6e362385e0c100f" +checksum = "b265bed7c51e1921fdae6419791d31af77d33662ee56d7b0fa0704dc8d231cab" dependencies = [ "serde", "serde_derive", @@ -152,9 +170,9 @@ dependencies = [ [[package]] name = "cranelift-entity" -version = "0.117.2" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0fd6d4aae680275fcbceb08683416b744e65c8b607352043d3f0951d72b3b2" +checksum = "0c2c67d95507c51b4a1ff3f3555fe4bfec36b9e13c1b684ccc602736f5d5f4a2" dependencies = [ "cranelift-bitset", "serde", @@ -209,18 +227,22 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "flate2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "foldhash" version = "0.1.4" @@ -343,9 +365,7 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ - "fallible-iterator", "indexmap", - "stable_deref_trait", ] [[package]] @@ -534,29 +554,23 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-component-bindgen" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18372544112a99025288113017b9a57897b7c26837116edb5463a3662b8592e2" +checksum = "6a4e7f0ba445896fbec0f2294c213c889bd0e73ed65b11e00662c6cb70e6156d" dependencies = [ "anyhow", "base64", "heck", "log", "semver", - "wasm-encoder 0.225.0", - "wasmparser 0.225.0", + "wasm-encoder 0.227.1", + "wasmparser 0.227.1", "wasmtime-environ", "wit-bindgen-core", "wit-component", "wit-parser", ] -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -593,6 +607,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miniz_oxide" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +dependencies = [ + "adler2", +] + [[package]] name = "object" version = "0.36.7" @@ -611,20 +634,6 @@ version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" -[[package]] -name = "orca-wasm" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46eaa8a677bb315786f1464efcc76c9bffcd5bcb270898a55876dcee51907c98" -dependencies = [ - "gimli", - "log", - "serde_json", - "tempfile", - "wasm-encoder 0.224.1", - "wasmparser 0.224.1", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -683,6 +692,21 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + [[package]] name = "rustix" version = "1.0.2" @@ -778,9 +802,11 @@ dependencies = [ "clap", "heck", "js-component-bindgen", - "orca-wasm", - "wasm-encoder 0.225.0", - "wasmparser 0.224.1", + "rand", + "serde_json", + "wasm-encoder 0.227.1", + "wasmparser 0.239.0", + "wirm", "wit-bindgen", "wit-bindgen-core", "wit-component", @@ -867,6 +893,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "topological-sort" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -925,56 +957,58 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.224.1" +version = "0.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab7a13a23790fe91ea4eb7526a1f3131001d874e3e00c2976c48861f2e82920" +checksum = "f7d81b727619aec227dce83e7f7420d4e56c79acd044642a356ea045b98d4e13" dependencies = [ - "leb128", - "wasmparser 0.224.1", + "leb128fmt", + "wasmparser 0.226.0", ] [[package]] name = "wasm-encoder" -version = "0.225.0" +version = "0.227.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f7eac0445cac73bcf09e6a97f83248d64356dccf9f2b100199769b6b42464e5" +checksum = "80bb72f02e7fbf07183443b27b0f3d4144abf8c114189f2e088ed95b696a7822" dependencies = [ "leb128fmt", - "wasmparser 0.225.0", + "wasmparser 0.227.1", ] [[package]] name = "wasm-encoder" -version = "0.227.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bb72f02e7fbf07183443b27b0f3d4144abf8c114189f2e088ed95b696a7822" +checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" dependencies = [ "leb128fmt", - "wasmparser 0.227.1", + "wasmparser 0.239.0", ] [[package]] name = "wasm-metadata" -version = "0.225.0" +version = "0.227.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d20d0bf2c73c32a5114cf35a5c10ccf9f9aa37a3a2c0114b3e11cbf6faac12" +checksum = "ce1ef0faabbbba6674e97a56bee857ccddf942785a336c8b47b42373c922a91d" dependencies = [ "anyhow", + "auditable-serde", + "flate2", "indexmap", "serde", "serde_derive", "serde_json", "spdx", "url", - "wasm-encoder 0.225.0", - "wasmparser 0.225.0", + "wasm-encoder 0.227.1", + "wasmparser 0.227.1", ] [[package]] name = "wasmparser" -version = "0.224.1" +version = "0.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11" +checksum = "bc28600dcb2ba68d7e5f1c3ba4195c2bddc918c0243fd702d0b6dbd05689b681" dependencies = [ "bitflags", "hashbrown", @@ -985,9 +1019,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.225.0" +version = "0.227.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e5456165f81e64cb9908a0fe9b9d852c2c74582aa3fe2be3c2da57f937d3ae" +checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2" dependencies = [ "bitflags", "hashbrown", @@ -997,36 +1031,39 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.227.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ "bitflags", + "hashbrown", "indexmap", + "semver", + "serde", ] [[package]] name = "wasmprinter" -version = "0.224.1" +version = "0.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0095b53a3b09cbc2f90f789ea44aa1b17ecc2dad8b267e657c7391f3ded6293d" +checksum = "753a0516fa6c01756ee861f36878dfd9875f273aea9409d9ea390a333c5bcdc2" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.224.1", + "wasmparser 0.226.0", ] [[package]] name = "wasmtime-component-util" -version = "30.0.2" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a7108498a8a0afc81c7d2d81b96cdc509cd631d7bbaa271b7db5137026f10e3" +checksum = "f292ef5eb2cf3d414c2bde59c7fa0feeba799c8db9a8c5a656ad1d1a1d05e10b" [[package]] name = "wasmtime-environ" -version = "30.0.2" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e90f6cba665939381839bbf2ddf12d732fca03278867910348ef1281b700954" +checksum = "5b6b4bf08e371edf262cccb62de10e214bd4aaafaa069f1cd49c9c1c3a5ae8e4" dependencies = [ "anyhow", "cranelift-bitset", @@ -1041,8 +1078,8 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasm-encoder 0.224.1", - "wasmparser 0.224.1", + "wasm-encoder 0.226.0", + "wasmparser 0.226.0", "wasmprinter", "wasmtime-component-util", ] @@ -1151,21 +1188,34 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wirm" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14732cb9a0eaf9ec52ecd36b9394ade5c16eea5405d160d8829f0199d97d507d" +dependencies = [ + "log", + "serde_json", + "tempfile", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", +] + [[package]] name = "wit-bindgen" -version = "0.39.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4dd9a372b25d6f35456b0a730d2adabeb0c4878066ba8f8089800349be6ecb5" +checksum = "10fb6648689b3929d56bbc7eb1acf70c9a42a29eb5358c67c10f54dbd5d695de" dependencies = [ - "wit-bindgen-rt 0.39.0", + "wit-bindgen-rt 0.41.0", "wit-bindgen-rust-macro", ] [[package]] name = "wit-bindgen-core" -version = "0.39.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f108fa9b77a346372858b30c11ea903680e7e2b9d820b1a5883e9d530bf51c7e" +checksum = "92fa781d4f2ff6d3f27f3cc9b74a73327b31ca0dc4a3ef25a0ce2983e0e5af9b" dependencies = [ "anyhow", "heck", @@ -1183,9 +1233,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.39.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "c4db52a11d4dfb0a59f194c064055794ee6564eb1ced88c25da2cf76e50c5621" dependencies = [ "bitflags", "futures", @@ -1194,9 +1244,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rust" -version = "0.39.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ba5b852e976d35dbf6cb745746bf1bd4fc26782bab1e0c615fc71a7d8aac05" +checksum = "9d0809dc5ba19e2e98661bf32fc0addc5a3ca5bf3a6a7083aa6ba484085ff3ce" dependencies = [ "anyhow", "heck", @@ -1210,9 +1260,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rust-macro" -version = "0.39.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401529c9af9304a20ed99fa01799e467b7d37727126f0c9a958895471268ad7a" +checksum = "ad19eec017904e04c60719592a803ee5da76cb51c81e3f6fbf9457f59db49799" dependencies = [ "anyhow", "prettyplease", @@ -1225,9 +1275,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.225.0" +version = "0.227.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2505c917564c1d74774563bbcd3e4f8c216a6508050862fd5f449ee56e3c5125" +checksum = "635c3adc595422cbf2341a17fb73a319669cc8d33deed3a48368a841df86b676" dependencies = [ "anyhow", "bitflags", @@ -1236,18 +1286,18 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.225.0", + "wasm-encoder 0.227.1", "wasm-metadata", - "wasmparser 0.225.0", + "wasmparser 0.227.1", "wat", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.225.0" +version = "0.227.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebefaa234e47224f10ce60480c5bfdece7497d0f3b87a12b41ff39e5c8377a78" +checksum = "ddf445ed5157046e4baf56f9138c124a0824d4d1657e7204d71886ad8ce2fc11" dependencies = [ "anyhow", "id-arena", @@ -1258,7 +1308,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.225.0", + "wasmparser 0.227.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 73e403b1..3767688e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,14 +7,26 @@ resolver = "2" edition = "2021" version = "0.1.0" +[workspace.lints.clippy] +too_many_arguments = 'allow' + [workspace.dependencies] -anyhow = "1.0.95" -heck = "0.5" -js-component-bindgen = "1.10.0" -wasm-encoder = "0.225.0" -wasmparser = "0.224.0" -wit-bindgen = "0.39.0" -wit-bindgen-core = "0.39.0" -wit-component = { version = "0.225.0", features = ["dummy-module"] } -wit-parser = "0.225.0" -orca-wasm = "0.9.0" +anyhow = { version = "1.0.95", default-features = false } +heck = { version = "0.5", default-features = false } +js-component-bindgen = { version = "1.11.0" } +wirm = { version = "2.1.0", default-features = false } +rand = { version = "0.8", default-features = false } +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +wasm-encoder = { version = "0.227.1", features = [ "component-model", "std" ] } +wasmparser = { version = "0.239.0", features = ["features", + "component-model", + "hash-collections", + "serde", + "simd" , + "std", + "validate", +] } +wit-bindgen = { version = "0.41.0", features = [ "macros", "async", "realloc" ] } +wit-bindgen-core = { version = "0.41.0", default-features = false } +wit-component = { version = "0.227.1", features = ["dummy-module"] } +wit-parser = { version = "0.227.1", features = [ "decoding", "serde"] } diff --git a/Makefile b/Makefile index eb1617fd..3ff03015 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # WASM_OPT ?= $(shell rm node_modules/.bin/wasm-opt ; which wasm-opt) -JCO ?= ./node_modules/.bin/jco +JCO ?= npx jco STARLINGMONKEY_SRC ?= StarlingMonkey ifndef JCO @@ -15,25 +15,18 @@ STARLINGMONKEY_DEPS = $(STARLINGMONKEY_SRC)/cmake/* embedding/* $(STARLINGMONKEY all: release debug: lib/starlingmonkey_embedding.debug.wasm lib/spidermonkey-embedding-splicer.js release: lib/starlingmonkey_embedding.wasm lib/spidermonkey-embedding-splicer.js -release-weval: lib/starlingmonkey_ics.wevalcache lib/spidermonkey-embedding-splicer.js lib/spidermonkey-embedding-splicer.js: target/wasm32-wasip1/release/splicer_component.wasm crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit | obj lib @$(JCO) new target/wasm32-wasip1/release/splicer_component.wasm -o obj/spidermonkey-embedding-splicer.wasm --wasi-reactor @$(JCO) transpile -q --name spidermonkey-embedding-splicer obj/spidermonkey-embedding-splicer.wasm -o lib -- -O1 -target/wasm32-wasip1/release/splicer_component.wasm: Cargo.toml crates/spidermonkey-embedding-splicer/Cargo.toml crates/spidermonkey-embedding-splicer/src/*.rs +target/wasm32-wasip1/release/splicer_component.wasm: Cargo.toml crates/spidermonkey-embedding-splicer/Cargo.toml crates/spidermonkey-embedding-splicer/src/*.rs crates/splicer-component/src/*.rs cargo build --lib --release --target wasm32-wasip1 lib/starlingmonkey_embedding.wasm: $(STARLINGMONKEY_DEPS) | lib cmake -B build-release -DCMAKE_BUILD_TYPE=Release make -j16 -C build-release starlingmonkey_embedding -lib/starlingmonkey_embedding_weval.wasm: $(STARLINGMONKEY_DEPS) | lib - cmake -B build-release-weval -DCMAKE_BUILD_TYPE=Release -DUSE_WASM_OPT=OFF -DWEVAL=ON - make -j16 -C build-release-weval starlingmonkey_embedding - -lib/starlingmonkey_ics.wevalcache: lib/starlingmonkey_embedding_weval.wasm - @cp build-release-weval/starling-raw.wasm/starling-ics.wevalcache $@ lib/starlingmonkey_embedding.debug.wasm: $(STARLINGMONKEY_DEPS) | lib cmake -B build-debug -DCMAKE_BUILD_TYPE=RelWithDebInfo diff --git a/README.md b/README.md index b276184c..f79fb093 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Establishing this initial prototype as a singular flexible engine foundation tha ### Weval AOT Compilation - +Note: unfortunately Weval AOT Compilation is disabled for the time being, due to incompatibilities with newer versions of the LLVM toolchain used to compile StarlingMonkey. See [this](https://bytecodealliance.zulipchat.com/#narrow/channel/459697-StarlingMonkey/topic/Updating.20Gecko.20version/near/527089464) and the following messages for details. ## Platform APIs @@ -59,16 +59,17 @@ The following APIs are available: * **Legacy Encoding**: `atob`, `btoa`, `decodeURI`, `encodeURI`, `decodeURIComponent`, `encodeURIComponent` * **Streams**: `ReadableStream`, `ReadableStreamBYOBReader`, `ReadableStreamBYOBRequest`, `ReadableStreamDefaultReader`, `ReadableStreamDefaultController`, `ReadableByteStreamController`, `WritableStream` `ByteLengthQueuingStrategy` `CountQueuingStrategy`, `TransformStream` -* **URL**: `URL` `URLSearchParams` +* **URL**: `URL`, `URLSearchParams` * **Console**: `console` * **Performance**: `Performance` * **Task**: `queueMicrotask`, `setInterval` `setTimeout` `clearInterval` `clearTimeout` * **Location**: `WorkerLocation`, `location` * **Encoding**: `TextEncoder`, `TextDecoder`, `CompressionStream`, `DecompressionStream` * **Structured Clone**: `structuredClone` -* **Fetch**: `fetch` `Request` `Response` `Headers` +* **Fetch**: `fetch`, `Request`, `Response`, `Headers` * **Forms, Files, and Blobs**: `FormData`, `MultipartFormData`, `File`, `Blob` -* **Crypto**: `SubtleCrypto` `Crypto` `crypto` `CryptoKey` +* **Crypto**: `SubtleCrypto`, `Crypto`, `crypto`, `CryptoKey` +* **Abort**: `AbortController`, `AbortSignal` ## Usage @@ -105,23 +106,11 @@ await writeFile('test.component.wasm', component); See [types.d.ts](types.d.ts) for the full interface options. -The component iself can be executed in any component runtime, see the [example](EXAMPLE.md) for an end to end workflow in Wasmtime. - -### AOT Compilation - -To enable AOT compilation, set the `enableAot: true` option to run [Weval][weval] ahead-of-time compilation. - -AOT compilation can also be configured with the following options: - -| Option | Type | Example | Description | -|------------------------|-------------------------------------|-----------------|--------------------------------------------------------------------------| -| `aotMinStackSizeBytes` | `nubmer | Number | bigint | BigInt` | `2_007_846_092` | The minimum stack size (via `RUST_MIN_STACK` to set when running `weval` | - -[weval]: https://github.com/bytecodealliance/weval +The component itself can be executed in any component runtime, see the [example](EXAMPLE.md) for an end to end workflow in Wasmtime. -### Custom `weval` binary +### Custom `wizer` binary -To use a custom (pre-downloaded) [`weval`][weval] binary, set the `wevalBin` option to the path to your desired weval binary. +To use a custom (pre-downloaded) [`wizer`](https://github.com/bytecodealliance/wizer) binary, set the `wizerBin` option to the path to your desired wizer binary. ### Async Support @@ -180,33 +169,131 @@ The default set of features includes: * `'random'`: Support for cryptographic random, depends on `wasi:random`. **When disabled, random numbers will still be generated but will not be random and instead fully deterministic.** * `'clocks'`: Support for clocks and duration polls, depends on `wasi:clocks` and `wasi:io`. **When disabled, using any timer functions like setTimeout or setInterval will panic.** * `'http'`: Support for outbound HTTP via the `fetch` global in JS. +* `'fetch-event'`: Support for `fetch` based incoming request handling (i.e. `addEventListener('fetch', ...)`) -Setting `disableFeatures: ['random', 'stdio', 'clocks', 'http']` will disable all features creating a minimal "pure component", that does not depend on any WASI APIs at all and just the target world. +Setting `disableFeatures: ['random', 'stdio', 'clocks', 'http', 'fetch-event']` will disable all features creating a minimal "pure component", that does not depend on any WASI APIs at all and just the target world. Note that pure components **will not report errors and will instead trap**, so that this should only be enabled after very careful testing. Note that features explicitly imported by the target world cannot be disabled - if you target a component to a world that imports `wasi:clocks`, then `disableFeatures: ['clocks']` will not be supported. +Note that depending on your component implementation, some features may be automatically disabled. For example, if using +`wasi:http/incoming-handler` manually, the `fetch-event` cannot be used. + ## Using StarlingMonkey's `fetch-event` -The StarlingMonkey engine provides the ability to use `fetchEvent` to handle calls to `wasi:http/incoming-handler@0.2.0#handle`. When targeting worlds that export `wasi:http/incoming-handler@0.2.0` the fetch event will automatically be attached. Alternatively, to override the fetch event with a custom handler, export an explicit `incomingHandler` or `'wasi:http/incoming-handler@0.2.0'` object. Using the `fetchEvent` requires enabling the `http` feature. +The StarlingMonkey engine provides the ability to use `fetchEvent` to handle calls to `wasi:http/incoming-handler@0.2.0#handle`. + +When targeting worlds that export `wasi:http/incoming-handler@0.2.0` the fetch event will automatically be attached. Alternatively, +to override the fetch event with a custom handler, export an explicit `incomingHandler` or `'wasi:http/incoming-handler@0.2.0'` +object. Using the `fetchEvent` requires enabling the `http` feature. + +> [!WARNING] +> If using `fetch-event`, ensure that you *do not* manually import (i.e. exporting `incomingHandler` from your ES module). +> +> Modules that export `incomingHandler` and have the `http` feature enabled are assumed to be using `wasi:http` manually. ## API ```ts export function componentize(opts: { - sourcePath: string, - witPath: string, - worldName: string, - debug?: bool, - debugBuild?: bool, - engine?: string, - preview2Adapter?: string, - disableFeatures?: ('stdio' | 'random' | 'clocks' | 'http')[], -}): { - component: Uint8Array, - imports: string[] -} + /** + * The path to the file to componentize. + * + * This file must be a valid JavaScript module, and can import other modules using relative paths. + */ + sourcePath: string; + /** + * Path to WIT file or folder + */ + witPath?: string; + /** + * Target world name for componentization + */ + worldName?: string; + /** + * Path to custom ComponentizeJS engine build to use + */ + engine?: string; + /** + * Use a pre-existing path to the `wizer` binary, if present + */ + wizerBin?: string; + /** + * Path to custom Preview2 Adapter + */ + preview2Adapter?: string; + /** + * Disable WASI features in the base engine + * Disabling all features results in a pure component with no WASI dependence + * + * - stdio: console.log(), console.error and errors are provided to stderr + * - random: Math.random() and crypto.randomBytes() + * - clocks: Date.now(), performance.now() + * - http: fetch() support + * + */ + disableFeatures?: ('stdio' | 'random' | 'clocks' | 'http' | 'fetch-event')[]; + /** + * Enable WASI features in the base engine + * (no experimental subsystems currently supported) + */ + enableFeatures?: []; + /** + * Pass environment variables to the spawned Wizer Process + * If set to true, all host environment variables are passed + * To pass only a subset, provide an object with the desired variables + */ + env?: boolean | Record; + /** + * Runtime arguments to provide to the StarlingMonkey engine initialization + * (see https://github.com/bytecodealliance/StarlingMonkey/blob/main/include/config-parser.h) + */ + runtimeArgs?: string; + /** + * Use a debug build + * Note that the debug build only includes the names section only for size optimization, and not DWARF + * debugging sections, due to a lack of support in Node.js for these debugging workflows currently. + */ + debugBuild?: boolean; + /** + * Debug options + */ + debug?: { + /** Whether to enable bindings-specific debugging */ + bindings?: boolean; + /** Path to debug bindings to use */ + bindingsDir?: string; + /** Whether to enable binary-specific debugging */ + binary?: boolean; + /** Path to enable binary-specific debugging */ + binaryPath?: string; + /** Whether to enable wizer logging */ + wizerLogging: false; + } +}): Promise<{ + /** + * Component binary + */ + component: Uint8Array; + /** + * Used guest imports in JavaScript (excluding those from StarlingMonkey engine) + */ + imports: [[string, string]][]; + /** + * Debugging output (only present if enabled) + */ + debug?: { + /** Whether bindings debugging was enabled */ + bindings?: boolean; + /** Work directory used during processing */ + workDir?: string; + /** Whether binary debugging was enabled */ + binary?: boolean; + /** Path to the produced binary */ + binaryPath?: string; + }; +}> ``` Converts a JS source into a component binary. @@ -216,43 +303,52 @@ imports. Direct component analysis should be used to correctly infer the real im ## Contributing -### Pre-requisites +To contribute, you'll need to set up the following: * `git submodule update --init --recursive` to update the submodules. * Stable Rust with the `wasm32-unknown-unknown` and `wasm32-wasi` targets installed. * `wasi-sdk-20.0` installed at `/opt/wasi-sdk/` -### Building and testing +## Building Building and testing the project can be performed via NPM scripts (see [`package.json`](./package.json)): ```console npm install npm run build -npm run test ``` -Before being able to use `componetize-js` (ex. via `npm link`, from `jco`), you'll need to run: +To clean up a local installation (i.e. remove the installation of StarlingMonkey): +```console +npm run clean ``` -npm run build:weval + +## Testing + +To run all tests: + +```console +npm run test ``` -This will produce a few files, most importantly `lib/starlingmonkey_embedding_weval.wasm`. +### Running a specific test -To clean up a local installation (i.e. remove the installation of StarlingMonkey): +To run a specific test suite, you can pass an argument to [`vitest`][vitest]: ```console -npm run clean +npm run test -- test/wasi.js ``` +[vitest]: https://vitest.dev + # License This project is licensed under the Apache 2.0 license with the LLVM exception. See [LICENSE](LICENSE) for more details. -### Contribution +## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, diff --git a/StarlingMonkey b/StarlingMonkey index 727d0904..6cdcc0e8 160000 --- a/StarlingMonkey +++ b/StarlingMonkey @@ -1 +1 @@ -Subproject commit 727d090469be4b1163b799c17d7de7b02c8653a1 +Subproject commit 6cdcc0e8ba3cc8a80e026af3c0867a1f63e57d2a diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..663374fa --- /dev/null +++ b/cliff.toml @@ -0,0 +1,81 @@ +# https://git-cliff.org/docs/configuration + +[changelog] +header = """ +# Changelog\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + * {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message | split(pat="\n") | first | trim }}\ + {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif %}\ + {% if commit.remote.pr_number %} in #{{ commit.remote.pr_number }}{%- endif %} + {% endfor %} +{% endfor %}\n + +{%- if github -%} +{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} + {% raw %}\n{% endraw -%} + ## New Contributors +{%- endif %}\ +{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} + * @{{ contributor.username }} made their first contribution + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor -%} +{% raw %}\n{% endraw -%} +{% raw %}\n{% endraw -%} +{% raw %}\n{% endraw -%} +{%- endif -%} + +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} +""" +# remove the leading and trailing spaces +trim = true + +[git] +# parse the commits based on https://www.conventionalcommits.org + +# regex for parsing and grouping commits +commit_parsers = [ + { message = '^feat', group = '🚀 Features' }, + { message = '^fix', group = '🐛 Bug Fixes' }, + { message = '^doc', group = '📚 Documentation' }, + { message = '^perf', group = '⚡ Performance' }, + { message = '^refactor', group = '🚜 Refactor' }, + { message = '^style', group = '🎨 Styling' }, + { message = '^test', group = '🧪 Testing' }, + { message = '^release', skip = true }, + { message = '^chore', group = '⚙️ Miscellaneous Tasks' }, + { message = ".*", group = "Other Changes", default_scope = "other changes"}, +] + +# filter out the commits that are not matched by commit parsers +filter_commits = false + +filter = { exclude = { scopes = ["ci", "infra", "ops"] } } + +# sort the tags topologically +topo_order = false + +# sort the commits inside sections by oldest/newest order +sort_commits = "newest" + +# glob pattern for matching git tags +tag_pattern = "^[0-9]+.[0-9]+.[0-9]+$" + +# allow commits that don't follow the conventional commits standard +filter_unconventional = false diff --git a/crates/spidermonkey-embedding-splicer/Cargo.toml b/crates/spidermonkey-embedding-splicer/Cargo.toml index ab09acd8..438408df 100644 --- a/crates/spidermonkey-embedding-splicer/Cargo.toml +++ b/crates/spidermonkey-embedding-splicer/Cargo.toml @@ -8,15 +8,20 @@ edition.workspace = true [lib] +[lints] +workspace = true + [dependencies] anyhow = { workspace = true } +clap = { version = "4.5.31", features = ["suggestions", "color", "derive"] } heck = { workspace = true } -js-component-bindgen = { workspace = true } -wasmparser = { workspace = true } +js-component-bindgen = { workspace = true, features = [ "transpile-bindgen" ] } +wirm = { workspace = true } +rand = { workspace = true } +serde_json = { workspace = true } wasm-encoder = { workspace = true } +wasmparser = { workspace = true } +wit-bindgen = { workspace = true } +wit-bindgen-core = { workspace = true } wit-component = { workspace = true } wit-parser = { workspace = true } -wit-bindgen-core = { workspace = true } -wit-bindgen = { workspace = true } -orca-wasm.workspace = true -clap = { version = "4.5.31", features = ["suggestions", "color", "derive"] } diff --git a/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs b/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs index 6ccf4b50..7d62a8d8 100644 --- a/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs +++ b/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs @@ -1,9 +1,11 @@ -use anyhow::{Context, Result}; -use clap::{Parser, Subcommand}; use std::fs; use std::path::PathBuf; +use std::str::FromStr; + +use anyhow::{Context, Result}; +use clap::{Parser, Subcommand}; -use spidermonkey_embedding_splicer::wit::Features; +use spidermonkey_embedding_splicer::wit::exports::local::spidermonkey_embedding_splicer::splicer::Feature; use spidermonkey_embedding_splicer::{splice, stub_wasi}; #[derive(Parser, Debug)] @@ -48,6 +50,10 @@ enum Commands { #[arg(short, long)] out_dir: PathBuf, + /// Features to enable (multiple allowed) + #[arg(short, long)] + features: Vec, + /// Path to WIT file or directory #[arg(long)] wit_path: Option, @@ -62,27 +68,6 @@ enum Commands { }, } -/// Maps the list of features passed as strings into the list of features as given by the enum -/// -/// enum features { -/// stdio, -/// clocks, -/// random, -/// http, -///} -fn map_features(features: &Vec) -> Vec { - features - .iter() - .map(|f| match f.as_str() { - "stdio" => Features::Stdio, - "clocks" => Features::Clocks, - "random" => Features::Random, - "http" => Features::Http, - _ => panic!("Unknown feature: {}", f), - }) - .collect() -} - fn main() -> Result<()> { let cli = Cli::parse(); @@ -98,7 +83,10 @@ fn main() -> Result<()> { .with_context(|| format!("Failed to read input file: {}", input.display()))?; let wit_path_str = wit_path.as_ref().map(|p| p.to_string_lossy().to_string()); - let features = map_features(&features); + let features = features + .iter() + .map(|v| Feature::from_str(v)) + .collect::>>()?; let result = stub_wasi::stub_wasi(wasm, features, None, wit_path_str, world_name) .map_err(|e| anyhow::anyhow!(e))?; @@ -115,6 +103,7 @@ fn main() -> Result<()> { Commands::SpliceBindings { input, out_dir, + features, wit_path, world_name, debug, @@ -129,15 +118,22 @@ fn main() -> Result<()> { let wit_path_str = wit_path.as_ref().map(|p| p.to_string_lossy().to_string()); - let result = splice::splice_bindings(engine, world_name, wit_path_str, None, debug) - .map_err(|e| anyhow::anyhow!(e))?; - fs::write(&out_dir.join("component.wasm"), result.wasm).with_context(|| { + let features = features + .iter() + .map(|v| Feature::from_str(v)) + .collect::>>()?; + + let result = + splice::splice_bindings(engine, features, None, wit_path_str, world_name, debug) + .map_err(|e| anyhow::anyhow!(e))?; + + fs::write(out_dir.join("component.wasm"), result.wasm).with_context(|| { format!( "Failed to write output file: {}", out_dir.join("component.wasm").display() ) })?; - fs::write(&out_dir.join("initializer.js"), result.js_bindings).with_context(|| { + fs::write(out_dir.join("initializer.js"), result.js_bindings).with_context(|| { format!( "Failed to write output file: {}", out_dir.join("initializer.js").display() diff --git a/crates/spidermonkey-embedding-splicer/src/bindgen.rs b/crates/spidermonkey-embedding-splicer/src/bindgen.rs index 1c61106e..e66a15e8 100644 --- a/crates/spidermonkey-embedding-splicer/src/bindgen.rs +++ b/crates/spidermonkey-embedding-splicer/src/bindgen.rs @@ -1,4 +1,6 @@ -use crate::{uwrite, uwriteln}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::fmt::Write; + use anyhow::Result; use heck::*; use js_component_bindgen::function_bindgen::{ @@ -7,8 +9,6 @@ use js_component_bindgen::function_bindgen::{ use js_component_bindgen::intrinsics::{render_intrinsics, Intrinsic}; use js_component_bindgen::names::LocalNames; use js_component_bindgen::source::Source; -use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::fmt::Write; use wit_bindgen_core::abi::{self, LiftLower}; use wit_bindgen_core::wit_parser::Resolve; use wit_bindgen_core::wit_parser::{ @@ -19,6 +19,10 @@ use wit_component::StringEncoding; use wit_parser::abi::WasmType; use wit_parser::abi::{AbiVariant, WasmSignature}; +use crate::wit::exports::local::spidermonkey_embedding_splicer::splicer::Feature; + +use crate::{uwrite, uwriteln}; + #[derive(Debug)] pub enum Resource { None, @@ -102,6 +106,9 @@ struct JsBindgen<'a> { resource_directions: HashMap, imported_resources: BTreeSet, + + /// Features that were enabled at the time of generation + features: &'a Vec, } #[derive(Debug)] @@ -129,7 +136,11 @@ pub struct Componentization { pub resource_imports: Vec<(String, String, u32)>, } -pub fn componentize_bindgen(resolve: &Resolve, wid: WorldId) -> Result { +pub fn componentize_bindgen( + resolve: &Resolve, + wid: WorldId, + features: &Vec, +) -> Result { let mut bindgen = JsBindgen { src: Source::default(), esm_bindgen: EsmBindgen::default(), @@ -144,6 +155,7 @@ pub fn componentize_bindgen(resolve: &Resolve, wid: WorldId) -> Result Result Result Result Result Result {} WorldItem::Type(id) => { let ty = &resolve.types[*id]; - match ty.kind { - TypeDefKind::Resource => { - imported_resource_modules.insert(*id, key_name.clone()); - } - _ => {} + if ty.kind == TypeDefKind::Resource { + imported_resource_modules.insert(*id, key_name.clone()); } } } @@ -388,75 +401,25 @@ pub fn componentize_bindgen(resolve: &Resolve, wid: WorldId) -> Result { fn intrinsic(&mut self, intrinsic: Intrinsic) -> String { self.all_intrinsics.insert(intrinsic); - return intrinsic.name().to_string(); + intrinsic.name().to_string() } - fn exports_bindgen( - &mut self, - // guest_exports: &Option>, - // features: Vec, - ) -> Result<()> { + fn exports_bindgen(&mut self) -> Result<()> { for (key, export) in &self.resolve.worlds[self.world].exports { let name = self.resolve.name_world_key(key); - if name.starts_with("wasi:http/incoming-handler@0.2.") { + + // Skip bindings generation for wasi:http/incoming-handler if the fetch-event + // feature was enabled. We expect that the built-in engine implementation will be used + if name.starts_with("wasi:http/incoming-handler@0.2.") + && self.features.contains(&Feature::FetchEvent) + { continue; } - // Do not generate exports when the guest export is not implemented. - // We check both the full interface name - "ns:pkg@v/my-interface" and the - // aliased interface name "myInterface". All other names are always - // camel-case in the check. - // match key { - // WorldKey::Interface(iface) => { - // if !guest_exports.contains(&name) { - // let iface = &self.resolve.interfaces[*iface]; - // if let Some(iface_name) = iface.name.as_ref() { - // let camel_case_name = iface_name.to_lower_camel_case(); - // if !guest_exports.contains(&camel_case_name) { - // // For wasi:http/incoming-handler, we treat it - // // as a special case as the engine already - // // provides the export using fetchEvent and that - // // can be used when an explicit export is not - // // defined by the guest content. - // if iface_name == "incoming-handler" - // || name.starts_with("wasi:http/incoming-handler@0.2.") - // { - // if !features.contains(&Features::Http) { - // bail!( - // "JS export definition for '{}' not found. Cannot use fetchEvent because the http feature is not enabled.", - // camel_case_name - // ) - // } - // continue; - // } - // bail!("Expected a JS export definition for '{}'", camel_case_name); - // } - // // TODO: move populate_export_aliases to a preprocessing - // // step that doesn't require esm_bindgen, so that we can - // // do alias deduping here as well. - // } else { - // continue; - // } - // } - // } - // WorldKey::Name(export_name) => { - // let camel_case_name = export_name.to_lower_camel_case(); - // if !guest_exports.contains(&camel_case_name) { - // bail!("Expected a JS export definition for '{}'", camel_case_name); - // } - // } - // } match export { WorldItem::Function(func) => { let local_name = self.local_names.create_once(&func.name).to_string(); - self.export_bindgen( - name.into(), - false, - None, - &local_name, - StringEncoding::UTF8, - func, - ); + self.export_bindgen(name, false, None, &local_name, StringEncoding::UTF8, func); self.esm_bindgen.add_export_func( None, local_name.to_string(), @@ -485,7 +448,7 @@ impl JsBindgen<'_> { interface_name(self.resolve, *id), &local_name, StringEncoding::UTF8, - &func, + func, ); self.esm_bindgen.add_export_func( Some(name), @@ -502,7 +465,7 @@ impl JsBindgen<'_> { let local_name = self .local_names .get_or_create( - &format!("resource:{resource_name}"), + format!("resource:{resource_name}"), &resource_name, ) .0 @@ -513,14 +476,17 @@ impl JsBindgen<'_> { interface_name(self.resolve, *id), &local_name, StringEncoding::UTF8, - &func, + func, ); self.esm_bindgen.ensure_exported_resource( - Some(&name), + Some(name), local_name, resource_name, ); } + FunctionKind::AsyncFreestanding => todo!(), + FunctionKind::AsyncMethod(_id) => todo!(), + FunctionKind::AsyncStatic(_id) => todo!(), }; } } @@ -545,7 +511,7 @@ impl JsBindgen<'_> { .as_ref() .unwrap() .to_upper_camel_case(), - &iface_name, + iface_name, ); uwriteln!(self.src, "\nclass import_{name} {{"); @@ -566,7 +532,7 @@ impl JsBindgen<'_> { let prefix = iface_name .as_deref() .map(|s| format!("{s}$")) - .unwrap_or(String::new()); + .unwrap_or_default(); let resource_symbol = self.intrinsic(Intrinsic::SymbolResourceHandle); let dispose_symbol = self.intrinsic(Intrinsic::SymbolDispose); @@ -610,10 +576,14 @@ impl JsBindgen<'_> { BTreeMap::<_, Vec<_>>::new(), |mut map, (name, func)| { map.entry(match &func.kind { - FunctionKind::Freestanding => None, + FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => { + None + } FunctionKind::Method(ty) | FunctionKind::Static(ty) - | FunctionKind::Constructor(ty) => Some(*ty), + | FunctionKind::Constructor(ty) + | FunctionKind::AsyncMethod(ty) + | FunctionKind::AsyncStatic(ty) => Some(*ty), }) .or_default() .push((name.as_str(), func)); @@ -640,44 +610,38 @@ impl JsBindgen<'_> { } WorldItem::Type(id) => { let ty = &self.resolve.types[*id]; - match ty.kind { - TypeDefKind::Resource => { - self.resource_directions - .insert(*id, AbiVariant::GuestImport); - - let resource_name = ty.name.as_ref().unwrap(); - - let mut resource_fns = Vec::new(); - for (_, impt) in &self.resolve.worlds[self.world].imports { - match impt { - WorldItem::Function(function) => { - let stripped = if let Some(stripped) = - function.name.strip_prefix("[constructor]") - { - stripped - } else if let Some(stripped) = - function.name.strip_prefix("[method]") - { - stripped - } else if let Some(stripped) = - function.name.strip_prefix("[static]") - { - stripped - } else { - continue; - }; - - if stripped.starts_with(resource_name) { - resource_fns.push((function.name.as_str(), function)); - } - } - _ => {} + if ty.kind == TypeDefKind::Resource { + self.resource_directions + .insert(*id, AbiVariant::GuestImport); + + let resource_name = ty.name.as_ref().unwrap(); + + let mut resource_fns = Vec::new(); + for (_, impt) in &self.resolve.worlds[self.world].imports { + if let WorldItem::Function(function) = impt { + let stripped = if let Some(stripped) = + function.name.strip_prefix("[constructor]") + { + stripped + } else if let Some(stripped) = + function.name.strip_prefix("[method]") + { + stripped + } else if let Some(stripped) = + function.name.strip_prefix("[static]") + { + stripped + } else { + continue; + }; + + if stripped.starts_with(resource_name) { + resource_fns.push((function.name.as_str(), function)); } } - - self.resource_bindgen(*id, "$root", &None, resource_fns); } - _ => {} + + self.resource_bindgen(*id, "$root", &None, resource_fns); } } }; @@ -694,11 +658,12 @@ impl JsBindgen<'_> { let fn_name = func.item_name(); let fn_camel_name = fn_name.to_lower_camel_case(); - use binding_name as binding_name_fn; + use generate_binding_name_import as binding_name_fn; let (binding_name, resource) = match &func.kind { FunctionKind::Freestanding => { - let binding_name = binding_name(&fn_camel_name, &iface_name); + let binding_name = + generate_binding_name_import(&fn_camel_name, &iface_name, &import_name); uwrite!(self.src, "\nfunction import_{binding_name}"); @@ -731,6 +696,9 @@ impl JsBindgen<'_> { Resource::Constructor(self.resolve.types[*ty].name.clone().unwrap()), ) } + FunctionKind::AsyncFreestanding => todo!(), + FunctionKind::AsyncMethod(_id) => todo!(), + FunctionKind::AsyncStatic(_id) => todo!(), }; // imports are canonicalized as exports because @@ -739,7 +707,11 @@ impl JsBindgen<'_> { func.params.len(), &format!( "$import_{}", - binding_name_fn(&resource.func_name(fn_name), &iface_name) + binding_name_fn( + &resource.func_name(fn_name), + &iface_name, + import_name.as_str() + ) ), StringEncoding::UTF8, func, @@ -786,8 +758,8 @@ impl JsBindgen<'_> { for (_, ty) in func.params.iter() { self.iter_resources(ty, &mut resource_map); } - for ty in func.results.iter_types() { - self.iter_resources(ty, &mut resource_map); + if let Some(ty) = func.result { + self.iter_resources(&ty, &mut resource_map); } resource_map } @@ -896,23 +868,25 @@ impl JsBindgen<'_> { } } + let err = if get_result_types(self.resolve, func.result).is_some() { + match abi { + AbiVariant::GuestExport => ErrHandling::ThrowResultErr, + AbiVariant::GuestImport => ErrHandling::ResultCatchHandler, + AbiVariant::GuestImportAsync => todo!(), + AbiVariant::GuestExportAsync => todo!(), + AbiVariant::GuestExportAsyncStackful => todo!(), + } + } else { + ErrHandling::None + }; + let mut f = FunctionBindgen { is_async: false, tracing_prefix: None, intrinsics: &mut self.all_intrinsics, valid_lifting_optimization: true, sizes: &self.sizes, - err: if func.results.throws(self.resolve).is_some() { - match abi { - AbiVariant::GuestExport => ErrHandling::ThrowResultErr, - AbiVariant::GuestImport => ErrHandling::ResultCatchHandler, - AbiVariant::GuestImportAsync => todo!(), - AbiVariant::GuestExportAsync => todo!(), - AbiVariant::GuestExportAsyncStackful => todo!(), - } - } else { - ErrHandling::None - }, + err, block_storage: Vec::new(), blocks: Vec::new(), callee, @@ -976,6 +950,9 @@ impl JsBindgen<'_> { Resource::Constructor(self.resolve.types[*ty].name.clone().unwrap()), format!("new {callee}"), ), + FunctionKind::AsyncFreestanding => todo!(), + FunctionKind::AsyncMethod(_id) => todo!(), + FunctionKind::AsyncStatic(_id) => todo!(), }; let binding_name = format!( @@ -1020,8 +997,8 @@ impl JsBindgen<'_> { CoreFn { retsize: if sig.retptr { let mut retsize: u32 = 0; - for ret_ty in func.results.iter_types() { - retsize += self.sizes.size(ret_ty).size_wasm32() as u32; + if let Some(ret_ty) = func.result { + retsize += self.sizes.size(&ret_ty).size_wasm32() as u32; } retsize } else { @@ -1096,8 +1073,7 @@ impl EsmBindgen { iface = match iface.get_mut(&iface_id_or_kebab).unwrap() { Binding::Interface(iface) => iface, Binding::Resource(_) | Binding::Local(_) => panic!( - "Exported interface {} cannot be both a function and an interface or resource", - iface_id_or_kebab + "Exported interface {iface_id_or_kebab} cannot be both a function and an interface or resource" ), }; } @@ -1127,8 +1103,7 @@ impl EsmBindgen { iface = match iface.get_mut(&iface_id_or_kebab).unwrap() { Binding::Interface(iface) => iface, Binding::Resource(_) | Binding::Local(_) => panic!( - "Exported interface {} cannot be both a function and an interface or resource", - iface_id_or_kebab + "Exported interface {iface_id_or_kebab} cannot be both a function and an interface or resource" ), }; } @@ -1142,7 +1117,7 @@ impl EsmBindgen { let expt_name_sans_version = if let Some(version_idx) = expt_name.find('@') { &expt_name[0..version_idx] } else { - &expt_name + expt_name }; if let Some(alias) = interface_name_from_string(expt_name_sans_version) { if !self.exports.contains_key(&alias) @@ -1162,7 +1137,7 @@ impl EsmBindgen { ) { // TODO: bring back these validations of imports // including using the flattened bindings - if self.exports.len() > 0 { + if !self.exports.is_empty() { // error handling uwriteln!(output, " class BindingsError extends Error {{ @@ -1312,12 +1287,9 @@ fn interface_name_from_string(name: &str) -> Option { let path_idx = name.rfind('/')?; let name = &name[path_idx + 1..]; let at_idx = name.rfind('@'); - let alias = name[..at_idx.unwrap_or_else(|| name.len())].to_lower_camel_case(); + let alias = name[..at_idx.unwrap_or(name.len())].to_lower_camel_case(); let iface_name = Some(if let Some(at_idx) = at_idx { - format!( - "{alias}_{}", - name[at_idx + 1..].replace('.', "_").replace('-', "_") - ) + format!("{alias}_{}", name[at_idx + 1..].replace(['.', '-'], "_")) } else { alias }); @@ -1327,6 +1299,55 @@ fn interface_name_from_string(name: &str) -> Option { fn binding_name(func_name: &str, iface_name: &Option) -> String { match iface_name { Some(iface_name) => format!("{iface_name}${func_name}"), - None => format!("{func_name}"), + None => func_name.to_string(), + } +} + +/// Determine the binding name of a given import +/// example wit: +/// package local:hello; +/// interface greeter { +/// greet(name: string): string; +/// } +/// word main { +/// export greeter; +/// } +/// +/// # Arguments +/// * `func_name` - function name (e.g. `greet`) +/// * `iface_name` - an interface name, if present (e.g. `greeter`) +/// * `import_name` - qualified import specifier (e.g. `local:hello`) +/// +fn generate_binding_name_import( + func_name: &str, + iface_name: &Option, + import_name: &str, +) -> String { + // import_name is only valid when FunctionKind is Freestanding + if import_name != "<>" { + let valid_import = import_name + .chars() + .map(|c| if c.is_alphanumeric() { c } else { '_' }) + .collect::(); + format!("{valid_import}${func_name}") + } else if let Some(iface_name) = iface_name { + format!("{iface_name}${func_name}") + } else { + func_name.to_string() + } +} + +/// Extract success and error types from a given optional type, if it is a Result +pub fn get_result_types( + resolve: &Resolve, + return_type: Option, +) -> Option<(Option<&Type>, Option<&Type>)> { + match return_type { + None => None, + Some(Type::Id(id)) => match &resolve.types[id].kind { + TypeDefKind::Result(r) => Some((r.ok.as_ref(), r.err.as_ref())), + _ => None, + }, + _ => None, } } diff --git a/crates/spidermonkey-embedding-splicer/src/lib.rs b/crates/spidermonkey-embedding-splicer/src/lib.rs index f200ccb7..222f0e89 100644 --- a/crates/spidermonkey-embedding-splicer/src/lib.rs +++ b/crates/spidermonkey-embedding-splicer/src/lib.rs @@ -1,19 +1,14 @@ -use anyhow::{bail, Context, Result}; use std::path::Path; +use anyhow::{bail, Context, Result}; +use wit_parser::{PackageId, Resolve}; + pub mod bindgen; pub mod splice; pub mod stub_wasi; +pub mod wit; -use crate::wit::{CoreFn, CoreTy}; -use wit_parser::{PackageId, Resolve}; - -pub mod wit { - wit_bindgen::generate!({ - world: "spidermonkey-embedding-splicer", - pub_export_macro: true - }); -} +use wit::exports::local::spidermonkey_embedding_splicer::splicer::{CoreFn, CoreTy}; /// Calls [`write!`] with the passed arguments and unwraps the result. /// @@ -60,28 +55,29 @@ fn map_core_fn(cfn: &bindgen::CoreFn) -> CoreFn { } = cfn; CoreFn { params: params.iter().map(&map_core_ty).collect(), - ret: match ret { - Some(ref core_ty) => Some(map_core_ty(core_ty)), - None => None, - }, + ret: ret.as_ref().map(map_core_ty), retptr: *retptr, retsize: *retsize, paramptr: *paramptr, } } -fn parse_wit(path: &Path) -> Result<(Resolve, PackageId)> { +fn parse_wit(path: impl AsRef) -> Result<(Resolve, PackageId)> { let mut resolve = Resolve::default(); + let path = path.as_ref(); let id = if path.is_dir() { - resolve.push_dir(&path)?.0 + resolve + .push_dir(path) + .with_context(|| format!("resolving WIT in {}", path.display()))? + .0 } else { let contents = - std::fs::read(&path).with_context(|| format!("failed to read file {path:?}"))?; + std::fs::read(path).with_context(|| format!("reading file {}", path.display()))?; let text = match std::str::from_utf8(&contents) { Ok(s) => s, Err(_) => bail!("input file is not valid utf-8"), }; - resolve.push_str(&path, text)? + resolve.push_str(path, text)? }; Ok((resolve, id)) } diff --git a/crates/spidermonkey-embedding-splicer/src/splice.rs b/crates/spidermonkey-embedding-splicer/src/splice.rs index 3b805cb0..a1a137f7 100644 --- a/crates/spidermonkey-embedding-splicer/src/splice.rs +++ b/crates/spidermonkey-embedding-splicer/src/splice.rs @@ -1,23 +1,27 @@ -use crate::bindgen::BindingItem; -use crate::wit::{CoreFn, CoreTy, SpliceResult}; -use crate::{bindgen, map_core_fn, parse_wit, splice}; -use anyhow::Result; -use orca_wasm::ir::function::{FunctionBuilder, FunctionModifier}; -use orca_wasm::ir::id::{ExportsID, FunctionID, LocalID}; -use orca_wasm::ir::module::Module; -use orca_wasm::ir::types::{BlockType, ElementItems, InstrumentationMode}; -use orca_wasm::module_builder::AddLocal; -use orca_wasm::opcode::{Inject, InjectAt}; -use orca_wasm::{DataType, Opcode}; use std::path::PathBuf; + +use anyhow::Result; use wasm_encoder::{Encode, Section}; use wasmparser::ExternalKind; use wasmparser::MemArg; use wasmparser::Operator; +use wirm::ir::function::{FunctionBuilder, FunctionModifier}; +use wirm::ir::id::{ExportsID, FunctionID, LocalID}; +use wirm::ir::module::Module; +use wirm::ir::types::{BlockType, ElementItems, InstrumentationMode}; +use wirm::module_builder::AddLocal; +use wirm::opcode::{Inject, InjectAt}; +use wirm::{DataType, Opcode}; use wit_component::metadata::{decode, Bindgen}; use wit_component::StringEncoding; use wit_parser::Resolve; +use crate::bindgen::BindingItem; +use crate::wit::exports::local::spidermonkey_embedding_splicer::splicer::{ + CoreFn, CoreTy, Feature, SpliceResult, +}; +use crate::{bindgen, map_core_fn, parse_wit, splice}; + // Returns // pub struct SpliceResult { // pub wasm: _rt::Vec::, @@ -28,20 +32,25 @@ use wit_parser::Resolve; // } pub fn splice_bindings( engine: Vec, - world_name: Option, - wit_path: Option, + features: Vec, wit_source: Option, + wit_path: Option, + world_name: Option, debug: bool, ) -> Result { - let (mut resolve, id) = if let Some(wit_source) = wit_source { - let mut resolve = Resolve::default(); - let path = PathBuf::from("component.wit"); - let id = resolve - .push_str(&path, &wit_source) - .map_err(|e| e.to_string())?; - (resolve, id) - } else { - parse_wit(&PathBuf::from(wit_path.unwrap())).map_err(|e| format!("{:?}", e))? + let (mut resolve, id) = match (wit_source, wit_path) { + (Some(wit_source), _) => { + let mut resolve = Resolve::default(); + let path = PathBuf::from("component.wit"); + let id = resolve + .push_str(&path, &wit_source) + .map_err(|e| e.to_string())?; + (resolve, id) + } + (_, Some(wit_path)) => parse_wit(&wit_path).map_err(|e| format!("{e:?}"))?, + (None, None) => { + return Err("neither wit source nor path have been specified".into()); + } }; let world = resolve @@ -52,6 +61,7 @@ pub fn splice_bindings( wit_component::dummy_module(&resolve, world, wit_parser::ManglingAndAbi::Standard32); // merge the engine world with the target world, retaining the engine producers + let (engine_world, producers) = if let Ok(( _, Bindgen { @@ -105,7 +115,7 @@ pub fn splice_bindings( }; let componentized = - bindgen::componentize_bindgen(&resolve, world).map_err(|err| err.to_string())?; + bindgen::componentize_bindgen(&resolve, world, &features).map_err(|err| err.to_string())?; resolve .merge_worlds(engine_world, world) @@ -183,7 +193,7 @@ pub fn splice_bindings( ) in &componentized.exports { let expt = if *iface { - let name = resource.canon_string(&name); + let name = resource.canon_string(name); format!("{export_name}#{name}") } else { export_name.clone() @@ -206,7 +216,7 @@ pub fn splice_bindings( if *iface { imports.push(( specifier.to_string(), - resource.canon_string(&name), + resource.canon_string(name), map_core_fn(func), if func.retsize > 0 { Some(func.retsize as i32) @@ -248,7 +258,7 @@ pub fn splice_bindings( } let mut wasm = - splice::splice(engine, imports, exports, debug).map_err(|e| format!("{:?}", e))?; + splice::splice(engine, imports, exports, features, debug).map_err(|e| format!("{e:?}"))?; // add the world section to the spliced wasm wasm.push(section.id()); @@ -265,7 +275,7 @@ pub fn splice_bindings( BindingItem { binding_name, func, .. }, - )| { (binding_name.to_string(), map_core_fn(&func)) }, + )| { (binding_name.to_string(), map_core_fn(func)) }, ) .collect(), imports: componentized @@ -289,7 +299,7 @@ pub fn splice_bindings( "$root".into() }, if *iface { - resource.canon_string(&name) + resource.canon_string(name) } else { specifier.to_string() }, @@ -330,19 +340,25 @@ pub fn splice( engine: Vec, imports: Vec<(String, String, CoreFn, Option)>, exports: Vec<(String, CoreFn)>, + features: Vec, debug: bool, ) -> Result> { - let mut module = Module::parse(&*engine, false).unwrap(); + let mut module = Module::parse(&engine, false).unwrap(); // since StarlingMonkey implements CLI Run and incoming handler, // we override them only if the guest content exports those functions remove_if_exported_by_js(&mut module, &exports, "wasi:cli/run@0.2.", "#run"); - remove_if_exported_by_js( - &mut module, - &exports, - "wasi:http/incoming-handler@0.2.", - "#handle", - ); + + // if 'fetch-event' feature is disabled (default being default-enabled), + // remove the built-in incoming-handler which is built around it's use. + if !features.contains(&Feature::FetchEvent) { + remove_if_exported_by_js( + &mut module, + &exports, + "wasi:http/incoming-handler@0.2.", + "#handle", + ); + } // we reencode the WASI world component data, so strip it out from the // custom section @@ -366,7 +382,7 @@ pub fn splice( fn remove_if_exported_by_js( module: &mut Module, - content_exports: &Vec<(String, CoreFn)>, + content_exports: &[(String, CoreFn)], name_start: &str, name_end: &str, ) { @@ -403,7 +419,7 @@ fn get_export_fid(module: &Module, expt_id: &ExportsID) -> FunctionID { fn synthesize_import_functions( module: &mut Module, - imports: &Vec<(String, String, CoreFn, Option)>, + imports: &[(String, String, CoreFn, Option)], debug: bool, ) -> Result<()> { let mut coreabi_get_import: Option = None; @@ -576,7 +592,7 @@ fn synthesize_import_functions( func.i32_wrap_i64(); } CoreTy::I64 => { - func.call(get_export_fid(&module, &coreabi_from_bigint64)); + func.call(get_export_fid(module, &coreabi_from_bigint64)); } CoreTy::F32 => { // isInt: (r.asRawBits() >> 32) == 0xFFFFFF81 @@ -629,7 +645,7 @@ fn synthesize_import_functions( // if a retptr, // allocate and put the retptr on the call stack as the last passed argument if impt_sig.retptr { - assert!(!impt_sig.ret.is_some()); + assert!(impt_sig.ret.is_none()); // prepare the context arg for the return set shortly func.local_get(vp_arg); @@ -665,7 +681,7 @@ fn synthesize_import_functions( func.inject(instr.clone()); }), Some(CoreTy::I64) => { - func.call(get_export_fid(&module, &coreabi_to_bigint64)); + func.call(get_export_fid(module, &coreabi_to_bigint64)); func.i64_extend_i32u(); func.i64_const(-511101108224); func.i64_or(); @@ -709,13 +725,10 @@ fn synthesize_import_functions( // create imported function table let els = module.elements.iter_mut().next().unwrap(); - match &mut els.1 { - ElementItems::Functions(ref mut funcs) => { - for fid in import_fnids { - funcs.push(fid); - } + if let ElementItems::Functions(ref mut funcs) = &mut els.items { + for fid in import_fnids { + funcs.push(fid); } - _ => {} } } @@ -744,20 +757,25 @@ fn synthesize_import_functions( .get_fn_modifier(coreabi_get_import_fid) .unwrap(); - // walk until we get to the const representing the table index - let mut table_instr_idx = 0; - for (idx, instr) in builder.body.instructions.iter_mut().enumerate() { - if let Operator::I32Const { value: ref mut v } = instr.op { - // we specifically need the const "around" 3393 - // which is the coreabi_sample_i32 table offset - if *v < 1000 || *v > 5000 { - continue; + // Find the I32Const base index and compute the delta to new base + let mut table_instr_idx = 0usize; + let mut delta: i32 = 0; + { + let ops_ro = builder.body.instructions.get_ops(); + for (idx, op) in ops_ro.iter().enumerate() { + if let Operator::I32Const { value } = op { + // we specifically need the const "around" 3393 + // which is the coreabi_sample_i32 table offset + if *value < 1000 || *value > 5000 { + continue; + } + delta = import_fn_table_start_idx - *value; + table_instr_idx = idx; + break; } - *v = import_fn_table_start_idx; - table_instr_idx = idx; - break; } } + builder.inject_at( table_instr_idx, InstrumentationMode::Before, @@ -770,6 +788,17 @@ fn synthesize_import_functions( InstrumentationMode::Before, Operator::I32Add, ); + + if delta != 0 { + builder + .body + .instructions + .add_instr(table_instr_idx, Operator::I32Const { value: delta }); + builder + .body + .instructions + .add_instr(table_instr_idx, Operator::I32Add); + } } // remove unnecessary exports @@ -783,7 +812,7 @@ fn synthesize_import_functions( Ok(()) } -fn synthesize_export_functions(module: &mut Module, exports: &Vec<(String, CoreFn)>) -> Result<()> { +fn synthesize_export_functions(module: &mut Module, exports: &[(String, CoreFn)]) -> Result<()> { let cabi_realloc = get_export_fid( module, &module @@ -986,7 +1015,7 @@ fn synthesize_export_functions(module: &mut Module, exports: &Vec<(String, CoreF vec![] }; let mut func = FunctionBuilder::new(¶ms, &[]); - func.set_name(format!("post_{}", expt_name)); + func.set_name(format!("post_{expt_name}")); // calls post_call with just the function number argument // internally post_call is already tracking the frees needed @@ -996,7 +1025,7 @@ fn synthesize_export_functions(module: &mut Module, exports: &Vec<(String, CoreF let fid = func.finish_module(module); module .exports - .add_export_func(format!("cabi_post_{}", expt_name), *fid); + .add_export_func(format!("cabi_post_{expt_name}"), *fid); } // remove unnecessary exports diff --git a/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs b/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs index e7b03efc..7484d405 100644 --- a/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs +++ b/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs @@ -1,20 +1,20 @@ -use crate::parse_wit; -use crate::wit::Features; +use std::collections::HashSet; +use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; + use anyhow::{bail, Result}; -use orca_wasm::ir::function::FunctionBuilder; -use orca_wasm::ir::id::{FunctionID, LocalID}; -use orca_wasm::ir::module::module_functions::FuncKind; -use orca_wasm::ir::types::{BlockType, InitExpr, Value}; -use orca_wasm::module_builder::AddLocal; -use orca_wasm::{DataType, Instructions, Module, Opcode}; -use std::{ - collections::HashSet, - path::PathBuf, - time::{SystemTime, UNIX_EPOCH}, -}; use wasmparser::{MemArg, TypeRef}; +use wirm::ir::function::FunctionBuilder; +use wirm::ir::id::{FunctionID, LocalID}; +use wirm::ir::module::module_functions::FuncKind; +use wirm::ir::types::{BlockType, InitExpr, Value}; +use wirm::module_builder::AddLocal; +use wirm::{DataType, InitInstr, Module, Opcode}; use wit_parser::Resolve; +use crate::parse_wit; +use crate::wit::exports::local::spidermonkey_embedding_splicer::splicer::Feature; + const WASI_VERSIONS: [&str; 4] = ["0.2.0", "0.2.1", "0.2.2", "0.2.3"]; fn stub_wasi_imports( @@ -44,15 +44,15 @@ where }; let ty = module.types.get(ty_id).unwrap(); - let (params, results) = (ty.params().to_vec(), ty.results().to_vec()); - let mut builder = FunctionBuilder::new(params.as_slice(), results.as_slice()); + let mut builder = FunctionBuilder::new(ty.params().as_slice(), ty.results().as_slice()); let _args = stub(&mut builder)?; builder.replace_import_in_module(module, iid); return Ok(Some(fid)); } - return Ok(None); + + Ok(None) } fn stub_import( @@ -96,7 +96,7 @@ fn unreachable_stub(body: &mut FunctionBuilder) -> Result> { pub fn stub_wasi( wasm: Vec, - features: Vec, + features: Vec, wit_source: Option, wit_path: Option, world_name: Option, @@ -108,7 +108,7 @@ pub fn stub_wasi( (resolve, ids) } else { - parse_wit(&PathBuf::from(wit_path.unwrap()))? + parse_wit(PathBuf::from(wit_path.unwrap()))? }; let world = resolve.select_world(ids, world_name.as_deref())?; @@ -127,25 +127,42 @@ pub fn stub_wasi( stub_filesystem(&mut module, &target_world_imports)?; stub_cli(&mut module, &target_world_imports)?; - if !features.contains(&Features::Random) { + if !features.contains(&Feature::Random) { stub_random(&mut module)?; } - if !features.contains(&Features::Clocks) { + if !features.contains(&Feature::Clocks) { stub_clocks(&mut module)?; } - if !features.contains(&Features::Stdio) { + if !features.contains(&Feature::Stdio) { stub_stdio(&mut module)?; } - if !features.contains(&Features::Http) { - stub_http(&mut module)?; + match ( + features.contains(&Feature::Http), + features.contains(&Feature::FetchEvent), + ) { + // If both are disabled, then disable all HTTP related imports + (false, false) => { + stub_http_types(&mut module)?; + stub_http_outgoing(&mut module)?; + } + // If HTTP is disabled but fetch-event is enabled we want to stub only the `wasi:http/outgoing-handler` + // and leave the rest of `wasi:http/types` in place for StarlingMonkey's implementation of `FetchEvent` to use. + // + // Note that we cannot *know* that the user will make use of fetch-event, but we must be prepared + // for it, as the feature is enabled. + (false, true) => { + stub_http_outgoing(&mut module)?; + } + // For all other cases we can avoid stubbing + _ => {} } - let has_io = features.contains(&Features::Clocks) - || features.contains(&Features::Stdio) - || features.contains(&Features::Http) + let has_io = features.contains(&Feature::Clocks) + || features.contains(&Feature::Stdio) + || features.contains(&Feature::Http) || target_world_requires_io(&target_world_imports); if !has_io { stub_io(&mut module)?; @@ -189,7 +206,7 @@ fn stub_random(module: &mut Module) -> Result<()> { // create a mutable random seed global let seed_val: i64 = 0; let seed_global = module.add_global( - InitExpr::new(vec![Instructions::Value(Value::I64(seed_val))]), + InitExpr::new(vec![InitInstr::Value(Value::I64(seed_val))]), DataType::I64, true, false, @@ -380,7 +397,17 @@ fn stub_stdio(module: &mut Module) -> Result<()> { Ok(()) } -fn stub_http(module: &mut Module) -> Result<()> { +fn stub_http_outgoing(module: &mut Module) -> Result<()> { + stub_wasi_imports( + module, + "wasi:http/outgoing-handler", + "handle", + unreachable_stub, + )?; + Ok(()) +} + +fn stub_http_types(module: &mut Module) -> Result<()> { stub_wasi_imports( module, "wasi:http/types", @@ -753,12 +780,6 @@ fn stub_http(module: &mut Module) -> Result<()> { "[method]future-incoming-response.get", unreachable_stub, )?; - stub_wasi_imports( - module, - "wasi:http/outgoing-handler", - "handle", - unreachable_stub, - )?; Ok(()) } diff --git a/crates/spidermonkey-embedding-splicer/src/wit.rs b/crates/spidermonkey-embedding-splicer/src/wit.rs new file mode 100644 index 00000000..ff54bba4 --- /dev/null +++ b/crates/spidermonkey-embedding-splicer/src/wit.rs @@ -0,0 +1,23 @@ +use anyhow::{bail, Result}; + +wit_bindgen::generate!({ + world: "spidermonkey-embedding-splicer", + pub_export_macro: true +}); + +use crate::wit::exports::local::spidermonkey_embedding_splicer::splicer::Feature; + +impl std::str::FromStr for Feature { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s { + "stdio" => Ok(Feature::Stdio), + "clocks" => Ok(Feature::Clocks), + "random" => Ok(Feature::Random), + "http" => Ok(Feature::Http), + "fetch-event" => Ok(Feature::FetchEvent), + _ => bail!("unrecognized feature string [{s}]"), + } + } +} diff --git a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit index 96f4d87f..27fefa42 100644 --- a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit +++ b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit @@ -1,6 +1,6 @@ package local:spidermonkey-embedding-splicer; -world spidermonkey-embedding-splicer { +interface splicer { enum core-ty { i32, i64, @@ -8,11 +8,12 @@ world spidermonkey-embedding-splicer { %f64 } - enum features { + enum feature { stdio, clocks, random, http, + fetch-event, } record core-fn { @@ -30,7 +31,31 @@ world spidermonkey-embedding-splicer { imports: list>, } - export stub-wasi: func(engine: list, features: list, wit-world: option, wit-path: option, world-name: option) -> result, string>; + /// Stub the WASI imports/exports of a given JS engine WebAssembly module + /// + /// Depending on which features have been enabled, different default-provided WASI + /// imports may be stubbed (for example to be made unreachable). + stub-wasi: func( + engine: list, + features: list, + wit-world: option, + wit-path: option, + world-name: option + ) -> result, string>; + + /// Splice blindings for a given WIT world into the spider monkey engine binary (spidermonkey.wasm) + /// this function produces a new WebAssembly component + splice-bindings: func( + spidermonkey-engine: list, + features: list, + wit-world: option, + wit-path: option, + world-name: option, + debug: bool, + ) -> result; - export splice-bindings: func(spidermonkey-engine: list, wit-world: option, wit-path: option, world-name: option, debug: bool) -> result; +} + +world spidermonkey-embedding-splicer { + export splicer; } diff --git a/crates/splicer-component/Cargo.toml b/crates/splicer-component/Cargo.toml index b86ed533..33725ebd 100644 --- a/crates/splicer-component/Cargo.toml +++ b/crates/splicer-component/Cargo.toml @@ -7,5 +7,8 @@ version.workspace = true [lib] crate-type = ["cdylib"] +[lints] +workspace = true + [dependencies] spidermonkey-embedding-splicer = { path = "../spidermonkey-embedding-splicer" } diff --git a/crates/splicer-component/src/lib.rs b/crates/splicer-component/src/lib.rs index 77133af3..07a21f58 100644 --- a/crates/splicer-component/src/lib.rs +++ b/crates/splicer-component/src/lib.rs @@ -1,13 +1,14 @@ use spidermonkey_embedding_splicer::stub_wasi::stub_wasi; -use spidermonkey_embedding_splicer::wit::{export, Features, Guest, SpliceResult}; -use spidermonkey_embedding_splicer::{splice, wit}; +use spidermonkey_embedding_splicer::wit::{self, export}; +use spidermonkey_embedding_splicer::wit::exports::local::spidermonkey_embedding_splicer::splicer::{Feature, Guest, SpliceResult}; +use spidermonkey_embedding_splicer::splice; struct SpidermonkeyEmbeddingSplicerComponent; impl Guest for SpidermonkeyEmbeddingSplicerComponent { fn stub_wasi( wasm: Vec, - features: Vec, + features: Vec, wit_source: Option, wit_path: Option, world_name: Option, @@ -17,12 +18,13 @@ impl Guest for SpidermonkeyEmbeddingSplicerComponent { fn splice_bindings( engine: Vec, - world_name: Option, - wit_path: Option, + features: Vec, wit_source: Option, + wit_path: Option, + world_name: Option, debug: bool, ) -> Result { - splice::splice_bindings(engine, wit_source, wit_path, world_name, debug) + splice::splice_bindings(engine, features, wit_source, wit_path, world_name, debug) } } diff --git a/embedding/embedding.cpp b/embedding/embedding.cpp index 585f3edb..68463f8f 100644 --- a/embedding/embedding.cpp +++ b/embedding/embedding.cpp @@ -1,4 +1,5 @@ #include "embedding.h" +#include "debugger.h" #include "builtins/web/performance.h" namespace builtins::web::console { @@ -131,6 +132,12 @@ cabi_realloc_adapter(void *ptr, size_t orig_size, size_t org_align, } // This MUST override the StarlingMonkey core cabi_realloc export +// +// NOTE: You *should* avoid external host calls during realloc +// (ex. using the LOG macro to log a message), as this is a condition +// under which the component may be marked to prevent leaving (doing a new host call). +// +// see: https://github.com/bytecodealliance/wasmtime/blob/aec935f2e746d71934c8a131be15bbbb4392138c/crates/wasmtime/src/runtime/component/func/host.rs#L741 __attribute__((export_name("cabi_realloc"))) void * cabi_realloc(void *ptr, size_t orig_size, size_t org_align, size_t new_size) { void *ret = JS_realloc(Runtime.cx, ptr, orig_size, new_size); @@ -139,14 +146,13 @@ cabi_realloc(void *ptr, size_t orig_size, size_t org_align, size_t new_size) { if (!ret) { Runtime.engine->abort("(cabi_realloc) Unable to realloc"); } - LOG("(cabi_realloc) [%d %zu %zu] %d\n", (uint32_t)ptr, orig_size, new_size, - (uint32_t)ret); return ret; } __attribute__((export_name("call"))) uint32_t call(uint32_t fn_idx, void *argptr) { if (Runtime.first_call) { + content_debugger::maybe_init_debugger(Runtime.engine, true); js::ResetMathRandomSeed(Runtime.cx); Runtime.first_call = false; if (Runtime.clocks) { @@ -226,7 +232,7 @@ __attribute__((export_name("call"))) uint32_t call(uint32_t fn_idx, void *retptr = nullptr; if (fn->retptr) { LOG("(call) setting retptr at arg %d\n", argcnt); - retptr = JS_realloc(Runtime.cx, 0, 0, fn->retsize); + retptr = cabi_realloc(nullptr, 0, 4, fn->retsize); args[argcnt].setInt32((uint32_t)retptr); } diff --git a/examples/hello-world/guest/componentize.js b/examples/hello-world/guest/componentize.js index 8f250158..5a8eac6e 100644 --- a/examples/hello-world/guest/componentize.js +++ b/examples/hello-world/guest/componentize.js @@ -3,14 +3,10 @@ import { resolve } from 'node:path'; import { componentize } from '@bytecodealliance/componentize-js'; -// AoT compilation makes use of weval (https://github.com/bytecodealliance/weval) -const enableAot = process.env.ENABLE_AOT == '1'; - const jsSource = await readFile('hello.js', 'utf8'); const { component } = await componentize(jsSource, { witPath: resolve('hello.wit'), - enableAot }); await writeFile('hello.component.wasm', component); diff --git a/examples/hello-world/guest/package.json b/examples/hello-world/guest/package.json index 0688020c..f766077e 100644 --- a/examples/hello-world/guest/package.json +++ b/examples/hello-world/guest/package.json @@ -1,10 +1,10 @@ { "type": "module", "devDependencies": { - "@bytecodealliance/jco": "*", "@bytecodealliance/componentize-js": "*" }, "scripts": { - "build": "node componentize.js && cargo build --release" + "build": "node componentize.js", + "all": "npm run build" } } diff --git a/package-lock.json b/package-lock.json index e919e466..87c396dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,29 @@ { "name": "@bytecodealliance/componentize-js", - "version": "0.18.0", + "version": "0.19.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bytecodealliance/componentize-js", - "version": "0.18.0", + "version": "0.19.2", "workspaces": [ "." ], "dependencies": { - "@bytecodealliance/jco": "^1.9.1", - "@bytecodealliance/weval": "^0.3.3", - "@bytecodealliance/wizer": "^7.0.5", - "es-module-lexer": "^1.6.0" + "@bytecodealliance/jco": "^1.15.1", + "@bytecodealliance/wizer": "^10.0.0", + "es-module-lexer": "^1.6.0", + "oxc-parser": "^0.76.0" }, "bin": { "componentize-js": "src/cli.js" }, "devDependencies": { - "@bytecodealliance/preview2-shim": "^0.17.1", + "@bytecodealliance/preview2-shim": "^0.17.4", "cross-env": "^7.0.3", - "mocha": "^11.1.0" + "semver": "^7.7.2", + "vitest": "^3.2.4" } }, "node_modules/@bytecodealliance/componentize-js": { @@ -30,19 +31,15 @@ "link": true }, "node_modules/@bytecodealliance/jco": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@bytecodealliance/jco/-/jco-1.9.1.tgz", - "integrity": "sha512-Xmd1iw2OrWhlLOPZraFTBuE1AGfMSQVqKzswmq3k1vQ5B0EJe8O1CFG/UJeRXwbq1fxHHS9DTtlfAZiTeOdLWQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco/-/jco-1.15.1.tgz", + "integrity": "sha512-xyn/mvCjMCHX5dr2m7Ijx7HK/EaPbFvAU/BQ9F6HaZ6W2N/ajx5/eP+UgkQpiN58tjKGLSKbyoOjRxpCJOYfWg==", "license": "(Apache-2.0 WITH LLVM-exception)", - "workspaces": [ - "packages/preview2-shim" - ], "dependencies": { - "@bytecodealliance/componentize-js": "^0.15.0", - "@bytecodealliance/preview2-shim": "^0.17.1", - "binaryen": "^120.0.0", - "chalk-template": "^1", - "commander": "^12", + "@bytecodealliance/componentize-js": "^0.19.1", + "@bytecodealliance/preview2-shim": "^0.17.3", + "binaryen": "^123.0.0", + "commander": "^14", "mkdirp": "^3", "ora": "^8", "terser": "^5" @@ -51,45 +48,16 @@ "jco": "src/jco.js" } }, - "node_modules/@bytecodealliance/jco/node_modules/@bytecodealliance/componentize-js": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@bytecodealliance/componentize-js/-/componentize-js-0.15.1.tgz", - "integrity": "sha512-bTQT+uwWNeyFXRiV6cp+5ERUKC2g6lyiMoeMys2/yg8IcWPwq+3btV1Pj/q0ueAwyiIsuQ//c+peMHPrNTmHOg==", - "workspaces": [ - "." - ], - "dependencies": { - "@bytecodealliance/jco": "^1.8.1", - "@bytecodealliance/weval": "^0.3.3", - "@bytecodealliance/wizer": "^7.0.5", - "es-module-lexer": "^1.5.4" - } - }, "node_modules/@bytecodealliance/preview2-shim": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.1.tgz", - "integrity": "sha512-h1qLL0TN5KXk/zagY2BtbZuDX6xYjz4Br9RZXEa0ID4UpiPc0agUMhTdz9r89G4vX5SU/tqBg1A6UNv2+DJ5pg==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.4.tgz", + "integrity": "sha512-vRfxQ6ob5wCgXlpVNoeIUHrqJ2+JTcnQASNMpoi3OVPRYA2oUfhMJdWFP0u5JVL9FlC4YKe+QKqerr345B3T4A==", "license": "(Apache-2.0 WITH LLVM-exception)" }, - "node_modules/@bytecodealliance/weval": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@bytecodealliance/weval/-/weval-0.3.3.tgz", - "integrity": "sha512-hrQI47O1l3ilFscixu0uuSJTj5tbQW0QmCATQWWNW0E8wJxbKH4yo8y57O5gqpRSKk/T+da1sH/GJNrnGHTFNA==", - "license": "Apache-2.0", - "dependencies": { - "@napi-rs/lzma": "^1.1.2", - "decompress": "^4.2.1", - "decompress-tar": "^4.1.1", - "decompress-unzip": "^4.0.1" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@bytecodealliance/wizer": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer/-/wizer-7.0.5.tgz", - "integrity": "sha512-xIbLzKxmUNaPwDWorcGtdxh1mcgDiXI8fe9KiDaSICKfCl9VtUKVyXIc3ix+VpwFczBbdhek+TlMiiCf+9lpOQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer/-/wizer-10.0.0.tgz", + "integrity": "sha512-ziWmovyu1jQl9TsKlfC2bwuUZwxVPFHlX4fOqTzxhgS76jITIo45nzODEwPgU+jjmOr8F3YX2V2wAChC5NKujg==", "license": "Apache-2.0", "bin": { "wizer": "wizer.js" @@ -98,18 +66,18 @@ "node": ">=16" }, "optionalDependencies": { - "@bytecodealliance/wizer-darwin-arm64": "7.0.5", - "@bytecodealliance/wizer-darwin-x64": "7.0.5", - "@bytecodealliance/wizer-linux-arm64": "7.0.5", - "@bytecodealliance/wizer-linux-s390x": "7.0.5", - "@bytecodealliance/wizer-linux-x64": "7.0.5", - "@bytecodealliance/wizer-win32-x64": "7.0.5" + "@bytecodealliance/wizer-darwin-arm64": "10.0.0", + "@bytecodealliance/wizer-darwin-x64": "10.0.0", + "@bytecodealliance/wizer-linux-arm64": "10.0.0", + "@bytecodealliance/wizer-linux-s390x": "10.0.0", + "@bytecodealliance/wizer-linux-x64": "10.0.0", + "@bytecodealliance/wizer-win32-x64": "10.0.0" } }, "node_modules/@bytecodealliance/wizer-darwin-arm64": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-arm64/-/wizer-darwin-arm64-7.0.5.tgz", - "integrity": "sha512-Tp0SgVQR568SVPvSfyWDT00yL4ry/w9FS2qy8ZwaP0EauYyjFSZojj6mESX6x9fpYkEnQdprgfdvhw5h1hTwCQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-arm64/-/wizer-darwin-arm64-10.0.0.tgz", + "integrity": "sha512-dhZTWel+xccGTKSJtI9A7oM4yyP20FWflsT+AoqkOqkCY7kCNrj4tmMtZ6GXZFRDkrPY5+EnOh62sfShEibAMA==", "cpu": [ "arm64" ], @@ -123,9 +91,9 @@ } }, "node_modules/@bytecodealliance/wizer-darwin-x64": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-x64/-/wizer-darwin-x64-7.0.5.tgz", - "integrity": "sha512-HYmG5Q9SpQJnqR7kimb5J3VAh6E62b30GLG/E+6doS/UwNhSpSmYjaggVfuJvgFDbUxsnD1l36qZny0xMwxikA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-x64/-/wizer-darwin-x64-10.0.0.tgz", + "integrity": "sha512-r/LUIZw6Q3Hf4htd46mD+EBxfwjBkxVIrTM1r+B2pTCddoBYQnKVdVsI4UFyy7NoBxzEg8F8BwmTNoSLmFRjpw==", "cpu": [ "x64" ], @@ -139,9 +107,9 @@ } }, "node_modules/@bytecodealliance/wizer-linux-arm64": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-arm64/-/wizer-linux-arm64-7.0.5.tgz", - "integrity": "sha512-01qqaiIWrYXPt2bjrfiluSSOmUL/PMjPtJlYa/XqZgK75g3RVn3sRkSflwoCXtXMRbHdb03qNrJ9w81+F17kvA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-arm64/-/wizer-linux-arm64-10.0.0.tgz", + "integrity": "sha512-pGSfFWXzeTqHm6z1PtVaEn+7Fm3QGC8YnHrzBV4sQDVS3N1NwmuHZAc8kslmlFPNdu61ycEvdOsSgCny8JPQvg==", "cpu": [ "arm64" ], @@ -155,9 +123,9 @@ } }, "node_modules/@bytecodealliance/wizer-linux-s390x": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-s390x/-/wizer-linux-s390x-7.0.5.tgz", - "integrity": "sha512-smGfD4eJou81g6yDlV7MCRoKgKlqd4SQL00pHxQGrNfUPnfYKhZ4z80N9J9T2B++uo2FM14BFilsRrV5UevKlA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-s390x/-/wizer-linux-s390x-10.0.0.tgz", + "integrity": "sha512-O8vHxRTAdb1lUnVXMIMTcp/9q4pq1D4iIKigJCipg2JN15taV9uFAWh0fO88wylXwuSlO7dOE1AwQl54fMKXQg==", "cpu": [ "s390x" ], @@ -171,9 +139,9 @@ } }, "node_modules/@bytecodealliance/wizer-linux-x64": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-x64/-/wizer-linux-x64-7.0.5.tgz", - "integrity": "sha512-lxMb25jLd6n+hhjPhlqRBnBdGRumKkcEavqJ3p4OAtjr6pEPdbSfSVmYDt9LnvtqmqQSnUCtFRRr5J2BmQ3SkQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-x64/-/wizer-linux-x64-10.0.0.tgz", + "integrity": "sha512-fJtM1sy43FBMnp+xpapFX6U1YdTBKA/1T4CYfG/qeE8jn0SXk2EuiYoY/EnC2uyNy9hjTrvfdYO5n4MXW0EIdQ==", "cpu": [ "x64" ], @@ -187,9 +155,9 @@ } }, "node_modules/@bytecodealliance/wizer-win32-x64": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-win32-x64/-/wizer-win32-x64-7.0.5.tgz", - "integrity": "sha512-eUY9a82HR20qIfyEffWdJZj7k4GH2wGaZpr70dinDy8Q648LeQayL0Z6FW5nApoezjy+CIBj0Mv+rHUASV9Jzw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-win32-x64/-/wizer-win32-x64-10.0.0.tgz", + "integrity": "sha512-55BPLfGT7iT7gH5M69NpTM16QknJZ7OxJ0z73VOEoeGA9CT8QPKMRzFKsPIvLs+W8G28fdudFA94nElrdkp3Kg==", "cpu": [ "x64" ], @@ -203,20 +171,20 @@ } }, "node_modules/@emnapi/core": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz", - "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.4.tgz", + "integrity": "sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.1", + "@emnapi/wasi-threads": "1.0.3", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.4.tgz", + "integrity": "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==", "license": "MIT", "optional": true, "dependencies": { @@ -224,1584 +192,1545 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", - "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.3.tgz", + "integrity": "sha512-8K5IFFsQqF9wQNJptGbS6FNKgUTsSRYnTqNCG1vPP8jFdjSv18n2mQfJpkt2Oibo9iBEzcDnDxNwKTzC7svlJw==", "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma/-/lzma-1.4.1.tgz", - "integrity": "sha512-5f8K9NHjwHjZKGm3SS+7CFxXQhz8rbg2umBm/9g0xQRXBdYEI31N5z1ACuk9bmBQOusXAq9CArGfs/ZQso2rUA==", - "license": "MIT", - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/lzma-android-arm-eabi": "1.4.1", - "@napi-rs/lzma-android-arm64": "1.4.1", - "@napi-rs/lzma-darwin-arm64": "1.4.1", - "@napi-rs/lzma-darwin-x64": "1.4.1", - "@napi-rs/lzma-freebsd-x64": "1.4.1", - "@napi-rs/lzma-linux-arm-gnueabihf": "1.4.1", - "@napi-rs/lzma-linux-arm64-gnu": "1.4.1", - "@napi-rs/lzma-linux-arm64-musl": "1.4.1", - "@napi-rs/lzma-linux-ppc64-gnu": "1.4.1", - "@napi-rs/lzma-linux-riscv64-gnu": "1.4.1", - "@napi-rs/lzma-linux-s390x-gnu": "1.4.1", - "@napi-rs/lzma-linux-x64-gnu": "1.4.1", - "@napi-rs/lzma-linux-x64-musl": "1.4.1", - "@napi-rs/lzma-wasm32-wasi": "1.4.1", - "@napi-rs/lzma-win32-arm64-msvc": "1.4.1", - "@napi-rs/lzma-win32-ia32-msvc": "1.4.1", - "@napi-rs/lzma-win32-x64-msvc": "1.4.1" - } - }, - "node_modules/@napi-rs/lzma-android-arm-eabi": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-android-arm-eabi/-/lzma-android-arm-eabi-1.4.1.tgz", - "integrity": "sha512-yenreSpZ9IrqppJOiWDqWMmja7XtSgio9LhtxYwgdILmy/OJTe/mlTYv+FhJBf7hIV9Razu5eBuEa3zKri81IA==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", "cpu": [ - "arm" + "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-android-arm64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-android-arm64/-/lzma-android-arm64-1.4.1.tgz", - "integrity": "sha512-piutVBz5B1TNxXeEjub0n/IKI6dMaXPPRbVSXuc4gnZgzcihNDUh68vcLZgYd+IMiACZvBxvx2O3t5nthtph3A==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "android" + "darwin" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-darwin-arm64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-darwin-arm64/-/lzma-darwin-arm64-1.4.1.tgz", - "integrity": "sha512-sDfOhQQFqV8lGbpgJN9DqNLBPR7QOfYjcWUv8FOGPaVP1LPJDnrc5uCpRWWEa2zIKmTiO8P9xzIl0TDzrYmghg==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", "cpu": [ - "arm64" + "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-darwin-x64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-darwin-x64/-/lzma-darwin-x64-1.4.1.tgz", - "integrity": "sha512-S5/RbC6EP4QkYy2xhxbfm48ZD9FkysfpWY4Slve0nj5RGGsHvcJBg2Pi69jrTPB/zLKz2SUa0i+RfUt9zvZNaw==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", "cpu": [ - "x64" + "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-freebsd-x64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-freebsd-x64/-/lzma-freebsd-x64-1.4.1.tgz", - "integrity": "sha512-4AFnq6aZnclwameSBkDWu5Ftb8y4GwvVXeQXJKbN7hf7O5GG/8QpQB1R1NJw2QORUhpKwjAQUpbkTyhL2GFWWw==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-arm-gnueabihf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-arm-gnueabihf/-/lzma-linux-arm-gnueabihf-1.4.1.tgz", - "integrity": "sha512-j5rL1YRIm6rWmmGAvN6DPX6QuRjvFGB93xJ7DTRB47GXW4zHekXae6ivowjJ95vT4Iz4hSWkZbuwAy95eFrWRA==", + "node_modules/@esbuild/linux-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-arm64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-arm64-gnu/-/lzma-linux-arm64-gnu-1.4.1.tgz", - "integrity": "sha512-1XdFGKyTS9m+VrRQYs9uz+ToHf4Jwm0ejHU48k9lT9MPl8jSqzKdVtFzZBPzronHteSynBfKmUq0+HeWmjrsOQ==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-arm64-musl": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-arm64-musl/-/lzma-linux-arm64-musl-1.4.1.tgz", - "integrity": "sha512-9d09tYS0/rBwIk1QTcO2hMZEB/ZpsG2+uFW5am1RHElSWMclObirB1An7b6AMDJcRvcomkOg2GZ9COzrvHKwEA==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", "cpu": [ - "arm64" + "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-ppc64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-ppc64-gnu/-/lzma-linux-ppc64-gnu-1.4.1.tgz", - "integrity": "sha512-UzEkmsgoJ3IOGIRb6kBzNiw+ThUpiighop7dVYfSqlF5juGzwf7YewC57RGn4FoJCvadOCrSm5VikAcgrwVgAw==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", "cpu": [ - "ppc64" + "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-riscv64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-riscv64-gnu/-/lzma-linux-riscv64-gnu-1.4.1.tgz", - "integrity": "sha512-9dUKlZ1PdwxTaFF+j3oc+xjlk9nqFwo1NWWOH30uwjl4Rm5Gkv+Fx0pHrzu4kR/iVA+oyQqa9/2uDYnGSTijBA==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", "cpu": [ - "riscv64" + "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-s390x-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-s390x-gnu/-/lzma-linux-s390x-gnu-1.4.1.tgz", - "integrity": "sha512-MOVXUWJSLLCJDCCAlGa39sh7nv9XjvXzCf7QJus7rD8Ciz0mpXNXF9mg0ji7/MZ7pZlKPlXjXDnpVCfFdSEaFQ==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", "cpu": [ - "s390x" + "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-x64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.4.1.tgz", - "integrity": "sha512-Sxu7aJxU1sDbUTqjqLVDV3DCOAlbsFKvmuCN/S5uXBJd1IF2wJ9jK3NbFzfqTAo5Hudx8Y7kOb6+3K+fYPI1KQ==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", "cpu": [ - "x64" + "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-linux-x64-musl": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-musl/-/lzma-linux-x64-musl-1.4.1.tgz", - "integrity": "sha512-4I3BeKBQJSE5gF2/VTEv7wCLLjhapeutbCGpZPmDiLHZ74rm9edmNXAlKpdjADQ4YDLJ2GIBzttvwLXkJ9U+cw==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", "cpu": [ - "x64" + "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-wasm32-wasi": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-wasm32-wasi/-/lzma-wasm32-wasi-1.4.1.tgz", - "integrity": "sha512-s32HdKqQWbohf6DGWpG9YMODaBdbKJ++JpNr6Ii7821sKf4h/o+p8IRFTOaWdmdJdllEWlRirnd5crA29VivJQ==", + "node_modules/@esbuild/linux-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", "cpu": [ - "wasm32" + "x64" ], + "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.4" - }, + "os": [ + "linux" + ], "engines": { - "node": ">=14.0.0" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-win32-arm64-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-win32-arm64-msvc/-/lzma-win32-arm64-msvc-1.4.1.tgz", - "integrity": "sha512-ISz+v7ML5mKnjEZ7Kk4Z1BIn411r/fz3tDy9j5yDnwQI0MgTsUQFrIQElGUpULWYs2aYc6EZ9PhECbLBfSjh7A==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "netbsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-win32-ia32-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-win32-ia32-msvc/-/lzma-win32-ia32-msvc-1.4.1.tgz", - "integrity": "sha512-3WKuCpZBrd7Jrw+h1jSu5XAsRWepMJu0sYuRoA4Y4Cwfu9gI7p5Z5Bc510nfjg7M7xvdpkI4UoW2WY7kBFRYrQ==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", "cpu": [ - "ia32" + "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "netbsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/lzma-win32-x64-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-win32-x64-msvc/-/lzma-win32-x64-msvc-1.4.1.tgz", - "integrity": "sha512-0ixRo5z1zFXdh62hlrTV+QCTKHK0te5NHKaExOluhtcc6AdpMmpslvM9JhUxNHI+zM46w/DmmcvcOtqsaTmHgg==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", "cpu": [ - "x64" + "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "openbsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.7.tgz", - "integrity": "sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/core": "^1.3.1", - "@emnapi/runtime": "^1.3.1", - "@tybys/wasm-util": "^0.9.0" + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=14" + "node": ">=18" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, + "os": [ + "sunos" + ], "engines": { - "node": ">=0.4.0" + "node": ">=18" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "cpu": [ + "ia32" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=18" } }, - "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "node_modules/@esbuild/win32-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=18" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">= 8" + "node": ">=6.0.0" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/binaryen": { - "version": "120.0.0", - "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-120.0.0.tgz", - "integrity": "sha512-MaNC1qW5ubk5S7MNNxNpAb9ivKp6TAf8CDknRk4XeCC2wkrpdaubK10S1CAwUXaDDF54gZLtk6opzbEA9VTtJw==", - "license": "Apache-2.0", - "bin": { - "wasm-as": "bin/wasm-as", - "wasm-ctor-eval": "bin/wasm-ctor-eval", - "wasm-dis": "bin/wasm-dis", - "wasm-merge": "bin/wasm-merge", - "wasm-metadce": "bin/wasm-metadce", - "wasm-opt": "bin/wasm-opt", - "wasm-reduce": "bin/wasm-reduce", - "wasm-shell": "bin/wasm-shell", - "wasm2js": "bin/wasm2js" + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" } }, - "node_modules/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "license": "MIT", "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", "license": "MIT", + "optional": true, "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "license": "ISC" - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.76.0.tgz", + "integrity": "sha512-1XJW/16CDmF5bHE7LAyPPmEEVnxSadDgdJz+xiLqBrmC4lfAeuAfRw3HlOygcPGr+AJsbD4Z5sFJMkwjbSZlQg==", + "cpu": [ + "arm64" ], "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=20.0.0" } }, - "node_modules/buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.76.0.tgz", + "integrity": "sha512-yoQwSom8xsB+JdGsPUU0xxmxLKiF2kdlrK7I56WtGKZilixuBf/TmOwNYJYLRWkBoW5l2/pDZOhBm2luwmLiLw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.0.0" } }, - "node_modules/buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "license": "MIT" - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.76.0.tgz", + "integrity": "sha512-uRIopPLvr3pf2Xj7f5LKyCuqzIU6zOS+zEIR8UDYhcgJyZHnvBkfrYnfcztyIcrGdQehrFUi3uplmI09E7RdiQ==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "*" + "node": ">=20.0.0" } }, - "node_modules/buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", - "license": "MIT" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.76.0.tgz", + "integrity": "sha512-a0EOFvnOd2FqmDSvH6uWLROSlU6KV/JDKbsYDA/zRLyKcG6HCsmFnPsp8iV7/xr9WMbNgyJi6R5IMpePQlUq7Q==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=20.0.0" } }, - "node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.76.0.tgz", + "integrity": "sha512-ikRYDHL3fOdZwfJKmcdqjlLgkeNZ3Ez0qM8wAev5zlHZ+lY/Ig7qG5SCqPlvuTu+nNQ6zrFFaKvvt69EBKXU/g==", + "cpu": [ + "arm" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=20.0.0" } }, - "node_modules/chalk-template": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-1.1.0.tgz", - "integrity": "sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==", + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.76.0.tgz", + "integrity": "sha512-dtRv5J5MRCLR7x39K8ufIIW4svIc7gYFUaI0YFXmmeOBhK/K2t/CkguPnDroKtsmXIPHDRtmJ1JJYzNcgJl6Wg==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "chalk": "^5.2.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/chalk/chalk-template?sponsor=1" + "node": ">=20.0.0" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.76.0.tgz", + "integrity": "sha512-IE4iiiggFH2snagQxHrY5bv6dDpRMMat+vdlMN/ibonA65eOmRLp8VLTXnDiNrcla/itJ1L9qGABHNKU+SnE8g==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=20.0.0" } }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.76.0.tgz", + "integrity": "sha512-wi9zQPMDHrBuRuT7Iurfidc9qlZh7cKa5vfYzOWNBCaqJdgxmNOFzvYen02wVUxSWGKhpiPHxrPX0jdRyJ8Npg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=20.0.0" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.76.0.tgz", + "integrity": "sha512-0tqqu1pqPee2lLGY8vtYlX1L415fFn89e0a3yp4q5N9f03j1rRs0R31qesTm3bt/UK8HYjECZ+56FCVPs2MEMQ==", + "cpu": [ + "riscv64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=20.0.0" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.76.0.tgz", + "integrity": "sha512-y36Hh1a5TA+oIGtlc8lT7N9vdHXBlhBetQJW0p457KbiVQ7jF7AZkaPWhESkjHWAsTVKD2OjCa9ZqfaqhSI0FQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">=20.0.0" } }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.76.0.tgz", + "integrity": "sha512-7/acaG9htovp3gp/J0kHgbItQTuHctl+rbqPPqZ9DRBYTz8iV8kv3QN8t8Or8i/hOmOjfZp9McDoSU1duoR4/A==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=20.0.0" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.76.0.tgz", + "integrity": "sha512-AxFt0reY6Q2rfudABmMTFGR8tFFr58NlH2rRBQgcj+F+iEwgJ+jMwAPhXd2y1I2zaI8GspuahedUYQinqxWqjA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=20.0.0" } }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.76.0.tgz", + "integrity": "sha512-wHdkHdhf6AWBoO8vs5cpoR6zEFY1rB+fXWtq6j/xb9j/lu1evlujRVMkh8IM/M/pOUIrNkna3nzST/mRImiveQ==", + "cpu": [ + "wasm32" + ], "license": "MIT", + "optional": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@napi-rs/wasm-runtime": "^0.2.11" }, "engines": { - "node": ">=8" + "node": ">=14.0.0" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.76.0.tgz", + "integrity": "sha512-G7ZlEWcb2hNwCK3qalzqJoyB6HaTigQ/GEa7CU8sAJ/WwMdG/NnPqiC9IqpEAEy1ARSo4XMALfKbKNuqbSs5mg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=20.0.0" } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.76.0.tgz", + "integrity": "sha512-0jLzzmnu8/mqNhKBnNS2lFUbPEzRdj5ReiZwHGHpjma0+ullmmwP2AqSEqx3ssHDK9CpcEMdKOK2LsbCfhHKIA==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=20.0.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@oxc-project/types": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.76.0.tgz", + "integrity": "sha512-CH3THIrSViKal8yV/Wh3FK0pFhp40nzW1MUDCik9fNuid2D/7JJXKJnfFOAvMxInGXDlvmgT6ACAzrl47TqzkQ==", "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" + "optional": true, + "os": [ + "android" + ] }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/decompress": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", - "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "engines": { - "node": ">=4" - } + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "engines": { - "node": ">=4" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "engines": { - "node": ">=4" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/decompress-tarbz2/node_modules/file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "engines": { - "node": ">=4" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "engines": { - "node": ">=4" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "cpu": [ + "loong64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "engines": { - "node": ">=4" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/decompress-unzip/node_modules/file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/es-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", - "license": "MIT" + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">=6" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", "license": "MIT", - "engines": { - "node": ">=4" + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" + "@types/deep-eql": "*" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" + "url": "https://opencollective.com/vitest" } }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, - "node_modules/get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, "license": "MIT", "dependencies": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "tinyspy": "^4.0.3" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://opencollective.com/vitest" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", + "node_modules/binaryen": { + "version": "123.0.0", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-123.0.0.tgz", + "integrity": "sha512-/hls/a309aZCc0itqP6uhoR+5DsKSlJVfB8Opd2BY9Ndghs84IScTunlyidyF4r2Xe3lQttnfBNIDjaNpj6mTw==", + "license": "Apache-2.0", "bin": { - "he": "bin/he" + "wasm-as": "bin/wasm-as", + "wasm-ctor-eval": "bin/wasm-ctor-eval", + "wasm-dis": "bin/wasm-dis", + "wasm-merge": "bin/wasm-merge", + "wasm-metadce": "bin/wasm-metadce", + "wasm-opt": "bin/wasm-opt", + "wasm-reduce": "bin/wasm-reduce", + "wasm-shell": "bin/wasm-shell", + "wasm2js": "bin/wasm2js" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/chai": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz", + "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==", "dev": true, "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 16" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==", - "license": "MIT" + "node_modules/commander": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", + "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "license": "MIT", + "engines": { + "node": ">=20" + } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", "dev": true, "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, "engines": { - "node": ">=0.12.0" + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "license": "MIT" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/esbuild": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=18" }, "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "@types/estree": "^1.0.0" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12.0.0" } }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, "license": "ISC" }, - "node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" }, - "node_modules/make-dir/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/loupe": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.0.tgz", + "integrity": "sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/mimic-function": { @@ -1816,29 +1745,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/mkdirp": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", @@ -1854,42 +1760,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", - "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1897,32 +1767,23 @@ "dev": true, "license": "MIT" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/onetime": { @@ -2026,53 +1887,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "node_modules/oxc-parser": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.76.0.tgz", + "integrity": "sha512-l98B2e9evuhES7zN99rb1QGhbzx25829TJFaKi2j0ib3/K/G5z1FdGYz6HZkrU3U8jdH7v2FC8mX1j2l9JrOUg==", "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "@oxc-project/types": "^0.76.0" }, "engines": { - "node": ">=10" + "node": ">=20.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" + "url": "https://github.com/sponsors/Boshen" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "optionalDependencies": { + "@oxc-parser/binding-android-arm64": "0.76.0", + "@oxc-parser/binding-darwin-arm64": "0.76.0", + "@oxc-parser/binding-darwin-x64": "0.76.0", + "@oxc-parser/binding-freebsd-x64": "0.76.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.76.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.76.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.76.0", + "@oxc-parser/binding-linux-arm64-musl": "0.76.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.76.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.76.0", + "@oxc-parser/binding-linux-x64-gnu": "0.76.0", + "@oxc-parser/binding-linux-x64-musl": "0.76.0", + "@oxc-parser/binding-wasm32-wasi": "0.76.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.76.0", + "@oxc-parser/binding-win32-x64-msvc": "0.76.0" } }, "node_modules/path-key": { @@ -2085,130 +1929,57 @@ "node": ">=8" } }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "license": "MIT" }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { + "node_modules/pathval": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, "license": "MIT", - "dependencies": { - "pinkie": "^2.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 14.16" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" + "license": "ISC" }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >=14" } }, "node_modules/restore-cursor": { @@ -2227,53 +1998,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/seek-bzip": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", - "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", + "node_modules/rollup": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", + "dev": true, "license": "MIT", "dependencies": { - "commander": "^2.8.1" + "@types/estree": "1.0.8" }, "bin": { - "seek-bunzip": "bin/seek-bunzip", - "seek-table": "bin/seek-bzip-table" + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", + "fsevents": "~2.3.2" } }, - "node_modules/seek-bzip/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/shebang-command": { @@ -2299,221 +2074,106 @@ "node": ">=8" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { - "node": ">=12" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", "dependencies": { - "is-natural-number": "^4.0.1" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "dev": true, + "license": "MIT" + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "node_modules/strip-literal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", + "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", + "dev": true, "license": "MIT", "dependencies": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" + "js-tokens": "^9.0.1" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "url": "https://github.com/sponsors/antfu" } }, "node_modules/terser": { @@ -2540,312 +2200,346 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, "license": "MIT" }, - "node_modules/to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, "license": "MIT" }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "fdir": "^6.4.4", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true - }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "license": "MIT", - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "engines": { - "node": ">= 8" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "^18.0.0 || >=20.0.0" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14.0.0" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/tinyspy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", + "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=14.0.0" } }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/vite": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz", + "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.40.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "engines": { - "node": ">=12" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" }, "engines": { - "node": ">=10" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" }, "engines": { "node": ">=8" } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/package.json b/package.json index 37682866..3b8e5956 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "@bytecodealliance/componentize-js", - "version": "0.18.1", + "version": "0.19.3", "homepage": "https://github.com/bytecodealliance/componentize-js#readme", "description": "ESM -> WebAssembly Component creator, via a SpiderMonkey JS engine embedding", "type": "module", + "repository": { + "url": "https://github.com/bytecodealliance/ComponentizeJS" + }, "bin": { "componentize-js": "src/cli.js" }, @@ -12,41 +15,38 @@ "import": "./src/componentize.js" }, "devDependencies": { - "@bytecodealliance/preview2-shim": "^0.17.1", + "@bytecodealliance/preview2-shim": "^0.17.4", "cross-env": "^7.0.3", - "mocha": "^11.1.0" + "semver": "^7.7.2", + "vitest": "^3.2.4" }, "dependencies": { - "@bytecodealliance/jco": "^1.9.1", - "@bytecodealliance/weval": "^0.3.3", - "@bytecodealliance/wizer": "^7.0.5", - "es-module-lexer": "^1.6.0" + "@bytecodealliance/jco": "^1.15.1", + "@bytecodealliance/wizer": "^10.0.0", + "es-module-lexer": "^1.6.0", + "oxc-parser": "^0.76.0" }, "types": "types.d.ts", "scripts": { "clean": "npm run clean:starlingmonkey", "clean:starlingmonkey": "rm -rf build-release", - "build": "npm run build:release && npm run build:debug && npm run build:weval", + "build": "npm run build:release && npm run build:debug", "build:release": "make release", - "build:weval": "make release-weval", "build:debug": "make debug", - "test": "mocha -u tdd test/test.js --timeout 120000", - "test:release": "mocha -u tdd test/test.js --timeout 120000", - "test:weval": "cross-env WEVAL_TEST=1 mocha -u tdd test/test.js --timeout 120000", - "test:debug": "cross-env DEBUG_TEST=1 mocha -u tdd test/test.js --timeout 120000", - "prepublishOnly": "npm run build" + "test": "vitest run -c test/vitest.ts", + "test:release": "vitest run -c test/vitest.ts", + "test:debug": "cross-env DEBUG_TEST=1 vitest run -c test/vitest.ts", + "prepack": "node scripts/prepack.mjs" }, "files": [ "lib/interfaces", "lib/spidermonkey-*", "lib/starlingmonkey_embedding.wasm", "lib/starlingmonkey_embedding.debug.wasm", - "lib/starlingmonkey_embedding_weval.wasm", - "lib/starlingmonkey_ics.wevalcache", "src", "types.d.ts" ], "workspaces": [ "." ] -} \ No newline at end of file +} diff --git a/scripts/prepack.mjs b/scripts/prepack.mjs new file mode 100644 index 00000000..017d03bf --- /dev/null +++ b/scripts/prepack.mjs @@ -0,0 +1,12 @@ +import { env } from 'node:process'; +import { spawn } from 'node:child_process'; + +async function main() { + if (env.PREPACK_SKIP_BUILD) { + console.error(`SKIP_BUILD set, skipping prepack build step`); + return; + } + await spawn('npm', ['run', 'build'], { stdio: 'inherit' }); +} + +await main(); diff --git a/scripts/semver-get-prerelease.mjs b/scripts/semver-get-prerelease.mjs new file mode 100644 index 00000000..4306b1e3 --- /dev/null +++ b/scripts/semver-get-prerelease.mjs @@ -0,0 +1,22 @@ +import { stdout, argv } from "node:process"; + +import semver from "semver"; + +async function main() { + let version = argv[2]; + if (version?.startsWith("v")) { + version = version.slice(1); + } + if (!version || !semver.valid(version)) { + throw new Error("Missing/invalid semver value"); + } + + let p = semver.prerelease(version); + if (!p) { + stdout.write(""); + return; + } + stdout.write(`${p[0]}`); +} + +await main(); diff --git a/scripts/semver-is-prerelease.mjs b/scripts/semver-is-prerelease.mjs new file mode 100644 index 00000000..03baa0e5 --- /dev/null +++ b/scripts/semver-is-prerelease.mjs @@ -0,0 +1,18 @@ +import { stdout, argv } from "node:process"; + +import semver from "semver"; + +async function main() { + let version = argv[2]; + if (version?.startsWith("v")) { + version = version.slice(1); + } + if (!version || !semver.valid(version)) { + throw new Error("Missing/invalid semver value"); + } + + let isPrerelease = semver.prerelease(version) !== null; + stdout.write(`${isPrerelease}`); +} + +await main(); diff --git a/scripts/semver-lt.mjs b/scripts/semver-lt.mjs new file mode 100644 index 00000000..66fdf887 --- /dev/null +++ b/scripts/semver-lt.mjs @@ -0,0 +1,17 @@ +import { stdout, argv } from "node:process"; + +import semver from "semver"; + +async function main() { + let [lhs, rhs] = argv.slice(2, 4); + if (!lhs || !semver.valid(lhs)) { + throw new Error("Missing/invalid LHS semver value"); + } + if (!rhs || !semver.valid(rhs)) { + throw new Error("Missing/invalid RHS semver value"); + } + + stdout.write(`${semver.lt(lhs, rhs)}`); +} + +await main(); diff --git a/src/cli.js b/src/cli.js index 7ac7d522..ca2e3884 100755 --- a/src/cli.js +++ b/src/cli.js @@ -1,17 +1,16 @@ #! /usr/bin/env node import { program, Option } from 'commander'; -import { componentize } from "./componentize.js"; +import { componentize, DEFAULT_FEATURES } from './componentize.js'; import { writeFile } from 'node:fs/promises'; import { resolve } from 'node:path'; -export async function componentizeCmd (jsSource, opts) { - const { component } = await componentize( { +export async function componentizeCmd(jsSource, opts) { + const { component } = await componentize({ sourcePath: jsSource, witPath: resolve(opts.wit), worldName: opts.worldName, runtimeArgs: opts.runtimeArgs, - enableAot: opts.aot, disableFeatures: opts.disable, preview2Adapter: opts.preview2Adapter, debugBindings: opts.debugBindings, @@ -22,27 +21,36 @@ export async function componentizeCmd (jsSource, opts) { } program + .version('0.19.3') .description('Create a component from a JavaScript module') .usage(' --wit wit-world.wit -o ') .argument('', 'JS source file to build') .requiredOption('-w, --wit ', 'WIT path to build with') .option('-n, --world-name ', 'WIT world to build') .option('--runtime-args ', 'arguments to pass to the runtime') - .option('--aot', 'enable AOT compilation') - .addOption(new Option('-d, --disable ', 'disable WASI features').choices(['stdio', 'random', 'clocks', 'http'])) - .option('--preview2-adapter ', 'provide a custom preview2 adapter path') + .addOption( + new Option('-d, --disable ', 'disable WASI features').choices( + DEFAULT_FEATURES, + ), + ) + .option( + '--preview2-adapter ', + 'provide a custom preview2 adapter path', + ) .option('--use-debug-build', 'use a debug build of StarlingMonkey') .option('--debug-bindings', 'enable debug logging for bindings generation') - .option('--enable-wizer-logging', 'enable debug logging for calls in the generated component') + .option( + '--enable-wizer-logging', + 'enable debug logging for calls in the generated component', + ) .requiredOption('-o, --out ', 'output component file') .action(asyncAction(componentizeCmd)); - program.showHelpAfterError(); program.parse(); -function asyncAction (cmd) { +function asyncAction(cmd) { return function () { const args = [...arguments]; (async () => { diff --git a/src/componentize.js b/src/componentize.js index cb50f527..9991849f 100644 --- a/src/componentize.js +++ b/src/componentize.js @@ -1,92 +1,67 @@ -import { freemem } from "node:os"; +import { freemem } from 'node:os'; +import { TextDecoder } from 'node:util'; +import { Buffer } from 'node:buffer'; +import { fileURLToPath, URL } from 'node:url'; +import { cwd, stdout, platform } from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { tmpdir } from 'node:os'; +import { resolve, join, dirname, relative } from 'node:path'; +import { readFile, writeFile, mkdir, rm, stat } from 'node:fs/promises'; +import { rmSync, existsSync } from 'node:fs'; +import { createHash } from 'node:crypto'; + +import oxc from 'oxc-parser'; import wizer from '@bytecodealliance/wizer'; -import getWeval from '@bytecodealliance/weval'; import { componentNew, metadataAdd, preview1AdapterReactorPath, } from '@bytecodealliance/jco'; -import { spawnSync } from 'node:child_process'; -import { tmpdir } from 'node:os'; -import { resolve, join, dirname } from 'node:path'; -import { readFile, writeFile, mkdir, rm } from 'node:fs/promises'; -import { rmSync, existsSync } from 'node:fs'; -import { createHash } from 'node:crypto'; -import { - spliceBindings, - stubWasi, -} from '../lib/spidermonkey-embedding-splicer.js'; -import { fileURLToPath } from 'node:url'; -import { cwd, stdout, platform } from 'node:process'; + +import { splicer } from '../lib/spidermonkey-embedding-splicer.js'; + +import { maybeWindowsPath } from './platform.js'; + export const { version } = JSON.parse( await readFile(new URL('../package.json', import.meta.url), 'utf8'), ); -const isWindows = platform === 'win32'; - -function maybeWindowsPath(path) { - if (!path) return path; - const resolvedPath = resolve(path); - if (!isWindows) return resolvedPath; - - // Strip any existing UNC prefix check both the format we add as well as what - // the windows API returns when using path.resolve - let cleanPath = resolvedPath; - while (cleanPath.startsWith('\\\\?\\') || cleanPath.startsWith('//?/')) { - cleanPath = cleanPath.substring(4); - } - return '//?/' + cleanPath.replace(/\\/g, '/'); -} +/** Prefix into wizer error output that indicates a error/trap */ +const WIZER_ERROR_CAUSE_PREFIX = `Error: the \`componentize.wizer\` function trapped -/** - * Clean up the given input string by removing the given patterns if - * found as line prefixes. - */ -function stripLinesPrefixes(input, prefixPatterns) { - return input.split('\n') - .map(line => prefixPatterns.reduce((line, n) => line.replace(n, ''), line)) - .join('\n').trim(); -} +Caused by:`; -const WizerErrorCause = `Error: the \`componentize.wizer\` function trapped +/** Prefix into wizer error output that indicates exit status */ +const WIZER_EXIT_CODE_PREFIX = 'Exited with i32 exit status'; -Caused by:`; +/** Response code from check_init() that denotes success */ +const CHECK_INIT_RETURN_OK = 0; -const WizerExitCode = "Exited with i32 exit status"; +/** Response code from check_init() that denotes being unable to extract exports list */ +const CHECK_INIT_RETURN_FN_LIST = 1; -function parseWizerStderr(stderr) { - let output = `${stderr}`; - let causeStart = output.indexOf(WizerErrorCause); - let exitCodeStart = output.indexOf(WizerExitCode); - if (causeStart === -1 || exitCodeStart === -1) { - return output; - } +/** Response code from check_init() that denotes being unable to parse core ABI export types */ +const CHECK_INIT_RETURN_TYPE_PARSE = 2; - let causeEnd = output.indexOf('\n', exitCodeStart + 1); - return `${output.substring(0, causeStart)}${output.substring(causeEnd)}`.trim(); -} +/** Default settings for debug options */ +const DEFAULT_DEBUG_SETTINGS = { + bindings: false, + bindingsDir: null, -/** - * Check whether a value is numeric (including BigInt) - * - * @param {any} n - * @returns {boolean} whether the value is numeric - */ -function isNumeric(n) { - switch (typeof n) { - case 'bigint': - case 'number': - return true; - case 'object': - return n.constructor == BigInt || n.constructor == Number; - default: - return false; - } -} + binary: false, + binaryPath: null, + + wizerLogging: false, +}; -export async function componentize(opts, +/** Features that are used by default if not explicitly disabled */ +export const DEFAULT_FEATURES = ['stdio', 'random', 'clocks', 'http', 'fetch-event']; + +export async function componentize( + opts, _deprecatedWitWorldOrOpts = undefined, - _deprecatedOpts = undefined) { + _deprecatedOpts = undefined, +) { let useOriginalSourceFile = true; let jsSource; @@ -102,103 +77,133 @@ export async function componentize(opts, } else { if (typeof _deprecatedWitWorldOrOpts !== 'object') { throw new Error( - `componentize: second argument must be an object or a string, but is ${typeof _deprecatedWitWorldOrOpts}` + `componentize: second argument must be an object or a string, but is ${typeof _deprecatedWitWorldOrOpts}`, ); } opts = _deprecatedWitWorldOrOpts; } } - const tmpDir = join( - tmpdir(), - createHash('sha256') - .update(Math.random().toString()) - .digest('hex') - .slice(0, 12) - ); - await mkdir(tmpDir); - const sourceDir = maybeWindowsPath(join(tmpDir, 'sources')); - await mkdir(sourceDir); + // Prepare a working directory for use during componentization + const { sourcesDir, baseDir: workDir } = await prepWorkDir(); let { sourceName = 'source.js', - sourcePath = join(sourceDir, sourceName), + sourcePath = maybeWindowsPath(join(sourcesDir, sourceName)), preview2Adapter = preview1AdapterReactorPath(), witPath, witWorld, worldName, disableFeatures = [], enableFeatures = [], + + debug = { ...DEFAULT_DEBUG_SETTINGS }, debugBuild = false, - runtimeArgs, debugBindings = false, enableWizerLogging = false, - aotCache = fileURLToPath( - new URL(`../lib/starlingmonkey_ics.wevalcache`, import.meta.url), - ), + + runtimeArgs, + } = opts; - const engine = - opts.engine || - fileURLToPath( - new URL( - opts.enableAot - ? `../lib/starlingmonkey_embedding_weval.wasm` - : `../lib/starlingmonkey_embedding${debugBuild ? '.debug' : ''}.wasm`, - import.meta.url, - ), - ); + debugBindings = debugBindings || debug?.bindings; + debugBuild = debugBuild || debug?.build; + enableWizerLogging = enableWizerLogging || debug?.enableWizerLogging; - let { wasm, jsBindings, exports, imports } = spliceBindings( + // Determine the path to the StarlingMonkey binary + const engine = getEnginePath(opts); + + // Determine the default features that should be included + const features = new Set(); + for (let f of DEFAULT_FEATURES) { + if (!disableFeatures.includes(f)) { + features.add(f); + } + } + + if (!jsSource && sourcePath) { + jsSource = await readFile(sourcePath, 'utf8'); + } + const detectedExports = await detectKnownSourceExportNames( + sourceName, + jsSource, + ); + + // If there is an export of incomingHandler, there is likely to be a + // manual implementation of wasi:http/incoming-handler, so we should + // disable fetch-event + if (features.has('http') && detectedExports.has('incomingHandler')) { + if (debugBindings) { + console.error( + 'Detected `incomingHandler` export, disabling fetch-event...', + ); + } + features.delete('fetch-event'); + } + + // Splice the bindigns for the given WIT world into the engine WASM + let { wasm, jsBindings, exports, imports } = splicer.spliceBindings( await readFile(engine), + [...features], witWorld, maybeWindowsPath(witPath), worldName, - false + false, ); - const input = join(tmpDir, 'in.wasm'); - const output = join(tmpDir, 'out.wasm'); + const inputWasmPath = join(workDir, 'in.wasm'); + const outputWasmPath = join(workDir, 'out.wasm'); - await writeFile(input, Buffer.from(wasm)); - await writeFile(join(sourceDir, "initializer.js"), jsBindings); + await writeFile(inputWasmPath, Buffer.from(wasm)); + let initializerPath = maybeWindowsPath(join(sourcesDir, 'initializer.js')); + await writeFile(initializerPath, jsBindings); if (debugBindings) { - console.log('--- JS Bindings ---'); - console.log( - jsBindings - .split('\n') - .map((ln, idx) => `${(idx + 1).toString().padStart(4, ' ')} | ${ln}`) - .join('\n') - ); - console.log('--- JS Imports ---'); - console.log(imports); - console.log('--- JS Exports ---'); - console.log(exports); + // If a bindings output directory was specified, output generated bindings to files + if (debug?.bindingsDir) { + console.error(`Storing debug files in "${debug?.bindingsDir}"\n`); + // Ensure the debug bindings dir exists, and is a directory + if (!(await stat(debug?.bindingsDir).then((s) => s.isDirectory()))) { + throw new Error( + `Missing/invalid debug bindings directory [${debug?.bindingsDir}]`, + ); + } + // Write debug to bindings debug directory + await Promise.all([ + writeFile(join(debug?.bindingsDir, 'source.debug.js'), jsSource), + writeFile(join(debug?.bindingsDir, 'bindings.debug.js'), jsBindings), + writeFile( + join(debug?.bindingsDir, 'imports.debug.json'), + JSON.stringify(imports, null, 2), + ), + writeFile( + join(debug?.bindingsDir, 'exports.debug.json'), + JSON.stringify(exports, null, 2), + ), + ]); + } else { + // If a bindings output directory was not specified, output to stdout + console.error('--- JS Bindings ---'); + console.error( + jsBindings + .split('\n') + .map((ln, idx) => `${(idx + 1).toString().padStart(4, ' ')} | ${ln}`) + .join('\n'), + ); + console.error('--- JS Imports ---'); + console.error(imports); + console.error('--- JS Exports ---'); + console.error(exports); + } } if (!useOriginalSourceFile) { if (debugBindings) { - console.log(`> Writing JS source to ${tmpDir}/sources`); + console.error(`> Writing JS source to ${tmpDir}/sources`); } await writeFile(sourcePath, jsSource); } - // we never disable a feature that is already in the target world usage - const features = []; - if (!disableFeatures.includes('stdio')) { - features.push('stdio'); - } - if (!disableFeatures.includes('random')) { - features.push('random'); - } - if (!disableFeatures.includes('clocks')) { - features.push('clocks'); - } - if (!disableFeatures.includes('http')) { - features.push('http'); - } - let hostenv = {}; if (opts.env) { @@ -210,7 +215,7 @@ export async function componentize(opts, DEBUG: enableWizerLogging ? '1' : '', SOURCE_NAME: sourceName, EXPORT_CNT: exports.length.toString(), - FEATURE_CLOCKS: features.includes('clocks') ? '1' : '', + FEATURE_CLOCKS: features.has('clocks') ? '1' : '', }; for (const [idx, [export_name, expt]] of exports.entries()) { @@ -228,211 +233,102 @@ export async function componentize(opts, env['IMPORT_CNT'] = imports.length; if (debugBindings) { - console.log('--- Wizer Env ---'); - console.log(env); + console.error('--- Wizer Env ---'); + console.error(env); } - let initializerPath = maybeWindowsPath(join(sourceDir, 'initializer.js')); sourcePath = maybeWindowsPath(sourcePath); let workspacePrefix = dirname(sourcePath); // If the source path is within the current working directory, strip the // cwd as a prefix from the source path, and remap the paths seen by the // component to be relative to the current working directory. - // This only works in wizer, not in weval, because the latter doesn't - // support --mapdir. - if (!opts.enableAot) { - if (!useOriginalSourceFile) { - workspacePrefix = sourceDir; - sourcePath = sourceName; - } - let currentDir = maybeWindowsPath(cwd()); - if (workspacePrefix.startsWith(currentDir)) { - workspacePrefix = currentDir; - sourcePath = sourcePath.slice(workspacePrefix.length + 1); - } - } - let args = `--initializer-script-path ${initializerPath} --strip-path-prefix ${workspacePrefix}/ ${sourcePath}`; - runtimeArgs = runtimeArgs ? `${runtimeArgs} ${args}` : args; - let preopens = [`--dir ${sourceDir}`]; - if (opts.enableAot) { - preopens.push(`--dir ${workspacePrefix}`); - } else { - preopens.push(`--mapdir /::${workspacePrefix}`); + // This only works in wizer. + if (!useOriginalSourceFile) { + workspacePrefix = sourcesDir; + sourcePath = sourceName; } + let currentDir = maybeWindowsPath(cwd()); - let wizerProcess; + if (workspacePrefix.startsWith(currentDir)) { + workspacePrefix = currentDir; + sourcePath = sourcePath.slice(workspacePrefix.length + 1); + } - if (opts.enableAot) { - // Determine the weval bin path, possibly using a pre-downloaded version - let wevalBin; - if (opts.wevalBin && existsSync(opts.wevalBin)) { - wevalBin = opts.wevalBin; - } else { - wevalBin = await getWeval(); - } + // Ensure source path is relative to workspacePrefix for the args list, + // regardless of the directory + if (resolve(sourcePath).startsWith(resolve(workspacePrefix))) { + sourcePath = relative(workspacePrefix, sourcePath); + } - // Set the min stack size, if one was provided - if (opts.aotMinStackSizeBytes) { - if (!isNumeric(opts.aotMinStackSizeBytes)) { - throw new TypeError( - `aotMinStackSizeBytes must be a numeric value, received [${opts.aotMinStackSizeBytes}] (type ${typeof opts.aotMinStackSizeBytes})`, - ); - } - env.RUST_MIN_STACK = opts.aotMinStackSizeBytes; - } else { - env.RUST_MIN_STACK = defaultMinStackSize(); - } + let args = `--initializer-script-path ${initializerPath} --strip-path-prefix ${workspacePrefix}/ ${sourcePath}`; + runtimeArgs = runtimeArgs ? `${runtimeArgs} ${args}` : args; - wizerProcess = spawnSync( - wevalBin, - [ - 'weval', - `--cache-ro ${aotCache}`, - ...preopens, - '-w', - '--init-func', - 'componentize.wizer', - `-i ${input}`, - `-o ${output}`, - ], - { - stdio: [null, stdout, "pipe"], - env, - input: runtimeArgs, - shell: true, - encoding: 'utf-8', - } - ); - } else { - wizerProcess = spawnSync( - wizer, - [ - '--allow-wasi', - '--init-func', - 'componentize.wizer', - ...preopens, - `--wasm-bulk-memory=true`, - '--inherit-env=true', - `-o=${output}`, - input, - ], - { - stdio: [null, stdout, "pipe"], - env, - input: runtimeArgs, - shell: true, - encoding: 'utf-8', - } - ); - } + let preopens = [`--dir=${sourcesDir}`]; + preopens.push(`--mapdir=/::${workspacePrefix}`); + + let postProcess; + + const wizerBin = opts.wizerBin ?? wizer; + postProcess = spawnSync( + wizerBin, + [ + '--allow-wasi', + '--init-func', + 'componentize.wizer', + ...preopens, + `--wasm-bulk-memory=true`, + '--inherit-env=true', + `-o=${outputWasmPath}`, + inputWasmPath, + ], + { + stdio: [null, stdout, 'pipe'], + env, + input: runtimeArgs, + encoding: 'utf-8', + }, + ); - if (wizerProcess.status !== 0) { - let wizerErr = parseWizerStderr(wizerProcess.stderr); + // If the wizer process failed, parse the output and display to the user + if (postProcess.status !== 0) { + let wizerErr = parseWizerStderr(postProcess.stderr); let err = `Failed to initialize component:\n${wizerErr}`; if (debugBindings) { - err += `\n\nBinary and sources available for debugging at ${tmpDir}\n`; + err += `\n\nBinary and sources available for debugging at ${workDir}\n`; } else { - rmSync(tmpDir, { recursive: true }); + await rm(workDir, { recursive: true }); } throw new Error(err); } - const bin = await readFile(output); - - const tmpdirRemovePromise = debugBindings - ? Promise.resolve() - : rm(tmpDir, { recursive: true }); + // Read the generated WASM back into memory + const bin = await readFile(outputWasmPath); - // Check for initialization errors - // By actually executing the binary in a mini sandbox to get back - // the initialization state + // Check for initialization errors, by actually executing the binary in + // a mini sandbox to get back the initialization state const { exports: { check_init }, getStderr, } = await initWasm(bin); - await tmpdirRemovePromise; - - async function initWasm(bin) { - const eep = (name) => () => { - throw new Error( - `Internal error: unexpected call to "${name}" during Wasm verification`, - ); - }; - - let stderr = ''; - const wasmModule = await WebAssembly.compile(bin); - - const mockImports = { - // "wasi-logging2": { - // log: eep("log"), - // }, - wasi_snapshot_preview1: { - fd_write: function (fd, iovs, iovs_len, nwritten) { - if (fd !== 2) return 0; - const mem = new DataView(exports.memory.buffer); - let written = 0; - for (let i = 0; i < iovs_len; i++) { - const bufPtr = mem.getUint32(iovs + i * 8, true); - const bufLen = mem.getUint32(iovs + 4 + i * 8, true); - stderr += new TextDecoder().decode( - new Uint8Array(exports.memory.buffer, bufPtr, bufLen), - ); - written += bufLen; - } - mem.setUint32(nwritten, written, true); - return 1; - }, - }, - }; - - for (const { module, name } of WebAssembly.Module.imports(wasmModule)) { - mockImports[module] = mockImports[module] || {}; - if (!mockImports[module][name]) mockImports[module][name] = eep(name); - } - - const { exports } = await WebAssembly.instantiate(wasmModule, mockImports); - return { - exports, - getStderr() { - return stderr; - }, - }; - } - - const INIT_OK = 0; - const INIT_FN_LIST = 1; - const INIT_TYPE_PARSE = 2; - - const status = check_init(); - let err = null; - switch (status) { - case INIT_OK: - break; - case INIT_FN_LIST: - err = `Unable to extract expected exports list`; - break; - case INIT_TYPE_PARSE: - err = `Unable to parse the core ABI export types`; - break; - default: - err = `Unknown error during initialization: ${status}`; + // If not in debug mode, clean up + if (!debugBindings) { + await rm(workDir, { recursive: true }); } - if (err) { - let msg = err; - const stderr = getStderr(); - if (stderr) { - msg += `\n${stripLinesPrefixes(stderr, [new RegExp(`${initializerPath}[:\\d]* ?`)], tmpDir)}`; - } - throw new Error(msg); - } + /// Process output of check init, throwing if necessary + await handleCheckInitOutput( + check_init(), + initializerPath, + workDir, + getStderr, + ); - // after wizening, stub out the wasi imports depending on what features are enabled - const finalBin = stubWasi( + // After wizening, stub out the wasi imports depending on what features are enabled + const finalBin = splicer.stubWasi( bin, - features, + [...features], witWorld, maybeWindowsPath(witPath), worldName, @@ -456,14 +352,26 @@ export async function componentize(opts, }), ); - // convert CABI import conventions to ESM import conventions + // Convert CABI import conventions to ESM import conventions imports = imports.map(([specifier, impt]) => - specifier === '$root' ? [impt, 'default'] : [specifier, impt] + specifier === '$root' ? [impt, 'default'] : [specifier, impt], ); + // Build debug object to return + let debugOutput; + if (debugBindings) { + debugOutput.bindings = debug.bindings; + debugOutput.workDir = workDir; + } + if (debug?.binary) { + debugOutput.binary = debug.binary; + debugOutput.binaryPath = debug.binaryPath; + } + return { component, imports, + debug: debugOutput, }; } @@ -477,3 +385,202 @@ function defaultMinStackSize(freeMemoryBytes) { freeMemoryBytes = freeMemoryBytes ?? freemem(); return Math.max(8 * 1024 * 1024, Math.floor(freeMemoryBytes * 0.1)); } + +/** + * Clean up the given input string by removing the given patterns if + * found as line prefixes. + */ +function stripLinesPrefixes(input, prefixPatterns) { + return input + .split('\n') + .map((line) => + prefixPatterns.reduce((line, n) => line.replace(n, ''), line), + ) + .join('\n') + .trim(); +} + +/** + * Parse output of post-processing Wizer step + * + * @param {Stream} stderr + * @returns {string} String that can be printed to describe error output + */ +function parseWizerStderr(stderr) { + let output = `${stderr}`; + let causeStart = output.indexOf(WIZER_ERROR_CAUSE_PREFIX); + let exitCodeStart = output.indexOf(WIZER_EXIT_CODE_PREFIX); + if (causeStart === -1 || exitCodeStart === -1) { + return output; + } + + let causeEnd = output.indexOf('\n', exitCodeStart + 1); + return `${output.substring(0, causeStart)}${output.substring(causeEnd)}`.trim(); +} + +/** + * Check whether a value is numeric (including BigInt) + * + * @param {any} n + * @returns {boolean} whether the value is numeric + */ +function isNumeric(n) { + switch (typeof n) { + case 'bigint': + case 'number': + return true; + case 'object': + return n.constructor == BigInt || n.constructor == Number; + default: + return false; + } +} + +/** Determine the correct path for the engine */ +function getEnginePath(opts) { + if (opts.engine) { + return opts.engine; + } + const debugSuffix = opts?.debugBuild ? '.debug' : ''; + let engineBinaryRelPath = `../lib/starlingmonkey_embedding${debugSuffix}.wasm`; + + return fileURLToPath(new URL(engineBinaryRelPath, import.meta.url)); +} + +/** Prepare a work directory for use with componentization */ +async function prepWorkDir() { + const baseDir = maybeWindowsPath( + join( + tmpdir(), + createHash('sha256') + .update(Math.random().toString()) + .digest('hex') + .slice(0, 12), + ), + ); + await mkdir(baseDir); + const sourcesDir = maybeWindowsPath(join(baseDir, 'sources')); + await mkdir(sourcesDir); + return { baseDir, sourcesDir }; +} + +/** + * Initialize a WebAssembly binary, given the + * + * @param {Buffer} bin - WebAssembly binary bytes + * @throws If a binary is invalid + */ +async function initWasm(bin) { + const eep = (name) => () => { + throw new Error( + `Internal error: unexpected call to "${name}" during Wasm verification`, + ); + }; + + let stderr = ''; + const wasmModule = await WebAssembly.compile(bin); + + const mockImports = { + wasi_snapshot_preview1: { + fd_write: function (fd, iovs, iovs_len, nwritten) { + if (fd !== 2) return 0; + const mem = new DataView(exports.memory.buffer); + let written = 0; + for (let i = 0; i < iovs_len; i++) { + const bufPtr = mem.getUint32(iovs + i * 8, true); + const bufLen = mem.getUint32(iovs + 4 + i * 8, true); + stderr += new TextDecoder().decode( + new Uint8Array(exports.memory.buffer, bufPtr, bufLen), + ); + written += bufLen; + } + mem.setUint32(nwritten, written, true); + return 1; + }, + }, + }; + + for (const { module, name } of WebAssembly.Module.imports(wasmModule)) { + mockImports[module] = mockImports[module] || {}; + if (!mockImports[module][name]) mockImports[module][name] = eep(name); + } + + const { exports } = await WebAssembly.instantiate(wasmModule, mockImports); + return { + exports, + getStderr() { + return stderr; + }, + }; +} + +/** + * Handle the output of `check_init()` + * + * @param {number} status - output of check_init + * @param {string} initializerPath + * @param {string} workDir + * @param {() => string} getStderr - A function that resolves to the stderr output of check init + */ +async function handleCheckInitOutput( + status, + initializerPath, + workDir, + getStderr, +) { + let err = null; + switch (status) { + case CHECK_INIT_RETURN_OK: + break; + case CHECK_INIT_RETURN_FN_LIST: + err = `Unable to extract expected exports list`; + break; + case CHECK_INIT_RETURN_TYPE_PARSE: + err = `Unable to parse the core ABI export types`; + break; + default: + err = `Unknown error during initialization: ${status}`; + } + + if (err) { + let msg = err; + const stderr = getStderr(); + if (stderr) { + msg += `\n${stripLinesPrefixes(stderr, [new RegExp(`${initializerPath}[:\\d]* ?`)], workDir)}`; + } + throw new Error(msg); + } +} + +/** + * Detect known exports that correspond to certain interfaces + * + * @param {string} filename - filename + * @param {string} code - JS source code + * @returns {Promise} A Promise that resolves to a list of string that represent unversioned interfaces + */ +async function detectKnownSourceExportNames(filename, code) { + if (!filename) { + throw new Error('missing filename'); + } + if (!code) { + throw new Error('missing JS code'); + } + + const names = new Set(); + + const results = await oxc.parseAsync(filename, code); + if (results.errors.length > 0) { + throw new Error( + `failed to parse JS source, encountered [${results.errors.length}] errors`, + ); + } + + for (const staticExport of results.module.staticExports) { + for (const entry of staticExport.entries) { + names.add(entry.exportName.name); + } + } + + return names; +} diff --git a/src/platform.js b/src/platform.js new file mode 100644 index 00000000..d7264a1c --- /dev/null +++ b/src/platform.js @@ -0,0 +1,21 @@ +import { resolve } from 'node:path'; +import { platform } from 'node:process'; + +/** Whether the current platform is windows */ +export const IS_WINDOWS = platform === 'win32'; + +/** Convert a path that to be usable on windows, if necessary */ +export function maybeWindowsPath(path) { + if (!path) return path; + const resolvedPath = resolve(path); + if (!IS_WINDOWS) return resolvedPath; + + // Strip any existing UNC prefix check both the format we add as well as what + // the windows API returns when using path.resolve + let cleanPath = resolvedPath; + while (cleanPath.startsWith('\\\\?\\') || cleanPath.startsWith('//?/')) { + cleanPath = cleanPath.substring(4); + } + + return '//?/' + cleanPath.replace(/\\/g, '/'); +} diff --git a/test/api.js b/test/api.js new file mode 100644 index 00000000..ac455b7d --- /dev/null +++ b/test/api.js @@ -0,0 +1,39 @@ +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { fileURLToPath, URL } from 'node:url'; +import { copyFile, mkdtemp } from 'node:fs/promises'; + +import { suite, test, assert } from 'vitest'; + +import { setupComponent } from "./util.js"; + +import { + DEBUG_TRACING_ENABLED, + DEBUG_TEST_ENABLED, +} from './util.js'; + +suite('API', () => { + // When using a different directory sourcePath as an arg to componentize() + // (called via setupComponent() in this test), wizer would fail to initialize the component + // due to a missing file -- the path prefix stripping was not correctly being resolved. + test('componentize() in a different dir', async () => { + const tmpDir = await mkdtemp(join(tmpdir(), 'componentize-diff-dir-')); + const outputPath = join(tmpDir, "index.js"); + await copyFile(resolve('./test/api/index.js'), outputPath); + const { instance } = await setupComponent({ + componentize: { + opts: { + sourcePath: outputPath, + witPath: fileURLToPath(new URL('./wit', import.meta.url)), + worldName: 'test1', + debugBuild: DEBUG_TEST_ENABLED, + }, + }, + transpile: { + opts: { + tracing: DEBUG_TRACING_ENABLED, + }, + }, + }); + }); +}); diff --git a/test/bindings.js b/test/bindings.js new file mode 100644 index 00000000..7d08c6b7 --- /dev/null +++ b/test/bindings.js @@ -0,0 +1,156 @@ +import { fileURLToPath, URL } from 'node:url'; +import { readFile, readdir, mkdir, writeFile } from 'node:fs/promises'; + +import { componentize } from '@bytecodealliance/componentize-js'; +import { transpile } from '@bytecodealliance/jco'; + +import { suite, test } from 'vitest'; + +import { + DEBUG_TRACING_ENABLED, + DEBUG_TEST_ENABLED, + maybeLogging, +} from './util.js'; + +suite('Bindings', async () => { + const bindingsCases = await readdir(new URL('./cases', import.meta.url)); + + for (const name of bindingsCases) { + test.concurrent(name, async () => { + const source = await readFile( + new URL(`./cases/${name}/source.js`, import.meta.url), + 'utf8', + ); + + // NOTE: import separated from await due to issues on windows (see note in util.js) + const testcasePromise = import(`./cases/${name}/test.js`); + const testcase = await testcasePromise; + + // Determine the relevant WIT world to use + let witWorld, + witPath, + worldName, + isWasiTarget = false; + if (testcase.worldName) { + witPath = fileURLToPath(new URL('./wit', import.meta.url)); + worldName = testcase.worldName; + isWasiTarget = true; + } else { + try { + witWorld = await readFile( + new URL(`./cases/${name}/world.wit`, import.meta.url), + 'utf8', + ); + } catch (e) { + if (e?.code == 'ENOENT') { + try { + isWasiTarget = true; + witPath = fileURLToPath( + new URL(`./cases/${name}/wit`, import.meta.url), + ); + await readdir(witPath); + } catch (e) { + if (e?.code === 'ENOENT') { + witPath = fileURLToPath(new URL('./wit', import.meta.url)); + worldName = 'test2'; + } else { + throw e; + } + } + } else { + throw e; + } + } + } + + const enableFeatures = testcase.enableFeatures || ['http']; + const disableFeatures = + testcase.disableFeatures || + (isWasiTarget ? [] : ['random', 'clocks', 'http', 'stdio']); + + let testArg; + let instance; + try { + const { component, imports } = await componentize(source, { + sourceName: `${name}.js`, + witWorld, + witPath, + worldName, + enableFeatures, + disableFeatures: maybeLogging(disableFeatures), + debugBuild: DEBUG_TEST_ENABLED, + }); + + const map = { + 'wasi:cli-base/*': '@bytecodealliance/preview2-shim/cli-base#*', + 'wasi:clocks/*': '@bytecodealliance/preview2-shim/clocks#*', + 'wasi:filesystem/*': '@bytecodealliance/preview2-shim/filesystem#*', + 'wasi:http/*': '@bytecodealliance/preview2-shim/http#*', + 'wasi:io/*': '@bytecodealliance/preview2-shim/io#*', + 'wasi:logging/*': '@bytecodealliance/preview2-shim/logging#*', + 'wasi:poll/*': '@bytecodealliance/preview2-shim/poll#*', + 'wasi:random/*': '@bytecodealliance/preview2-shim/random#*', + 'wasi:sockets/*': '@bytecodealliance/preview2-shim/sockets#*', + }; + + for (let [impt] of imports) { + if (impt.startsWith('wasi:')) continue; + if (impt.startsWith('[')) impt = impt.slice(impt.indexOf(']') + 1); + let importName = impt.split('/').pop(); + if (testcase.importNameOverride) + importName = testcase.importNameOverride(impt); + if (importName === 'test') importName = 'imports'; + map[impt] = `../../cases/${name}/${importName}.js`; + } + + const { + files, + imports: componentImports, + exports: componentExports, + } = await transpile(component, { + name, + map, + wasiShim: true, + validLiftingOptimization: false, + tracing: DEBUG_TRACING_ENABLED, + }); + + testArg = { imports, componentImports, componentExports }; + + await mkdir(new URL(`./output/${name}/interfaces`, import.meta.url), { + recursive: true, + }); + + await writeFile( + new URL(`./output/${name}.component.wasm`, import.meta.url), + component, + ); + + for (const file of Object.keys(files)) { + let source = files[file]; + await writeFile( + new URL(`./output/${name}/${file}`, import.meta.url), + source, + ); + } + + const outputPath = fileURLToPath( + new URL(`./output/${name}/${name}.js`, import.meta.url), + ); + + // NOTE: import separated from await due to issues on windows (see note in util.js) + const instancePromise = import(outputPath); + instance = await instancePromise; + + } catch (e) { + if (testcase.err) { + testcase.err(e); + return; + } + throw e; + } + + await testcase.test(instance, testArg); + }); + } +}); diff --git a/test/builtins.js b/test/builtins.js new file mode 100644 index 00000000..1b0f132d --- /dev/null +++ b/test/builtins.js @@ -0,0 +1,129 @@ +import { readFile, readdir, mkdir, writeFile } from 'node:fs/promises'; +import { spawn } from 'node:child_process'; +import { fileURLToPath, URL } from 'node:url'; + +import { componentize } from '@bytecodealliance/componentize-js'; +import { transpile } from '@bytecodealliance/jco'; + +import { suite, test, assert } from 'vitest'; + +import { + DEBUG_TRACING_ENABLED, + DEBUG_TEST_ENABLED, + maybeLogging, +} from './util.js'; + +suite('Builtins', async () => { + const builtins = await readdir(new URL('./builtins', import.meta.url)); + + for (const filename of builtins) { + const name = filename.slice(0, -3); + test.concurrent(name, { retry: 3 }, async () => { + // NOTE: import separated from await due to issues on windows (see note in util.js) + const builtinModulePromise = import(`./builtins/${name}.js`); + + const { + source, + test: runTest, + disableFeatures, + enableFeatures, + } = await builtinModulePromise; + + const { component } = await componentize( + source, + ` + package local:runworld; + world runworld { + export run: func(); + } + `, + { + sourceName: `${name}.js`, + debugBuild: DEBUG_TEST_ENABLED, + enableFeatures, + disableFeatures: maybeLogging(disableFeatures), + }, + ); + + const { files } = await transpile(component, { + name, + wasiShim: true, + tracing: DEBUG_TRACING_ENABLED, + }); + + await mkdir(new URL(`./output/${name}/interfaces`, import.meta.url), { + recursive: true, + }); + + await writeFile( + new URL(`./output/${name}.component.wasm`, import.meta.url), + component, + ); + + for (const file of Object.keys(files)) { + await writeFile( + new URL(`./output/${name}/${file}`, import.meta.url), + files[file], + ); + } + + await writeFile( + new URL(`./output/${name}/run.js`, import.meta.url), + ` + import { run } from './${name}.js'; + run(); + `, + ); + + try { + await runTest(async function run() { + let stdout = '', + stderr = '', + timeout; + try { + await new Promise((resolve, reject) => { + const cp = spawn( + process.argv[0], + [ + fileURLToPath( + new URL(`./output/${name}/run.js`, import.meta.url), + ), + ], + { stdio: 'pipe' }, + ); + cp.stdout.on('data', (chunk) => { + stdout += chunk; + }); + cp.stderr.on('data', (chunk) => { + stderr += chunk; + }); + cp.on('error', reject); + cp.on('exit', (code) => + code === 0 ? resolve() : reject(new Error(stderr || stdout)), + ); + timeout = setTimeout(() => { + reject( + new Error( + 'test timed out with output:\n' + + stdout + + '\n\nstderr:\n' + + stderr, + ), + ); + }, 10_000); + }); + } catch (err) { + throw { err, stdout, stderr }; + } finally { + clearTimeout(timeout); + } + + return { stdout, stderr }; + }); + } catch (err) { + if (err.stderr) console.error(err.stderr); + throw err.err || err; + } + }); + } +}); diff --git a/test/builtins/fetch.js b/test/builtins/fetch.js index 328957cb..8d04af6a 100644 --- a/test/builtins/fetch.js +++ b/test/builtins/fetch.js @@ -1,8 +1,37 @@ +import { URL, fileURLToPath } from 'node:url'; +import { createServer } from 'node:http'; + import { strictEqual, ok } from 'node:assert'; +import { maybeWindowsPath } from '../../src/platform.js'; + +const FETCH_URL = 'http://localhost'; + +const [server, port, url] = await new Promise((resolve, reject) => { + let port; + const server = createServer(async (req, res) => { + res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' }); + res.write( + JSON.stringify({ + status: 'ok', + url, + }), + ); + res.end(); + }); + server.listen(0, function (err) { + if (err) { + reject(err); + return; + } + port = this.address().port; + resolve([server, port, `${FETCH_URL}:${port}`]); + }); +}); + export const source = ` export async function run () { - const res = await fetch('https://httpbin.org/anything'); + const res = await fetch('${FETCH_URL}:${port}'); const source = await res.json(); console.log(source.url); } @@ -14,7 +43,20 @@ export const source = ` export const enableFeatures = ['http']; export async function test(run) { + // Wait until the server is ready + let ready = false; + while (!ready) { + try { + const res = await fetch(url); + ready = true; + } catch (err) { + await new Promise((resolve) => setTimeout(resolve, 250)); + } + } + const { stdout, stderr } = await run(); strictEqual(stderr, ''); - strictEqual(stdout.trim(), 'https://httpbin.org/anything'); + strictEqual(stdout.trim(), url); + + server.close(); } diff --git a/test/builtins/globals.js b/test/builtins/globals.js index 1f8adc95..56025da1 100644 --- a/test/builtins/globals.js +++ b/test/builtins/globals.js @@ -6,11 +6,125 @@ export const source = ` } `; +const EXPECTED_GLOBALS = [ + 'undefined', + 'Function', + 'Object', + 'eval', + 'globalThis', + 'Array', + 'Boolean', + 'JSON', + 'Date', + 'Math', + 'isNaN', + 'isFinite', + 'parseInt', + 'parseFloat', + 'NaN', + 'Infinity', + 'Number', + 'escape', + 'unescape', + 'decodeURI', + 'encodeURI', + 'decodeURIComponent', + 'encodeURIComponent', + 'String', + 'RegExp', + 'Error', + 'InternalError', + 'AggregateError', + 'EvalError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError', + 'ArrayBuffer', + 'Int8Array', + 'Uint8Array', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array', + 'Uint8ClampedArray', + 'BigInt64Array', + 'BigUint64Array', + 'Float16Array', + 'BigInt', + 'Proxy', + 'WeakMap', + 'Map', + 'Set', + 'DataView', + 'Symbol', + 'Reflect', + 'WeakSet', + 'Promise', + 'Iterator', + 'FinalizationRegistry', + 'WeakRef', + 'ReadableStream', + 'ReadableStreamBYOBReader', + 'ReadableStreamBYOBRequest', + 'ReadableStreamDefaultReader', + 'ReadableStreamDefaultController', + 'ReadableByteStreamController', + 'WritableStream', + 'ByteLengthQueuingStrategy', + 'CountQueuingStrategy', + 'self', + 'queueMicrotask', + 'structuredClone', + 'atob', + 'btoa', + 'Blob', + 'File', + 'Event', + 'EventTarget', + 'CustomEvent', + 'addEventListener', + 'removeEventListener', + 'dispatchEvent', + 'AbortSignal', + 'AbortController', + 'FormData', + 'MultipartFormData', + 'DOMException', + 'URL', + 'URLSearchParams', + 'console', + 'Performance', + 'performance', + 'setInterval', + 'setTimeout', + 'clearInterval', + 'clearTimeout', + 'WorkerLocation', + 'location', + 'TextEncoder', + 'TextDecoder', + 'TransformStream', + 'CompressionStream', + 'DecompressionStream', + 'fetch', + 'Request', + 'Response', + 'Headers', + 'SubtleCrypto', + 'Crypto', + 'crypto', + 'CryptoKey', +]; + export async function test(run) { const { stdout, stderr } = await run(); strictEqual( stdout, - `["undefined", "Function", "Object", "eval", "globalThis", "Array", "Boolean", "JSON", "Date", "Math", "isNaN", "isFinite", "parseInt", "parseFloat", "NaN", "Infinity", "Number", "escape", "unescape", "decodeURI", "encodeURI", "decodeURIComponent", "encodeURIComponent", "String", "RegExp", "Error", "InternalError", "AggregateError", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "ArrayBuffer", "Int8Array", "Uint8Array", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array", "Float16Array", "BigInt", "Proxy", "WeakMap", "Map", "Set", "DataView", "Symbol", "Reflect", "WeakSet", "Promise", "FinalizationRegistry", "WeakRef", "ReadableStream", "ReadableStreamBYOBReader", "ReadableStreamBYOBRequest", "ReadableStreamDefaultReader", "ReadableStreamDefaultController", "ReadableByteStreamController", "WritableStream", "ByteLengthQueuingStrategy", "CountQueuingStrategy", "self", "queueMicrotask", "structuredClone", "atob", "btoa", "Blob", "File", "FormData", "MultipartFormData", "DOMException", "URL", "URLSearchParams", "console", "Performance", "performance", "setInterval", "setTimeout", "clearInterval", "clearTimeout", "WorkerLocation", "location", "TextEncoder", "TextDecoder", "TransformStream", "CompressionStream", "DecompressionStream", "fetch", "Request", "Response", "Headers", "addEventListener", "SubtleCrypto", "Crypto", "crypto", "CryptoKey"]\n` + '[' + EXPECTED_GLOBALS.map((v) => `"${v}"`).join(', ') + ']\n', ); strictEqual(stderr, ''); } diff --git a/test/builtins/now-disabled.js b/test/builtins/now-disabled.js index 4c675f7e..ebfb1d9c 100644 --- a/test/builtins/now-disabled.js +++ b/test/builtins/now-disabled.js @@ -18,9 +18,11 @@ export async function test(run) { strictEqual(stderr, ''); const times = stdout.split('\n'); - // verify now was taken at build time (within 15 seconds ago) + // verify now was taken at build time + // NOTE: While build time is expected to be within 15 seconds, + // we avoid ensuring a specific bound on build time due to the + // unreliability of combinations of CI systems and specific OSes ok(Number(times[0]) < curNow); - ok(Number(times[0]) > curNow - 15_000); // verify disabled time doesn't progress strictEqual(times[1], times[0]); diff --git a/test/builtins/performance.js b/test/builtins/performance.js deleted file mode 100644 index 3f3821da..00000000 --- a/test/builtins/performance.js +++ /dev/null @@ -1,28 +0,0 @@ -import { ok, strictEqual } from 'node:assert'; - -export const source = ` - export function run () { - const start = performance.now(); - let previous = 0, cur = 1; - for (let i = 1; i < 1000; i++) { - const tmp = cur; - cur = previous + cur; - previous = tmp; - } - const end = performance.now(); - console.log('Calculated fib 1000: ' + cur); - console.error((end - start) + ' ms'); - }; -`; - -export async function test(run) { - const { stdout, stderr } = await run(); - strictEqual(stdout, 'Calculated fib 1000: 4.346655768693743e+208\n'); - - ok(stderr.includes(' ms')); - const time = Number(stderr.split(' ms')[0]); - // TODO: fix back to half a millisecond when Weval fix is added - if (time > 5) { - throw new Error('took more than half a millisecond - ' + time + ' ms'); - } -} diff --git a/test/cases/fetch-event-server/source.js b/test/cases/fetch-event-server/source.js new file mode 100644 index 00000000..2b01332c --- /dev/null +++ b/test/cases/fetch-event-server/source.js @@ -0,0 +1,7 @@ +addEventListener("fetch", (event) => + event.respondWith( + (async () => { + return new Response("Hello World"); + })(), + ), +); diff --git a/test/cases/fetch-event-server/test.js b/test/cases/fetch-event-server/test.js new file mode 100644 index 00000000..296424b4 --- /dev/null +++ b/test/cases/fetch-event-server/test.js @@ -0,0 +1,22 @@ +import { strictEqual } from 'node:assert'; + +import { HTTPServer } from '@bytecodealliance/preview2-shim/http'; + +export const enableFeatures = ['http', 'fetch-event']; +export const worldName = 'test3'; + +export async function test(instance) { + let server; + try { + server = new HTTPServer(instance.incomingHandler); + server.listen(0); + const { port } = server.address(); + const resp = await fetch(`http://localhost:${port}`); + const text = await resp.text(); + strictEqual(text, 'Hello World'); + } finally { + if (server) { + server.stop(); + } + } +} diff --git a/test/cases/http-request/source.js b/test/cases/http-request/source.js index a2a52831..121ad9a6 100644 --- a/test/cases/http-request/source.js +++ b/test/cases/http-request/source.js @@ -11,7 +11,7 @@ export function getResult() { new Fields([ ['User-agent', encoder.encode('WASI-HTTP/0.0.1')], ['Content-type', encoder.encode('application/json')], - ]) + ]), ); req.setScheme({ tag: 'HTTPS' }); @@ -27,10 +27,11 @@ export function getResult() { const responseHeaders = incomingResponse.headers().entries(); const headers = Object.fromEntries( - responseHeaders.map(([k, v]) => [k, decoder.decode(v)]) + responseHeaders.map(([k, v]) => [k, decoder.decode(v)]), ); let responseBody; + const incomingBody = incomingResponse.consume(); { const bodyStream = incomingBody.stream(); diff --git a/test/cases/http-server/source.js b/test/cases/http-server/source.js new file mode 100644 index 00000000..0241e566 --- /dev/null +++ b/test/cases/http-server/source.js @@ -0,0 +1,27 @@ +import { + IncomingRequest, + ResponseOutparam, + OutgoingBody, + OutgoingResponse, + Fields, +} from 'wasi:http/types@0.2.3'; + +export const incomingHandler = { + handle(incomingRequest, responseOutparam) { + const outgoingResponse = new OutgoingResponse(new Fields()); + let outgoingBody = outgoingResponse.body(); + { + let outputStream = outgoingBody.write(); + outputStream.blockingWriteAndFlush( + new Uint8Array(new TextEncoder().encode('Hello world!')), + ); + outputStream[Symbol.dispose](); + } + outgoingResponse.setStatusCode(200); + OutgoingBody.finish(outgoingBody, undefined); + ResponseOutparam.set(responseOutparam, { + tag: 'ok', + val: outgoingResponse, + }); + }, +}; diff --git a/test/cases/http-server/test.js b/test/cases/http-server/test.js new file mode 100644 index 00000000..bce018cc --- /dev/null +++ b/test/cases/http-server/test.js @@ -0,0 +1,24 @@ +import { strictEqual } from 'node:assert'; + +import { HTTPServer } from '@bytecodealliance/preview2-shim/http'; + +import { getRandomPort } from '../../util.js'; + +export const enableFeatures = ['http']; +export const worldName = 'test3'; + +export async function test(instance) { + let server; + try { + server = new HTTPServer(instance.incomingHandler); + server.listen(0); + const { port } = server.address(); + const resp = await fetch(`http://localhost:${port}`); + const text = await resp.text(); + strictEqual(text, 'Hello world!'); + } finally { + if (server) { + server.stop(); + } + } +} diff --git a/test/cases/import-duplicated-interface/local-hello-hello.js b/test/cases/import-duplicated-interface/local-hello-hello.js new file mode 100644 index 00000000..6c521712 --- /dev/null +++ b/test/cases/import-duplicated-interface/local-hello-hello.js @@ -0,0 +1,3 @@ +export function hello(name) { + return `Hello 1.0.0, ${name}` +} diff --git a/test/cases/import-duplicated-interface/local-hello-second-hello.js b/test/cases/import-duplicated-interface/local-hello-second-hello.js new file mode 100644 index 00000000..eccacb91 --- /dev/null +++ b/test/cases/import-duplicated-interface/local-hello-second-hello.js @@ -0,0 +1,7 @@ +export function hello(name) { + if (name) { + return `Hello 2.0.0, ${name}` + } else { + return undefined + } +} diff --git a/test/cases/import-duplicated-interface/source.js b/test/cases/import-duplicated-interface/source.js new file mode 100644 index 00000000..c36e3a37 --- /dev/null +++ b/test/cases/import-duplicated-interface/source.js @@ -0,0 +1,14 @@ +import { hello as hello1 } from 'local:hello/hello'; +import { hello as hello2 } from 'local:hello-second/hello'; + +export const exports = { + hello(str) { + if (str === 'hello') { + return `world ${str} (${hello1('world')})`; + } + if (str === 'hello-second') { + return `world ${str} (${hello2('world')})`; + } + return `world unknown ${str}`; + }, +}; diff --git a/test/cases/import-duplicated-interface/test.js b/test/cases/import-duplicated-interface/test.js new file mode 100644 index 00000000..8d559149 --- /dev/null +++ b/test/cases/import-duplicated-interface/test.js @@ -0,0 +1,17 @@ +import { strictEqual } from 'node:assert'; + +export function test(instance) { + strictEqual( + instance.exports.hello('hello'), + 'world hello (Hello 1.0.0, world)' + ); + strictEqual( + instance.exports.hello('hello-second'), + 'world hello-second (Hello 2.0.0, world)' + ); + strictEqual(instance.exports.hello('unknown'), 'world unknown unknown'); +} + +export function importNameOverride(importName) { + return importName.replace('/', '-').replace(':', '-'); +} \ No newline at end of file diff --git a/test/cases/import-duplicated-interface/wit/deps/local-hello-second/hello.wit b/test/cases/import-duplicated-interface/wit/deps/local-hello-second/hello.wit new file mode 100644 index 00000000..390b7d4a --- /dev/null +++ b/test/cases/import-duplicated-interface/wit/deps/local-hello-second/hello.wit @@ -0,0 +1,5 @@ +package local:hello-second; + +interface hello { + hello: func(name: option) -> option; +} diff --git a/test/cases/import-duplicated-interface/wit/deps/local-hello/hello.wit b/test/cases/import-duplicated-interface/wit/deps/local-hello/hello.wit new file mode 100644 index 00000000..c5a662c4 --- /dev/null +++ b/test/cases/import-duplicated-interface/wit/deps/local-hello/hello.wit @@ -0,0 +1,5 @@ +package local:hello; + +interface hello { + hello: func(name: string) -> string; +} diff --git a/test/cases/import-duplicated-interface/wit/world.wit b/test/cases/import-duplicated-interface/wit/world.wit new file mode 100644 index 00000000..8514dc97 --- /dev/null +++ b/test/cases/import-duplicated-interface/wit/world.wit @@ -0,0 +1,10 @@ +package test:test; + +world hello { + import local:hello/hello; + import local:hello-second/hello; + + export exports: interface { + hello: func(name: string) -> string; + } +} diff --git a/test/cases/variants/world.wit b/test/cases/variants/world.wit index 4de475c3..57777c8f 100644 --- a/test/cases/variants/world.wit +++ b/test/cases/variants/world.wit @@ -131,8 +131,8 @@ interface variants { is-clone-arg: func(a: is-clone); is-clone-return: func() -> is-clone; - return-named-option: func() -> (a: option); - return-named-result: func() -> (a: result); + return-named-option: func() -> option; + return-named-result: func() -> result; } world my-world { diff --git a/test/meta-resolve-stub.ts b/test/meta-resolve-stub.ts new file mode 100644 index 00000000..93501b60 --- /dev/null +++ b/test/meta-resolve-stub.ts @@ -0,0 +1,4 @@ +// see: https://github.com/vitest-dev/vitest/issues/6953#issuecomment-2505310022 +import { vi } from 'vitest'; +import { createRequire } from 'node:module'; +vi.stubGlobal('globalCreateRequire', createRequire); diff --git a/test/test.js b/test/test.js deleted file mode 100644 index df4e45d8..00000000 --- a/test/test.js +++ /dev/null @@ -1,340 +0,0 @@ -import { componentize } from '@bytecodealliance/componentize-js'; -import { transpile } from '@bytecodealliance/jco'; -import { readFile, readdir, mkdir, writeFile } from 'node:fs/promises'; -import { spawn } from 'node:child_process'; -import { fileURLToPath } from 'node:url'; -import { strictEqual } from 'node:assert'; - -const DEBUG_TRACING = false; -const LOG_DEBUGGING = false; - -const enableAot = process.env.WEVAL_TEST == '1'; -const debugBuild = process.env.DEBUG_TEST == '1'; - -function maybeLogging(disableFeatures) { - if (!LOG_DEBUGGING) return disableFeatures; - if (disableFeatures && disableFeatures.includes('stdio')) { - disableFeatures.splice(disableFeatures.indexOf('stdio'), 1); - } - return disableFeatures; -} - -const builtinsCases = await readdir(new URL('./builtins', import.meta.url)); -suite('Builtins', () => { - for (const filename of builtinsCases) { - const name = filename.slice(0, -3); - test(name, async () => { - const { - source, - test: runTest, - disableFeatures, - enableFeatures, - } = await import(`./builtins/${filename}`); - - const { component } = await componentize( - source, - ` - package local:runworld; - world runworld { - export run: func() -> (); - } - `, - { - sourceName: `${name}.js`, - // also test the debug build while we are about it (unless testing Weval) - debugBuild, - enableFeatures, - disableFeatures: maybeLogging(disableFeatures), - enableAot, - } - ); - - const { files } = await transpile(component, { - name, - wasiShim: true, - tracing: DEBUG_TRACING, - }); - - await mkdir(new URL(`./output/${name}/interfaces`, import.meta.url), { - recursive: true, - }); - - await writeFile( - new URL(`./output/${name}.component.wasm`, import.meta.url), - component - ); - - for (const file of Object.keys(files)) { - await writeFile( - new URL(`./output/${name}/${file}`, import.meta.url), - files[file] - ); - } - - await writeFile( - new URL(`./output/${name}/run.js`, import.meta.url), - ` - import { run } from './${name}.js'; - run(); - ` - ); - - try { - await runTest(async function run() { - let stdout = '', - stderr = '', - timeout; - try { - await new Promise((resolve, reject) => { - const cp = spawn( - process.argv[0], - [ - fileURLToPath( - new URL(`./output/${name}/run.js`, import.meta.url) - ), - ], - { stdio: 'pipe' } - ); - cp.stdout.on('data', (chunk) => { - stdout += chunk; - }); - cp.stderr.on('data', (chunk) => { - stderr += chunk; - }); - cp.on('error', reject); - cp.on('exit', (code) => - code === 0 ? resolve() : reject(new Error(stderr || stdout)) - ); - timeout = setTimeout(() => { - reject( - new Error( - 'test timed out with output:\n' + - stdout + - '\n\nstderr:\n' + - stderr - ) - ); - }, 10_000); - }); - } catch (err) { - throw { err, stdout, stderr }; - } finally { - clearTimeout(timeout); - } - - return { stdout, stderr }; - }); - } catch (err) { - if (err.stderr) console.error(err.stderr); - throw err.err || err; - } - }); - } -}); - -const bindingsCases = await readdir(new URL('./cases', import.meta.url)); -suite('Bindings', () => { - for (const name of bindingsCases) { - test(name, async () => { - const source = await readFile( - new URL(`./cases/${name}/source.js`, import.meta.url), - 'utf8' - ); - - let witWorld, - witPath, - worldName, - isWasiTarget = false; - try { - witWorld = await readFile( - new URL(`./cases/${name}/world.wit`, import.meta.url), - 'utf8' - ); - } catch (e) { - if (e?.code == 'ENOENT') { - try { - isWasiTarget = true; - witPath = fileURLToPath( - new URL(`./cases/${name}/wit`, import.meta.url) - ); - await readdir(witPath); - } catch (e) { - if (e?.code === 'ENOENT') { - witPath = fileURLToPath(new URL('./wit', import.meta.url)); - worldName = 'test2'; - } else { - throw e; - } - } - } else { - throw e; - } - } - - const test = await import(`./cases/${name}/test.js`); - - const enableFeatures = test.enableFeatures || ['http']; - const disableFeatures = - test.disableFeatures || - (isWasiTarget ? [] : ['random', 'clocks', 'http', 'stdio']); - - let testArg; - try { - const { component, imports } = await componentize(source, { - sourceName: `${name}.js`, - witWorld, - witPath, - worldName, - enableFeatures, - disableFeatures: maybeLogging(disableFeatures), - enableAot, - debugBuild, - }); - const map = { - 'wasi:cli-base/*': '@bytecodealliance/preview2-shim/cli-base#*', - 'wasi:clocks/*': '@bytecodealliance/preview2-shim/clocks#*', - 'wasi:filesystem/*': '@bytecodealliance/preview2-shim/filesystem#*', - 'wasi:http/*': '@bytecodealliance/preview2-shim/http#*', - 'wasi:io/*': '@bytecodealliance/preview2-shim/io#*', - 'wasi:logging/*': '@bytecodealliance/preview2-shim/logging#*', - 'wasi:poll/*': '@bytecodealliance/preview2-shim/poll#*', - 'wasi:random/*': '@bytecodealliance/preview2-shim/random#*', - 'wasi:sockets/*': '@bytecodealliance/preview2-shim/sockets#*', - }; - for (let [impt] of imports) { - if (impt.startsWith('wasi:')) continue; - if (impt.startsWith('[')) impt = impt.slice(impt.indexOf(']') + 1); - let importName = impt.split('/').pop(); - if (importName === 'test') importName = 'imports'; - map[impt] = `../../cases/${name}/${importName}.js`; - } - - const { - files, - imports: componentImports, - exports: componentExports, - } = await transpile(component, { - name, - map, - wasiShim: true, - validLiftingOptimization: false, - tracing: DEBUG_TRACING, - }); - - testArg = { imports, componentImports, componentExports }; - - await mkdir(new URL(`./output/${name}/interfaces`, import.meta.url), { - recursive: true, - }); - - await writeFile( - new URL(`./output/${name}.component.wasm`, import.meta.url), - component - ); - - for (const file of Object.keys(files)) { - let source = files[file]; - await writeFile( - new URL(`./output/${name}/${file}`, import.meta.url), - source - ); - } - - var instance = await import(`./output/${name}/${name}.js`); - } catch (e) { - if (test.err) { - test.err(e); - return; - } - throw e; - } - await test.test(instance, testArg); - }); - } -}); - -suite('WASI', () => { - test('basic app (old API)', async () => { - const { component } = await componentize( - ` - import { now } from 'wasi:clocks/wall-clock@0.2.3'; - import { getRandomBytes } from 'wasi:random/random@0.2.3'; - - let result; - export const run = { - run () { - result = \`NOW: \${now().seconds}, RANDOM: \${getRandomBytes(2n)}\`; - } - }; - - export const getResult = () => result; - `, - { - witPath: fileURLToPath(new URL('./wit', import.meta.url)), - worldName: 'test1', - enableAot, - debugBuild, - } - ); - - await writeFile( - new URL(`./output/wasi.component.wasm`, import.meta.url), - component - ); - - const { files } = await transpile(component, { tracing: DEBUG_TRACING }); - - await mkdir(new URL(`./output/wasi/interfaces`, import.meta.url), { - recursive: true, - }); - - for (const file of Object.keys(files)) { - await writeFile( - new URL(`./output/wasi/${file}`, import.meta.url), - files[file] - ); - } - - var instance = await import(`./output/wasi/component.js`); - instance.run.run(); - const result = instance.getResult(); - strictEqual(result.slice(0, 10), `NOW: ${String(Date.now()).slice(0, 5)}`); - strictEqual(result.split(',').length, 3); - }); - - test('basic app (OriginalSourceFile API)', async () => { - const { component } = await componentize( - { - sourcePath: "./test/api/index.js", - witPath: fileURLToPath(new URL('./wit', import.meta.url)), - worldName: 'test1', - enableAot, - debugBuild, - } - ); - - await writeFile( - new URL(`./output/wasi.component.wasm`, import.meta.url), - component - ); - - const { files } = await transpile(component, { tracing: DEBUG_TRACING }); - - await mkdir(new URL(`./output/wasi/interfaces`, import.meta.url), { - recursive: true, - }); - - for (const file of Object.keys(files)) { - await writeFile( - new URL(`./output/wasi/${file}`, import.meta.url), - files[file] - ); - } - - var instance = await import(`./output/wasi/component.js`); - instance.run.run(); - const result = instance.getResult(); - strictEqual(result.slice(0, 10), `NOW: ${String(Date.now()).slice(0, 5)}`); - strictEqual(result.split(',').length, 3); - }); -}); diff --git a/test/util.js b/test/util.js new file mode 100644 index 00000000..6b77fabd --- /dev/null +++ b/test/util.js @@ -0,0 +1,76 @@ +import { join } from 'node:path'; +import { env } from 'node:process'; +import { readFile, readdir, mkdir, writeFile, mkdtemp } from 'node:fs/promises'; +import { createServer } from 'node:net'; + +import { componentize } from '@bytecodealliance/componentize-js'; +import { transpile } from '@bytecodealliance/jco'; + +export const DEBUG_TRACING_ENABLED = isEnabledEnvVar(env.DEBUG_TRACING); +export const LOG_DEBUGGING_ENABLED = isEnabledEnvVar(env.LOG_DEBUGGING); +export const DEBUG_TEST_ENABLED = isEnabledEnvVar(env.DEBUG_TEST); + +function isEnabledEnvVar(v) { + return ( + typeof v === 'string' && ['1', 'yes', 'true'].includes(v.toLowerCase()) + ); +} + +export function maybeLogging(disableFeatures) { + if (!LOG_DEBUGGING_ENABLED) return disableFeatures; + if (disableFeatures && disableFeatures.includes('stdio')) { + disableFeatures.splice(disableFeatures.indexOf('stdio'), 1); + } + return disableFeatures; +} + +export async function setupComponent(opts) { + const componentizeSrc = opts?.componentize?.src; + const componentizeOpts = opts?.componentize?.opts; + const transpileOpts = opts?.transpile?.opts; + + let component; + if (componentizeSrc) { + const srcBuild = await componentize(componentizeSrc, componentizeOpts); + component = srcBuild.component; + } else if (!componentizeSrc && componentizeOpts) { + const optsBuild = await componentize(componentizeOpts); + component = optsBuild.component; + } else { + throw new Error('no componentize options or src provided'); + } + + const outputDir = join('./test/output', 'wasi-test'); + await mkdir(outputDir, { recursive: true }); + + await writeFile(join(outputDir, 'wasi.component.wasm'), component); + + const { files } = await transpile(component, transpileOpts); + + const wasiDir = join(outputDir, 'wasi'); + const interfacesDir = join(wasiDir, 'interfaces'); + await mkdir(interfacesDir, { recursive: true }); + + for (const file of Object.keys(files)) { + await writeFile(join(wasiDir, file), files[file]); + } + + const componentJsPath = join(wasiDir, 'component.js'); + + // NOTE: On Windows, vitest has stated suddenly hanging when processing code with an + // `await import(...)` in it, when the `...` is a bare identifier. + // + // This can be worked around in many ways: + // - doing a trivial tranformation on the identifier/argument + // - returning a more traditional promise + // - separating await and import() calls + // + // Here we choose to return the promise more traditionally + return import(componentJsPath) + .then(instance => { + return { + instance, + outputDir, + }; + }); +} diff --git a/test/vitest.ts b/test/vitest.ts new file mode 100644 index 00000000..b7f8aef5 --- /dev/null +++ b/test/vitest.ts @@ -0,0 +1,44 @@ +import { defineConfig } from 'vitest/config'; + +/** + * Under high concurrency, tests (in partticular bindings generation) can take + * much longer than expected. + * + * This issues primarily happen in CI and not locally on a sufficiently powerful machine. + */ +const TIMEOUT_MS = process.env.CI ? 240_000 : 120_000; + +const REPORTERS = process.env.GITHUB_ACTIONS + ? ['verbose', 'github-actions'] + : ['verbose']; + +/** + * + * Retry is set because there are issues that can randomly happen under high test concurrency: + * - file systems issues + * - performance under concurrency issues (see `builtins.performance.js` test) + * + * These issues primarily happen in CI and not locally, on a sufficiently powerful machine. + */ +const RETRY = process.env.CI ? 3 : 0; + +export default defineConfig({ + test: { + reporters: REPORTERS, + disableConsoleIntercept: true, + printConsoleTrace: true, + passWithNoTests: false, + include: ['test/**/*.js'], + setupFiles: ['test/meta-resolve-stub.ts'], + exclude: [ + 'test/api/*', + 'test/builtins/*', + 'test/cases/*', + 'test/output/*', + 'test/util.js', + ], + testTimeout: TIMEOUT_MS, + hookTimeout: TIMEOUT_MS, + teardownTimeout: TIMEOUT_MS, + }, +}); diff --git a/test/wasi.js b/test/wasi.js new file mode 100644 index 00000000..07155ade --- /dev/null +++ b/test/wasi.js @@ -0,0 +1,89 @@ +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { spawn } from 'node:child_process'; +import { fileURLToPath, URL } from 'node:url'; +import { readFile, readdir, mkdir, writeFile, mkdtemp } from 'node:fs/promises'; + +import { componentize } from '@bytecodealliance/componentize-js'; +import { transpile } from '@bytecodealliance/jco'; + +import { suite, test, assert } from 'vitest'; + +import { setupComponent } from "./util.js"; + +import { + DEBUG_TRACING_ENABLED, + DEBUG_TEST_ENABLED, +} from './util.js'; + +suite('WASI', () => { + test('basic app (old API)', async () => { + const { instance } = await setupComponent({ + componentize: { + src: ` + import { now } from 'wasi:clocks/wall-clock@0.2.3'; + import { getRandomBytes } from 'wasi:random/random@0.2.3'; + + let result; + export const run = { + run () { + result = \`NOW: \${now().seconds}, RANDOM: \${getRandomBytes(2n)}\`; + return { tag: 'ok' }; + } + }; + + export const getResult = () => result; + `, + opts: { + witPath: fileURLToPath(new URL('./wit', import.meta.url)), + worldName: 'test1', + debugBuild: DEBUG_TEST_ENABLED, + }, + }, + transpile: { + opts: { + tracing: DEBUG_TRACING_ENABLED, + }, + }, + }); + + instance.run.run(); + + const result = instance.getResult(); + + assert.strictEqual( + result.slice(0, 10), + `NOW: ${String(Date.now()).slice(0, 5)}`, + ); + assert.strictEqual(result.split(',').length, 3); + }); + + test('basic app (OriginalSourceFile API)', async () => { + const { instance } = await setupComponent({ + componentize: { + opts: { + sourcePath: './test/api/index.js', + witPath: fileURLToPath(new URL('./wit', import.meta.url)), + worldName: 'test1', + debugBuild: DEBUG_TEST_ENABLED, + }, + }, + transpile: { + opts: { + tracing: DEBUG_TRACING_ENABLED, + }, + }, + }); + + instance.run.run(); + + const result = instance.getResult(); + + assert.strictEqual( + result.slice(0, 10), + `NOW: ${String(Date.now()).slice(0, 5)}`, + ); + assert.strictEqual(result.split(',').length, 3); + }); +}); + diff --git a/test/wit/test1.wit b/test/wit/test1.wit index 0b540de6..a844374c 100644 --- a/test/wit/test1.wit +++ b/test/wit/test1.wit @@ -64,3 +64,10 @@ world test2 { export get-result: func() -> string; } + +world test3 { + import wasi:cli/environment@0.2.3; + import wasi:http/types@0.2.3; + + export wasi:http/incoming-handler@0.2.3; +} diff --git a/types.d.ts b/types.d.ts index f43af3b3..296db2e0 100644 --- a/types.d.ts +++ b/types.d.ts @@ -4,68 +4,75 @@ interface ComponentizeOptions { * * This file must be a valid JavaScript module, and can import other modules using relative paths. */ - sourcePath: string, + sourcePath: string; /** - * Use a debug build - * Note that the debug build only includes the names section only for size optimization, and not DWARF - * debugging sections, due to a lack of support in Node.js for these debugging workflows currently. - */ - debugBuild?: boolean, - /** - * Path to custom ComponentizeJS engine build to use + * Path to WIT file or folder */ - engine?: string, + witPath?: string; /** - * Path to custom weval cache to use + * Target world name for componentization */ - aotCache?: string, + worldName?: string; /** - * Enable AoT using weval + * Path to custom ComponentizeJS engine build to use */ - enableAot?: boolean, + engine?: string; /** - * Use a pre-existing path to the `weval` binary, if present + * Use a pre-existing path to the `wizer` binary, if present */ - wevalBin?: string, + wizerBin?: string; /** * Path to custom Preview2 Adapter */ - preview2Adapter?: string, - /** - * Path to WIT file or folder - */ - witPath?: string, - /** - * Target world name for componentization - */ - worldName?: string, + preview2Adapter?: string; /** * Disable WASI features in the base engine * Disabling all features results in a pure component with no WASI dependence - * + * * - stdio: console.log(), console.error and errors are provided to stderr * - random: Math.random() and crypto.randomBytes() * - clocks: Date.now(), performance.now() * - http: fetch() support - * + * */ - disableFeatures?: ('stdio' | 'random' | 'clocks' | 'http')[], + disableFeatures?: ('stdio' | 'random' | 'clocks' | 'http' | 'fetch-event')[]; /** * Enable WASI features in the base engine * (no experimental subsystems currently supported) */ - enableFeatures?: [], + enableFeatures?: []; /** - * Pass environment variables to the spawned Wizer or Weval Process + * Pass environment variables to the spawned Wizer Process * If set to true, all host environment variables are passed * To pass only a subset, provide an object with the desired variables */ - env?: boolean | Record, + env?: boolean | Record; /** * Runtime arguments to provide to the StarlingMonkey engine initialization * (see https://github.com/bytecodealliance/StarlingMonkey/blob/main/include/config-parser.h) */ - runtimeArgs?: string, + runtimeArgs?: string; + /** + * Use a debug build + * Note that the debug build only includes the names section only for size optimization, and not DWARF + * debugging sections, due to a lack of support in Node.js for these debugging workflows currently. + */ + debugBuild?: boolean; + /** + * Debug options + */ + debug?: { + /** Whether to enable bindings-specific debugging */ + bindings?: boolean; + /** Path to debug bindings to use */ + bindingsDir?: string; + /** Whether to enable binary-specific debugging */ + binary?: boolean; + /** Path to the binary that was output */ + binaryPath?: string; + /** Whether to enable wizer logging */ + wizerLogging: false; + }; } /** @@ -73,7 +80,9 @@ interface ComponentizeOptions { * * @param opts Componentize options */ -export function componentize(opts: ComponentizeOptions): Promise +export function componentize( + opts: ComponentizeOptions, +): Promise; /** * @deprecated Use `componentize(opts)` instead @@ -81,7 +90,10 @@ export function componentize(opts: ComponentizeOptions): Promise +export function componentize( + source: string, + opts: ComponentizeOptions, +): Promise; /** * @deprecated Use `componentize(opts)` instead @@ -90,20 +102,37 @@ export function componentize(source: string, opts: ComponentizeOptions): Promise * @param witWorld Inline WIT string to componentize to * @param opts Componentize options */ -export function componentize(source: string, witWorld: string, opts?: ComponentizeOptions): Promise +export function componentize( + source: string, + witWorld: string, + opts?: ComponentizeOptions, +): Promise; interface ComponentizeOutput { /** * Component binary */ - component: Uint8Array, + component: Uint8Array; /** * Used guest imports in JavaScript (excluding those from StarlingMonkey engine) */ - imports: [[string, string]][] + imports: [[string, string]][]; + /** + * Debugging output (only present if enabled) + */ + debug?: { + /** Whether bindings debugging was enabled */ + bindings?: boolean; + /** Work directory used during processing */ + workDir?: string; + /** Whether binary debugging was enabled */ + binary?: boolean; + /** Path to the produced binary */ + binaryPath?: string; + }; } /** * ComponentizeJS version string */ -export const version: string \ No newline at end of file +export const version: string;